redis使用详解

  1. 云栖社区>
  2. 博客>
  3. 正文

redis使用详解

技术小胖子 2017-11-08 17:30:00 浏览1166
展开阅读全文

循例介绍一下了,redis是内存数据库,是简单的key-value结构,也是nosql数据库,因为结构简单,而且用的是内存,所以速度非常之快.至于问有多快?大家知道以前的机械硬盘,单盘速度其实也还好,而内存的读写速度是机械硬盘的6万倍.所以,redis比硬盘有多快,可见一斑了.当然现在都用固态硬盘,情况还是比以前好不少的.这里不再详细类比,知道是这回事就好.


安装

================================

好了,当然先说安装了,安装redis很简单,先说明,我们服务器都是linux.

首先要说明一下,内存数据库并不代表完全不用硬盘空间,因为一般为了数据安全,配置上会备份一定数据到硬盘的,所以还是得准备一定的硬盘空间.

下载地址:

1
wget "http://download.redis.io/releases/redis-3.2.0.tar.gz"

是编译版本,现在都出到3.2了,不过版本差异不大,低版本只是不支持集群或主从而已,实际上功能没差.

安装时有依赖包提示就记得yum下,一般就C语言库相关的,这些大部分在初始化系统就必须装上的了.

下面来看安装方法,很简单:

1
2
3
4
5
6
7
8
9
#解压编译包
tar xzf redis-3.2.0.tar.gz
#进入解压后的文件夹
cd redis-3.2.0
#编译安装
make
make install
#顺便说说,如果你想安装在自定义目录也是可以的
make prefix=(你的目录) install

当make install命令执行完成后,会在/usr/local/bin目录下生成几个可执行文件,它们的作用如下:

redis-server:    Redis服务器的daemon启动程序

redis-cli:       Redis命令行操作工具。也可以用telnet根据其纯文本协议来操作

redis-benchmark: Redis性能测试工具,测试Redis在当前系统下的读写性能

redis-check-aof: 数据修复

redis-check-dump:检查导出工具 

安装完了,就要看配置了,配置文件名可以随便改,位置也不固定要放什么位置,因为启动的时候可以指定配置文件启动.

还记得编译目录吗?里面就有配置文件模板,复制过来就可以用了,当然了,按照你自己的需求改一下还是有必要的,

1
2
3
4
cd redis-3.2.0
ll *.conf
-rw-rw-r-- 1 root root 45390 May  6 15:11 redis.conf
-rw-rw-r-- 1 root root  7109 May  6 15:11 sentinel.conf

一个是redis的配置文件,一个是哨兵,属于redis集群应用的配置文件

配置太多,我们先看一些重点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
cat redis.conf
#允许后台运行
daemonize  yes
#设置端口,最好是非默认端口
port 6666
#绑定登录IP,安全考虑,最好是内网
bind 10.10.2.21
#命名并指定当前redis的PID路径,用以区分多个redis
pidfile /data/redis/data/config/redis_6666.pid
#命名并指定当前redis日志文件路径
logfile "/data/redis/data/logs/redis_6666.log"
#指定RDB文件名,用以备份数据到硬盘并区分不同redis,当使用内存超过可用内存的45%时触发快照功能
dbfilename dump_6666.rdb
#指定当前redis的根目录,用来存放RDB/AOF文件
dir /data/redis/data
#当前redis的认证密钥,redis运行速度非常快,这个密码要足够强大
requirepass gggggggGGGGGGGGG999999999
#当前redis的最大容量限制,建议设置为可用内存的45%内,最高能设置为系统可用内存的95%
#可用config set maxmemory 去在线修改,但重启失效,需要使用config rewrite命令去刷新配置文件
maxmemory 1024000000
#LRU的策略,有四种,看情况选择
maxmemory-policy allkeys-lru
#关闭自动持久化操作,默认情况下RDB自动持久化是开启的,会定时自动压缩保存redis的全量数据.
#由于redis是单线程操作的,这个操作无疑比较耗费资源并阻塞操作,有些只做缓存的环境也不见得数据有多重要.
#save ""
#默认情况下AOF持久化方式是关闭的,有需要可以开启,但是要注意时间一长很占硬盘空间,相对RDB没那么阻塞操作.
#appendonly yes

详细解析如下:

-----------------------------------------------------------------------------------

1 daemonize  no

默认情况下,redis 不是在后台运行的,如果需要在后台运行,把该项的值更改为yes。

2 pidfile  /var/run/redis.pid

当Redis 在后台运行的时候,Redis 默认会把pid 文件放在/var/run/redis.pid,你可以配置到其他地址。当运行多个redis 服务时,需要指定不同的pid 文件和端口

3 port

监听端口,默认为6379

4 #bind 127.0.0.1

指定Redis 只接收来自于该IP 地址的请求,如果不进行设置,那么将处理所有请求,在生产环境中为了安全最好设置该项。默认注释掉,不开启

5 timeout 0

设置客户端连接时的超时时间,单位为秒。当客户端在这段时间内没有发出任何指令,那么关闭该连接

6 tcp-keepalive 0

指定TCP连接是否为长连接,"侦探"信号有server端维护。默认为0.表示禁用

7 loglevel notice

log 等级分为4 级,debug,verbose, notice, 和warning。生产环境下一般开启notice

8 logfile stdout

配置log 文件地址,默认使用标准输出,即打印在命令行终端的窗口上,修改为日志文件目录

9 databases 16

设置数据库的个数,可以使用SELECT 命令来切换数据库。默认使用的数据库是0号库。默认16个库

10 

save 900 1

save 300 10

save 60 10000

