案例一:内存申请报错

解决redis连接错误:MISCONF Redis is configured to save RDB snapshots, but it is currently not able to persi

安装redis后在设置过期时间时,突然报错:MISCONF Redis is configured to save RDB snapshots, but it is currently not able to persist on disk. Commands that may modify the data set are disabled, because this instance is configured to report errors during writes if RDB snapshotting fails (stop-writes-on-bgsave-error option). Please check the Redis logs for details about the RDB error.

究其原因是因为强制把redis快照关闭了导致不能持久化的问题,在网上查了一些相关解决方案。

通过stop-writes-on-bgsave-error值设置为no即可避免这种问题。

有两种修改方法,一种是通过redis命令行修改,这种方式方便,直接,更改后直接生效,解决问题。

命令行修改方式示例: 127.0.0.1:6379> config set stop-writes-on-bgsave-error no

另一种是直接修改redis.conf配置文件,但是更改后需要重启redis。

修改redis.conf文件:

vi打开redis-server配置的redis.conf文件,然后使用快捷匹配模式:/ stop-writes-on-bgsave-error定位到stop-writes-on-bgsave-error字符串所在位置,接着把后面的yes设置为no即可。然后重启,redis-cli -h 127.0.0.1 -p 6379 shutdown。

也可以使用终极武器 kill -9。

案例二:Redis 2种持久化模式的缺陷

一、RDB持久化模式缺陷

1.问题描述:
并发200路,模拟不断写Redis,持续4小时后,接口调用开始出现大量失败,错误信息如下:

{"data":{"sendResult":null},"base":{"returncode":"99999","returndesc":"系统异常:MISCONF Redis is configured to save RDB snapshots, but is currently not able to persist on disk. Commands that may modify the data set are disabled. Please check Redis logs for details about the error."},"qrybase":{"total":0,"count":0,"start":0}}

2.原因分析:
解读错误信息,以为是磁盘不够用引起,结果发现磁盘还剩余42%,如下所示:

具体原因:Redis在保存数据到硬盘时为了避免主进程假死,需要Fork一份主进程,然后在Fork进程内完成数据保存到硬盘的操作,如果主进程使用了2.2GB的内存,Fork子进程的时候需要额外的2.2GB,此时内存就不够了,Fork失败,进而数据保存硬盘也失败了。

3.缓解方案(不能根本解决问题):

3.1 修改redis.conf文件中配置项stop-writes-on-bgsave-error no (默认值为yes),即当bgsave快照操作出错时停止写数据到磁盘,这样后面写错做均会失败,为了不影响后续写操作,故需将该项值改为no

3.2 修改内核参数(如下3种方式),但需要root权限:

1) 编辑/etc/sysctl.conf ,改vm.overcommit_memory=1,然后sysctl -p 使配置文件生效
(2)sysctl vm.overcommit_memory=13)echo 1 > /proc/sys/vm/overcommit_memory

二、AOF持久化模式缺陷

1.问题1描述:
Redis主从节点均开启AOF模式,并发200路,模拟不断写Redis,持续15分钟后,接口调用开始出现大量失败,且Redis所在的Linux虚拟服务器挂起。

接口报错如下:

{"data":null,"base":{"returndesc":"系统异常","returncode":"999999"},"qrybase":null}
Biz(dubbo)接口报错如下:
2015-06-05 11:28:28.760 [DubboServerHandler-192.168.57.144:20882-thread-173] ERROR com.iflytek.diange.biz.redis.JedisFactory - error while validate jedis!
redis.clients.jedis.exceptions.JedisConnectionException: java.net.SocketTimeoutException: Read timed out

原因分析:
从dubbo接口报错信息来看,是由于接口API操作Redis超时导致。从系统日志和IO监控来看,均说明上述问题是由于IO瓶颈(系统IO过于繁忙)所致,如下所示:

从系统日志也能看出,IO阻塞时间超过了120秒,由于系统安全机制导致机器挂起。

总结
测试结果证明AOF模式存在最明显缺陷,即访问压力大时IO会成为性能瓶颈,进而导致服务不可用。

3.缓解方案(不能根本解决问题)
编辑/etc/sysctl.conf ,添加如下配置:

vm.dirty_background_ratio = 5
vm.dirty_ratio = 10

然后sysctl -p 使配置文件生效。

问题2描述:
无论采用AOF模式还是RDB(快照模式),当两文件(.aof或.rdb)大小超过系统内存80%,Redis进程会被系统Kill掉,导致服务不可用。

