☰
Tendis集群部署实战:从源码编译到冷数据迁移的完整指南
2026/10/21 14:39:17 网站建设 项目流程

Tendis这个词,早期关注过缓存生态的人应该不陌生。它是某大厂开源的一个兼容Redis协议的分布式KV存储系统,底层用RocksDB做持久化,核心目标就是为了解决两个问题:一是数据量大了之后纯内存Redis太贵,二是冷数据长期占着内存太浪费。这套环境部署说起来不算难,但坑确实不少,尤其是首次编译、集群分片、磁盘和内存参数这几块,很容易踩到文档里没写明白的细节。

这篇文章就按我实际部署的经验来写,目标是把Tendis从源码编译、单实例启动、集群模式搭建到数据迁移的完整过程捋一遍,把那些配置项为什么这么设、设错会有什么后果讲清楚。适合三类人看:一是正准备把部分冷数据从Redis迁到Tendis的运维同学,二是想了解Redis协议兼容存储方案的架构师,三是对存储引擎有兴趣、想动手跑一套Tendis试试的开发者。

1. 部署前先搞清楚:Tendis到底在什么场景下值得用

1.1 Tendis和Redis的本质差异

先说定位。Tendis不是Redis的替代品,它是Redis生态的补充。Redis把数据全放内存,读写快但成本高,数据量上了几百GB甚至TB级别,内存成本会把你压得很难受。Tendis的做法是:兼容Redis的访问协议,但数据真正落在磁盘上,靠RocksDB这层LSM-Tree结构的存储引擎来保证读写性能。

这意味着什么?简单类比一下:如果说Redis是一个你随取随用的钱夹,钱都在手上,拿取快但身上带不了太多钱;那Tendis更像一个带抽屉的办公桌,常用的能放在桌面(缓存层),不常用的放在抽屉里(磁盘存储),钱多也能放得下,取用速度虽然比钱夹慢,但比从银行金库临时调度快得多。

这个差异决定了选型方向。QPS要求极高、单条数据访问延迟必须稳定在亚毫秒级的核心热数据,老老实实放Redis。数据量大、访问频率有高有低、允许P99延迟到几毫秒甚至十几毫秒的业务,用Tendis就很划算。我见过不少团队把登录token、订单历史、消息记录这类数据迁到Tendis,内存成本直降一半以上,读性能依然够用。

1.2 版本和形态怎么选

部署之前一定要先决定用哪种形态,因为不同形态的部署方式和配置参数差异很大。Tendis常见的有单机版、集群版和分布式版三类,一般的中小团队最常用的是前两种。

单机版适合验证功能、压测性能、跑数据量在单节点可承受范围内的小业务。它部署最简单,一个二进制文件加一份配置就能跑起来,适合刚入门时用来理解Tendis的运行机制。

集群版适合生产环境。它会把Key按Slot(槽位)分散到多个分片节点上,每个分片可以有主从节点,主挂了从节点能顶上来。这解决了单机容量和单点故障的问题。集群版部署涉及节点发现、槽位分配、主从关系设置,步骤要多一些,但这是生产环境的标准形态。

分布式版适合对强一致、跨机房容灾有要求的场景。它引入了Meta节点和额外的调度组件,部署复杂度明显提升,不是特别大规模的业务其实用不上。我建议先跑集群版,确认业务确实需要更高等级的容灾能力后再研究分布式版,不要一上来就全铺开。

1.3 部署前要确认的几个业务参数

动手部署前,先回答下面四个问题,它们直接决定你的节点配置和分片数量:

  • 数据总量预估:当前Redis数据量多大?半年后预计增长到多大?这个数值决定你需要多少分片。
  • 读写比例和热点分布:读多写少还是写多读少?热点Key是否集中?这影响你对缓存层和磁盘IO的规划。
  • 延迟容忍度:业务能接受的最差读延迟是多少?如果P99不能超过5ms,那磁盘性能至少要上SSD。
  • 持久化要求:数据丢失容忍程度如何?如果完全不能丢,必须开主从同步和合理的数据刷盘策略。

这几个参数没想清楚就盲目按默认配置部署,后面大概率要返工。我有一次就是没评估好数据增长,按3个分片设计了集群,上线两个月就发现磁盘快满了,不得不做在线扩容,搞得运维同学连续加了几天班。