rdb自动持久化参数,保存数据快照的频率,即将数据持久化到dump.rdb文件中的频度。用来描述"在多少秒期间至少多少个变更操作"触发snapshot数据保存动作,

    默认设置,意思是:

    if(在60 秒之内有10000 个keys 发生变化时){

    进行镜像备份

    }else if(在300 秒之内有10 个keys 发生了变化){

    进行镜像备份

    }else if(在900 秒之内有1 个keys 发生了变化){

    进行镜像备份

    }

    如果设置为空,例如:

    save ""

    即关闭rdb自动持久化.

    默认情况下RDB自动持久化是开启的,会定时自动压缩保存redis的全量数据,但是由于redis是单线程操作的,这个操作无疑比较耗费资源而阻塞操作,有些只做缓存的环境也不见得数据有多重要,关闭也是可以的.

    注意:手动bgsave命令还是可以使用的,还需要留意dir参数的文件是否存在,如果存在,重启后会把文件的数据加载进来

11 stop-writes-on-bgsave-error yes

当持久化出现错误时,是否依然继续进行工作,是否终止所有的客户端write请求。默认设置"yes"表示终止,一旦snapshot数据保存故障,那么此server为只读服务。如果为"no",那么此次snapshot将失败,但下一次snapshot不会受到影响,不过如果出现故障,数据只能恢复到"最近一个成功点"

12 rdbcompression yes

在进行数据镜像备份时,是否启用rdb文件压缩手段,默认为yes。压缩可能需要额外的cpu开支,不过这能够有效的减小rdb文件的大,有利于存储/备份/传输/数据恢复

13 rdbchecksum yes

读取和写入时候,会损失10%性能

14 rdbchecksum yes

是否进行校验和,是否对rdb文件使用CRC64校验和,默认为"yes",那么每个rdb文件内容的末尾都会追加CRC校验和,利于第三方校验工具检测文件完整性

14 dbfilename dump.rdb

镜像快照备份文件的文件名,默认为 dump.rdb,当使用内存超过可用内存的45%时触发快照功能

15 dir ./

数据库镜像备份的文件rdb/AOF文件放置的路径。这里的路径跟文件名要分开配置是因为Redis 在进行备份时,先会将当前数据库的状态写入到一个临时文件中,等备份完成时,再把该临时文件替换为上面所指定的文件,而这里的临时文件和上面所配置的备份文件都会放在这个指定的路径当中

16 # slaveof <masterip> <masterport>

设置该数据库为其他数据库的从数据库,并为其指定master信息。

17 masterauth

当主数据库连接需要密码验证时,在这里指定

18 slave-serve-stale-data yes

当主master服务器挂机或主从复制在进行时,是否依然可以允许客户访问可能过期的数据。在"yes"情况下,slave继续向客户端提供只读服务,有可能此时的数据已经过期;在"no"情况下,任何向此server发送的数据请求服务(包括客户端和此server的slave)都将被告知"error"

19 slave-read-only yes

slave是否为"只读",强烈建议为"yes"

20 # repl-ping-slave-period 10

slave向指定的master发送ping消息的时间间隔(秒),默认为10

21 # repl-timeout 60

slave与master通讯中,最大空闲时间,默认60秒.超时将导致连接关闭

22 repl-disable-tcp-nodelay no

slave与master的连接,是否禁用TCP nodelay选项。"yes"表示禁用,那么socket通讯中数据将会以packet方式发送(packet大小受到socket buffer限制)。

可以提高socket通讯的效率(tcp交互次数),但是小数据将会被buffer,不会被立即发送,对于接受者可能存在延迟。"no"表示开启tcp nodelay选项,任何数据都会被立即发送,及时性较好,但是效率较低,建议设为no

23 slave-priority 100

适用Sentinel模块(unstable,M-S集群管理和监控),需要额外的配置文件支持。slave的权重值,默认100.当master失效后,Sentinel将会从slave列表中找到权重值最低(>0)的slave,并提升为master。如果权重值为0,表示此slave为"观察者",不参与master选举

24 # requirepass foobared

设置客户端连接后进行任何其他指定前需要使用的密码。警告:因为redis 速度相当快,所以在一台比较好的服务器下,一个外部的用户可以在一秒钟进行150K 次的密码尝试,这意味着你需要指定非常非常强大的密码来防止暴力破解。

25 # rename-command CONFIG 3ed984507a5dcd722aeade310065ce5d    (方式:MD5('CONFIG^!'))

重命名指令,对于一些与"server"控制有关的指令,可能不希望远程客户端(非管理员用户)链接随意使用,那么就可以把这些指令重命名为"难以阅读"的其他字符串

26 # maxclients 10000

限制同时连接的客户数量。当连接数超过这个值时,redis 将不再接收其他连接请求,客户端尝试连接时将收到error 信息。默认为10000,要考虑系统文件描述符限制,不宜过大,浪费文件描述符,具体多少根据具体情况而定

27 # maxmemory <bytes>

redis-cache所能使用的最大内存(bytes),默认为0,表示"无限制",最终由OS物理内存大小决定(如果物理内存不足,有可能会使用swap)。此值尽量不要超过机器的物理内存尺寸,从性能和实施的角度考虑,可以为物理内存3/4。此配置需要和"maxmemory-policy"配合使用,当redis中内存数据达到maxmemory时,触发"清除策略"。在"内存不足"时,任何write操作(比如set,lpush等)都会触发"清除策略"的执行。在实际环境中,建议redis的所有物理机器的硬件配置保持一致(内存一致),同时确保master/slave中"maxmemory""policy"配置一致。可以使用客户端命令config set maxmemory 去在线修改值,这个命令是立即生效的,但会在重启后会失效,需要使用config rewrite命令去刷新配置文件

当内存满了的时候,如果还接收到set 命令,redis 将先尝试剔除设置过expire 信息的key,而不管该key 的过期时间还没有到达。在删除时,

