PikiwiDB(Pika) 是 360 技术中台中间件团队基于 RocksDB 开发的大容量类 Redis 存储系统,力求在完全兼容 Redis 协议、继承 Redis 便捷运维设计的前提下通过持久化存储方式解决 Redis 在大容量场景下主从同步代价高、恢复时间慢、单线程相对脆弱、内存成本高等问题。

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

之一

在微信群(群管理员微信号:PikiwiDB)中提问时,请主动带上版本号,可大幅度加快问题解决速度。

之二

PikiwiDB(Pika) 已在 2024 年 5 月更新至 3.5.4,但仍然有大量用户停留在 3.3.6 或3.3.2,我们建议使用 3.5.4 的最新版(预计本周内发布 v4.0.0),你会发现你遇到的很多问题都在我们的 bug 修复列表中。

之三

PikiwiDB(Pika) 的线程数量 thread-num 建议设置为 CPU core 数目的 80% 左右,如果是单机多实例的部署,每个 PikiwiDB(Pika) 实例的线程数量可以酌情降低,但不建议低于 CPU core 数的 1/2。

之四

PikiwiDB(Pika) 的工作线程池数量 thread-pool-size 建议和 CPU core 数目一致,如果是单机多实例的部署,每个 PikiwiDB(Pika) 实例的线程数量可以酌情降低,但不建议低于 1/2 CPU core 数。

之五

PikiwiDB(Pika) 的性能和 IO 性能息息相关,如果对耗时非常敏感,建议使用 NVMe SSD。另外,主从服务器的硬件规格应当尽量一致。

之六

在使用 PikiwiDB(Pika) 复合数据结构(hash,list,zset,zset)时,尽量确保每个 key 中的二级 key(或者成为 field)不要太多(不要超过 1 万个),在业务层或者代理层对大 key 符合数据结构进行拆分(类似于分库分表), 这样可以避免超大 key 带来很多潜在的性能风险。

之七

root-connection-num 参数非常有用,意为“允许通过 127.0.0.1 登录 PikiwiDB(Pika) 的连接数”,它不会被算进客户端最大连接数配置项 maxclients,因此在发生异常 maxclients 被用尽的场景中,管理员仍然可以登录 PikiwiDB(Pika) 所在服务器并通过 127.0.0.1 登入 PikiwiDB(Pika) 处理问题,可以认为是超级管理员通道。

之八

client kill 命令被加强了,如果你想一次性杀掉当前 PikiwiDB(Pika) 的所有客户端连接,只需要执行 client kill all 命令即可。注意,主从同步的网络连接不受影响。

之九

适当地调整 timeout 参数,PikiwiDB(Pika) 会主动断开不活跃时间超过 timeout 值的连接,避免连接数耗尽。由于网络连接会占用主机内存,因此合理的配置 timeout 参数也能够在一定程度上降低 PikiwiDB(Pika) 的内存使用量。

之十

PikiwiDB(Pika) 的内存占用主要集中在 SST 文件的 cache 和网络连接内存占用量,通常网络连接内存量会比 SST 的 cache 大,PikiwiDB(Pika) 目前已支持连接申请内存的动态调整与回收,因此连接占用的总内存大小是可以粗略估算的,如果你的 PikiwiDB(Pika) 内存占用远超预估(如大于 10GiB),那么可能为你当前使用的版本存在内存泄漏问题,尝试依次执行命令 client kill all 对连接内存进行强制回收,或者升级到最新版本。

之十一

非常不建议单副本运行 PikiwiDB(Pika),单副本的数据安全性无法保障,诸如 RocksDB Bug 或者资源不够(如:ERR IO error: While fdatasync: /data1/db/zsets/16566747.log: Cannot allocate memory)导致 RocksDB 存储数据被污染,此时无法全量恢复数据。 最简集群状态应为一主一从。

之十二