2. 环境准备:硬件评估、依赖安装和内核参数

2.1 硬件配置怎么定

Tendis是磁盘型存储系统,硬件选择和Redis有显著区别。Redis内存型实例主要看内存大小;Tendis要同时关注内存、磁盘和CPU。

内存方面,不要以为数据在磁盘就很省内存。RocksDB本身要占一块内存做块缓存(Block Cache),写路径还有MemTable内存结构,再加上Tendis自身的线程栈、网络缓冲,内存少了照样卡顿。个人经验是1TB有效数据至少配32GB内存,64GB会更从容。MemTable在写入量大时如果频繁刷盘,会产生大量小文件,影响后续读性能。

磁盘是重头戏。有条件直接上NVMe SSD,SATA SSD也勉强能用,机械硬盘建议别碰,除非你的业务对延迟完全无感。磁盘容量按预估数据量的1.5倍准备,因为RocksDB有空间放大效应,同一份数据可能会在多个Level中暂时存在,加上Compact(合并)过程需要预留临时空间,太抠容易出问题。

CPU按分片数和吞吐量来配。每个分片建议至少2核,另外留出2~4核给后台Compact任务。我见过一个配置了4分片但只有4核的案例,Compaction一跑,前台读写延迟直接飙升,业务方秒级报警。

2.2 编译依赖与基础软件

Tendis提供源码,需要自行编译。别怕编译,其实依赖不复杂,最核心的几个是:

  • Linux操作系统,我用的是CentOS 7系的发行版,其他主流发行版同样能编。
  • gcc-c++编译器,版本建议4.8.5及以上,C++11是跑不掉的。
  • CMake,建议3.5以上。
  • glibc-devel、libstdc++-devel这些基础库。
  • snappy、zlib、bz2、lz4这些压缩库,RocksDB的压缩功能需要它们,缺了会编不过或者运行时告警。

编译依赖用系统自带的包管理器装就行,命令就是yum install或apt-get install那几行。这里提示一点:压缩库版本尽量用系统源里的稳定版,不要手动编译最新版去替换,容易和朋友库冲突。我在测试机上图新鲜装了新版lz4,结果Tendis启动时动态库加载报错,折腾了半小时才定位到是库版本被顶掉了。

2.3 内核参数调整

Tendis对网络和文件句柄有一些基本要求,部署前建议调整下面这些系统参数:

  • 文件句柄数:单机实例可能要开几百甚至上千个文件,默认的1024肯定不够,我习惯把ulimit -n设为65535。
  • 网络连接队列:高并发下backlog太短会丢连接,net.core.somaxconn建议设成1024以上。
  • vm.swappiness:建议设为10左右或更低。虽然Tendis数据主要在磁盘,但内存里的缓存也很重要,别让系统把Cache页面优先切出去。
  • 禁用透明大页:这个一定要做。透明大页会导致RocksDB性能不稳定,延迟偶发飙升,echo never写入/sys/kernel/mm/transparent_hugepage/enabled可以关掉它。

这些参数修改是部署前最不起眼但收益最明显的部分。曾有同事跳过参数调优直接跑压测,结果P99抖动得厉害,翻来覆去找不到原因,最后发现是透明大页没关。

3. 单实例部署实操:从源码编译到启动验证

3.1 获取源码并完成编译

Tendis的源码通过Git仓库获取。操作流程是拉取代码、切到稳定分支、然后编译。整个编译过程在配置还行的机器上大约需要20到40分钟,取决于CPU核数和磁盘速度。

git clone https://github.com/tds/tdins.git cd tdins git checkout -b stable origin/stable

需要说明的是,我对版本号记忆不一定准确,具体以官方仓库当前的分支和Tag为准。切分支这一步很重要,不要直接编master分支,开发中的代码不稳定,我在测试时碰到过编译告警和运行时异常,切到稳定分支后一切正常。

编译命令一般是这样的:

mkdir build && cd build cmake .. make -j$(nproc)

make -j后面的线程数可以按机器核数来写。但注意,编译RocksDB这类大型C++项目时,-j开太大反而容易内存爆炸,因为每个编译任务都比较吃内存。如果机器内存不够(比如只有8GB),老老实实写成make -j2或-j4,别贪快。

编译完成后,二进制文件会生成在build目录下的bin路径中,核心程序名是tendis。你可以用ldd命令检查动态库依赖是否完整:

ldd bin/tendis

如果输出里出现了not found,说明有依赖库缺失,回头把2.2节的依赖包补装一遍再编。

3.2 配置文件里最容易踩坑的五个参数

Tendis启动时需要指定一个配置文件。默认配置模板在源码的conf目录下,搬出来改一改就行。核心参数我用之前部署时实际踩过坑的五个来举例:

port 监听端口,默认是9000,和Redis默认的6379区分开。这个随便设,只要不冲突就行。

dir 数据文件存放目录。这个要特别注意,目录必须预先创建好,并且确保启动用户的写权限。Tendis不会帮你创建目录,启动时发现路径不存在会直接报错退出。

logDir 日志目录,同样需要手动创建。日志文件按天滚动,建议单独挂一块磁盘,避免和数据目录抢IO。

rocksdbBlockCacheSize RocksDB的块缓存大小,相当于数据在内存中的热缓存。生产环境建议设为机器内存的一半左右。设太小,热数据频繁读磁盘,延迟上不去;设太大,和操作系统的Page Cache重叠浪费内存。我见过有人把128GB内存的机器给块缓存设了100GB,结果系统内存吃紧,其他进程频繁告警。

rocksdbMaxBackgroundCompactions 后台合并任务线程数。这个参数设多少直接关系写放大时的运行稳定性。设太小,数据文件合并不及时,读性能会退化;设太大,合并任务和前台读写抢CPU。经验值是2到4,按CPU核数来。

maxClients 最大客户端连接数。注意,这个值也受系统ulimit限制,你把它设成100000但系统文件句柄上限是1024,那是不会生效的。

配置文件里还有个关键点:单机版和集群版的配置差异。单机模式不需要开cluster-enable,集群模式要显式开启。这个后面单独讲。

3.3 启动验证和基本读写检查

配置文件改好后,启动命令很简单:

./bin/tendis -c ./conf/tendis.conf

如果想放后台运行,可以用nohup启动,或者交给systemd托管。我个人倾向用systemd,因为可以设置崩溃自动重启、开机自启、日志统一管理,比裸跑进程省心很多。

启动后先看日志。日志文件里有启动关键信息,比如各模块初始化完成、端口监听成功。确认没有报错后,用Redis自带的客户端工具来连接测试(Tendis兼容Redis协议,redis-cli可以直接用):

redis-cli -p 9000 ping

如果返回PONG,说明进程活着。接着写入一条数据再读出来:

redis-cli -p 9000 set hello tendis redis-cli -p 9000 get hello

能正常返回tendis就说明基础读写没问题。这个环节还可以顺手验证一下数据持久化:写入后kill进程再重新启动,然后get刚刚的Key,如果还在,说明落盘和加载都正常。

启动验证还有一个必做的项目是查看INFO信息。Tendis的INFO输出和Redis相似,但多了存储引擎相关字段。重点关注dbSize(数据量)、rocksdb相关统计、内存使用这些指标。通过这些指标你可以判断当前实例的健康度基线,后续压测或排障时才有参照物。

4. 集群模式部署:分片规划、主从复制和槽位分配

4.1 集群形态设计和分片数量怎么算

部署集群版之前,要先搞明白Tendis集群版的架构模型。它和Redis Cluster非常相似:整个Key空间被划分为固定数量的Slot(槽位),每个分片负责一部分Slot。数据根据Key哈希到Slot,再路由到对应分片。这样做的好处是增删节点时只需迁移Slot,不需要全量数据重排。

分片数量怎么定?核心看数据总量和单节点容量。假设预估数据量是2TB,单节点(分片)如果配置3TB磁盘且预留安全余量,那至少需要1个分片,但为了容灾,主从至少各一份,实际就是2个节点承载1个分片。为保证多分片并行和扩容空间,我建议按最大预估数据量的两倍来规划分片数。数据量小就用3分片起步,中等规模用6到9分片,单分片数据量尽量控制在500GB以内,这样迁移和恢复都更快。

每个分片建议搭配一个从节点,形成一主一从。总节点数大致就是分片数乘以副本数。机器充足的情况下,主从最好分布在不同的物理机器甚至不同机柜,避免单机故障把主从一起带走。

4.2 集群部署和节点发现流程