将按照过期时间进行删除,最早将要被过期的key 将最先被删除。如果带有expire 信息的key 都删光了,内存还不够用,那么将返回错误。这样,redis 将不再接收写请求,只接收get 请求。maxmemory 的设置比较适合于把redis 当作于类似memcached的缓存来使用。

28 # maxmemory-policy volatile-lru

内存不足"时,数据清除策略,默认为"volatile-lru"。

volatile-lru  ->对"过期集合"中的数据采取LRU(近期最少使用)算法.如果对key使用"expire"指令指定了过期时间,那么此key将会被添加到"过期集合"中。将已经过期/LRU的数据优先移除.如果"过期集合"中全部移除仍不能满足内存需求,将OOM.

allkeys-lru ->对所有的数据,采用LRU算法

volatile-random ->对"过期集合"中的数据采取"随即选取"算法,并移除选中的K-V,直到"内存足够"为止. 如果如果"过期集合"中全部移除全部移除仍不能满足,将OOM

allkeys-random ->对所有的数据,采取"随机选取"算法,并移除选中的K-V,直到"内存足够"为止

volatile-ttl ->对"过期集合"中的数据采取TTL算法(最小存活时间),移除即将过期的数据.

noeviction ->不做任何干扰操作,直接返回OOM异常

另外,如果数据的过期不会对"应用系统"带来异常,且系统中write操作比较密集,建议采取"allkeys-lru"

29 # maxmemory-samples 3

默认值3,上面LRU和最小TTL策略并非严谨的策略,而是大约估算的方式,因此可以选择取样值以便检查

29 appendonly no

aof持久化开关,默认情况下,redis 会在后台异步的把数据库镜像备份到磁盘,但是该备份是非常耗时的,而且备份也不能很频繁。所以redis 提供了另外一种更加高效的数据库备份及灾难恢复方式。开启append only 模式之后,redis 会把所接收到的每一次写操作请求都追加到appendonly.aof 文件中,当redis 重新启动时,会从该文件恢复出之前的状态。但是这样会造成appendonly.aof 文件过大,所以redis 还支持了BGREWRITEAOF 指令,对appendonly.aof 进行重新整理。如果不经常进行数据迁移操作,推荐生产环境下的做法为关闭镜像,开启appendonly.aof,同时可以选择在访问较少的时间每天对appendonly.aof 进行重写一次。

另外,对master机器,主要负责写,建议使用AOF,对于slave,主要负责读,挑选出1-2台开启AOF,其余的建议关闭

30 # appendfilename appendonly.aof

aof文件名字,默认为appendonly.aof

31 

# appendfsync always

appendfsync everysec

# appendfsync no

设置对appendonly.aof 文件进行同步的频率。always 表示每次有写操作都进行同步,everysec 表示对写操作进行累积,每秒同步一次。no不主动fsync,由OS自己来完成。这个需要根据实际业务场景进行配置

32 no-appendfsync-on-rewrite no

在aof rewrite期间,是否对aof新记录的append暂缓使用文件同步策略,主要考虑磁盘IO开支和请求阻塞时间。默认为no,表示"不暂缓",新的aof记录仍然会被立即同步

33 auto-aof-rewrite-percentage 100

当Aof log增长超过指定比例时,重写log file, 设置为0表示不自动重写Aof 日志,重写是为了使aof体积保持最小,而确保保存最完整的数据。

34 auto-aof-rewrite-min-size 64mb

触发aof rewrite的最小文件尺寸

35 lua-time-limit 5000

lua脚本运行的最大时间

36 slowlog-log-slower-than 10000

"慢操作日志"记录,单位:微秒(百万分之一秒,1000 * 1000),如果操作时间超过此值,将会把command信息"记录"起来.(内存,非文件)。其中"操作时间"不包括网络IO开支,只包括请求达到server后进行"内存实施"的时间."0"表示记录全部操作

37 slowlog-max-len 128

"慢操作日志"保留的最大条数,"记录"将会被队列化,如果超过了此长度,旧记录将会被移除。可以通过"SLOWLOG <subcommand> args"查看慢记录的信息(SLOWLOG get 10,SLOWLOG reset)

38

 hash-max-ziplist-entries 512

hash类型的数据结构在编码上可以使用ziplist和hashtable。ziplist的特点就是文件存储(以及内存存储)所需的空间较小,在内容较小时,性能和hashtable几乎一样.因此redis对hash类型默认采取ziplist。如果hash中条目的条目个数或者value长度达到阀值,将会被重构为hashtable。

这个参数指的是ziplist中允许存储的最大条目个数,,默认为512,建议为128

hash-max-ziplist-value 64

ziplist中允许条目value值最大字节数,默认为64,建议为1024

39 

list-max-ziplist-entries 512

list-max-ziplist-value 64

对于list类型,将会采取ziplist,linkedlist两种编码类型。解释同上。

40 set-max-intset-entries 512

intset中允许保存的最大条目个数,如果达到阀值,intset将会被重构为hashtable

41 

zset-max-ziplist-entries 128

zset-max-ziplist-value 64

zset为有序集合,有2中编码类型:ziplist,skiplist。因为"排序"将会消耗额外的性能,当zset中数据较多时,将会被重构为skiplist。

42 activerehashing yes

是否开启顶层数据结构的rehash功能,如果内存允许,请开启。rehash能够很大程度上提高K-V存取的效率

43 

client-output-buffer-limit normal 0 0 0

client-output-buffer-limit slave 256mb 64mb 60

client-output-buffer-limit pubsub 32mb 8mb 60

客户端buffer控制。在客户端与server进行的交互中,每个连接都会与一个buffer关联,此buffer用来队列化等待被client接受的响应信息。如果client不能及时的消费响应信息,那么buffer将会被不断积压而给server带来内存压力.如果buffer中积压的数据达到阀值,将会导致连接被关闭,buffer被移除。

