通过经历Redis正式故障我认识到了代码审查的要点
Redis的问题如果没有得到适当利用,很多时候会在生产环境中显现出来,就像定时炸弹一样存在着。要事先防止这种情况发生,只能在代码审查阶段进行打击。
Redis和脚本语言非常配合,正确使用可以比RDB快得多地编写程序。去年受到尊敬的前辈斧头一样的100多条评论进行了代码审查,虽然被砸得浑身是血,但从中学到了很多东西,并总结成了一份报告。总的来说,如果数据可以被删除,那就选择Redis。
如果Redis的内存溢出…
这个故事不是事实,而是幻想。
我被深夜电话吵醒了。似乎是遭遇了访问障碍。
当我们几个人进行现场确认时,发现游戏完全无法进行。为了避免数据不一致问题,进行了维护。
不久之后,发现Redis因内存不足而无法进行新的写入操作。由于服务器的内存容量已达到64G字节且无法进一步扩展,我们开始削减Redis的内存容量。
无法有效地对巨大的RedisDB进行配置文件。
在本地环境中,可以使用类似 RDM 的工具将键值以树状结构展示出来,从而可视化展示哪些键值较多。但当Redis服务器的内存容量达到约64Gb时,无法通过树状结构一览全局情况,无法确定导致问题的键值。因此只能从代码方面着手来解决问题。
Redis的垂直拆分花费太多时间,令人感到绝望。
我不知道原因,但是通过一些分析,我已经找到了一些线索。突然间外面变得亮起来了。看样子似乎是使用Redis作为存储,重要用户数据保存在其中,因此无法直接删除。只好准备另一台Redis服务器,决定将一半的键复制过去。写了复制批处理并执行,结果过了两个小时还没有结束。检查了新的Redis服务器上的键数,发现只完成了5%的复制,还需要38个小时才能全部复制完。生产环境不能停机两天,因此决定再使用并行方式进行数据复制……
Redis服务器常见的崩溃方式
Redis服务器是否崩溃或APP服务器是否崩溃取决于情况。
1. 通过KEYS命令或ZRANGE命令访问超过数万条数据时,出现I/O等待而崩溃。
2. 由于数据设计错误导致内存不足而无法写入而崩溃。
在Redis服务器发生故障时的基本应对措施。
首先,需要将问题划分为内存不足或I/O等待两种情况。
1. 检查使用时间较长的ZRANGE或keys *命令。
2. 删除不必要的键。
3. 添加服务器并进行垂直分割。
4. 改变数据设计,将数据存储位置从Redis改为RDB。
代码审查的角度
Redis在不正确使用时经常在实际运行中暴露出问题,并像定时炸弹一样存在。要预防这种情况发生,只能在代码审查阶段进行打击。我们会从Redis服务器的I/O是否衰退、内存使用量是否爆炸以及数据的一致性是否能够保持这三个角度进行代码审查。
如果使用Redis,就要保持警惕。如果是一个用户数量众多的服务,在一个数据设计错误的情况下,可能会导致生产Redis服务器或APP服务器停止运行的风险。在使用Redis的阶段,要设想最糟糕的情况,并提高代码审查的警惕级别。
如果使用存储而不是缓存,就会提醒您。将重要的数据记录在RDB中,仅将缓存保存在Redis中。标准是“如果数据丢失也没关系就用Redis”。如果将重要数据记录在Redis中,在数据库事务回滚时无法回滚Redis端的数据,导致数据不一致性。
– Redis是否设置了过期时间(TTL)?
在Redis中,可以为每个key设置Expire(TTL)。如果作为缓存使用的话,应该设置一个最长一个月左右的过期时间就没有问题。如果需要设置超过一个月的过期时间,几乎可以确定这是在明确使用Redis作为存储。建议进行设计更改以使用RDB。
■ 5. 不使用keys命令
keys命令是用于返回与通配符匹配的KEY的命令。如果数据不均匀,服务器将在I/O等待中发生故障。与其使用keys命令进行线性搜索,不如将其放入RDB中,建立索引并使用WHERE子句进行查询。
■ 6. 如果有必要使用Redis作为存储设备,也可能有例外情况。
万事皆有例外。例如,像Redis的SortedSet一样,存在少量只能通过使用Redis独有功能才能实现的功能。在这种情况下,我们将根据以下观点进行评估。
在数据库交易中出现问题时,当进行回滚时,Redis不会回滚。因此,在出现RDB和Redis之间的数据不一致时,需要确认系统是否采用了能够将数据恢复到正确状态的设计。可以通过在RDB和Redis中重复存储数据,并且从视图层通过访问Redis来获得高速化的好处,并在数据更新时将RDB的值作为正确值来覆盖Redis数据来解决这个问题。
■ 6-2. Redis的数据丢失后能否恢复(非必需)
为了在Redis出现崩溃或数据不一致时能够进行恢复操作,事先准备好完整的恢复命令是必要的。只要数据能保存到RDB中,即使在出现故障后再编写代码也没有问题,因此这并不是必须的处理措施。
Redis的配置文件中,bigkeys命令非常有用。
由于bigkeys命令只是样本调查,即使在巨大的数据库上,调查也可以在合理的时间内完成。对于拥有1100万KEY的Redis数据库,大约只需要1分钟左右。
我在多人PJ的正式环境中经常会发现很多看不出来是否可以删除的旧Key,并且经常因此感到困惑,但偶尔也有一些改善的提示。由于互联网上的信息很少,所以直接阅读redis-cli.c中bigkeys的实现无疑是更快的方法。
>> redis-cli -n 11 --bigkeys
# Scanning the entire keyspace to find biggest keys as well as
# average sizes per key type. You can use -i 0.1 to sleep 0.1 sec
# per 100 SCAN commands (not usually needed).
[00.00%] Biggest list found so far 'CF:INDEX:GOODS-HIS:CAMERA:563749' with 51 items
[00.00%] Biggest hash found so far 'CF:GOODS:TAG:208737' with 1 fields
[00.00%] Biggest list found so far 'CF:INDEX:GOODS-HIS:TAG7:554718' with 56 items
[00.00%] Biggest list found so far 'CF:INDEX:GOODS-HIS:CAMERA:62917' with 65 items
[00.01%] Biggest list found so far 'CF:INDEX:GOODS-HIS:TAG10:798984' with 66 items
[00.01%] Biggest list found so far 'CF:INDEX:GOODS-HIS:DVD:585528' with 73 items
[00.06%] Biggest list found so far 'CF:INDEX:GOODS-HIS:CLOTHES:739957' with 74 items
[00.44%] Biggest list found so far 'CF:INDEX:GOODS-HIS:DVD:241918' with 83 items
[06.03%] Biggest list found so far 'CF:INDEX:GOODS-HIS:CLOTHES:452765' with 87 items
[09.01%] Sampled 1000000 keys so far
[18.02%] Sampled 2000000 keys so far
[27.03%] Sampled 3000000 keys so far
[36.03%] Sampled 4000000 keys so far
[45.04%] Sampled 5000000 keys so far
[54.05%] Sampled 6000000 keys so far
[63.06%] Sampled 7000000 keys so far
[69.93%] Biggest list found so far 'CF:INDEX:GOODS-HIS:COMPUTER:328426' with 89 items
[72.07%] Sampled 8000000 keys so far
[81.08%] Sampled 9000000 keys so far
[90.09%] Sampled 10000000 keys so far
[99.10%] Sampled 11000000 keys so far
-------- summary -------
Sampled 11100436 keys in the keyspace!
Total key length in bytes is 588720855 (avg len 53.04)
Biggest list found 'CF:INDEX:GOODS-HIS:COMPUTER:328426' has 89 items
Biggest hash found 'CF:GOODS:TAG:208737' has 1 fields
0 strings with 0 bytes (00.00% of keys, avg size 0.00)
10100437 lists with 100997852 items (90.99% of keys, avg size 10.00)
0 sets with 0 members (00.00% of keys, avg size 0.00)
999999 hashs with 999999 fields (09.01% of keys, avg size 1.00)
0 zsets with 0 members (00.00% of keys, avg size 0.00)
请你给我提供一个选择。
只需要一种选项,在中文中进行以下重述:redis-cli.c