集群版的部署步骤比单机版多出一个节点握手确认的过程。大致流程是这样的:

  • 所有节点安装好Tendis二进制。
  • 每台机器分别启动Tendis进程,配置文件里要设置相同集群名称并启用集群模式。
  • 选一台节点执行节点握手命令,让其他节点加入集群。
  • 规划槽位分配,把整个Slot空间按分片数均匀分配到各个主节点。
  • 设置从节点的主从复制关系。

这里我补充两个细节。第一,节点握手命令看起来只是让两个节点认识一下,实际上它会同步整个集群的节点视图,任何一个节点知道所有节点信息后,新节点就自动被整个集群感知了。所以只需执行一次加入操作,不需要每对节点之间都握手一次。第二,槽位分配是集群可用性的前提,Slot没分配完之前,集群处于不完整状态,未覆盖的Slot范围内的Key读写会报错。分配完成后务必要检查,确认每个Slot都有归属。

分配和执行脚本的过程我不在这里贴完整代码了,操作以你实际获取到的集群管理工具和文档为准。大原则是:分配槽位前确认所有节点状态健康,分配后至少测试几个分散的Key能正常写入和读取,确认路由正确。

4.3 从Redis迁移数据时的注意事项

集群搭建完成后,最常做的一件事就是把Redis里的冷数据迁过来。迁移有几种常见方式:通过客户端双写逐步迁移、用工具做全量导出再导入、或者用同步组件持续同步增量。不管用哪种方式,有几条注意事项是通用的:

  • 迁移前关闭目标集群的自动合并任务,或者把合并线程调低,避免导入数据过程中Compaction和写入相互抢资源。导入完成后再调回来。
  • 如果源数据量大,建议按Key前缀分批导出导入,不要一次性全量灌进去。一次导入太多,RocksDB的写放大会让磁盘IO长时间饱和,甚至影响节点间的复制心跳。
  • Key的过期时间要提前理清楚。Redis的过期策略是惰性删除加定时删除,Tendis的过期处理机制不同,如果业务依赖过期时间,上线前必须在测试环境验证过期行为是否一致,尤其是批量设置过期时间的场景。

我曾经帮一个团队迁移消息记录数据,大概1.5TB的量,导出导入本身很顺利。但没考虑到过期Key的处理逻辑差异,上线后一批本应在两天后过期的Key没有被及时清理,导致磁盘占用一直下不来,最后手动跑了一轮清理才解决。这类问题不亲身踩过很难意识到。

5. 运维排障:编译失败、数据丢失和性能抖动怎么定位

5.1 编译阶段的常见报错

编译报错基本集中在依赖缺失和版本不兼容两类。最常见的是找不到某某头文件或者某某库文件,这时候不用慌,看准缺失的名字装对应开发包就行。比如缺snappy头文件,就装snappy-devel;缺zlib,就装zlib-devel。注意开发包的命名后缀往往是-devel,光装运行库不够。

另一种情况是gcc版本太老,代码里用到了新语法编译不过。升级编译器版本是解决办法,但升级时尽量用系统自带的工具链或者可靠的软件源,不要手动去装来路不明的二进制包,很容易引入新的链接问题。

遇到编译报错时我建议先看第一个报错信息而不是只看最后一个,因为后续报错往往是第一处报错引发的连锁反应。把这一个修复掉,后面的错误可能自动消失。

5.2 启动失败和数据目录异常

启动失败最常见的原因就那么几个:配置项写错、目录不存在、端口被占用、依赖库缺失。排查时先看进程的error日志,Tendis会把详细原因打进去。如果日志都没有,用命令行直接启动(前台模式)看输出,报错信息会直接打到终端。

数据目录异常的高发场景是磁盘空间满了。RocksDB在空间不足时不会立即崩掉,而是先报写失败,如果持续无法写入,最终进程会退出。所以监控磁盘空间对Tendis来说格外重要。我习惯设置磁盘使用率超过80%就告警,超过90%就得立刻处理,这个红线比Redis的运维要严格得多,因为RocksDB的临时文件和Compaction中间产物往往会在几小时内吃掉大量空间。

5.3 读写延迟突刺的排查顺序