buffer控制类型包括:normal -> 普通连接;slave ->与slave之间的连接;pubsub ->pub/sub类型连接,此类型的连接,往往会产生此种问题;因为pub端会密集的发布消息,但是sub端可能消费不足.

指令格式:client-output-buffer-limit <class> <hard> <soft> <seconds>",其中hard表示buffer最大值,一旦达到阀值将立即关闭连接;

soft表示"容忍值",它和seconds配合,如果buffer值超过soft且持续时间达到了seconds,也将立即关闭连接,如果超过了soft但是在seconds之后,buffer数据小于了soft,连接将会被保留.

其中hard和soft都设置为0,则表示禁用buffer控制.通常hard值大于soft.

44 hz 10

Redis server执行后台任务的频率,默认为10,此值越大表示redis对"间歇性task"的执行次数越频繁(次数/秒)。"间歇性task"包括"过期集合"检测、关闭"空闲超时"的连接等,此值必须大于0且小于500。此值过小就意味着更多的cpu周期消耗,后台task被轮询的次数更频繁。此值过大意味着"内存敏感"性较差。建议采用默认值。

45 

# include /path/to/local.conf

# include /path/to/other.conf

额外载入配置文件。

------------------------------------------------------------------------------------

然后来看看启动

1
2
3
4
5
6
7
8
9
10
11
12
#使用配置文件启动redis
redis-server /(自定义路径)/redis.conf
#然后测试下能不能用
redis-cli -p 6379(指定的端口号,可不填,即默认) -a "密码" [-c "命令"(可选,非交互式操作)]
set mykey  "hi"
ok
get mykey
"hi"
#关闭redis
redis-cli shutdown
#或
kill pid

注意:在重启服务器之前,需要在Redis-cli工具上输入shutdown save命令,意思是强制让Redis数据库执行保存操作并关闭Redis服务,这样做能保证在执行Redis关闭时不丢失任何数据。 


操作

 首先来看看命令行终端输出模式操作介绍:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
#在Shell命令行下启动Redis客户端工具。
redis-cli -h 127.0.0.1 -p 6379 -a '********'  
#清空当前选择的数据库,以便于对后面示例的理解。
redis 127.0.0.1:6379> flushdb
OK
#添加String类型的模拟数据。
redis 127.0.0.1:6379> set mykey 2
OK
redis 127.0.0.1:6379> set mykey2 "hello"
OK
#添加Set类型的模拟数据。
redis 127.0.0.1:6379> sadd mysetkey 1 2 3
(integer) 3
#添加Hash类型的模拟数据。
redis 127.0.0.1:6379> hset mmtest username "stephen"
(integer) 1
#根据参数中的模式,获取当前数据库中符合该模式的所有key,从输出可以看出,该命令在执行时并不区分与Key关联的Value类型。
redis 127.0.0.1:6379> keys my*
1) "mysetkey"
2) "mykey"
3) "mykey2"
#删除了两个Keys。
redis 127.0.0.1:6379> del mykey mykey2
(integer) 2
#查看一下刚刚删除的Key是否还存在,从返回结果看,mykey确实已经删除了。
redis 127.0.0.1:6379> exists mykey
(integer) 0
#查看一下没有删除的Key,以和上面的命令结果进行比较。
redis 127.0.0.1:6379> exists mysetkey
(integer) 1
#将当前数据库中的mysetkey键移入到ID为1的数据库中,从结果可以看出已经移动成功。
redis 127.0.0.1:6379> move mysetkey 1
(integer) 1
#打开ID为1的数据库。
redis 127.0.0.1:6379> select 1
OK
#查看一下刚刚移动过来的Key是否存在,从返回结果看已经存在了。
redis 127.0.0.1:6379[1]> exists mysetkey
(integer) 1
#在重新打开ID为0的缺省数据库。
redis 127.0.0.1:6379[1]> select 0
OK
#查看一下刚刚移走的Key是否已经不存在,从返回结果看已经移走。
redis 127.0.0.1:6379> exists mysetkey
(integer) 0
#准备新的测试数据。    
redis 127.0.0.1:6379> set mykey "hello"
OK
#将mykey改名为mykey1
redis 127.0.0.1:6379> rename mykey mykey1
OK
#由于mykey已经被重新命名,再次获取将返回nil。
redis 127.0.0.1:6379> get mykey
(nil)
#通过新的键名获取。
redis 127.0.0.1:6379> get mykey1
"hello"
#由于mykey已经不存在了,所以返回错误信息。
redis 127.0.0.1:6379> rename mykey mykey1
(error) ERR no such key
#为renamenx准备测试key
redis 127.0.0.1:6379> set oldkey "hello"
OK
redis 127.0.0.1:6379> set newkey "world"
OK
#由于newkey已经存在,因此该命令未能成功执行。
redis 127.0.0.1:6379> renamenx oldkey newkey
(integer) 0
#查看newkey的值,发现它也没有被renamenx覆盖。
redis 127.0.0.1:6379> get newkey
"world"
         
