redis
性能测试
**redis-benchmark:**Redis官方提供的性能测试工具,参数选项如下:
redis-benchmark -h localhost -p 6379 -c 100 -n 100000
使用该命令对性能进行测试
基础知识说明
redis默认使用的是第一个数据库,共有16个数据库可以使用通过配置文件可以进行查看。
基本命令
ping #测试数据库是否联通
select index 选择使用第几个数据库
dbsize 查看数据库的空间
set key value #向对应的数据库中存值
get name #在对应的数据库中取出指定的值
keys * 查看数据库中所有的键
对16个数据库中存放值的操作都是相对独立的可以通过切换数据库来实现。
flushdb 清空当前的数据库
flushall 清空所有的数据库
redis是单线程的 表明redis是很快的redis是基于内存操作的,cpu不是redis性能瓶颈,redis瓶颈是内存和网络的带宽
那么为什么Redis的速度如此快呢,性能这么高呢?QPS达到10W+
Redis为什么单线程还这么快?
- 误区1:高性能的服务器一定是多线程的?
- 误区2:多线程(CPU上下文会切换!)一定比单线程效率高!
核心:Redis是将所有的数据放在内存中的,所以说使用单线程去操作效率就是最高的,多线程(CPU上下文会切换:耗时的操作!),对于内存系统来说,如果没有上下文切换效率就是最高的,多次读写都是在一个CPU上的,在内存存储数据情况下,单线程就是最佳的方案。
五大数据类型
Redis是一个开源(BSD许可),内存存储的数据结构服务器,可用作数据库,高速缓存和消息队列代理。它支持字符串、哈希表、列表、集合、有序集合,位图,hyperloglogs等数据类型。内置复制、Lua脚本、LRU收回、事务以及不同级别磁盘持久化功能,同时通过Redis Sentinel提供高可用,通过Redis Cluster提供自动分区。
Redis key操作
下面学习的命令:
exists key :判断键是否存在del key :删除键值对move key db :将键值对移动到指定数据库expire key second :设置键值对的过期时间type key :查看value的数据类型
127.0.0.1:6379[3]> set name chenrxu
OK
127.0.0.1:6379[3]> keys *
1) "name"
127.0.0.1:6379[3]> type name
string
127.0.0.1:6379[3]> exists name
(integer) 1
127.0.0.1:6379[3]> move name select 3
(error) ERR wrong number of arguments for 'move' command
127.0.0.1:6379[3]> move name db3
(error) ERR index out of range
127.0.0.1:6379[3]> move name db
(error) ERR index out of range
127.0.0.1:6379[3]> move name 3
(error) ERR source and destination objects are the same
127.0.0.1:6379[3]> keys *
1) "name"
127.0.0.1:6379[3]> move name 1
(integer) 1
127.0.0.1:6379[3]> keys *
(empty list or set)
127.0.0.1:6379[3]> select 1
OK
127.0.0.1:6379[1]> keys *
1) "name"
127.0.0.1:6379[1]> get name
"chenrxu"
127.0.0.1:6379[1]> expire name 20
(integer) 1
127.0.0.1:6379[1]> ttl name
(integer) 17
127.0.0.1:6379[1]> ttl name
(integer) 15
127.0.0.1:6379[1]> ttl name
(integer) 14
127.0.0.1:6379[1]> ttl name
(integer) 11
127.0.0.1:6379[1]> ttl name
(integer) -2
127.0.0.1:6379[1]> keys *
String
APPEND key value : 向指定的key的value后追加字符串
127.0.0.1:6379> set msg hello
OK
127.0.0.1:6379> append msg " world"
(integer) 11
127.0.0.1:6379> get msg
“hello world”
DECR/INCR key : 将指定key的value数值进行+1/-1(仅对于数字)
127.0.0.1:6379> set age 20
OK
127.0.0.1:6379> incr age
(integer) 21
127.0.0.1:6379> decr age
(integer) 20
INCRBY/DECRBY key n : 按指定的步长对数值进行加减
127.0.0.1:6379> INCRBY age 5
(integer) 25
127.0.0.1:6379> DECRBY age 10
(integer) 15
setrange key index n:修改指定位置的值的元素
127.0.0.1:6379> set key2 abcdefg OK 127.0.0.1:6379> setrange key2 1 xx (integer) 7 127.0.0.1:6379> get key2 “axxdefg”
setex key3 30 123
setnx mykey hello
27.0.0.1:6379> set mykey “redis” OK 127.0.0.1:6379> setex mykey 30 “redis” OK 127.0.0.1:6379> ttl mykey (integer) 25 127.0.0.1:6379> ttl mykey (integer) 23 127.0.0.1:6379> ttl mykey (integer) 20 127.0.0.1:6379> ttl mykey (integer) 4 127.0.0.1:6379> ttl mykey (integer) -2 127.0.0.1:6379> setnx mykey “mysql”
MSET key1 value1 [key2 value2..] : 批量set键值对
127.0.0.1:6379> MSET k1 v1 k2 v2 k3 v3
OK
MSETNX key1 value1 [key2 value2..] : 批量设置键值对,仅当参数中所有的key都不存在时执行
127.0.0.1:6379> MSETNX k1 v1 k4 v4
(integer) 0
MGET key1 [key2..] : 批量获取多个key保存的值
127.0.0.1:6379> MGET k1 k2 k3
1) “v1”
2) “v2”
3) “v3”
组合命令 get set命令如果不存在值则返回null如果存在值就先get 在set
String类似的使用场景:value除了是字符串还可以是数字,用途举例:
- 计数器
- 统计多单位的数量:uid:123666:follow 0
- 粉丝数
- 对象存储缓存
List
所有的list命令都是以l开头的
Redis列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)
一个列表最多可以包含 232 - 1 个元素 (4294967295, 每个列表超过40亿个元素)。
首先我们列表,可以经过规则定义将其变为队列、栈、双端队列等。
Lpush:将一个值或者多个值插入到列表的额头部
LPUSH/RPUSH key value1[value2..] 从左边/右边向列表中PUSH值(一个或者多个)。LRANGE key start end 获取list 起止元素==(索引从左往右 递增)==
27.0.0.1:6379> lpush list one
(integer) 1
127.0.0.1:6379> lpush list two
(integer) 2
127.0.0.1:6379> lpush list three
(integer) 3
127.0.0.1:6379> lrange list 0 0
1) "three"
127.0.0.1:6379> lrange list -1 -1
1) "one"
127.0.0.1:6379> lrange list 0 2
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> lrange list -1 2
1) "one"
127.0.0.1:6379> lrange list -1 1
(empty list or set)
127.0.0.1:6379> lrange list 0 3
1) "three"
2) "two"
3) "one"
lpop list *#从左边移除值* rpop list *#从右边移除值 *
整个列表的操作类似于python中的列表元素,类似于数据结构中的双端队列或者入栈和出栈的操作
127.0.0.1:6379> lrange list 0 -1
1) "four"
2) "three"
3) "two"
4) "one"
5) "test"
127.0.0.1:6379> lpop list
"four"
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "test"
127.0.0.1:6379> rpop list
"test"
127.0.0.1:6379> rpop list 0 1
lindex获取指定元素的列表的下标
127.0.0.1:6379> lindex list 0
"three"
127.0.0.1:6379> lindex list 1
"two"
127.0.0.1:6379> lindex list 2
"one"
127.0.0.1:6379> lindex list 3
(nil)
Llen # 获取列表的长度
127.0.0.1:6379> llen list
(integer) 3
使用lrem移除指定元素的值
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
4) "three"
5) "three"
6) "three"
7) "three"
127.0.0.1:6379> lrem list 1 three
(integer) 1
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
3) "three"
4) "three"
5) "three"
6) "three"
127.0.0.1:6379> lrem list 3 three
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
3) "three"
LTRIM key start end 通过下标截取指定范围内的列表
127.0.0.1:6379> ltrim list 0 1
OK
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
127.0.0.1:6379>
RPOPLPUSH source destination 将列表的尾部(右)最后一个值弹出,并返回,然后加到另一个列表的头部
127.0.0.1:6379> rpoplpush list mylist
"one"
127.0.0.1:6379> keys *
1) "list"
2) "mylist"
127.0.0.1:6379> lrange mylist 0 -1
1) "one"
127.0.0.1:6379>
127.0.0.1:6379> lrange mylist 0 -1
1) "one"
127.0.0.1:6379> lpush mylist text
(integer) 2
127.0.0.1:6379> lrange mylist 0 -1
1) "text"
2) "one"
127.0.0.1:6379> lset mylist 0 second
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "second"
2) "one"
127.0.0.1:6379>
- 使用linsert命令向列表的某个指定元素的前面或者后面插入指定的元素
127.0.0.1:6379> lrange mylist 0 -1
1) "second"
2) "one"
127.0.0.1:6379> linsert mylist before one other
(integer) 3
127.0.0.1:6379> lrange mylist 0 -1
1) "second"
2) "other"
3) "one"
127.0.0.1:6379>
- list实际上是一个链表,before Node after , left, right 都可以插入值
- 如果key不存在,则创建新的链表
- 如果key存在,新增内容
- 如果移除了所有值,空链表,也代表不存在
- 在两边插入或者改动值,效率最高!修改中间元素,效率相对较低
set
set 集合中不允许存在相同的元素,大都数的命令都以s进行开头的。
127.0.0.1:6379> sadd set "chen"
(integer) 1
127.0.0.1:6379> sadd set ru
(integer) 1
127.0.0.1:6379> sadd set xu
(integer) 1
127.0.0.1:6379> smembers set
1) "chen"
2) "ru"
3) "xu"
SISMEMBER key member 查询member元素是否是集合的成员,结果是无序的
127.0.0.1:6379> sismember set chen
(integer) 1
127.0.0.1:6379> scard set
(integer) 3
SREM key member1[member2..] 移除集合中一个/多个成员
127.0.0.1:6379> smembers set
1) "chen"
2) "ru"
3) "xu"
127.0.0.1:6379> srem set "chen" "ru"
(integer) 2
127.0.0.1:6379> smembers set
1) "xu"
srandmember key随机的抽选出一个元素
127.0.0.1:6379> srandmember set
"xu"
- 随机删除一个指定的set集合中的一个元素使用spop命令
127.0.0.1:6379> sadd set chen
(integer) 1
127.0.0.1:6379> sadd set ru
(integer) 1
127.0.0.1:6379> sadd set xu
(integer) 0
127.0.0.1:6379> smembers set
1) "chen"
2) "ru"
3) "xu"
127.0.0.1:6379> spop set
"xu"
127.0.0.1:6379> smembers set
1) "chen"
2) "ru"
127.0.0.1:6379> spop set
"chen"
127.0.0.1:6379> smembers set
1) "ru"
SMOVE source destination member 将source集合的成员member移动到destination集合
127.0.0.1:6379> sadd set chen
(integer) 1
127.0.0.1:6379> smove set set2 "chen"
(integer) 1
127.0.0.1:6379> smembers set2
1) "chen"
2) "test"
127.0.0.1:6379>
set集合中的数集的运算
SDIFF key1[key2..] 返回所有集合的差集 key1- key2 -
127.0.0.1:6379> sadd set1 x
(integer) 1
127.0.0.1:6379> sadd set1 y
(integer) 1
127.0.0.1:6379> sadd set1 z
(integer) 1
127.0.0.1:6379> sadd set2 y
(integer) 1
127.0.0.1:6379> sadd set2 z
(integer) 1
127.0.0.1:6379> sdiff set1 set2
1) "x"
SINTER key1 [key2..] 返回所有集合的交集
127.0.0.1:6379> sinter set1 set2
1) "y"
2) "z"
SUNION key1 [key2..] 返回所有集合的并集
127.0.0.1:6379> sunion set1 set2
1) "y"
2) "x"
3) "z"
Hash(哈希 key value)
map集合,key-map 时候这个值是一个map集合
Redis hash 是一个string类型的field和value的映射表,hash特别适合用于存储对象。
Set就是一种简化的Hash,只变动key,而value使用默认值填充。可以将一个Hash表作为一个对象进行存储,表中存放对象的信息。
-
HSET key field value 将哈希表 key 中的字段 field 的值设为 value 。重复设置同一个field会覆盖,返回0
127.0.0.1:6379> hset myhash field1 chenruxu (integer) 1
-
HMSET key field1 value1 [field2 value2..] 同时将多个 field-value (域-值)对设置到哈希表 key 中。
127.0.0.1:6379> hmset myhash field2 hello field world OK
-
HGET key field value 获取存储在哈希表中指定字段的值
127.0.0.1:6379> hget myhash field1 “chenruxu”
-
HMGET key field1 [field2..] 获取所有给定字段的值
127.0.0.1:6379> hmget myhash field2 field
- “hello”
- “world”
127.0.0.1:6379> hmget myhash field2 field field1 - “hello”
- “world”
- “chenruxu”
127.0.0.1:6379>
-
hgetall获取hash中的所有的值
127.0.0.1:6379> hgetall myhash
- “field1”
- “chenruxu”
- “field2”
- “hello”
- “field”
- “world”
-
HDEL key field1 [field2..] 删除哈希表key中一个/多个field字段
127.0.0.1:6379> hgetall myhash
1) "field1"
2) "chenruxu"
3) "name"
4) "chenruxu"
127.0.0.1:6379> hdel myhash name
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "field1"
2) "chenruxu"
127.0.0.1:6379>
Hash变更的数据user name age,尤其是用户信息之类的,经常变动的信息!Hash更适合于对象的存储,Sring更加适合字符串存储!
zset(有序数据集合)
不同的是每个元素都会关联一个double类型的分数(score)。redis正是通过分数来为集合中的成员进行从小到大的排序。
score相同:按字典顺序排序
有序集合的成员是唯一的,但分数(score)却可以重复。
在set的基础上增加了一个值 set k1 v1 zset k1 score v1
ZADD key score member1 [score2 member2] 向有序集合添加一个或多个成员,或者更新已存在成员的分数
127.0.0.1:6379> zadd myset 1 one (integer) 1 127.0.0.1:6379> zdd myset 2 two (error) ERR unknown command zdd , with args beginning with: myset , 2 , two , 127.0.0.1:6379> zadd myset 2 two (integer) 1 127.0.0.1:6379> zadd myset 3 three (integer) 1
ZRANGEBYSCORE key min max 通过分数返回有序集合指定区间内的成员==-inf 和 +inf分别表示最小最大值,只支持开区间
127.0.0.1:6379> zrangebyscore myset -inf +inf
- “one”
- “two”
- “three”
127.0.0.1:6379> zrangebyscore myset -inf +inf withscores
- “one”
- “1”
- “two”
- “2”
- “three”
- “3”
ZRANGE key start end 通过索引区间返回有序集合成指定区间内的成员
127.0.0.1:6379> zrange myset 0 -1
- “one”
- “two”
- “three”
ZREM key member1 [member2..] 移除有序集合中一个/多个成员(移除有序集合中的元素值)
127.0.0.1:6379> zrem myset one (integer) 1 127.0.0.1:6379> zrange myset 0 -1
- “two”
- “three”
127.0.0.1:6379> zcard myset (integer) 2 127.0.0.1:6379>
ZCOUNT key min max 计算在有序集合中指定区间score的成员数(获取指定区间的成员的数量)
127.0.0.1:6379> zcount myset -inf +inf (integer) 2
127.0.0.1:6379> zcount myset 1 2 (integer) 1 127.0.0.1:6379> zcount myset 1 3 (integer) 2
应用案例:
- set排序 存储班级成绩表 工资表排序!
- 普通消息,1.重要消息 2.带权重进行判断
- 排行榜应用实现,取Top N测试
|