避免热点数据

短时间内被频繁访问的数据称为热点数据。避免热点数据,可以有效利用数据库的读写性能,优化数据分布。在 SequoiaDB 巨杉数据库中,某个数据组或者主数据节点繁忙,证明出现了热点数据。

  • 某个数据组繁忙:某个数据组繁忙程度远高于其它数据组时,代表大量的数据操作出现在该数据组上,需要将当前数据组上的数据切分到其他数据组,让其他数据组共同承担读写压力
  • 主数据节点繁忙:主数据节点繁忙程度远高于同组内备数据节点时,代表当前大量的数据操作为查询操作,可以将部分查询操作分散到备数据节点

某个数据组繁忙

某个数据组繁忙程度远高于其他数据组时,表示集合内的数据分布不合理。在 SequoiaDB 中,集合内的数据,会通过 hash和 range 两种方式切分到不同数据组上。下面从这两种分区方式介绍如何避免热点数据。

hash 分区

集合采用 hash 分区方式时,会对分区键字段进行路由运算,确定数据的落点。理论上这种分区方式数据可以保证数据均衡分布。

集合采用 hash 分区方式时,出现热点问题,代表了某一个 hash 值大量出现,即分区键上重复的数据较多。这种情况下需要重新选择分区键,对集合进行重构。

假如用户需要将集合 avoid_hot.user_info 作为散列分区集合存入巨杉数据库中,样例数据如下:

idnamegenderaddremaildate
U00001CeliaF北京celia@sina.cn2019-05-30
U00002HaleyF上海haley@sina.cn2019-05-31
U00003ByrneM深圳byrne@sina.cn2019-05-31
U00004CalebM北京caleb@sina.cn2019-05-31
U00005HaleyF北京haley@sina.cn2019-05-31

创建集合是选择 date 字段作为分区键,插入 2019-05-31 的数据时,所有的数据操作将集中在一个数据组中。

  1. > db.createCS("avoid_hot")
  2. > db.avoid_hot.createCL( "user_info", { ShardingKey: { date: 1 }, ShardingType: "hash", AutoSplit: true } )

处理方案

  • id 做分区键,创建新集合
  1. > db.avoid_hot.createCL( "user_info_new", { ShardingKey: { id: 1 }, ShardingType: "hash", AutoSplit: true } )
  • 导出原有集合中的数据
  1. $ sdbexprt -s localhost -p 11810 --type csv --file avoid_hot.user_info.csv -c avoid_hot -l user_info
  • 将数据导入新集合
  1. $ sdbimprt --hosts=localhost:11810 --type=csv --file=avoid_hot.user_info.csv -c avoid_hot -l user_info_new
  • 修改表明,用新集合替代原有集合
  1. > db.avoid_hot.renameCL( "user_info", "user_info_bak")
  2. > db.avoid_hot.renameCL( "user_info_new", "user_info")

range 分区

集合采用 range 分区方式时,会对分区键字段进行判断,将指定范围的数据放入指定数据组中。这种分区方式长期来看可以保证数据均衡分布,短期内对分区键连续操作时,容易出现热点问题。

集合采用 range 分区方式时,出现热点问题,需要将数据随机放入不同的数据组中,避免热点问题。在巨杉数据库中,可以利用多维分区方式解决该问题。

avoid_hot.user_info 集合的多维分区方式

  1. > db.avoid_hot.createCL( "user_info", { ShardingKey: { date: 1 }, ShardingType: "range", IsMainCL: true } )
  2. >
  3. > db.avoid_hot.createCL( "user_info_201905", { ShardingKey: { id: 1 }, ShardingType: "hash", AutoSplit: true } )
  4. > db.avoid_hot.createCL( "user_info_201906", { ShardingKey: { id: 1 }, ShardingType: "hash", AutoSplit: true } )
  5. >
  6. > db.avoid_hot.user_info.attachCL( "avoid_hot.user_info_201905", { LowBound: { date: "2019-05-01" }, UpBound: { date: "2019-06-01" } } )
  7. > db.avoid_hot.user_info.attachCL( "avoid_hot.user_info_201906", { LowBound: { date: "2019-06-01" }, UpBound: { date: "2019-07-01" } } )

某个数据组繁忙监测

单个数据组繁忙程度远高于其它数据组时,该数据节点对机器资源的消耗远高于其它数据节点,可以通过下面的方式进行监测。

CPU 性能监测