2. PERSIST/EXPIRE/EXPIREAT/TTL:    
#为后面的示例准备的测试数据。
redis 127.0.0.1:6379> set mykey "hello"
OK
#将该键的超时设置为100秒。
redis 127.0.0.1:6379> expire mykey 100
(integer) 1
#通过ttl命令查看一下还剩下多少秒。
redis 127.0.0.1:6379> ttl mykey
(integer) 97
#立刻执行persist命令,该存在超时的键变成持久化的键,即将该Key的超时去掉。
redis 127.0.0.1:6379> persist mykey
(integer) 1
#ttl的返回值告诉我们,该键已经没有超时了。
redis 127.0.0.1:6379> ttl mykey
(integer) -1
#为后面的expire命令准备数据。
redis 127.0.0.1:6379> del mykey
(integer) 1
redis 127.0.0.1:6379> set mykey "hello"
OK
#设置该键的超时被100秒。
redis 127.0.0.1:6379> expire mykey 100
(integer) 1
#用ttl命令看一下当前还剩下多少秒,从结果中可以看出还剩下96秒。
redis 127.0.0.1:6379> ttl mykey
(integer) 96
#重新更新该键的超时时间为20秒,从返回值可以看出该命令执行成功。
redis 127.0.0.1:6379> expire mykey 20
(integer) 1
#再用ttl确认一下,从结果中可以看出果然被更新了。
redis 127.0.0.1:6379> ttl mykey
(integer) 17
#立刻更新该键的值,以使其超时无效。
redis 127.0.0.1:6379> set mykey "world"
OK
#从ttl的结果可以看出,在上一条修改该键的命令执行后,该键的超时也无效了。
redis 127.0.0.1:6379> ttl mykey
(integer) -1
 
3. TYPE/RANDOMKEY/SORT:
#由于mm键在数据库中不存在,因此该命令返回none。
redis 127.0.0.1:6379> type mm
none
#mykey的值是字符串类型,因此返回string。
redis 127.0.0.1:6379> type mykey
string
#准备一个值是set类型的键。
redis 127.0.0.1:6379> sadd mysetkey 1 2
(integer) 2
#mysetkey的键是set,因此返回字符串set。
redis 127.0.0.1:6379> type mysetkey
set
#返回数据库中的任意键。
redis 127.0.0.1:6379> randomkey
"oldkey"
#清空当前打开的数据库。
redis 127.0.0.1:6379> flushdb
OK
#由于没有数据了,因此返回nil。
redis 127.0.0.1:6379> randomkey
(nil)

上面这些只是一部分的用法,但是对于一般测试就足够了?,其他还有list用法和hash用法什么的,有兴趣可以更加深入研究.

--------------------------------------------------------

类似于tail和tailf的概念,终端输出模式就是一直连线,而下面的命令结果输出模式就是命令执行就出一个结果,不会继续连线.

下面来看命令结果输出模式:

redis-cli参数

-h    设置检测主机IP地址,默认为127.0.0.1

-p    设置检测主机的端口号,默认为6379    

-s<socket>    服务器套接字(压倒主机和端口)    

-a    连接到Master服务器时使用的密码    

-r    执行指定的N次命令    

-i    执行命令后等待N秒,如–i 0.1 info(执行后等0.1秒)    

-n    指定连接N号ID数据库,如 –n 3(连接3号数据库)    

-x    从控制台输入的信息中读取最后一个参数    

-d    定义多个定界符为默认输出格式(默认: \n)    

--raw    使用原数据格式返回输出内容    

--latency    进入一个不断延时采样的特殊模式    

--slave    模拟一个从服务器到主服务器的命令显示反馈    

--pipe    使用管道协议模式    

--bigkeys    监听显示数据量大的key值,--bigkeys -i 0.1     

--help    显示命令行帮助信息    

--version    显示版本号    

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
$ redis-cli进入命令行模式
$ redis-cli -n 3 set mykey "hi" 把mykey插入到第三个数据库
$ redis-cli -r 3 info 重复执行info命令三次
下面还有一些比较特别的用法
GETSET: ./redis-cli getset nid 987654321 
# 表示返回指定key的原始值,并指定一个新值给他 
MGET: ./redis-cli mget nid uid … 
# 表示获取多个key的值 
SETNX: ./redis-cli setnx nnid 888888 
# 表示当一个指定的key不存在时,设置这个key指定的value,如果存在,则设置不成功 
SETEX: ./redis-cli setex nid 5 666666 
# 表示设置一个key指定的value保存5秒后失效,设置key/value的有效期 
MSET: ./redis-cli mset nid0001 "0001" nid0002 "0002" nid0003 "0003"
# 表示多键值对的数据保存 
INCR: ./redis-cli incr count 
# 表示对给定key的value进行递增(+1)的操作,当然value必须是一个integer 
INCRBY: ./redis-cli incrby count 5 
# 表示对给定key的value进行指定步长的递增操作 
DECR: ./redis-cli decr count 
# 表示对给定key的value进行递减(-1)的操作 
DECRBY: ./redis-cli decrby count 7 
# 表示对给定key的value进行指定步长的递减操作 
APPEND: ./redis-cli append content "bad"   或者  ./redis-cli append content "good"
# 表示追加一个value到指定的key中,如果key不存在,则新建key 
SUBSTR: ./redis-cli substr content 0 4 
# 表示返回指定key的value的部分字符串
# 列表操作,精华 
RPUSH key string — 将某个值加入到一个key列表末尾 
LPUSH key string — 将某个值加入到一个key列表头部 
LLEN key — 列表长度 
LRANGE key start end — 返回列表中某个范围的值,相当于mysql里面的分页查询那样 
LTRIM key start end — 只保留列表中某个范围的值 
LINDEX key index — 获取列表中特定索引号的值,要注意是O(n)复杂度 
LSET key index value — 设置列表中某个位置的值 
RPOP key 
# 集合操作 
SADD key member — 增加元素 
SREM key member — 删除元素 
SCARD key — 返回集合大小 
SISMEMBER key member — 判断某个值是否在集合中 
SINTER key1 key2 ... keyN — 获取多个集合的交集元素 
SMEMBERS key — 列出集合的所有元素 ?
更新日志检查 ,加--fix参数为修复log文件
redis-check-aof appendonly.aof
检查本地数据库文件
redis-check-dump  dump.rdb

========================================================


压力测试