总结
上述问题说明我们在使用Redis时需要事先做好系统内存的容量规划,因为一旦Redis宕掉会导致大量数据丢失且是不可恢复的。

案例三:Redis内存碎片率

一、 内存碎片率

mem_fragmentation_ratio = used_memory_rss / used_memory
used_memory :Redis使用其分配器分配的内存大小
used_memory_rss :操作系统分配给Redis实例的内存大小,表示该进程所占物理内存的大小
两者包括了实际缓存占用的内存和Redis自身运行所占用的内存,used_memory_rss指标还包含了内存碎片的开销,内存碎片是由操作系统低效的分配/回收物理内存导致的。

mem_fragmentation_ratio < 1 表示Redis内存分配超出了物理内存,操作系统正在进行内存交换,内存交换会引起非常明显的响应延迟;
mem_fragmentation_ratio > 1 是合理的;
mem_fragmentation_ratio > 1.5 说明Redis消耗了实际需要物理内存的150%以上,其中50%是内存碎片率,可能是操作系统或Redis实例中内存管理变差的表现

二、 内存碎片率高的原因

1.遇到变长key-value负载:存储的数据长短差异较大,频繁更新,redis的每个k-v对初始化的内存大小是最适合的,当修改的value改变的并且原来内存大小不适用的时候,就需要重新分配内存。重新分配之后,就会有一部分内存redis无法正常回收,一直占用着。

2.maxmemory限制导致key被回收删除
redis写入大量数据,这些数据的key和原来的数据很多不一致,数据超过maxmemory限制后redis会通过key的回收策略将部分旧数据淘汰,而被淘汰的数据本身占用的内存却没有被redis进程释放,导致redis内存的有效数据虽然没有超过最大内存,但是整个进程的内存在一直增长
info信息中的evicted_keys字段显示的是,因为maxmemory限制导致key被回收删除的数量
key经常需要回收,会使客户端命令响应延迟时间增加,因为Redis不但要处理客户端过来的命令请求,还要频繁的回收满足条件的key

三、 解决方法

限制内存交换: 如果内存碎片率低于1,Redis实例可能会把部分数据交换到硬盘上,应该增加可用物理内存或减少实Redis内存占用,设置maxmemory和回收策略可以避免强制内存交换

重启Redis服务器:如果内存碎片率超过1.5,重启Redis服务器可以让额外产生的内存碎片失效并重新作为新内存来使用,使操作系统恢复高效的内存管理。额外碎片的产生是由于Redis释放了内存块,但内存分配器并没有返回内存给操作系统

内存碎片清理:Redis 4.0-RC3 以上版本,使用jemalloc作为内存分配器(默认的) 支持内存碎片清理
支持在运行期进行自动内存碎片清理
设置自动清理 config set activedefrag yes,使用config rewrite 将redis内存中新配置刷新到配置文件
支持通过命令 memory purge 进行手动清理(与自动清理区域不同)

redis4支持内存碎片清理功能使用

最近看到redis4支持内存碎片清理了, 之前一直期待有这么一个功能, 因为之前遇到内存碎片的解决办法就是重启, 现在终于有了优雅的解决方案.^o^/, 这个功能其实oranagra 在2017年1月1日已经提交pr了, 相关地址: https://github.com/antirez/redis/pull/3720

版本说明:

Redis 4.0-RC3 以上版本才支持的
需要使用jemalloc作为内存分配器(默认的)
功能介绍:

支持在运行期进行自动内存碎片清理 (config set activedefrag yes)
支持通过命令 memory purge 进行清理(与自动清理区域不同)
功能验证流程:

(1) 首先需要拉取4.0-RC3之后的版本代码, 编译

(2) 启动时限定内存大小为1g并启动lru, 命令如下:

./src/redis-server --maxmemory 1gb --maxmemory-policy allkeys-lru --activedefrag no --port 6383

(3) 构造大量数据并导致lru, 这样可以触发内存碎片, 命令如下:

redis-cli -p 6383 debug populate 7000000 asdf 150

(4) 查看当前的内存使用情况, 会发现有200多万的数据被清理掉了

$ redis-cli -p 6383 info keyspace
# Keyspace
db0:keys=4649543,expires=0,avg_ttl=0

(5) 查看当前的内存碎片率, 这时碎片率(mem_fragmentation_ratio)很高 : 1.54, 意味着54%的内存浪费

