Aerospike集群单点XDR同步Lag过高问题解决
(转载公众号:晓磊聊DB)
一、名词解释
什么是Aerospike数据库?Aerospike是一款分布式NoSQL数据库:
- 数据混合存储架构(key存储时:key是以索引的方式存内存,value存SSD硬盘)
- 作为分布式数据库,大规模数据下的扩展性和稳定性
- 高性能+强一致
- 相比于纯内存的Redis方案,显著降低成本
- 运维成本的降低:易维护+自动rebalance数据
什么是XDR?跨数据中心复制 (XDR) 在 Aerospike 群集之间透明地、异步地复制数据。对于核心数据,一般都需要有备用集群,Aerospike使用 XDR 将数据从主机房集群同步到下游的从集群。
二、同步lag问题描述
通过监控发现集群某个节点(下图中78这台服务器)长期都有大量的数据要同步,并且lag较高(其他节点没有lag)。
三、分析排查
1、既然上面的Aerospike集群中只有单节点存在lag,首先判断是不是这个节点“写偏移”导致的,查看下面的监控确实发现78这个节点的avg写入是其他集群节点的10倍。
这个集群只有2个业务线在用,并且通过aql show sets方式查看sets数据变化情况,发现esc_join这个sets(对应mysql的table)数据写入变化较多(平均2~3w/s)
+------------------+----------+-------------+-------------------+----------------------------------------+-------------------+-------------------+--------------+------------+
| disable-eviction | ns | objects | stop-writes-count | set | memory_data_bytes | device_data_bytes | truncate_lut | tombstones |
+------------------+----------+-------------+-------------------+----------------------------------------+-------------------+-------------------+--------------+------------+
| "false" | "mediav" | "115437494" | "0" | "esc_join" | "0" | "140764973360" | "0" | "0" |
| "false" | "mediav" | "37096386" | "0" | "unionad_xxxxx_imei" | "0" | "66129833424" | "0" | "0" |
...................................
| "false" | "mediav" | "893118" | "0" | "mob_xxxxx_imei" | "0" | "217015248" | "0" | "0" |
| "false" | "mediav" | "12590" | "0" | "unionad_xxxxx_sug" | "0" | "15481216" | "0" | "0" |
+------------------+----------+-------------+-------------------+----------------------------------------+-------------------+-------------------+--------------+------------+
[127.0.0.1:3000] 12 rows in set (0.001 secs)
+------------------+----------+-------------+-------------------+----------------------------------------+-------------------+-------------------+--------------+------------+
| disable-eviction | ns | objects | stop-writes-count | set | memory_data_bytes | device_data_bytes | truncate_lut | tombstones |
+------------------+----------+-------------+-------------------+----------------------------------------+-------------------+-------------------+--------------+------------+
| "false" | "mediav" | "115457756" | "0" | "esc_join" | "0" | "140749777408" | "0" | "0" |
| "false" | "mediav" | "37096386" | "0" | "unionad_xxxxx_imei" | "0" | "66129833424" | "0" | "0" |
.................................
| "false" | "mediav" | "893118" | "0" | "mob_xxxxx_imei" | "0" | "217015248" | "0" | "0" |
| "false" | "mediav" | "12590" | "0" | "unionad_xxxxx_sug" | "0" | "15481216" | "0" | "0" |
+------------------+----------+-------------+-------------------+----------------------------------------+-------------------+-------------------+--------------+------------+
[127.0.0.1:3000] 12 rows in set (0.001 secs)
+------------------+----------+-------------+-------------------+----------------------------------------+-------------------+-------------------+--------------+------------+
| disable-eviction | ns | objects | stop-writes-count | set | memory_data_bytes | device_data_bytes | truncate_lut | tombstones |
+------------------+----------+-------------+-------------------+----------------------------------------+-------------------+-------------------+--------------+------------+
| "false" | "mediav" | "115483502" | "0" | "esc_join" | "0" | "140743240720" | "0" | "0" |
| "false" | "mediav" | "37096386" | "0" | "unionad_xxxxx_imei" | "0" | "66129833424" | "0" | "0" |
.................................
| "false" | "mediav" | "893118" | "0" | "mob_xxxxx_imei" | "0" | "217015248" | "0" | "0" |
| "false" | "mediav" | "12590" | "0" | "unionad_xxxxx_sug" | "0" | "15481216" | "0" | "0" |
+------------------+----------+-------------+-------------------+----------------------------------------+-------------------+-------------------+--------------+------------+
[127.0.0.1:3000] 12 rows in set (0.002 secs)
通过业务归属查到对应的负责人询问和协助排查写入情况,初步认定是写入偏移导致的,这里简单描述下Aerospike的写入分配:Aerospike 使用partition方案在各节点间分配数据,每个namespace(相当于mysql的database)被拆分为4096个partition,每个partition都有2个副本来保证可用性。当一个KV写入时,Aerospike使用 RIPEMD160 算法将一条记录的主键散列成 20 byte 的内存索引(RIPEMD160算法在发生hash冲突时具有极强的稳定性),其中分区id从这20 byte的前12个byte来确定。分区是 Aerospike 中最小的数据所有权和迁移单位,Aerospike 在群集中自动分配这些分区。
经过业务方排查,从接口调用等方面来看没有只针对某些keys的变更或者写入,从“写入异常”的78节点来看hot-keys,并且进行了hot-keys的统计发现并没有一小撮keys“过热”,从其他集群节点也查看了hot-keys情况跟78节点hot-keys的数据量和分布基本一致,从而排除写偏移导致的问题。
Mar 03 2022 18:04:59 GMT+0800: INFO (info): (ticker.c:725) {mediav} xdr-from-proxy: write (155545,0,0) delete (0,0,0,0)
Mar 03 2022 18:04:59 GMT+0800: INFO (info): (dc.c:1469) xdr-dc shyc-queryad: nodes 9 lag 26026 throughput 5477 latency-ms 3 in-queue 2306245 in-progress 36 complete (233214491,0,132723,0) retries (0,0,0) recoveries (437,292) hot-keys 43788323
Mar 03 2022 18:05:09 GMT+0800: INFO (info): (ticker.c:654) {mediav} xdr-client: write (846728899,0,0) delete (0,0,0,0)
Mar 03 2022 18:05:09 GMT+0800: INFO (info): (ticker.c:725) {mediav} xdr-from-proxy: write (155545,0,0) delete (0,0,0,0)
Mar 03 2022 18:05:09 GMT+0800: INFO (info): (dc.c:1469) xdr-dc shyc-queryad: nodes 9 lag 26036 throughput 5547 latency-ms 3 in-queue 2302292 in-progress 21 complete (233269989,0,132769,0) retries (0,0,0) recoveries (437,292) hot-keys 43803497
Mar 03 2022 18:05:19 GMT+0800: INFO (info): (ticker.c:654) {mediav} xdr-client: write (847012485,0,0) delete (0,0,0,0)
Mar 03 2022 18:05:19 GMT+0800: INFO (info): (ticker.c:725) {mediav} xdr-from-proxy: write (155545,0,0) delete (0,0,0,0)
Mar 03 2022 18:05:19 GMT+0800: INFO (info): (dc.c:1469) xdr-dc shyc-queryad: nodes 9 lag 26046 throughput 5171 latency-ms 3 in-queue 2299422 in-progress 24 complete (233321718,0,132819,0) retries (0,0,0) recoveries (437,292) hot-keys 43819544
写热点的排查路子已经断了,还能有啥原因导致的该节点同步lag过高?这个节点到底跟其他节点有什么不同,因为是同步lag的问题,我开始从XDR的配置开始寻找一些区别,我对比了集群各个节点的XDR配置,我发现只有这个节点的forward配置跟其他节点不一致。
这里就要了解下forword ture/false的含义了,先来官方说明的截图:
啥意思呢?就是默认false的情况下,源Aerospike集群同步到下游的目的Aerospike集群,目的Aerospike只有设定为true才能再往目的Aerospike集群下游Aerospike集群同步,主要用在Aerospike的链式复制架构中。听着很绕对不对?其实拿mysql的一个参数:logslaveupdates来类比最合适了,大家看到这个mysql参数应该能理解forward=ture的配置含义了。
说回到本次问题,我需要再给大家再详细的说明下我的架构:本来集群A和集群B都有不同的业务写入,希望通过XDR的配置使得集群A/B成为同城互备集群。因为A集群的一台78节点设定了forward=ture,导致A->B,B->A,A->B,形成一个死循环,导致的问题。
四、解决
(1)调整transaction-queue-limit参数来缓解lag,这个参数用来控制XDR在内存中单partition事务队列的最大元素数量,每个元素占用25字节。为啥要调整这个队列大小,因为从本文前面的AS日志中的in-queue的挤压情况,想通过增加事务队列来降低lag,事实证明只是简单缓解了lag上涨,没有真正的解决问题。下面的命令是将该参数调整到默认的2倍。
asinfo -v 'set-config:context=xdr;dc=DataCenter1;namespace=someNameSpace;transaction-queue-limit=32768'
下面是官网对transaction-queue-limit的解释:
transaction-queue-limit
Maximum number of elements allowed in XDR's in-memory transaction queue per partition, per namespace, per datacenter. Each element is 25 bytes.
Value must be a power of 2 and must be expressed as an integer, not an exponent.
Default: 16*1024 = 16384.
Minimum: 1024.
Maximum: 1048576.
(2)真正的解决:修改Aerospike集群78这个节点forward,禁止XDR的复制循环。
asinfo -v "set-config:context=xdr;dc=shyc-queryad;namespace=mediav;forward=false"
从下面2张图可以看出来,一段时间后,Aerospike再也没有出现lag,集群的写入也回归正常。
五、思考
(1)善于“找不同”,在Aerospike集群其他集群都没有问题,只有单节点有问题时,就需要找出该节点的数据库配置、节点硬件/软件环境跟其他其他节点的“不同”,找到了“不同”就是很好的解决问题突破点。
(2)业务沟通和协调,有时的读写“热点”可能是上游的数据偏移导致的,大家都知道2/8原则(在一个数据库中80%的操作都集中在20%的热数据上),如果是过于“集中”,可能是上游数据出了“问题”,需要找研发确认。
(3)其实对于这种单点的请求过多,还可以通过tcpdump抓包的方式查看写入情况。
(4)监控要做的更好,目前aerospike的exporter只有到事例级别,没有到sets(对应mysql的table)级别,其实可以通过Aerospike提供的接口将每个sets的数量、使用内存、使用磁盘的监控完善,这样可以通过监控更好的看到sets的变化情况,能够及时发现和定位问题。