redis测试分两种说法,第一种就是并发压力,另一种就是容量压力了,

并发压力可以用redis自带的软件redis-benchmark来测试?,具体如下:

redis-benchmark参数

-h    设置检测主机IP地址,默认为127.0.0.1    

-p    设置检测主机的端口号,默认为6379    

-s<socket>    服务器套接字(压倒主机和端口)    

-c    并发连接数    

-n    请求数    

-d    测试使用的数据集的大小/字节的值(默认3字节)    

-k    1:表示保持连接(默认值)0:重新连接    

-r    SET/GET/INCR方法使用随机数插入数值,设置10则插入值为rand:000000000000 - rand:000000000009    

-P    默认为1(无管道),当网络延迟过长时,使用管道方式通信(请求和响应打包发送接收)    

-q    简约信息模式,只显示查询和秒值等基本信息。    

--csv    以CSV格式输出信息    

-l    无线循环插入测试数据,ctrl+c停止    

-t<tests>    只运行<tests>测试逗号分隔的列表命令,如:-t ping,set,get    

-I    空闲模式。立即打开50个空闲连接和等待。   

例子: 

1
2
3
4
5
6
7
redis-benchmark -h 127.0.0.1 -p 6379 -q -d 100  
SET/GET 100 bytes 检测host为127.0.0.1 端口为6379的redis服务器性能
redis-benchmark -h 127.0.0.1 -p 6379 -c 5000 -n 100000 
5000个并发连接,100000个请求,检测host为127.0.0.1 端口为6379的redis服务器性能 
我们来详细解析下这条语句的意思:
redis-benchmark -n 100000 -c 60
向redis服务器发送100000个请求,每个请求附带60个并发客户端

结果(部分):

====== SET ======

对集合写入测试

  100000 requests completed in 2.38 seconds

100000个请求在2.38秒内完成

  60 parallel clients

每次请求有60个并发客户端

  3 bytes payload

每次写入3个字节的数据

  keep alive: 1

保持一个连接,一台服务器来处理这些请求

100.00% <= 62 milliseconds

所有请求在62毫秒内完成

42105.26 requests per second

每秒处理42105.26次请求

还是比较直观的

-----------------------------------

然后说说容量测试,其实很好理解,内存不是无限的,存放数据自然就是有限,虽然说可以去配置文件去用淘汰机制限制,但是知道容量顶点还是能解决不少问题.

顺便也说说,要是你设置的maxmemory 容量不够,或者整个内存都不够,而又没有使用有效的LRU配置,那么你的redis写满了之后会提示OOM,就是说内存不够用,写不进新数据.

说的就是maxmemory-policy这个设置,具体怎么设置才是合理的,则需要从业务层面去考虑了,例如说丢了一些旧key也没所谓的,allkeys-lru就是最好了,严格来或,你用了这个策略其实也不用测试了,因为他会自动删旧key,没什么顶不顶点的概念在..

测试容量的方法很简单,就是不停的往里面写数据,然后看他顶点是多少.? 

参考脚本如下:

1
2
3
4
5
6
7
8
9
10
11
#!/bin/sh
keyset="keytest5"
valueset='模拟数据,随便你写'
dbname=5
a=0
for in `seq 1 300000`
do
redis-cli -n $dbname 'set' ${keyset}${a} "${valueset}${a}" >/dev/null
#echo $a
let a++
done

测试结果很简单,看info的最后一个结果就好了,哪里会有显示现在有多少个key在.


性能分析

info信息:

在redis-cli进入登录界面后,输入info,或者redis-cli -h ${ip} -p ${post} -a "${pass}" -c info

之后,就会获取所有与Redis服务相关的实时性能信息,类似于linux命令top那样的东西.

info命令输出的数据可分为10个类别,分别是:

  • server

  • clients

  • memory

  • persistence

  • stats

  • replication

  • cpu

  • commandstats

  • cluster

  • keyspace

现在主要介绍比较重要的2部分性能指标memory和stats.

maxmemory/maxmemory_human:    配置文件redis.conf限制的可分配的最大内存总量

used_memory/used_memory_human:    当前redis实际使用的内存总量,如果used_memory > maxmemory ,那么操作系统开始进行内存与swap空间交换,以便腾出新的物理内存给新页或活动页(page)使用,那是有多糟糕大家可以想得到.

used_memory_rss/used_memory_rss_human:    从操作系统上显示已经分配的内存总量,比used_memory多出来的就可能是碎片.

mem_fragmentation_ratio:    内存碎片率,内存碎片率稍大于1是合理的,说明redis没有发生内存交换,如果内存碎片率超过1.5,那就说明Redis消耗了实际需要物理内存的150%,其中50%是内存碎片率。若是内存碎片率低于1的话,说明Redis内存分配超出了物理内存,操作系统正在进行内存交换。内存交换会引起非常明显的响应延迟.

    下面是计算公式:

        wKiom1jCaDyBrpuiAAAuFTm2d-w931.png

    当碎片率出现问题,有3种方法解决内存管理变差的问题,提高redis性能:

        1. 重启Redis服务器:如果内存碎片率超过1.5,重启Redis服务器可以让额外产生的内存碎片失效并重新作为新内存来使用,使操作系统恢复高效的内存管理。

        2.限制内存交换: 如果内存碎片率低于1,Redis实例可能会把部分数据交换到硬盘上。内存交换会严重影响Redis的性能,所以应该增加可用物理内存或减少实Redis内存占用

        3.修改内存分配器:
Redis支持glibc’s malloc、jemalloc11、tcmalloc几种不同的内存分配器,每个分配器在内存分配和碎片上都有不同的实现。不建议普通管理员修改Redis默认内存分配器,因为这需要完全理解这几种内存分配器的差异,也要重新编译Redis。