用户使用 top 监测各进程占用机器资源的多少,当发现某 SequoiaDB 节点占用 CPU 资源远高于其他节点占用的 CPU 资源时,表示有热点问题。

  1. $ top
  2. Tasks: 400 total, 1 running, 399 sleeping, 0 stopped, 0 zombie
  3. %Cpu(s): 81.0 us, 2.7 sy, 0.0 ni, 95.3 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
  4. KiB Mem: 2902952 total, 2880400 used, 22552 free, 0 buffers
  5. KiB Swap: 2097148 total, 11772 used, 2085376 free. 1831100 cached Mem
  6. PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
  7. 4974 sdbadmin 20 0 2082952 122816 21464 S 58.3 4.2 0:06.91 sequoiadb(11840) D
  8. 4973 sdbadmin 20 0 738828 67332 12896 S 20.3 2.3 0:00.88 sequoiadb(11810) S
  9. 4980 sdbadmin 20 0 1848188 111692 17936 S 0.3 3.8 0:01.03 sdbom(11780)
  10. 4985 sdbadmin 20 0 1689736 85572 13212 S 0.3 2.9 0:04.44 sequoiadb(11830) D
  11. 4988 sdbadmin 20 0 2400668 92708 14180 S 0.3 3.2 0:01.20 sequoiadb(11800) C

磁盘性能监测

用户使用 iostat 监控磁盘工作状况。如果在多个刷盘周期内,其中一块磁盘表现活跃,而其他磁盘几乎无刷盘行为,则热点问题出现在较活跃磁盘上的数据中。

  1. $ iostat -x -k 5
  2. Linux 3.10.0-123.el7.x86_64 (test) 06/03/2019 _x86_64_ (1 CPU)
  3. avg-cpu: %user %nice %system %iowait %steal %idle
  4. 5.55 0.00 10.69 3.52 0.00 80.24
  5. Device: rrqm/s wrqm/s r/s w/s rkB/s wkB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
  6. sda 1.67 4.26 48.63 3.14 4445.49 396.88 187.09 0.46 8.92 5.07 68.42 1.65 8.52
  7. scd0 0.00 0.00 0.02 0.00 0.07 0.00 8.00 0.00 1.09 1.09 0.00 1.09 0.00
  8. dm-0 0.00 0.00 47.91 2.72 4398.06 375.82 188.58 0.47 9.22 5.26 79.11 1.67 8.45
  9. dm-1 0.00 0.00 0.87 4.48 3.85 17.91 8.14 0.37 69.01 0.58 82.28 1.14 0.61

snapshot 监测

用户确定到某个数据节点存在热点问题后,可以通过 snapshot() 接口查找当前正在执行的操作,确定问题表。

  • 抓取快照信息
  1. > db.snapshot(SDB_SNAP_SESSIONS,{NodeName:"sdbserver1:11840"})
  • 查找当前正在执行的操作
  1. {
  2. "NodeName": "sdbserver1:11840",
  3. "SessionID": 17554,
  4. "TID": 31317,
  5. "Status": "Waiting",
  6. "Type": "ShardAgent",
  7. "Name": "Type:Shard,NetID:10,R-TID:27626,R-IP:192.168.1.80,R-Port:11810",
  8. "Source": "MySQL-2",
  9. "QueueSize": 0,
  10. "ProcessEventCount": 18447,
  11. "RelatedID": "c0a801502e2200006bea",
  12. "Contexts": [],
  13. "TotalDataRead": 1983,
  14. "TotalIndexRead": 14789,
  15. "TotalDataWrite": 1404,
  16. "TotalIndexWrite": 5757,
  17. "TotalUpdate": 456,
  18. "TotalDelete": 0,
  19. "TotalInsert": 948,
  20. "TotalSelect": 1527,
  21. "TotalRead": 1983,
  22. "TotalReadTime": 0,
  23. "TotalWriteTime": 0,
  24. "ReadTimeSpent": 0,
  25. "WriteTimeSpent": 0,
  26. "ConnectTimestamp": "2019-05-07-08.08.26.265864",
  27. "ResetTimestamp": "2019-05-07-08.08.26.265864",
  28. "LastOpType": "QUERY",
  29. "LastOpBegin": "--",
  30. "LastOpEnd": "2019-05-07-09.14.39.716133",
  31. "LastOpInfo": "Collection:avoid_hot.user_operand, Matcher:{ \"$and\": [ { \"$and\": [ { \"NAME_\": { \"$et\": \"applid\" } }, { \"EXECUTION_ID_\": { \"$et\": \"7b36d6e2-7065-11e9-a807-0050569f53de\" } }, { \"TASK_ID_\": { \"$isnull\": 1 } } ] }, { \"TASK_ID_\": { \"$isnull\": 1 } } ] }, Selector:{}, OrderBy:{ \"TASK_ID_\": 1 }, Hint:{ \"\": \"ACT_IDX_VARIABLE_TASK_ID\" }, Skip:0, Limit:-1, Flag:0x00000200(512)",
  32. "UserCPU": 5.52,
  33. "SysCPU": 3.34
  34. }