$ redis-cli -p 6383 info memory
# Memory
used_memory:1073741736
used_memory_human:1024.00M
used_memory_rss:1650737152
used_memory_rss_human:1.54G
used_memory_peak:1608721680
used_memory_peak_human:1.50G
used_memory_peak_perc:66.75%
used_memory_overhead:253906398
used_memory_startup:766152
used_memory_dataset:819835338
used_memory_dataset_perc:76.41%
total_system_memory:67535904768
total_system_memory_human:62.90G
used_memory_lua:37888
used_memory_lua_human:37.00K
maxmemory:1073741824
maxmemory_human:1.00G
maxmemory_policy:allkeys-lru
mem_fragmentation_ratio:1.54
mem_allocator:jemalloc-4.0.3
active_defrag_running:0
lazyfree_pending_objects:0

(6) 看看内存分配的详细情况, 这个地方看不懂可以看看: 科普文, 关键的是util指标, 指的是内存利用率, 最大的bins内存util是0.661, 说明内存利用率不高


$ echo "`redis-cli -p 6383 memory malloc-stats`"
___ Begin jemalloc statistics ___
Version: 4.0.3-0-ge9192eacf8935e29fc62fddc2701f7942b1cc02c
Assertions disabled
Run-time option settings:
  opt.abort: false
  opt.lg_chunk: 21
  opt.dss: "secondary"
  opt.narenas: 48
  opt.lg_dirty_mult: 3 (arenas.lg_dirty_mult: 3)
  opt.stats_print: false
  opt.junk: "false"
  opt.quarantine: 0
  opt.redzone: false
  opt.zero: false
  opt.tcache: true
  opt.lg_tcache_max: 15
CPUs: 12
Arenas: 48
Pointer size: 8
Quantum size: 8
Page size: 4096
Min active:dirty page ratio per arena: 8:1
Maximum thread-cached size class: 32768
Chunk size: 2097152 (2^21)
Allocated: 1074509704, active: 1609732096, metadata: 41779072, resident: 1651118080, mapped: 1652555776
Current active ceiling: 1610612736

arenas[0]:
assigned threads: 1
dss allocation precedence: secondary
min active:dirty page ratio: 8:1
dirty pages: 393001:24 active:dirty, 0 sweeps, 0 madvises, 0 purged
                            allocated      nmalloc      ndalloc    nrequests
small:                     1006565256     28412640      9802493     35714594
large:                         835584           20           11           20
huge:                        67108864            1            0            1
total:                     1074509704     28412661      9802504     35714615
active:                    1609732096
mapped:                    1650458624
metadata: mapped: 40202240, allocated: 491904
bins:           size ind    allocated      nmalloc      ndalloc    nrequests      curregs      curruns regs pgs  util       nfills     nflushes      newruns       reruns
                   8   0         1992          319           70          357          249            1  512   1 0.486            7            8            1            0
                  16   1    148618896     14110300      4821619     14310175      9288681        55119  256   1 0.658       141103        48825        55119            5
                  24   2    112104360      7200400      2529385      7300348      4671015        14064  512   3 0.648        72004        25881        14064            1
                  32   3          288          112          103      7003270            9            1  128   1 0.070            3            7            1            0
                  40   4          360          109          100          171            9            1  512   5 0.017            3            7            1            0
                  48   5         1248          112           86           63           26            1  256   3 0.101            2            5            1            0
                  56   6          896          106           90           16           16            1  512   7 0.031            2            6            1            0
                  64   7          128           64           62            5            2            1   64   1 0.031            1            3            1            0
                  80   8          880          106           95            7           11            1  256   5 0.042            2            4            1            0
                  96   9         9120          212          117           97           95            1  128   3 0.742            4            6            2            1
                 112  10          336          109          106            2            3            1  256   7 0.011            3            6            3            0
                 128  11          640           40           35            4            5            1   32   1 0.156            3            4            2            0
                 160  12    740617440      7000148      2371289      7000001      4628859        54688  128   5 0.661        70271        24334        54689            4
                 192  13          768           68           64            1            4            1   64   3 0.062            2            4            2            0
                 224  14      4683616       100000        79091        99946        20909          781  128   7 0.209         1000         1641          782            0
                 256  15            0           16           16            4            0            0   16   1 1                1            3            1            0
                 320  16         5120           64           48           16           16            1   64   5 0.250            1            3            1            0
                 384  17          768           33           31            2            2            1   32   3 0.062            1            3            1            0
                 448  18        28672           64            0            0           64            1   64   7 1                1            0            1            0
                 512  19         1024           10            8            4            2            1    8   1 0.250            1            2            2            0
                 640  20            0           32           32            1            0            0   32   5 1                1            3            1            0
                     ---
                 896  22        48384           85           31           50           54            2   32   7 0.843            2            3            2            0
                1024  23         3072           10            7            3            3            1    4   1 0.750            1            2            3            0
                1280  24        20480           16            0            0           16            1   16   5 1                1            0            1            0
                1536  25        15360           10            0            0           10            2    8   3 0.625            1            0            2            0
                1792  26        28672           16            0            0           16            1   16   7 1                1            0            1            0
                2048  27         4096           10            8            2            2            1    2   1 1                1            2            5            0
                     ---
                3584  30        35840           10            0            0           10            2    8   7 0.625            1            0            2            0
                     ---
                5120  32       250880           49            0           49           49           13    4   5 0.942            0            0           13            0
                     ---
                8192  35        81920           10            0            0           10           10    1   2 1                1            0           10            0
                     ---