used_memory_lua:    Lua脚本引擎所使用的内存大小。redis默认允许使用lua脚本,不过太多了的话就占用了可用内存

mem_allocator:    在编译时指定的Redis使用的内存分配器,可以是libc、jemalloc、tcmalloc.

total_commands_processed:    显示了Redis服务处理命令的总数,且值是递增的.因为Redis是个单线程模型,客户端过来的命令是按照顺序执行的,如果命令队列里等待处理的命令数量比较多,命令的响应时间就变慢,甚至于后面的命令完全被阻塞,导致Redis性能降低.所以这个时候就需要记录这个参数的值,是不是增长过快,导致了性能降低.

evicted_keys:    显示因为maxmemory限制导致key被回收删除的数量.根据配置文件中设置maxmemory-policy值来确定Redis是使用lru策略还是过期时间策略.如果是过期回收的,不会被记录在这里,通常这个值不为0,那就要考虑增加内存限制,不然就会造成内存交换,轻则性能变差,重则丢数据.

---------------------------------------------------------------------------------------------------

其他分析方法:

Redis的延迟数据是无法从info信息中获取的。倘若想要查看延迟时间,可以用 Redis-cli工具加--latency参数运行

redis-cli --latency -h 127.0.0.1 -p 6379

他将会持续扫描延迟时间,直到按ctrl+C退出,以毫秒为单位测量Redis的响应延迟时间,由于服务器不同的运行情况,延迟时间可能有所误差,通常1G网卡的延迟时间是0.2毫秒,若延时值远高于这个参考值,那明显是有性能问题了。也可以通过下面方法来分析延时慢的原因:

使用slowlog查出引发延迟的慢命令:Redis中的slowlog命令可以让我们快速定位到那些超出指定执行时间的慢命令,默认情况下命令若是执行时间超过10ms就会被记录到日志,最多记录128条,超过就删除,可通过参数slowlog-log-slower-than和slowlog-max-len来修改这个时间和限制条数。通常1gb带宽的网络延迟,预期在0.2ms左右,倘若一个命令仅执行时间就超过10ms,那比网络延迟慢了近50倍。可以通过使用Redis-cli工具,输入slowlog get命令查看,返回结果的第三个字段以微妙位单位显示命令的执行时间。假如只需要查看最后3个慢命令,输入slowlog get 10即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
127.0.0.1:6379> slowlog get 10
    .
    .
    .
4) 1) (integer) 215
    2) (integer) 1489099695
    3) (integer) 11983
    4) 1) "SADD"
       2) "USER_TOKEN_MAP51193"
       3) "qIzwZKBmBJozKprQgoTEI3Qo8QO2Fi!4"
 5) 1) (integer) 214
    2) (integer) 1489087112
    3) (integer) 18002
    4) 1) "SADD"
       2) "USER_TOKEN_MAP51192"
       3) "Z3Hs!iTUNfweqvLLf!ptdchSV2JAOrrH"
 6) 1) (integer) 213
    2) (integer) 1489069123
    3) (integer) 15407
    4) 1) "SADD"
       2) "USER_TOKEN_MAP51191"
       3) "S3rNzOBwUlaI3QfOK9dIITB6Bk7LIGYe"

  • 1=日志的唯一标识符

  • 2=被记录命令的执行时间点,以 UNIX 时间戳格式表示

  • 3=查询执行时间,以微秒为单位。例子中命令使用11毫秒。

  • 4= 执行的命令,以数组的形式排列。完整命令是拼在一起.

监控客户端的连接:因为Redis是单线程模型(只能使用单核),来处理所有客户端的请求, 但由于客户端连接数的增长,处理请求的线程资源开始降低分配给单个客户端连接的处理时间,这时每个客户端需要花费更多的时间去等待Redis共享服务的响应。

1
2
3
4
5
6
7
8
9
10
#查看客户端连接状态
127.0.0.1:6379> info clients
# Clients
connected_clients:11
client_longest_output_list:0
client_biggest_input_buf:0
blocked_clients:0
#查看每一个客户端的状态,全部都显示出来(慎用),注意很长,
127.0.0.1:6379> client list
id=821882 addr=10.25.138.2:60990 fd=8 name= age=53838 idle=24 flags=N db=0 sub=0 psub=0 multi=-1 qbuf=0 qbuf-free=0 obl=0 oll=0 omem=0 events=r cmd=ping

第一个字段(connected_clients)显示当前实例客户端连接的总数,Redis默认允许客户端连接的最大数量是10000。若是看到连接数超过5000以上,那可能会影响Redis的性能。倘若一些或大部分客户端发送大量的命令过来,这个数字会低的多。

还有些简单举例下:

1
2
3
4
#统计生产上比较大的key
redis-cli -h* -a* -p* --bigkeys
#查看某个key的持续时间
127.0.0.1:6379> OBJECT IDLETIME key名字

数据持久化引发的延迟

Redis的数据持久化工作本身就会带来延迟,需要根据数据的安全级别和性能要求制定合理的持久化策略:

1.AOF + fsync always的设置虽然能够绝对确保数据安全,但每个操作都会触发一次fsync,会对Redis的性能有比较明显的影响
2.AOF + fsync every second是比较好的折中方案,每秒fsync一次
3.AOF + fsync never会提供AOF持久化方案下的最优性能,使用RDB持久化通常会提供比使用AOF更高的性能,但需要注意RDB的策略配置
4.每一次RDB快照和AOF Rewrite都需要Redis主进程进行fork操作。fork操作本身可能会产生较高的耗时,与CPU和Redis占用的内存大小有关。根据具体的情况合理配置RDB快照和AOF Rewrite时机,避免过于频繁的fork带来的延迟.
例如:Redis在fork子进程时需要将内存分页表拷贝至子进程,以占用了24GB内存的Redis实例为例,共需要拷贝24GB / 4kB * 8 = 48MB的数据。在使用单Xeon 2.27Ghz的物理机上,这一fork操作耗时216ms。