Note:

在 SDB_SNAP_SESSIONS 快照中,LastOpInfo 项是该线程正在执行的操作 SQL,其中的 Collection:avoid_hot.user_operand 是集合名称。

主数据节点繁忙

主数据节点繁忙程度远高于同组内备数据节点时,代表当前大量的数据操作为查询操作,可以将部分查询操作分散到备数据节点。

设置备数据节点承担部分查询操作,需要将 preferedinstance 配置 A,保证主备节点繁忙度基本相同。

修改方式

  1. > db.updateConf({preferedinstance: "A"})

主数据节点繁忙的监测

主数据节点繁忙程度远高于备节点的监测,主要通过监控 Linux 系统 CPU 利用率来实现,对比同数据组内不同数据节点的 CPU 利用率,即可判断出是否存在繁忙程度差异。

  • 11840 主节点 CPU 占用率
  1. $ top
  2. Tasks: 400 total, 1 running, 399 sleeping, 0 stopped, 0 zombie
  3. %Cpu(s): 81.0 us, 2.7 sy, 0.0 ni, 95.3 id, 0.0 wa, 0.0 hi, 0.0 si, 0.0 st
  4. KiB Mem: 2902952 total, 2880400 used, 22552 free, 0 buffers
  5. KiB Swap: 2097148 total, 11772 used, 2085376 free. 1831100 cached Mem
  6. PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
  7. 4974 sdbadmin 20 0 2082952 122816 21464 S 58.3 4.2 0:06.91 sequoiadb(11840) D
  8. 4973 sdbadmin 20 0 738828 67332 12896 S 20.3 2.3 0:00.88 sequoiadb(11810) S
  9. 4980 sdbadmin 20 0 1848188 111692 17936 S 0.3 3.8 0:01.03 sdbom(11780)
  10. 4985 sdbadmin 20 0 1689736 85572 13212 S 0.3 2.9 0:04.44 sequoiadb(11830) D
  11. 4988 sdbadmin 20 0 2400668 92708 14180 S 0.3 3.2 0:01.20 sequoiadb(11800) C
  • 11840 备节点 CPU 占用率
  1. $ top
  2. top - 02:28:45 up 2:46, 2 users, load average: 0.18, 0.23, 0.35
  3. Tasks: 400 total, 1 running, 399 sleeping, 0 stopped, 0 zombie
  4. %Cpu(s): 8.1 us, 9.1 sy, 0.0 ni, 82.5 id, 0.0 wa, 0.0 hi, 0.3 si, 0.0 st
  5. KiB Mem: 2902952 total, 2876196 used, 26756 free, 0 buffers
  6. KiB Swap: 2097148 total, 11700 used, 2085448 free. 1807664 cached Mem
  7. PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
  8. 4974 sdbadmin 20 0 2082952 122828 21464 S 0.7 4.2 0:29.79 sequoiadb(11840) D
  9. 4980 sdbadmin 20 0 1848188 111728 17936 S 0.7 3.8 0:21.99 sdbom(11780)
  10. 4712 sdbadmin 20 0 632860 10052 6516 S 0.3 0.3 0:11.79 sdbcm(11790)
  11. 4973 sdbadmin 20 0 828984 69464 13700 S 0.3 2.4 0:20.66 sequoiadb(11810) S
  12. 4985 sdbadmin 20 0 1689736 85584 13212 S 0.3 2.9 0:26.32 sequoiadb(11830) D
  13. 4988 sdbadmin 20 0 2400668 92708 14180 S 0.3 3.2 0:31.63 sequoiadb(11800) C
  14. 4991 sdbadmin 20 0 1689736 115928 21460 S 0.3 4.0 0:29.18 sequoiadb(11820) D

Note:

  • 11840 主节点的cpu利用率较高,备节点几乎不消耗 CPU 资源,所以 11840 主节点繁忙程度更高,可以通过配置读写分离来优化数据库性能
  • CPU 利用率的比较主要是主节点间 CPU 利用率的比较、同机器不同节点间 CPU 利用率的比较以及同组内不同节点间 CPU 利用率的比较

其他情况下的读写热点监控,同样可以通过该方法进行。