large:          size ind    allocated      nmalloc      ndalloc    nrequests      curruns
               16384  39        16384            2            1            2            1
               20480  40        40960            2            0            2            2
                     ---
               32768  43        32768            1            0            1            1
               40960  44        40960           10            9           10            1
                     ---
               81920  48        81920            1            0            1            1
                     ---
              131072  51       131072            1            0            1            1
              163840  52       163840            1            0            1            1
                     ---
              327680  56       327680            1            0            1            1
                     ---
             1048576  63            0            1            1            1            0
                     ---
huge:           size ind    allocated      nmalloc      ndalloc    nrequests   curhchunks
                     ---
            67108864  87     67108864            1            0            1            1
                     ---
--- End jemalloc statistics ---

(7) 开启自动内存碎片整理

$ redis-cli -p 6383 config set activedefrag yes
OK

(8) 等会儿再看看, 发现内存碎片降低了

$ redis-cli -p 6383 info memory
# Memory
used_memory:1073740712
used_memory_human:1024.00M
used_memory_rss:1253371904
used_memory_rss_human:1.17G
used_memory_peak:1608721680
used_memory_peak_human:1.50G
used_memory_peak_perc:66.74%
used_memory_overhead:253906398
used_memory_startup:766152
used_memory_dataset:819834314
used_memory_dataset_perc:76.41%
total_system_memory:67535904768
total_system_memory_human:62.90G
used_memory_lua:37888
used_memory_lua_human:37.00K
maxmemory:1073741824
maxmemory_human:1.00G
maxmemory_policy:allkeys-lru
mem_fragmentation_ratio:1.17
mem_allocator:jemalloc-4.0.3
active_defrag_running:0
lazyfree_pending_objects:0

(9) 可以再看看内存利用率, 可以看到已经上升到0.82

$ echo "`redis-cli -p 6383 memory malloc-stats`"
___ Begin jemalloc statistics ___
Version: 4.0.3-0-ge9192eacf8935e29fc62fddc2701f7942b1cc02c
Assertions disabled
Run-time option settings:
  opt.abort: false
  opt.lg_chunk: 21
  opt.dss: "secondary"
  opt.narenas: 48
  opt.lg_dirty_mult: 3 (arenas.lg_dirty_mult: 3)
  opt.stats_print: false
  opt.junk: "false"
  opt.quarantine: 0
  opt.redzone: false
  opt.zero: false
  opt.tcache: true
  opt.lg_tcache_max: 15
CPUs: 12
Arenas: 48
Pointer size: 8
Quantum size: 8
Page size: 4096
Min active:dirty page ratio per arena: 8:1
Maximum thread-cached size class: 32768
Chunk size: 2097152 (2^21)
Allocated: 1074509800, active: 1307602944, metadata: 41779072, resident: 1512247296, mapped: 1652555776
Current active ceiling: 1308622848

arenas[0]:
assigned threads: 1
dss allocation precedence: secondary
min active:dirty page ratio: 8:1
dirty pages: 319239:39882 active:dirty, 4878 sweeps, 6343 madvises, 33915 purged
                            allocated      nmalloc      ndalloc    nrequests
