Pika 最佳实践

阅读数:18 2019 年 11 月 19 日 23:50

Pika最佳实践

Pika 是 360 热门的 c++ 开源项目,基于 rocksdb 开发的大容量类 Redis 存储,力求在完全兼容 Redis 协议、继承 Redis 便捷运维设计的前提下通过持久化存储方式解决 Redis 在大容量场景下主从同步代价高、恢复时间慢、单线程相对脆弱、内存成本高等问题。

我们根据 360 内部的 Pika 使用经验及社区用户的问题反馈,整理了本文并在这里分享给大家

Pika 最佳实践之一

在群里提问主动带上版本号能大幅度加快问题解决速度(Pika 社区 QQ 群:294254078)

Pika 最佳实践之二

Pika 已在 2019 年 1 月 24 日更新至 3.0.7,但仍然有大量用户停留在两年前的 2.2.X 或一年前的 2.3.X,我们建议使用 3.0 的最新版,如果不愿意使用 3.X 那么请使用 2.3.6,否则你会发现你遇到的很多问题都在我们的 bug 修复列表中

Pika 最佳实践之三

Pika 的线程数量建议和 cpu 总线程数一致,如果是单机多实例的部署,每个 Pika 实例的线程数量可以酌情降低,但不建议低于 cpu 总线程数的 1/2

Pika 最佳实践之四

Pika 的性能和 IO 性能息息相关,我们不建议在机械盘上部署耗时敏感项目的 Pika,另外为了避免一些稀奇古怪的问题,主从服务器的硬件性能应当尽量一致

Pika 最佳实践之五

在使用 Pika 多数据结构(hash,list,zset,zset)的时候,尽量确保每个 key 中的 field 不要太多,如果业务类型为耗时敏感型那么建议每个 key 的 field 数量不要超过 1 万个,特大 key 可以考虑拆分为多个小 key,这样可以避免超大 key 很多潜在的性能风险,而存储型业务(耗时不敏感)则没有这个要求

Pika 最佳实践之六

root-connection-num 参数非常有用,意为“允许通过 127.0.0.1 登录 Pika 的连接数”,它与最大连接数配置项 maxclients 独立,maxclients 的用尽并不会影响 root-connection-num,因此在发生异常 maxclients 被用尽的场景中,管理员仍然可以登录 Pika 所在服务器并通过 127.0.0.1 来登入 Pika 处理问题,避免了 maxclients 耗尽无法登录处理的尴尬局面

Pika 最佳实践之七

client kill 命令被加强了,如果你想一次性杀掉当前 Pika 的所有连接,只需要执行 client kill all,不用担心,用于同步的连接不会受到影响

Pika 最佳实践之八

适当地调整 timeout 参数,通过该参数 Pika 会主动断开不活动时间超过 timeout 值的连接,避免连接数耗尽问题的发生,由于连接也需要申请内存,因此合理的配置 timeout 参数也能够在一定程度上降低 Pika 的内存占用

Pika 最佳实践之九

Pika 的内存占用主要集中在 sst 文件的 cache 和连接申请内存,而通常连接申请内存会比 sst 的 cache 要大很多,Pika 目前已支持连接申请内存的动态调整、回收,因此连接占用的总内存大小是可以粗略估算的,如果你的 Pika 内存占用远超预估或大于 10g,那么可能为你当前使用的版本存在内存泄漏问题,尝试依次执行命令 client kill all 和 tcmalloc free 来对连接内存进行强制回收,如果效果不好请升级到最新版本

Pika 最佳实践之十

非常不建议单机运行 Pika,最简集群状态应为一主一从,而主从集群的容灾模式有很多种,可以考虑使用 lvs、vip 漂移、配置管理中间件等

Pika 最佳实践之十一

建议使用主从集群而不是双主模式,在实际使用中双主模式对使用规范的要求、网络环境要求相对更高,使用不规范、网络环境不好会造成双主模式出现问题,在出现问题后,双主模式的数据修复比主从集群数据修复复杂度要大

Pika 最佳实践之十二

如果你的 Pika 单机运行(非主从、主主集群),并部署在可靠的存储上,那么可以考虑通过关闭 binlog(将 write-binlog 参数设置为 no)来提高写入性能,不过我们并不推荐单机运行,至少应当有一个从库用于容灾

Pika 最佳实践之十三

Pika 的数据目录中有大量的 sst 文件,这些文件随着 Pika 数据量的增加而增加,因此你需要为 Pika 配置一个更大的 open_file_limit 避免不够用,如果你不希望 Pika 占用太多的文件描述符,可以通过适当增大单个 sst 的体积来降低 sst 的总数量,对应参数为 target-file-size-base

Pika 最佳实践之十四

不要修改 log 目录中的 write2file 文件和 manifest,它们是同步相关的重要文件,write2file 为 binlog 角色,而 manifest 则用来确保实例重启后的 binlog 续写及实例为从库时帮助同步中断重连后续传