Tendis的延迟突刺和Redis有本质区别:Redis通常是阻塞操作、大Key导致,排查相对直观;Tendis更多是存储引擎层面的问题。如果出现P99升高或偶发超时,按这个顺序去查:

  • 看磁盘IO:用iostat看%util和await,如果磁盘长期打满,先考虑是否Compaction在跑大合并,或者是否有数据导入任务并发执行。
  • 看CPU:用top看进程内线程的CPU占用,如果多个线程处于R状态且占用率高,可能是合并线程或压缩线程在干活。
  • 看内存:RocksDB块缓存是否命中率降低,内存是否被操作系统回收,透明大页是否被意外重新开启。
  • 看RocksDB统计:Tendis可以输出存储引擎的内部状态,关注写放大系数、Level数量、读放大这些指标。如果Level数量明显增长且短时间内降不下去,可能要手动触发合并或调整合并策略。

有个实际例子:某次压测中发现写入延迟从2ms飙升到50ms,排查发现是安装了监控脚本,每分钟执行一次find和du扫描全部数据目录,把磁盘IO抢走了。移除脚本后延迟立刻恢复。这种“案发现场不在数据库自身”的情况其实占比不低,排障时不要只盯着Tendis进程本身。

5.4 主从复制中断和数据一致性校验

集群模式下主从复制也可能出问题。最常见的原因是网络抖动导致复制中断,或者从节点磁盘空间不足导致复制堆积。复制中断后,从节点的数据会落后于主节点,如果落后太多,主节点的复制缓冲区可能被覆盖,这时只能重新全量同步。

全量同步是一件代价高昂的事情,尤其是数据量已经很大的时候,会占用大量带宽和磁盘IO。所以生产环境对复制状态要盯得紧一点,建议把同步延迟做成监控指标,超过阈值就告警。

主从数据一致性校验也不可忽视。RocksDB落盘虽然有校验机制,但主从复制链路、网络传输都可能引入差异。定期对集群做一致性检查是很有必要的习惯。可以找一个业务低峰期,从一个从节点导出数据样本,和主节点做比对;或者使用专门的校验工具定期核对。不要等到主从切换时才发现数据对不上,那就被动了。

这里有一个易混淆的点:Tendis是强一致还是最终一致,取决于部署形态和配置。在集群版默认配置下,主从采用异步复制,主节点写成功就返回客户端成功,从节点同步是异步完成的。因此主节点异常宕机时,理论上可能丢失少量最近写入的数据。这和Redis主从模式的性质类似。如果业务要求更强的数据安全等级,需要评估分布式形态或增加同步确认机制,这是一个必须提前和业务方确认清楚的取舍,不要默认认为是零丢失。

6. 部署完成后的性能验证和持续运维建议

一套Tendis部署完成只是开始,后续的验证和运维才是重头戏。部署完成后,至少要做一轮基础性能摸底,记录三条核心基线数据:平均读延迟、平均写延迟、P99读延迟。建议直接使用压测工具模拟业务实际特征,尤其要模拟高并发下读写混合的场景,因为纯读或纯写的压测结果往往过好,混合场景才能暴露真实性能瓶颈。

压测时留意一个现象:写入QPS上去之后,磁盘写入量会明显高于实际数据量,这就是RocksDB的写放大效应。记录一下写入放大系数,如果超过10,说明配置或数据模型不太合理,需要检查是否存在大量小Key随机写、合并策略是否需要调整。这些都是需要长期观察的指标。

日常运维还要关注Comaction统计、磁盘增长速率、节点间同步延迟。建议定期检查数据目录大小增长曲线,如果增长速率超出预期,要排查是否存在大量过期Key堆积、数据写入流量变化、合并任务是否正常执行。Tendis的合并任务有时会因为空间不足或配置问题陷入停滞,导致空间增长失控,这类问题早发现比晚发现容易处理得多。

对于团队第一次接触Tendis的情况,我建议先在测试环境完整跑一遍从部署、压测、主从切换、节点宕机恢复到数据迁移的演练,同时把操作步骤沉淀成运维手册。生产环境出事故时,脑子里的记忆往往不可靠,一份明确的操作手册才是保障。

我个人在实际部署中的体会是,Tendis最大的价值在于打破了缓存和存储的严格界限,让冷热数据有了更灵活的存放选择。但它毕竟是一个存储系统,部署和运维的复杂度远超普通缓存组件,对待它要像对待数据库一样敬畏,做足规划、监控和演练,才能把它用稳。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询