redis性能测试

redis-benchmark是随着redis安装,官方自带的一个redis性能测试工具

性能测试工具参数列表

参数

描述

默认值

-h

指定测试主机地址

127.0.0.1

-p

指定被测服务器端口

6379

-s

指定服务器socket

-c

指定并发连接数

50

-n

指定请求数

10000

-d

以字节的形式指定set/get值数据大小

2

-k

1=keep alive 0=reconnect

1

-r

set/get/incr 使用随机key,sadd使用随机值

-P

通过管道传输请求

1

-q

强制退出redis。仅显示query/sec值

–csv

以csv格式输出

-l(L小写)

生成循环,永久执行测试

-t

仅运行以逗号分隔的测试命令列表

-I(i大写)

Idle模式。仅打开n个Idle连接并等待

测试100并发,10,0000条请求

redis-benchmark -c 100 -n 100000

测试解读

====== GET ======                                                   
  100000 requests completed in 1.41 seconds #在1.41秒内处理完成100000个请求
  100 parallel clients #100个并发客户端发起请求
  3 bytes payload #每次传输3个字节的数据
  keep alive: 1  #保持一台服务器在线处理请求
  host configuration "save": 3600 1 300 100 60 10000
  host configuration "appendonly": no
  multi-thread: no

Latency by percentile distribution:  
0.000% <= 0.471 milliseconds (cumulative count 1)
50.000% <= 1.031 milliseconds (cumulative count 50963) #在1.031秒的时候完成50%的请求,已处理请求数量50963
75.000% <= 1.247 milliseconds (cumulative count 75531)
87.500% <= 1.415 milliseconds (cumulative count 87734)
93.750% <= 1.575 milliseconds (cumulative count 93767)
96.875% <= 1.735 milliseconds (cumulative count 96968)
98.438% <= 1.887 milliseconds (cumulative count 98449)
99.219% <= 2.023 milliseconds (cumulative count 99233)
99.609% <= 2.167 milliseconds (cumulative count 99617)
99.805% <= 2.287 milliseconds (cumulative count 99808)
99.902% <= 2.383 milliseconds (cumulative count 99905)
99.951% <= 2.503 milliseconds (cumulative count 99952)
99.976% <= 2.647 milliseconds (cumulative count 99976)
99.988% <= 2.799 milliseconds (cumulative count 99988)
99.994% <= 2.871 milliseconds (cumulative count 99994)
99.997% <= 2.903 milliseconds (cumulative count 99997)
99.998% <= 2.927 milliseconds (cumulative count 99999)
99.999% <= 2.943 milliseconds (cumulative count 100000)
100.000% <= 2.943 milliseconds (cumulative count 100000)

Cumulative distribution of latencies:
0.000% <= 0.103 milliseconds (cumulative count 0)
0.094% <= 0.503 milliseconds (cumulative count 94)
3.190% <= 0.607 milliseconds (cumulative count 3190)
10.049% <= 0.703 milliseconds (cumulative count 10049)
21.096% <= 0.807 milliseconds (cumulative count 21096)
33.435% <= 0.903 milliseconds (cumulative count 33435)
47.700% <= 1.007 milliseconds (cumulative count 47700)
60.244% <= 1.103 milliseconds (cumulative count 60244)
71.778% <= 1.207 milliseconds (cumulative count 71778)
80.330% <= 1.303 milliseconds (cumulative count 80330)
87.321% <= 1.407 milliseconds (cumulative count 87321)
91.495% <= 1.503 milliseconds (cumulative count 91495)
94.587% <= 1.607 milliseconds (cumulative count 94587)
96.487% <= 1.703 milliseconds (cumulative count 96487)
97.791% <= 1.807 milliseconds (cumulative count 97791)
98.555% <= 1.903 milliseconds (cumulative count 98555)
99.165% <= 2.007 milliseconds (cumulative count 99165)
99.472% <= 2.103 milliseconds (cumulative count 99472)
100.000% <= 3.103 milliseconds (cumulative count 100000)

Summary:
  throughput summary: 70771.41 requests per second #每秒钟处理70771.41个请求
  latency summary (msec):
          avg       min       p50       p95       p99       max
        1.064     0.464     1.031     1.631     1.983     2.943

基础知识

redis默认有16个数据库,默认使用第0个数据库,redis可以用作数据库、缓存、和队列

  1. 使用命令select切换数据库
  2. dbsize显示当前数据库大小(也就是当前选中的数据库存在多少个key)
  3. keys *查看当前数据库所有的key
  4. flushall清空所有的数据库
  5. flushdb清空当前数据库