可以通过INFO命令返回的latest_fork_usec字段查看上一次fork操作的耗时(微秒)。

Swap引发的延迟

当Linux将Redis所用的内存分页移至swap空间时,将会阻塞Redis进程,导致Redis出现不正常的延迟。Swap通常在物理内存不足或一些进程在进行大量I/O操作时发生,应尽可能避免上述两种情况的出现。

在/proc/redis进程号/smaps文件中会保存进程的swap记录,通过查看这个文件,能够判断Redis的延迟是否由Swap产生。如果这个文件中记录了较大的Swap size,则说明延迟很有可能是Swap造成的。

例子如下,可以看到当前swap的状态时0KB,也就是没用到swap,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#/proc/pid/smaps显示了进程运行时的内存影响,系统的运行时库(so),堆,栈信息均可在其中看到。
cat /proc/`ps aux |grep redis |grep -v grep |awk '{print $2}'`/smaps
00400000-00531000 r-xp 00000000 fc:02 805438521 /usr/local/bin/redis-server
Size:               1220 kB
Rss:                 924 kB
Pss:                 924 kB
Shared_Clean:          0 kB
Shared_Dirty:          0 kB
Private_Clean:       924 kB
Private_Dirty:         0 kB
Referenced:          924 kB
Anonymous:             0 kB
AnonHugePages:         0 kB
Shared_Hugetlb:        0 kB
Private_Hugetlb:       0 kB
Swap:                  0 kB
SwapPss:               0 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB
Locked:                0 kB


优化建议

系统优化

1.关闭Transparent huge pages

Transparent HugePages会让内核khugepaged线程在运行时动态分配内存。在大部分linux发行版本中默认是启用的,缺点是可能会造成内存在运行时的延迟分配,对于大内存应用并不友好,例如:oracle,redis等会占用大量内存的应用,所以建议关闭。

1
2
#关闭Transparent HugePages,默认状态是[always]
echo never > /sys/kernel/mm/transparent_hugepage/enabled

2.在物理机部署redis,这点不用多说了,虚拟机或者是docker都会有一定的延时,没有必要为了好管理二浪费这些性能。

3.多用连接池,而不是频繁断开再连接,效果我想不言而喻。

4.客户端进行的批量数据操作,应使用Pipeline特性在一次交互中完成。



行为优化

1.假如缓存数据小于4GB,可以选择使用32位的Redis实例。因为32位实例上的指针大小只有64位的一半,它的内存空间占用空间会更少些。Redis的dump文件在32位和64位之间是互相兼容的, 因此倘若有减少占用内存空间的需求,可以尝试先使用32位,后面再切换到64位上。

2.尽可能的使用Hash数据结构。因为Redis在储存小于100个字段的Hash结构上,其存储效率是非常高的。所以在不需要集合(set)操作或list的push/pop操作的时候,尽可能的使用Hash结构。Hash结构的操作命令是HSET(key, fields, value)和HGET(key, field),使用它可以存储或从Hash中取出指定的字段。

3.尽量设置key的过期时间。一个减少内存使用率的简单方法就是,每当存储对象时确保设置key的过期时间。倘若key在明确的时间周期内使用或者旧key不大可能被使用时,就可以用Redis过期时间命令(expire,expireat, pexpire, pexpireat)去设置过期时间,这样Redis会在key过期时自动删除key.用ttl命令可以查询过期时间,单位是秒,显示-2代表key不存在,显示-1代表没有设置超时时间(也就是永久的). 

4.使用多参数命令:若是客户端在很短的时间内发送大量的命令过来,会发现响应时间明显变慢,这由于后面命令一直在等待队列中前面大量命令执行完毕。举例来说,循环使用LSET命令去添加1000个元素到list结构中,是性能比较差的一种方式,更好的做法是在客户端创建一个1000元素的列表,用单个命令LPUSH或RPUSH,通过多参数构造形式一次性把1000个元素发送的Redis服务上。

5.管道命令:另一个减少多命令的方法是使用管道(pipeline),把几个命令合并一起执行,从而减少因网络开销引起的延迟问题。因为10个命令单独发送到服务端会引起10次网络延迟开销,使用管道会一次性把执行结果返回,仅需要一次网络延迟开销。Redis本身支持管道命令,大多数客户端也支持,倘若当前实例延迟很明显,那么使用管道去降低延迟是非常有效的。

6.避免操作大集合的慢命令:如果命令处理频率过低导致延迟时间增加,这可能是因为使用了高时间复杂度的命令操作导致,这意味着每个命令从集合中获取数据的时间增大。 所以减少使用高时间复杂的命令,能显著的提高的Redis的性能。

7.限制客户端连接数:自Redis2.6以后,允许使用者在配置文件(Redis.conf)maxclients属性上修改客户端连接的最大数,也可以通过在Redis-cli工具上输入config set maxclients 去设置最大连接数。根据连接数负载的情况,这个数字应该设置为预期连接数峰值的110%到150之间,若是连接数超出这个数字后,Redis会拒绝并立刻关闭新来的连接。通过设置最大连接数来限制非预期数量的连接数增长,是非常重要的。另外,新连接尝试失败会返回一个错误消息,这可以让客户端知道,Redis此时有非预期数量的连接数,以便执行对应的处理措施。 上述二种做法对控制连接数的数量和持续保持Redis的性能最优是非常重要的











     本文转自arthur376 51CTO博客,原文链接:http://blog.51cto.com/arthur376/1774737,如需转载请自行联系原作者





网友评论

登录后评论
0/500
评论