Pika 最佳实践之十五

Pika 的全量同步是通过 rsync 来进行的,因此我们提供了 rsync 的传输限速参数 db-sync-speed,该参数的单位是 mb,我们建议在千兆环境中该参数设置不应高于 75,而在万兆环境中不应高于 500,这样可以避免 Pika 在全量同步的时候将所在服务器网卡用尽而影响到部署在服务器上的其它服务

Pika 最佳实践之十六

在 Pika 中执行 key * 并不会造成 Pika 阻塞(Pika 是多线程的),但在存在巨量 key 的场景下可能会造成临时占用巨量内存(这些内存用于该连接存放 key * 的执行结果,会在 key * 执行完毕后释放),因此使用 keys * 一定要小心谨慎

Pika 最佳实践之十七

如果发现 Pika 有数据但 info keyspace 的显示均为 0,这是因为 Pika 并没有像 Redis 对 key 的数量做实时统计并展示,Pika 中 key 的统计需要人工触发,执行 info keyspace 1,注意执行 info keyspace 是不会触发统计的,没有带上最后的参数 1 将会仅仅展示上一次的统计结果,key 的统计是需要时间的,执行状态可以通过 info stats 中的 is_scaning_keyspace 进行查看,该项值为 yes 表明统计正在进行,为 no 时表明没有正在进行的统计 / 上一次统计已结束,在统计执行完毕前 info keyspace 不会更新,info keyspace 的数据是存放在内存里的,重启将清零

Pika 最佳实践之十八

不要在 Pika 执行全量 compact 的时候触发 key 统计(info keyspace 1)或执行 keys *,否则会造成数据体积暂时膨胀直到 key 统计、keys * 执行结束

Pika 最佳实践之十九

对存在大量过期、多数据结构内元素操作的实例配置 compact-cron 可以非常好地避免无效但还未被彻底清理的数据对性能造成的影响,或升级到 3.0 后打开新的 key 级 auto_compact 功能,如果你遇到了下面的情况,那么你的实例可能存在无效数据风险:

异常的数据体积(大于估算值 10% 以上),可以通过执行 compact 命令,在 compact 执行完毕后观察数据体积是否恢复正常

请求耗时突然异常增大,可以通过执行 compact 命令,在 compact 执行完毕后观察请求耗时是否恢复正常

Pika 最佳实践之二十

在 Pika3.0 中我们提供了过期 key 的统计(可通过 info keyspace 1 来触发统计,通过 info keyspace 查看统计结果),统计结果中的 invaild_keys 的值为“已删除 / 过期但还未被物理删除的 key 的数量”,Pika 会在后台逐步地对已删除 / 过期的 key 进行物理清理,由于这是一个后台行为,因此在存在大规模过期 key 的场景下这些 key 可能无法被及时清理,因此建议关注该值,若发现无效 key 数量过多可通过 compact 命令进行全面清理,这样能够将未物理清理的无效数据控制在一个较好的程度从而确保 Pika 的性能稳定,如果 Pika 中存储的数据是规律性过期的,例如每个 key 的过期时间为 7 天,那么建议通过配置 compact-cron 参数来实现每天的定时全自动全量 compact,compact 会占用一定的 IO 资源,因此如果磁盘 IO 压力过大,建议将其配置为业务低峰期执行,例如深夜

Pika 最佳实践之二十一

write2file 的角色相当于 binlog,应当根据实际写入情况调整 write2file 到合适的保留周期 / 数量,建议 write2file 保留周期 / 数量不低于 48 小时,足够的 write2file 能够让很多情况变得轻松,例如:大数据集群的从库扩容、从库服务器关机维修、从库迁移等等,不会因为主库 write2file 过期而被迫全量重传

Pika 最佳实践之二十二

在主库写入量过大(普通 ssd,大致写入 qps 大于 5 万)的情况下从库可能会发生同步延迟问题,可以调整从库的 sync-thread-num 参数来提高从库同步性能,该参数控制着从库的同步线程,每个线程通过 hash 来负责对应的 key 的同步,因此主库写入操作的不同的 key 的数量越多该参数的效果就会越好,而如果巨量的写入仅集中在几个 key 中,那么该参数可能无法达到预期效果

Pika 最佳实践之二十三

Pika 的备份生成为快照式,通过硬链接存放在 dump 目录中以日期为后缀,备份每天只能生成一份,多次生成备份时新的备份会覆盖之前的。在生成备份快照的时候,为了确保数据的一致性 Pika 会暂时阻塞写入,阻塞时间与实际数据量相关,根据测试 500g 的 Pika 生成备份快照也仅需 50ms,在写入阻塞的过程中连接不会中断请求不会异常,但 client 会感觉到“在那一瞬间请求耗时增加了一些”。由于 Pika 的快照是 db 目录中 sst 文件的硬连接,因此最初这个目录是不会占用磁盘空间的,而在 Pika db 目录中的 sst 文件发生了合并、删除后,硬链接会因为其特性而体现真实体积从而开始占用磁盘空间,所以请根据实际的磁盘空间调整备份保留天数,避免备份太多而造成磁盘空间用尽