redis5以及之前的版本都是单线程的,redis6以及之后的版本开始支持多线程。redis不受cpu瓶颈限制,性能关乎网络带宽和内存

关于Key的基本命令

判断某个键是否存在

127.0.0.1:6379> exists age
(integer) 1
127.0.0.1:6379> exists age1
(integer) 0

移动某个键到指定的数据库

127.0.0.1:6379> move age 1
# 1表示指定的数据库index
(integer) 1

删除键

del key

设置过期时间

为一个键设置过期时间,时间一到,该键自动过期无法再获得

  1. expire 键 过期时间(秒)
  2. ttl 键名查看该键的距离过期还剩余的时间

查看键的类型

type 键名

五大数据类型

String类型

redis中的字符串类型可以动态进行修改,可以使用追加命令在字符串值的后面直接追加内容。返回追加之后的字符串长度

127.0.0.1:6379> set k1 v1
OK
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> keys *
1) "k1"
2) "name"
127.0.0.1:6379> exists k1
(integer) 1
127.0.0.1:6379> append k1 zhong
(integer) 7
127.0.0.1:6379> get k1
"v1zhong"

strlen key获取字符串长度

127.0.0.1:6379> strlen k1
(integer) 7

append key value如果过追加的key不存在就相当于直接set一个key

自增和自减

incr key 让键自增1,decr key让键自减1

127.0.0.1:6379> set views 0
OK
127.0.0.1:6379> get views
"0"
127.0.0.1:6379> incr views
(integer) 1
127.0.0.1:6379> get views
"1"
127.0.0.1:6379> get views
"1"
127.0.0.1:6379> decr view
(integer) 0

incrby key stepdecrby key step指定步长的自增和自减,指定的步长只会在本条命令下生效,不会影响其他的命令的步长

127.0.0.1:6379> incrby views 10
(integer) 11
127.0.0.1:6379> incr views
(integer) 12
127.0.0.1:6379> decrby views 10
(integer) 2

查看字符串指定范围

getrange key start end可以查看一个字符串的指定范围,也就是某一个字符的下标到某一个字符的下标(闭区间),end位如果是**-1**就表示一直到这个字符串的末尾。

127.0.0.1:6379> set k1 hello
OK
127.0.0.1:6379> get k1
"hello"
127.0.0.1:6379> getrange k1 0 3
"hell"
127.0.0.1:6379> getrange k1 0 -1
"hello"

替换字符串指定位置的字符

可以通过setrange key offset value命令替换字符串中指定起始下标的字符。

127.0.0.1:6379> set k2 abcdefg
OK
127.0.0.1:6379> get k2
"abcdefg"
127.0.0.1:6379> setrange k2 1 xx #替换该字符串中下标为1以及之后的字符,指定替换内容为xx,类似于insert模式
(integer) 7
127.0.0.1:6379> get k2
"axxdefg"
127.0.0.1:6379>

设置键的同时指定过期时间

通过setex key seconde value新建键的同时为这个键设置过期时间。

127.0.0.1:6379> setex k3 30 zhong
OK
127.0.0.1:6379> ttl k3
(integer) 27
127.0.0.1:6379> ttl k3
(integer) -2
127.0.0.1:6379> get k3
(nil)

不存在的情况下新建键

在新建一个键的同时判断是否存在同名的键,存在同名的键则不会执行新建操作,也就是说不会出现覆盖原来的value的情况

127.0.0.1:6379> setnx k3 zhong
(integer) 1
127.0.0.1:6379> setnx k3 zhong2
(integer) 0
127.0.0.1:6379> get k3
"zhong"

批量获取值和设置值

通过msetmget批量设置和获取值

127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3
OK
127.0.0.1:6379> mget k1 k2 k3
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> keys *
1) "k2"
2) "k1"
3) "k3"

msetnx

redis的事务可以不是原子性操作,但是命令msetnx是一个原子性操作,他批量设置的值一起成功或者一起失败

127.0.0.1:6379> keys *
1) "k2"
2) "k1"
3) "k3"
127.0.0.1:6379> msetnx k1 v1 k4 v4
(integer) 0
127.0.0.1:6379> get k4
(nil)

可以看见新建键k4失败了,是因为k1键已经存在了,导致了整个命令都会失败

redis key 命名规范 键名称中的冒号 : 命名空间层次的表示

