奇技指南:
Pika是360 热门的c++开源项目,基于rocksdb开发的大容量类Redis存储,力求在完全兼容Redis协议、继承Redis便捷运维设计的前提下通过持久化存储方式解决Redis在大容量场景下主从同步代价高、恢复时间慢、单线程相对脆弱、内存成本高等问题。
开源地址:https://github.com/Qihoo360/pika
我们根据360内部的Pika使用经验及社区用户的问题反馈,整理了本文并在这里分享给大家
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最佳实践