small:                     1006565352     35456589     16846439     45126633
large:                         835584           24           15           24
huge:                        67108864            1            0            1
total:                     1074509800     35456614     16846454     45126658
active:                    1307602944
mapped:                    1650458624
metadata: mapped: 40202240, allocated: 491904
bins:           size ind    allocated      nmalloc      ndalloc    nrequests      curregs      curruns regs pgs  util       nfills     nflushes      newruns       reruns
                   8   0         1992          319           70          357          249            1  512   1 0.486            7            8            1            0
                  16   1    148618896     17658482      8369801     17858357      9288681        44332  256   1 0.818       141103        48825        55119        26364
                  24   2    112104360      8897298      4226283      8997246      4671015        11525  512   3 0.791        72004        25881        14064         6205
                  32   3          384          115          103      9371363           12            1  128   1 0.093            4            7            1            0
                  40   4          360          109          100          171            9            1  512   5 0.017            3            7            1            0
                  48   5         1248          112           86           63           26            1  256   3 0.101            2            5            1            0
                  56   6          896          106           90           16           16            1  512   7 0.031            2            6            1            0
                  64   7          128           64           62            5            2            1   64   1 0.031            1            3            1            0
                  80   8          880          106           95            7           11            1  256   5 0.042            2            4            1            0
                  96   9         9120          212          117           97           95            1  128   3 0.742            4            6            2            1
                 112  10          336          109          106            2            3            1  256   7 0.011            3            6            3            0
                 128  11          640           40           35            4            5            1   32   1 0.156            3            4            2            0
                 160  12    740617440      8788058      4159199      8787911      4628859        44056  128   5 0.820        70271        24334        54689        26488
                 192  13          768           68           64            1            4            1   64   3 0.062            2            4            2            0
                 224  14      4683616       110956        90047       110902        20909          467  128   7 0.349         1000         1641          782          105
                 256  15            0           16           16            4            0            0   16   1 1                1            3            1            0
                 320  16         5120           64           48           16           16            1   64   5 0.250            1            3            1            0
                 384  17          768           33           31            2            2            1   32   3 0.062            1            3            1            0
                 448  18        28672           64            0            0           64            1   64   7 1                1            0            1            0
                 512  19         1024           10            8            4            2            1    8   1 0.250            1            2            2            0
                 640  20            0           32           32            1            0            0   32   5 1                1            3            1            0
                     ---
                 896  22        48384           85           31           50           54            2   32   7 0.843            2            3            2            0
                1024  23         3072           10            7            3            3            1    4   1 0.750            1            2            3            0
                1280  24        20480           16            0            0           16            1   16   5 1                1            0            1            0
                1536  25        15360           10            0            0           10            2    8   3 0.625            1            0            2            0
                1792  26        28672           16            0            0           16            1   16   7 1                1            0            1            0
                2048  27         4096           10            8            2            2            1    2   1 1                1            2            5            0
                     ---
                3584  30        35840           10            0            0           10            2    8   7 0.625            1            0            2            0
                     ---
                5120  32       250880           49            0           49           49           13    4   5 0.942            0            0           13            0
                     ---
                8192  35        81920           10            0            0           10           10    1   2 1                1            0           10            0
                     ---
large:          size ind    allocated      nmalloc      ndalloc    nrequests      curruns
               16384  39        16384            2            1            2            1
               20480  40        40960            2            0            2            2
                     ---
               32768  43        32768            1            0            1            1
               40960  44        40960           14           13           14            1
                     ---
               81920  48        81920            1            0            1            1
                     ---
              131072  51       131072            1            0            1            1
              163840  52       163840            1            0            1            1
                     ---
              327680  56       327680            1            0            1            1
                     ---
             1048576  63            0            1            1            1            0
                     ---
huge:           size ind    allocated      nmalloc      ndalloc    nrequests   curhchunks
                     ---
            67108864  87     67108864            1            0            1            1
                     ---
--- End jemalloc statistics ---

(10) 别急, 还有一个大招: 手动清理

$ redis-cli -p 6383 memory purge

(11) 再次查看内存使用情况: 发现碎片率降到1.04, 内存利用率到0.998, 内存碎片基本上消灭了^_^
配置说明:

# Enabled active defragmentation
# 碎片整理总开关
# activedefrag yes

# Minimum amount of fragmentation waste to start active defrag
# 内存碎片达到多少的时候开启整理
active-defrag-ignore-bytes 100mb

# Minimum percentage of fragmentation to start active defrag
# 碎片率达到百分之多少开启整理
active-defrag-threshold-lower 10

# Maximum percentage of fragmentation at which we use maximum effort
# 碎片率小余多少百分比开启整理
active-defrag-threshold-upper 100

# Minimal effort for defrag in CPU percentage
active-defrag-cycle-min 25

# Maximal effort for defrag in CPU percentage
active-defrag-cycle-max 75

总结:
从测试的结果看, 效果还是非常不错的, 另外在配置中我们可以看到如下一段声明:

说明现在这个功能还是实验性质的, 对应的命令在官方文档中都没有看到. 但是它也说经过了压力测试, 而且现在也一年多了, 经受了一些考验, 可以尝试小流量上线观察

TODO redis 内存碎片整理实现

文档更新时间: 2019-11-04 09:36   作者:李延召