redis由于是kv键值对的方式存储数据,那对于一些有关系的某一类的数据直接存储会显得比较杂乱,于是出现这种key的命名规范(使用:表示层次,称作命名空间),这种key的命名方式能够让人一眼就能看出哪些key之间是存在联系的。但是redis本身是没有对冒号:做任何特殊处理的,类似这样使用命名空间的key会被整个当成string处理,也就是说key的名字就是keyname:name1:name2。通过keys *可以清楚的看出这一点

127.0.0.1:6379> set user:1:name zhong
OK
127.0.0.1:6379> set user:1:age 2
OK
127.0.0.1:6379> keys *
1) "user:1:age"
2) "k2"
3) "user:1:name"
4) "k1"
5) "k3"

组合命令

在redis中存在组合式的命令,例如getset key value,redis会先取该键的值然后再对该键写入新的value

list

list可以被用作栈和队列,所有的list命令都以字母l开头

添加元素

命令lpush key value添加元素。lpush的全程是left-push(左插入,头插法),可以把list想象成一个左右开口的队列,我们既可以从左边插入元素(也就是头),也可以从右边插入元素(也就是尾)。

127.0.0.1:6379>  lpush list 1
(integer) 1

rpush key value的全称是right-push(右插入,尾插法)

127.0.0.1:6379> rpush list 4
(integer) 5
127.0.0.1:6379> lrange list 0 -1
1) "3"
2) "2"
3) "1"
4) "0"
5) "4"

获取指定下标范围的value

lrange key start end,因为lpush类似于入栈操作,于是最后一个入栈的元素下标才为0

127.0.0.1:6379> lrange list 0 -1
1) "3"
2) "2"
3) "1"

弹出元素

命令lpop key rpop key左弹出元素和右弹出元素

127.0.0.1:6379> lpop list 
"3"
127.0.0.1:6379> rpop list
"4"

获取指定下标的元素

lindex key index

127.0.0.1:6379> lindex list 1
"1"

获取list的长度

llen key返回列表的长度

127.0.0.1:6379> llen list
(integer) 3

移除指定元素

lrem key count value可以指定移除某个元素并且可以移除多个

127.0.0.1:6379> lpush list 1
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "2"
3) "1"
4) "0"
127.0.0.1:6379> lrem list 2 1 #移除2次元素“1”
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "2"
2) "0"

截取指定区间的元素

ltrim key strat end 截取指定区间的元素,该明令会保留指定区间中的元素,不在区间中的元素会被删除

127.0.0.1:6379> lpush list hello hello1 hello2 hello3 
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "hello3"
2) "hello2"
3) "hello1"
4) "hello"
127.0.0.1:6379> ltrim list 1 2
OK
127.0.0.1:6379> lrange list 0 -1
1) "hello2"
2) "hello1"

组合命令rpoplpush

rpoplpush key1 key2 可以将一个list中的元素又弹出并且左压入一个新的list

127.0.0.1:6379> lrange list 0 -1
1) "hello2"
2) "hello1"
127.0.0.1:6379> rpoplpush list list2
"hello1"
127.0.0.1:6379> rpoplpush list list2
"hello2"
127.0.0.1:6379> rpoplpush list2 list2
"hello1"

lset

lset key index value 命令可以更新list中指定下标位置的元素,前提是,这个list已经被创建出来了,并且对应被更新下标的值存在。

插入语句

linsert key before|after value value可以指定插入到list中某个元素的前后

127.0.0.1:6379> lrange list2 0 -1
1) "hello1"
2) "hello2"
127.0.0.1:6379> linsert list2 before "hello2" "i" 
(integer) 3
127.0.0.1:6379> lrange list2 0 -1
1) "hello1"
2) "i"
3) "hello2"

set(集合)

set中的value是不会重复的

添加元素

sadd key value

127.0.0.1:6379> sadd set hello
(integer) 1
127.0.0.1:6379> sadd set hello1 hello2 hello3
(integer) 3

查看集合中的元素

smembers key

127.0.0.1:6379> smembers set
1) "hello2"
2) "hello"
3) "hello3"
4) "hello1"

判断某个元素是否存在集合中

sismember key value

127.0.0.1:6379> sismember set hello
(integer) 1
127.0.0.1:6379> sismember set hello6
(integer) 0

获取set长度

scard key

127.0.0.1:6379> scard set
(integer) 4

移除集合中的某个元素

srem key value

127.0.0.1:6379> smembers set
1) "hello"
2) "hello2"
3) "hello1"
4) "hello3"
127.0.0.1:6379> srem set hello3
(integer) 1
127.0.0.1:6379> smembers set
1) "hello"
2) "hello2"
3) "hello1"