如果 PikiwiDB(Pika) 单副本运行(非主从集群),只在乎性能,且不在乎数据安全性(如缓存场景),可以考虑通过关闭 binlog(将 write-binlog 参数设置为 no)来提高写入性能。

之十三

PikiwiDB(Pika) v3.5.2 以及之后的版本提供了关闭 RocksDB WAL (DisableWAL true) 的命令,如果你的 PikiwiDB(Pika) 实例出现间断性的写性能阻塞的情况,你可以通过关闭 WAL 命令暂时关闭 WAL,这种方式有断电情况下数据丢失的风险,待性能恢复时,请及时再打开。对数据完整性要求不高时,建议关闭 WAL。

之十四

PikiwiDB(Pika) 的数据目录中有大量的 SST 文件,这些文件随着 PikiwiDB(Pika) 数据量的增加而增加,建议为 PikiwiDB(Pika) 配置一个较大的 open_file_limit ,以避免 fd 不够用,如果不希望 Pika 占用太多的文件描述符,可以通过适当增大单个 SST 的体积来降低 SST 的总数量,对应参数为 target-file-size-base。

之十五

不要修改 log 目录中的 write2file 文件和 manifest。write2file 记录了 binlog 文件列表等关键信息,而 manifest 则记录了 RocksDB 的 version 信息,二者关乎 PikiwiDB(Pika) 实例重启后的 binlog 续写及 slave 断点续传时的数据正确性。

之十六

自 PikiwiDB(Pika) v3.5.0 之后的版本摒弃了用 rsync 进程进行全量同步,PikiwiDB(Pika) 进程内部重新实现了一套新的全量同步机制(通过名称为 rsync 的线程传输)。PikiwiDB(Pika) 提供了 rsync 的总传输限速参数 throttle-bytes-per-second 和并发 rsync 线程数 max-rsync-parallel-num,throttle-bytes-per-second 参数的单位是 MiB,建议在千兆环境中该参数设置不应高于 45,而在万兆环境中不应高于 500,以避免 PikiwiDB(Pika) 在全量同步的时候将所在服务器网卡流量用尽而影响到 PikiwiDB(Pika) 服务客户端。

之十七

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

之十八

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

之十九

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

之二十

对存在大量过期数据的 PikiwiDB(Pika) 实例,compact-cron 配置项可以在固定时段(一般配置为低峰流量时间段)进行过期数据清理。自 PikiwiDB(Pika) v3.5.0 之后还提供了 auto_compact 配置型,启用后 PikiwiDB(Pika) 会自动周期性执行 compact。

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

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

之二十一

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

之二十二

write2file 的角色相当于 binlog,建议 write2file 保留周期/数量不低于 48 小时,足够的 write2file 有利于 大数据集群的从库扩容、从库服务器关机维修、从库迁移 等工作,不会因为主库 write2file 过期而被迫全量重传。

之二十三

PikiwiDB(Pika) 的备份生成为快照式,通过硬链接存放在 dump 目录下,以日期为后缀,每天只生成一份,多次生成备份时新的备份会覆盖之前的旧文件。在生成备份快照的时,为了确保数据的一致性 PikiwiDB(Pika) 会暂时阻塞写入,阻塞时间与实际数据量相关,根据测试PikiwiDB(Pika) 生成 500GiB 备份快照仅需 50ms。在写入阻塞的过程中连接不会中断,但 client 会感觉到 “在那一瞬间请求耗时增加了一些”。由于PikiwiDB(Pika)Pika 的快照是 db 目录中 sst 文件的硬连接,因此最初这个目录是不会占用磁盘空间的。

但在 PikiwiDB(Pika) db 目录中的 SST 文件发生了合并、删除后,硬链接的旧文件并不删除,这会导致 PikiwiDB(Pika) 占用的磁盘空间超出预估,所以请根据实际的磁盘空间调整备份保留天数,避免备份太多而造成磁盘空间用尽。

之二十四