Pika 最佳实践之二十四

如果写入量巨大且磁盘性能不足以满足 rocksdb memtable 的及时刷盘需求,那么 rocksdb 很可能会进入写保护模式(写入将被全部阻塞),对于该问题我们建议更换性能更好的存储来支撑,或者降低写入频率(例如将集中写数据的 2 小时拉长到 4 小时),也可适当加大 write-buffer-size 的值来提高 memtable 的总容量从而降低整个 memtable 被写满的可能,但实际根据测试发现修改该参数并不能彻底解决该问题,因为“写的 memtable 迟早要刷下去的!之前刷不动,现在也刷不动!”

Pika 最佳实践之二十五

Pika 对数据进行了压缩,默认压缩算法为 snappy,并允许改为 zlib,因此每一次数据的存入、读出都需要经过压缩、解压,这对 cpu 有一定的消耗,非常建议像使用 Redis 一样使用 Pika:在 Pika 中关闭压缩,而在 client 中完成数据的压缩、解压,这样不仅能够降低数据体积,还能有效降低 Pika 的 cpu 压力,如果你的存储空间不是问题但并不想调整 client,可以关闭压缩来降低 cpu 压力,代价是磁盘占用的增加,注意关闭、开启压缩需要重启实例但无需重做数据

Pika 最佳实践之二十六

读写分离很重要,Pika 在常见的主从集群中由于写入是单点的(主库),因此写入性能是有极限的,而读取可以通过多个从库来共同支撑,因此 Pika 集群的读取性能是随着从库数量的增加而增加的,所以对于读取量很大的场景,建议在业务层代码加入读写分离策略同时在 Pika 层增加从库数量通过多个从库来提供读服务,这样能够大幅度提高集群稳定性并有效降低读耗时

Pika 最佳实践之二十七

全量 compact 的原理是逐步对 rocksdb 的每一层做数据合并、清理工作,在这个过程中会新增、删除大量的 sst 文件,因此在执行全量 compact 的时候可以发现数据体积先增大后减小并最终减小到一个稳定值(无效、重复数据合并、清理完毕仅剩有效数据),建议在执行 compact 前确保磁盘空余空间不低于 30% 避免新增 sst 文件时将磁盘空间耗尽,另外 pika 支持对指定数据结构进行 compact,例如一个实例中已知 hash 结构的无效数据很少但 hash 结构数据量很大,set 结构数据量很大且无效数据很多,在这个例子中 hash 结构的 compact 是没有必要的,你可以通过 compact set 实现仅仅对 set 结构的 compact

Pika 最佳实践之二十八

备份是以硬链接 db 目录中的 sst 的方式产生的,因此在存在备份文件的情况下,一旦执行全量 compact 由于 Pika db 目录中的所有 sst 都会被 compact“清洗”一遍(逐步将所有老的 sst 删除替换成新的 sst),这将造成备份硬链接文件的体积变为真实体积,极端情况下备份文件会额外占用一倍的空间,因此如果你的磁盘空余空间不大,那么在执行全量 compact 之前最好删除备份

Pika 最佳实践之二十九

Pika 和 Redis 一样支持慢日志功能并可通过 slowlog 命令查看,但我们知道 slowlog 的存储是有上限的,这个上限取决于你的配置,如果配置过大会造成 slowlog 占用太多内存,而 Pika 允许将慢日志记录到 pika.ERROR 日志中用于追溯、分析,该功能需要将 slowlog-write-errorlog 设置为 yes

Pika 最佳实践之三十

Pika 没有提供 Redis 的命令改名(rename-command)功能,因为部分命令的改名会造成一些工具、中间件的工作异常(例如将 config 改名后哨兵会无法工作),因此 Pika 额外增加了 userpass、userblacklist 来解决这一问题。userpass 对应 requirepass,使用 userpass 登录的用户会受到 userblacklist 的限制,它们无法执行配置在 userblacklist 中的命令,而 requirepass 则不受影响,可以简单的将通过 requirepass 登录 Pika 的用户理解为“超级用户”,将通过 userpass 登录 Pika 的用户理解为“普通用户”,我们非常建议 Pika 运维将 userpass 提供给业务用于代码访问并在 userblacklist 增加例如 slaveof,config,shutdown,bgsave,dumpoff,client,keys 等管理类、风险性命令来避免误操作造成的故障

我们会随着 Pika 版本的不断更新及用户的反馈定期更新 Pika 最佳实践

本文转载自公众号 360 云计算(ID:hulktalk)。

原文链接:

https://mp.weixin.qq.com/s/vvz4FcPP0TzeMhhkkGkEbw

评论

发布