随机给出某个set中的元素

srandmembers key [随机给出的元素个数]

127.0.0.1:6379> srandmember set
"hello"
127.0.0.1:6379> srandmember set
"hello1"

随机弹出元素

由于set是无序集合,于是弹出元素也是随机的spop key

127.0.0.1:6379> spop set
"hello1"

移动set元素

将一个set中的某个值移动到另一个set中smove source 目标set value

127.0.0.1:6379> sadd set1 hello hello1 hello2
(integer) 3
127.0.0.1:6379> sadd set2 zhong
(integer) 1
127.0.0.1:6379> smove set1 set2 hello
(integer) 1
127.0.0.1:6379> smembers set1
1) "hello2"
2) "hello1"
127.0.0.1:6379> smembers set2
1) "hello"
2) "zhong"

集合之间的运算

差集

sdiff key key

127.0.0.1:6379> sadd set1 a b c
(integer) 3
127.0.0.1:6379> sadd set2 c d e
(integer) 3
127.0.0.1:6379> sdiff set1 set2
1) "a"
2) "b"
并集

sinter key key

127.0.0.1:6379> sunion set1 set2
1) "e"
2) "b"
3) "c"
4) "a"
5) "d"
交集

sunion key key

127.0.0.1:6379> sinter set1 set2
1) "c"

Hash

哈希类型类似map类型,或者说像json类型,在redis中普遍都是kv键值对,但是hash类型的值也是一种键值对。key这样的类型

添加元素

hset key field value,在hash类中存在字段这个概念,我们需要通过具体的字段名来找到一个值。同时这个命令本身也支持同时存储多个字段

127.0.0.1:6379> hset hash field zhong
(integer) 1

获取元素

hget key field我们需要知道获取哪个hash的的具体哪一个字段

127.0.0.1:6379> hget hash field
"zhong"

批量获取

hmget key field...批量获取多个字段中的值

127.0.0.1:6379> hmget hash field1 field2 field3
1) "1"
2) "2"
3) "3"

获取所有字段

获取所有的字段和值

127.0.0.1:6379> hgetall hash
1) "field1"
2) "1"
3) "field2"
4) "2"
5) "field3"
6) "3"

删除字段

hdel key field删除字段

127.0.0.1:6379> hdel hash field3
(integer) 1

获取长度

127.0.0.1:6379> hlen hash
(integer) 2

只获取所有字段或者值

127.0.0.1:6379> hkeys hash
1) "field1"
2) "field2"
127.0.0.1:6379> hvals hash
1) "1"
2) "2"

自增和自减

127.0.0.1:6379> hincrby hash field1 5
(integer) 6
127.0.0.1:6379> hincrby hash field1 -1
(integer) 5

存在创建

当字段不存在才会创建值

127.0.0.1:6379> hsetnx hash field1 2
(integer) 0

Zset(有序集合)

保证了元素的唯一性,并且通过设置score字段将集合内的元素排序。这个字段本身并不属于key或者value,它只是标记了该key

添加元素

127.0.0.1:6379> zadd zset 1 one
(integer) 1
127.0.0.1:6379> zadd zset 2 two 3 three
(integer) 1

获取zset内的元素

127.0.0.1:6379> zrange zset 0 -1
1) "one"
2) "two"
3) "three"

通过排序获取元素

通过这种排序获得的元素始终现实为升序

127.0.0.1:6379> zrangebyscore salary -inf +inf
1) "ming"
2) "zhong"
3) "zhang"

降序命令

127.0.0.1:6379> zrevrangebyscore salary +inf -inf
1) "zhang"
2) "zhong"
3) "ming"

参数withscores,同时现实score字段值

127.0.0.1:6379> zrangebyscore salary -inf +inf withscores
1) "ming"
2) "2000"
3) "zhong"
4) "2000"
5) "zhang"
6) "5000"

移除元素

127.0.0.1:6379> zrem salary ming
(integer) 1
127.0.0.1:6379> zrangebyscore salary -inf +inf withscores
1) "zhong"
2) "2000"
3) "zhang"
4) "5000"

获取有序集合中的个数

127.0.0.1:6379> zcard salary
(integer) 2

获取指定区间的成员数量

指定区间是通过score表示

127.0.0.1:6379> zadd set 1 zhong 2 zhang 3 hello
(integer) 3
127.0.0.1:6379> zcount set 1 2 #表示获取score在1到2中的元素
(integer) 2