如果写入量巨大且磁盘性能不足以满足 RocksDB memtable 的及时刷盘需求,那么 RocksDB 很可能会进入写保护模式(write stall,写入将被全部阻塞),建议更换性能更好的存储系统来支撑,或者降低写入频率(例如将集中写数据的 2 小时拉长到 4 小时),也可适当加大 write-buffer-size 的值来提高 memtable 的总容量从而降低整个 memtable 被写满的可能。

之二十五

PikiwiDB(Pika) 对数据进行了压缩,默认压缩算法为 snappy,并允许改为 zlib,因此每一次数据的存入、读出都需要经过压缩、解压,这对 CPU 有一定的消耗,建议像使用 Redis 一样使用 PikiwiDB(Pika):在 PikiwiDB(Pika) 中关闭压缩,而在 client 中完成数据的压缩、解压,这样不仅能够降低数据体积,还能有效降低 Pikiw。注意关闭和开启压缩后,需要重启 PikiwiDB(Pika) 实例。

之二十六

读写分离很重要,PikiwiDB(Pika) 在常见的主从集群中由于写入是单点的(仅 master 支持写),因此写入性能是有极限的。可通过多个 slave 来共同支撑读流量,因此 PikiwiDB(Pika) 集群的读性能是随着 slave 数量的增加而增加的,所以对于读量很大的场景,建议在业务层代码加入读写分离策略,同时在 PikiwiDB(Pika) 层增加 slave 数量。

之二十七

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

注意:在 PikiwiDB v4.0.0 版本之后,不再支持对特定类型的 compaction。因为 PikiwiDB v3.x 使用的存储引擎是 Blackwidow,每个数据类型使用一个 RocksDB,而 v4.0.0 的存储引擎升级为 Floyd,可以在单个 RocksDB 中存储所有类型的数据。

之二十八

PikiwiDB(Pika) 3.5.0 以后的版本支持通过 rate-limiter-bandwidth 配置项以限制磁盘 IO 速率,可以通过调整该配置参数来调整读写速度。在 v4.0.0 之前只支持写限速,在 v4.0.0 之后支持读写限速,可以通过调整配置参数中的 rate-limiter-mode 来设置限速模式。

之二十九

PikiwiDB(Pika) 和 Redis 一样支持慢日志功能,可通过 slowlog 命令查看。slowlog 的原始内容只存于内存中,内存空间有上限,且这个上限可配置,当然如果配置过大会造成 slowlog 占用太多内存。PikiwiDB(Pika) 也允许将 slowlog-write-errorlog 设置为 yes,以把慢日志记录到 pika.ERROR 日志中,用于追溯、分析。

之三十

PikiwiDB(Pika) v3.5.2 以后的版本支持冷热数据分离,并在 Pika 磁盘存储之上增加了内存缓存层(称之为 RedisCache),将用户访问的热数据放在缓存层,冷数据放在磁盘,可减少查询磁盘的次数,提升服务的读性能,不论 PikiwiDB(Pika) 使用的是主从复制模式还是集群模式,可以配置 cache-mode 为 1 ,并设置缓存的大小和个数,以提升读性能。如果实例内存较小,不足以支撑缓存层的资源耗费,你可以选择将 cache-mode 设置成为 0 将缓存层关闭掉。

之三十一

PikiwiDB(Pika) 3.5.3 以后的版本支持了 Redis ACL 功能,设置用户密码的方式发生了变化,ACL的认证方式和 Redis 保持一致,在 config 文件中按照 ACL 规则对 user 进行配置。PikiwiDB(Pika) 3.5.3 仍然兼容以前旧版本的认证方式。

之三十二

PikiwiDB(Pika) 3.5.3 以后的版本支持快、慢命令分离,有快、慢两个线程池,可以防止慢命令对快命令线程池阻塞的影响。可以通过 slow-cmd-list 配置项设置慢命令列表,通过设置 slow-cmd-thread-pool-size 设置慢命令线程池个数。

之三十三

欲知后事如何,且待微信群里分解。请添加 小助手为好友,它会拉您加入官方微信群。