首先,并非说redis是内存应用就彻底没性能问题,用的很差,仍是会出现各类情况,例如RDB频繁,碎片太多等.mysql
性能分析
linux
info信息:
redis
在redis-cli进入登陆界面后,输入info all,或者redis-cli -h ${ip} -p ${post} -a "${pass}" -c info all,一般咱们只输入info就够了,是简介模式的意思,info all是详细模式
sql
以后,就会获取全部与Redis服务相关的实时性能信息,相似于linux命令top那样的东西.mongodb
info命令输出的数据可分为10个类别,分别是:docker
server数据库
clients后端
memory数组
persistence缓存
stats
replication
cpu
commandstats
cluster
keyspace
下面展开解析一些重点信息.
server 部分:
redis_version : Redis 服务器版本,不一样版本会有些功能和命令不一样
arch_bits : 架构(32 或 64 位),某些状况,容易被忽略的坑
tcp_port : TCP/IP 监听端口,确认你操做的对不对
uptime_in_seconds : 自 Redis 服务器启动以来,通过的秒数,能够确认有没有被重启过
uptime_in_days : 自 Redis 服务器启动以来,通过的天数,能够确认有没有被重启过
clients 部分:
connected_clients : 已链接客户端的数量(不包括经过从属服务器链接的客户端)
client_longest_output_list : 当前链接的客户端当中,最长的输出列表
client_longest_input_buf : 当前链接的客户端当中,最大输入缓存
blocked_clients : 正在等待阻塞命令(BLPOP、BRPOP、BRPOPLPUSH)的客户端的数量
memory部分:
maxmemory/maxmemory_human: 配置文件redis.conf限制的可分配的最大内存总量,当超过以后,就会触发LRU删除旧数据.
used_memory/used_memory_human: 当前redis-server实际使用的内存总量,若是used_memory > maxmemory ,那么操做系统开始进行内存与swap空间交换,以便腾出新的物理内存给新页或活动页(page)使用,那是有多糟糕你们能够想获得.
used_memory_rss/used_memory_rss_human: 从操做系统上显示已经分配的内存总量,也就是这个redis-server占用的系统物理内存实际值,比used_memory多出来的就多是碎片.
mem_fragmentation_ratio: 内存碎片率,内存碎片率稍大于1是合理的,说明redis没有发生内存交换,若是内存碎片率超过1.5,那就说明Redis消耗了实际须要物理内存的150%,其中50%是内存碎片率。如果内存碎片率低于1的话,说明Redis内存分配超出了物理内存,操做系统正在进行内存交换。内存交换会引发很是明显的响应延迟.
下面是计算公式:
当碎片率出现问题,有3种方法解决内存管理变差的问题,提升redis性能:
1. 重启Redis服务器:若是内存碎片率超过1.5,重启Redis服务器可让额外产生的内存碎片失效并从新做为新内存来使用,使操做系统恢复高效的内存管理。
2.限制内存交换: 若是内存碎片率低于1,Redis实例可能会把部分数据交换到硬盘上。内存交换会严重影响Redis的性能,因此应该增长可用物理内存或减小实Redis内存占用
3.修改内存分配器:
Redis支持glibc’s malloc、jemalloc十一、tcmalloc几种不一样的内存分配器,每一个分配器在内存分配和碎片上都有不一样的实现。不建议普通管理员修改Redis默认内存分配器,由于这须要彻底理解这几种内存分配器的差别,也要从新编译Redis。
used_memory_lua: Lua脚本引擎所使用的内存大小。redis默认容许使用lua脚本,不过太多了的话就占用了可用内存
mem_allocator: 在编译时指定的Redis使用的内存分配器,能够是libc、jemalloc、tcmalloc.
persistence 部分:
RDB信息,RDB的操做要用到bgsave命令,是比较耗费资源的持久化操做,并且不是实时的,容易形成宕机数据消失,若是内存容量满了,不能作bgsave操做的话,隐患会很大.
rdb_changes_since_last_save : 距离最近一次成功建立持久化文件以后,通过了多少秒。持久化是须要占用资源的,在高负载下须要尽可能避免持久化的影响,下列参数均有参考价值.
rdb_bgsave_in_progress: 当前是否在进行bgsave操做。是为1
rdb_last_save_time : 最近一次成功建立 RDB 文件的 UNIX 时间戳。
rdb_last_bgsave_time_sec : 记录了最近一次建立 RDB 文件耗费的秒数。
rdb_last_bgsave_status: 上次保存的状态
rdb_current_bgsave_time_sec : 若是服务器正在建立 RDB 文件,那么这个域记录的就是当前的建立操做已经耗费的秒数。
AOF信息,AOF是持续记录命令到持久化文件的方法,比较节省资源,可是AOF存储文件会没有限制存储,时间一长,或者操做太频繁,那就会出现AOF文件过大,撑爆硬盘的事.并且,这个方法仍是会按期bgsave操做.
aof_enabled: AOF文件是否启用
aof_rewrite_in_progress: 表示当前是否在进行写入AOF文件操做
aof_last_rewrite_time_sec : 最近一次建立 AOF 文件耗费的时长。
aof_current_rewrite_time_sec : 若是服务器正在建立 AOF 文件,那么这个域记录的就是当前的建立操做已经耗费的秒数。
aof_last_bgrewrite_status: 上次写入状态
aof_last_write_status: 上次写入状态
aof_base_size : 服务器启动时或者 AOF 重写最近一次执行以后,AOF 文件的大小。
aof_pending_bio_fsync : 后台 I/O 队列里面,等待执行的 fsync 调用数量。
aof_delayed_fsync : 被延迟的 fsync 调用数量。
stats部分:
total_commands_processed: 显示了Redis服务处理命令的总数,且值是递增的.由于Redis是个单线程模型,客户端过来的命令是按照顺序执行的,若是命令队列里等待处理的命令数量比较多,命令的响应时间就变慢,甚至于后面的命令彻底被阻塞,致使Redis性能下降.因此这个时候就须要记录这个参数的值,是否是增加过快,致使了性能下降.
instantaneous_ops_per_sec : 服务器每秒钟执行的命令数量,同上,若是增加过快就有问题。
expired_keys : 由于过时而被自动删除的数据库键数量,具备参考意义。
evicted_keys: 显示由于maxmemory限制致使key被回收删除的数量.根据配置文件中设置maxmemory-policy值来肯定Redis是使用lru策略仍是过时时间策略.若是是过时回收的,不会被记录在这里,一般这个值不为0,那就要考虑增长内存限制,否则就会形成内存交换,轻则性能变差,重则丢数据.
latest_fork_usec: 最近一次 fork() 操做耗费的微秒数。fork()是很耗费资源的操做,因此要留意一下.
commandstats部分:
cmdstat_XXX: 记录了各类不一样类型的命令的执行统计信息,命令包含有读有写,分得比较细,其中calls表明命令执行的次数,usec表明命令耗费的 CPU 时间,usec_per_call表明每一个命令耗费的平均 CPU 时间,单位为微秒.对于排错有必定用途.
---------------------------------------------------------------------------------------------------
通用术语解析:
1.缓存穿透
缓存一般是经过后端持久化存储的DB(mysql/mongodb/hbase等)查询数据,而后加载到内存的概念.从通常代码层逻辑来讲,当在缓存找不到对应的key和value时,就会主动去查询后端DB,这个时候缓存就不起做用了,压力都会打在后端的DB上,仿佛就是被穿透了同样.
缘由多是原本就没加载到缓存,多是LRU原则被删了,多是过时时间到了自动删除了,也多是后端DB的这个数据修改太过于频繁,没加载到缓存就又被访问了.
一般来讲,少许的穿透是被容许的,毕竟理论上来讲,把后端DB的全部数据加载到内存并不现实.若是出现大量的穿透,那就确定是有问题了,多是代码的逻辑有问题,也多是DB设计有问题.解决的方案大部分状况要在代码层解决,要么就是加大内存来作缓存.
2.缓存雪崩
当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,也会给后端系统(好比DB)带来很大压力,由于可能要把这些数据从新加载到缓存。
解决方案仍是要从代码层去作,最佳方案是不一样的key,设置不一样的过时时间,让缓存失效的时间点尽可能均匀。
其余问题的分析方法:
查看redis的网络延时:
网络延时对于redis性能影响是巨大的,咱们都知道内存处理数据的速度是很是快的,快到甚至能够忽略偏差.因此网络延时0.1毫秒,1毫秒,10毫秒看似相差不大,可是就等因而10倍和100倍的差异.
Redis的延迟数据是没法从info信息中获取的。假若想要查看延迟时间,能够用 Redis-cli工具加--latency参数运行
redis-cli --latency -h 10.1.2.11 -p 6379
他将会持续扫描延迟时间,直到按ctrl+C退出,以毫秒为单位测量Redis的响应延迟时间,因为服务器不一样的运行状况,延迟时间可能有所偏差,一般1G网卡的延迟时间是0.2毫秒,若延时值远高于这个参考值,那就有多是有性能问题了。这个时候咱们要考虑检查一下网络情况.
注意:网络延时的问题须要综合考虑,由于不一样的网络状况不尽相同,例如同交换机,同内网,跨城,集群化等等.通常来讲,同交换机单机redis的网络延时应该少于0.2毫秒,可是一个codis集群的网络延时可能就去到2毫秒,看起来没差多少,其实也有十倍,加上程序客户端的网络延时,相差就可能30倍,因此咱们部署redis应用时,必须把网络情况也考虑进去.
查看redis的慢查询:
Slow log 是 Redis 用来记录查询执行时间的日志系统。Redis中的slowlog命令可让咱们快速定位到那些超出指定执行时间的慢命令,默认状况下会记录执行时间超过10ms的记录到日志,由参数slowlog-log-slower-than控制.最多记录128条,由参数slowlog-max-len控制,超过就自动删除.
一般这个默认参数够用,也能够在线CONFIG SET修改参数slowlog-log-slower-than和slowlog-max-len来修改这个时间和限制条数。
一般1gb带宽的网络延迟,预期在0.2ms左右,假若一个命令仅执行时间就超过10ms,那比网络延迟慢了近50倍。能够经过使用Redis-cli工具,输入slowlog get命令查看,返回结果的第三个字段以微妙位单位显示命令的执行时间。假如只须要查看最后3个慢命令,输入slowlog get 10便可。
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共享服务的响应。
#查看客户端链接状态 127.0.0.1:6379> info clients # Clients connected_clients:11 client_longest_output_list:0 client_biggest_input_buf:0 blocked_clients:0
第一个字段(connected_clients)显示当前实例客户端链接的总数,Redis默认容许客户端链接的最大数量是10000。如果看到链接数超过5000以上,那可能会影响Redis的性能。假若一些或大部分客户端发送大量的命令过来,这个数字会低的多。
查当前客户端状态
#查看全部正在链接的客户端状态, 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
这个看起来有点绕,由于和历史数据是混在一块儿的:
addr:客户端的地址和端口,包含当前链接和历史链接
age:这个客户端连进来的生命周期,也就是连进来以后的持续时间,单位是秒
idle:这个客户端的空闲时间,也就是说这个时间内,客户端没有操做,单位是秒
db:操做的数据库,redis默认有db0~db15可用选择
cmd:客户端最后一次使用的命令
也就是说,idle越少,那就表明这个客户端刚刚操做,反则是历史记录而已.age越少就表明是刚刚创建的链接,越大则是历史链接.而有些时候个别使用者用了scan或keys命令,会对数据量大的redis形成很大的负载压力,因此须要特别关注.
特大key的统计:
在redis的单线程处理方式下,一些数据量比较大的key的操做明显是会影响性能,因此必要时,咱们要统计出来,交给开发来优化
#统计生产上比较大的key redis-cli -h* -a* -p* --bigkeys #查看某个key的持续时间 127.0.0.1:6379> OBJECT IDLETIME key名字
--bigkeys信息解析:
1.该命令使用scan方式对key进行统计,因此使用时无需担忧对redis形成阻塞。
2.输出大概分为两部分,summary之上的部分,只是显示了扫描的过程。summary部分给出了每种数据结构中最大的Key,因此下面部分更重要些。
3.统计出的最大key只有string类型是以字节长度为衡量标准的。list,set,zset等都是以元素个数做为衡量标准,不能说明其占的内存就必定多,须要另外计算。
得出最大key名字后,就去看看粗略大小,
#查看某个key序列化后的长度 debug object key
输出的项的说明:
Value at:key的内存地址
refcount:引用次数
encoding:编码类型
serializedlength:通过压缩后的序列化长度,单位是 B, 也就是 Byte(字节),由于压缩效果要看编码类型,不必定反应内存中的大小,只是有参考价值.
lru_seconds_idle:空闲时间
终上所述,咱们要关注的大key信息正是serializedlength的长度了.
另外还有一个工具[rdbtools],能够全面分析redis里面的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,
#/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
内存满了怎么办:
redis内存满了,那确实是很麻烦的事,可是再麻烦也得处理啊,这就得从redis架构原理提及了.
首先咱们要了解,redis的内存满,并不表明是用了系统的100%内存,为何这么说呢?咱们都知道redis作持久化是save和bgsave,而经常使用的bgsave(也是默认)是fork一个进程,把内存copy一份再压缩后存到硬盘成*.rdb文件.这里就涉及一个问题,你内存必须保证有和数据同样大的空间才能作bgsave,那严格来讲,只要你的内存超过系统内存的50%,那就能够被称为redis内存满了.
redis的持久化策略,上面只说了持久化会阻塞操做致使延时,而若是内存满了,数据量的增长会让持久化形成的延时会更严重,并且持久化失败后是默认每分钟重试一遍.
那么问题就来了,由于内存满了,持久化失败,而后一分钟后再持久化,就形成了恶性循环,redis的性能直线降低.那怎么办好呢?
更改持久化策略是个临时解决方案,
能够先尝试关闭持久化失败致使的终止全部的客户端write请求的选项,
config set stop-writes-on-bgsave-error no
可是这个方法治标不治本,咱们只是忽略了问题而已,
另外一种解决方案就是直接把rdb持久化关闭掉:
config set save ""
为何能解决,答案也很明显,关闭了持久化,那就不会阻塞操做,那你redis的性能仍是保证到了.可是又会引入新问题,没了持久化,内存数据若是redis-server程序重启或关闭就没了,仍是比较危险的.并且内存满的问题还在,若是内存用到了系统内存100%,甚至触发了系统的OOM,那就坑大了,由于内存被完全清空,数据也都没有了.也就是所谓的临时解决办法.
因此正确的作法是,在不阻塞操做以后,删掉能够删除的数据,再从新拉起持久化,而后准备扩容的工做.
占用内存看哪里,上面已经说了,可是内存满了的定义,并不必定只是实际内存占用,碎片也是要包含在内的,例如:
#这种状况,确定就是内存满 used_memory_human:4.2G maxmemory_human:4.00G #可是这种状况,也是内存满 used_memory_human:792.30M used_memory_rss_human:3.97G used_memory_peak_human:4.10G maxmemory_human:4.00G
由于内存碎片没有被释放,那它仍是会占用内存空间,对于系统来讲,碎片也是redis-server占用的内存,不是空闲的内存,那剩下的内存仍是不足以用来bgsave.那怎么解决碎片呢?
在redis4.0以前,没其余更好办法,只能重启redis-server,以后的新版本则新加了一个碎片回收参数,杜绝了这个问题.
而碎片问题其实影响颇大,由于正常状况下,这些用不了又确实占着内存的数据,会让咱们的redis浪费空间之余,还会额外形成内存满的风险.因此也正如上面说的那样,若是碎片率超过1.5以后,是该想一想回收一下.
那确实须要保存内存数据怎么办?只能忍痛割爱,把没必要要的数据删除掉,让内存降到能作bgsave以后再重启来回收碎片.要不,就是升级到4.0以后避免同类问题.
优化建议
系统优化
1.关闭Transparent huge pages
Transparent HugePages会让内核khugepaged线程在运行时动态分配内存。在大部分linux发行版本中默认是启用的,缺点是可能会形成内存在运行时的延迟分配,对于大内存应用并不友好,例如:oracle,redis等会占用大量内存的应用,因此建议关闭。
#关闭Transparent HugePages,默认状态是[always] echo never > /sys/kernel/mm/transparent_hugepage/enabled
2.修改 vm.overcommit_memory 参数
解析:
0 表示检查是否有足够的内存可用,若是是,容许分配;若是内存不够,拒绝该请求,并返回一个错误给应用程序。
1 容许分配超出物理内存加上交换内存的请求
2 内核老是返回 true
在作bgsave时,RDB文件写的时候会先fork一个子进程,至关于复制了一个内存镜像.当系统的内存是8G,而redis占用了近 5G的内存时,因为剩下的内存不足够fork一个镜像空间,所以确定会报内存没法分配而失败.默认状况下,vm.overcommit_memory设置为 0,在可用内存不足的状况下, 就没法分配新的内存。若是vm.overcommit_memory设置为1。 那么redis将使用交换分区swap来作fork,虽然速度会慢一些,可是至少是不会失败了。
#修改内核参数 vi /etc/sysctl #设置,没有就添加一行 vm.overcommit_memory = 1 #而后执行 sysctl -p
固然了,使用交换内存swap并非一个完美的方案,有些服务器在分配时甚至就没有swap。因此,最好的办法是扩大物理内存,或者合理分配合适的内存空间,让LRU规则来淘汰旧key。
3.在物理机部署redis,这点不用多说了,虚拟机或者是docker的内存都会有必定的延时,没有必要为了好管理而浪费这些性能。
4.多用链接池,而不是频繁断开再链接,效果我想不言而喻。
5.客户端进行的批量数据操做,应使用Pipeline特性在一次交互中完成。
6.当并发和QPS都很是大的状况下,应该改用redis-cluster或者codis这些高性能redis集群
行为优化
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的性能最优是很是重要的