深入探究,使用外部工具
机器访问允许操作员比日志和 nodetool
更深入地进行探究。虽然每个 Cassandra 操作员可能都有自己喜欢的故障排除工具集,但此页面包含一些最常见的操作员技术和这些工具的示例。许多这些命令仅在 Linux 上有效,但如果您在其他操作系统上部署,您可能可以使用其他类似的工具来评估类似的操作系统级指标和进程。
JVM 工具
JVM 附带了许多有用的工具。其中一些工具可用于调试 Cassandra 问题,尤其是与堆和执行堆栈相关的问题。
注意:JVM 工具和 Cassandra 有两个常见的陷阱
-
默认情况下,Cassandra 附带
-XX:+PerfDisableSharedMem
设置,以防止长时间暂停(有关详细信息,请参阅CASSANDRA-9242
和CASSANDRA-9483
)。如果您想使用 JVM 工具,您可以改为将/tmp
挂载到内存中的tmpfs
上,这也有效地解决了CASSANDRA-9242
。 -
确保您以与 Cassandra 运行相同的用户身份运行这些工具,例如,如果数据库以
cassandra
身份运行,则该工具也必须以cassandra
身份运行,例如,通过sudo -u cassandra <cmd>
。
垃圾回收状态 (jstat)
如果您怀疑堆压力,您可以使用 jstat
深入探究 Cassandra 进程的垃圾回收状态。此命令始终可以安全运行,并提供详细的堆信息,包括 eden 堆使用率 (E)、老年代堆使用率 (O)、eden 收集次数 (YGC)、eden 收集花费的时间 (YGCT)、老年代/混合代收集次数 (FGC) 以及老年代/混合代收集花费的时间 (FGCT)
jstat -gcutil <cassandra pid> 500ms
S0 S1 E O M CCS YGC YGCT FGC FGCT GCT
0.00 0.00 81.53 31.16 93.07 88.20 12 0.151 3 0.257 0.408
0.00 0.00 82.36 31.16 93.07 88.20 12 0.151 3 0.257 0.408
0.00 0.00 82.36 31.16 93.07 88.20 12 0.151 3 0.257 0.408
0.00 0.00 83.19 31.16 93.07 88.20 12 0.151 3 0.257 0.408
0.00 0.00 83.19 31.16 93.07 88.20 12 0.151 3 0.257 0.408
0.00 0.00 84.19 31.16 93.07 88.20 12 0.151 3 0.257 0.408
0.00 0.00 84.19 31.16 93.07 88.20 12 0.151 3 0.257 0.408
0.00 0.00 85.03 31.16 93.07 88.20 12 0.151 3 0.257 0.408
0.00 0.00 85.03 31.16 93.07 88.20 12 0.151 3 0.257 0.408
0.00 0.00 85.94 31.16 93.07 88.20 12 0.151 3 0.257 0.408
在本例中,我们看到我们有一个相对健康的堆配置文件,老年代堆使用率为 31.16%,eden 堆使用率为 83%。如果老年代经常超过 75%,那么您可能需要更多堆(假设 CMS 的占用率阈值为 75%)。如果您确实有如此持续的高老年代,这通常意味着您要么为老年代堆分配了不足,要么堆上存在太多活动数据,Cassandra 无法收集这些数据(例如,由于内存表)。另一个需要注意的是年轻代垃圾回收 (YGC) 之间的时间,这表明 eden 堆的回收频率。每次年轻代 gc 暂停大约 20-50 毫秒,因此如果您有很多暂停,您的客户端将在其高百分位延迟中注意到这一点。
线程信息 (jstack)
要获取 Cassandra 当前正在执行操作的快照,请针对 Cassandra PID 运行 jstack
。注意,这会短暂暂停 JVM(<20 毫秒)。
$ jstack <cassandra pid> > threaddump
# display the threaddump
$ cat threaddump
# look at runnable threads
$grep RUNNABLE threaddump -B 1
"Attach Listener" #15 daemon prio=9 os_prio=0 tid=0x00007f829c001000 nid=0x3a74 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
--
"DestroyJavaVM" #13 prio=5 os_prio=0 tid=0x00007f82e800e000 nid=0x2a19 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
--
"JPS thread pool" #10 prio=5 os_prio=0 tid=0x00007f82e84d0800 nid=0x2a2c runnable [0x00007f82d0856000]
java.lang.Thread.State: RUNNABLE
--
"Service Thread" #9 daemon prio=9 os_prio=0 tid=0x00007f82e80d7000 nid=0x2a2a runnable [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
--
"C1 CompilerThread3" #8 daemon prio=9 os_prio=0 tid=0x00007f82e80cc000 nid=0x2a29 waiting on condition [0x0000000000000000]
java.lang.Thread.State: RUNNABLE
--
# Note that the nid is the Linux thread id
线程转储中一些最重要的信息是等待/阻塞线程,包括线程正在阻塞/等待的锁或监视器。
基本操作系统工具
调试 Cassandra 问题时,首先要了解 Cassandra 如何与系统资源交互。以下是 Cassandra 大量使用的资源
-
CPU 内核。用于执行并发用户查询
-
CPU 处理时间。用于查询活动(数据解压缩、行合并等)
-
CPU 处理时间(低优先级)。用于后台任务(压缩、流式传输等)
-
用于 Java 堆的 RAM。用于保存内部数据结构,默认情况下还用于 Cassandra 内存表。堆空间是写入性能的关键组成部分,也是整体性能的关键组成部分。
-
用于操作系统磁盘缓存的 RAM。用于缓存经常访问的 SSTable 块。操作系统磁盘缓存是读取性能的关键组成部分。
-
磁盘。Cassandra 非常关注磁盘读取延迟、磁盘写入吞吐量,当然还有磁盘空间。
-
网络延迟。Cassandra 进行许多节点间请求,因此节点之间的网络延迟会直接影响性能。
-
网络吞吐量。Cassandra(与其他数据库一样)经常遇到所谓的“内聚”问题,即一个小请求(例如
SELECT * from foo.bar
)返回一个非常大的结果集(例如,整个数据集)。在这种情况下,出站带宽至关重要。
通常,Cassandra 故障排除归结为故障排除机器或集群耗尽的资源。然后,您创建更多这种资源或更改查询模式以减少对该资源的使用。
高级资源使用情况 (top/htop)
Cassandra 大量使用系统资源,通常最先有用的操作是运行 top
或 htop
(网站) 来查看机器的状态。
有用的查看内容
-
系统负载级别。虽然这些数字可能令人困惑,但一般来说,如果负载平均值大于 CPU 内核数量,Cassandra 可能不会有很好的(低于 100 毫秒)延迟。有关更多信息,请参阅 Linux 负载平均值。
-
CPU 利用率。特别是
htop
可以帮助将 CPU 利用率细分为user
(低优先级和正常优先级)、system
(内核)和io-wait
。Cassandra 查询线程以正常优先级user
线程执行,而压缩线程以低优先级user
线程执行。高system
时间可能表明存在线程争用问题,而高io-wait
可能表明磁盘驱动器速度慢。这可以帮助您了解 Cassandra 在处理资源方面花费了多少时间。 -
内存使用情况。查找哪些程序具有最多的驻留内存,这可能是 Cassandra。Cassandra 的数字可能不准确,因为 Linux(截至 2018 年)如何计算内存映射文件内存。
IO 使用情况 (iostat)
使用 iostat 来确定数据驱动器的运行状况,包括延迟分布、吞吐量和利用率
$ sudo iostat -xdm 2
Linux 4.13.0-13-generic (hostname) 07/03/2018 _x86_64_ (8 CPU)
Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.00 0.28 0.32 5.42 0.01 0.13 48.55 0.01 2.21 0.26 2.32 0.64 0.37
sdb 0.00 0.00 0.00 0.00 0.00 0.00 79.34 0.00 0.20 0.20 0.00 0.16 0.00
sdc 0.34 0.27 0.76 0.36 0.01 0.02 47.56 0.03 26.90 2.98 77.73 9.21 1.03
Device: rrqm/s wrqm/s r/s w/s rMB/s wMB/s avgrq-sz avgqu-sz await r_await w_await svctm %util
sda 0.00 0.00 2.00 32.00 0.01 4.04 244.24 0.54 16.00 0.00 17.00 1.06 3.60
sdb 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00
sdc 0.00 24.50 0.00 114.00 0.00 11.62 208.70 5.56 48.79 0.00 48.79 1.12 12.80
在本例中,我们可以看到 /dev/sdc1
是一个非常慢的驱动器,其 await
接近 50 毫秒,avgqu-sz
接近 5 个 IO。该驱动器没有特别饱和(利用率仅为 12.8%),但我们仍然应该关注这将如何影响我们的 p99 延迟,因为 50 毫秒对于典型的 Cassandra 操作来说太长了。话虽如此,在本例中,大多数延迟都存在于写入中(通常写入比读取更延迟),由于 Cassandra 的 LSM 特性,这通常对用户隐藏。
使用 iostat 评估的重要指标
-
每秒读取和写入次数。这些数字会随着工作负载而变化,但一般来说,Cassandra 从磁盘读取的数据越多,Cassandra 读取延迟就越慢。每秒读取次数过多可能是集群内存不足以进行操作系统页面缓存的明显标志。
-
写入吞吐量。Cassandra 的 LSM 模型会延迟用户写入并将它们一起批处理,这意味着底层介质的吞吐量是 Cassandra 最重要的写入指标。
-
读取延迟 (
r_await
)。当 Cassandra 错过操作系统页面缓存并从 SSTable 中读取时,读取延迟直接决定了 Cassandra 以多快的速度响应数据。 -
写入延迟。Cassandra 对写入延迟不太敏感,除非它同步提交日志。这通常会进入写入延迟的非常高的百分位数。
请注意,要获得详细的延迟细分,您需要使用更高级的工具,例如 bcc-tools
。
操作系统页面缓存使用情况
由于 Cassandra 大量使用内存映射文件,操作系统 页面缓存 的健康状况对于性能至关重要。首先找到系统中可用的缓存量。
$ free -g
total used free shared buff/cache available
Mem: 15 9 2 0 3 5
Swap: 0 0 0
在本例中,9GB 内存被用户进程(Cassandra 堆)使用,8GB 可用于操作系统页面缓存。其中,3GB 实际上用于缓存文件。如果大多数内存被使用并且无法用于页面缓存,Cassandra 性能会显著下降。这就是为什么 Cassandra 从为堆保留的合理小内存量开始。
网络延迟和可靠性
无论何时 Cassandra 执行涉及其他副本的写入或读取操作(例如 LOCAL_QUORUM
读取),延迟的主要影响因素之一是网络延迟。在尝试调试多机操作问题时,网络可能是需要调查的重要资源。您可以使用 ping
和 traceroute
等工具,或者最有效地使用 mtr
来确定节点间延迟。
$ mtr -nr www.google.com
Start: Sun Jul 22 13:10:28 2018
HOST: hostname Loss% Snt Last Avg Best Wrst StDev
1.|-- 192.168.1.1 0.0% 10 2.0 1.9 1.1 3.7 0.7
2.|-- 96.123.29.15 0.0% 10 11.4 11.0 9.0 16.4 1.9
3.|-- 68.86.249.21 0.0% 10 10.6 10.7 9.0 13.7 1.1
4.|-- 162.141.78.129 0.0% 10 11.5 10.6 9.6 12.4 0.7
5.|-- 162.151.78.253 0.0% 10 10.9 12.1 10.4 20.2 2.8
6.|-- 68.86.143.93 0.0% 10 12.4 12.6 9.9 23.1 3.8
7.|-- 96.112.146.18 0.0% 10 11.9 12.4 10.6 15.5 1.6
9.|-- 209.85.252.250 0.0% 10 13.7 13.2 12.5 13.9 0.0
10.|-- 108.170.242.238 0.0% 10 12.7 12.4 11.1 13.0 0.5
11.|-- 74.125.253.149 0.0% 10 13.4 13.7 11.8 19.2 2.1
12.|-- 216.239.62.40 0.0% 10 13.4 14.7 11.5 26.9 4.6
13.|-- 108.170.242.81 0.0% 10 14.4 13.2 10.9 16.0 1.7
14.|-- 72.14.239.43 0.0% 10 12.2 16.1 11.0 32.8 7.1
15.|-- 216.58.195.68 0.0% 10 25.1 15.3 11.1 25.1 4.8
在这个 mtr
示例中,我们可以快速评估数据包所走的路径,以及它们的典型丢包率和延迟。数据包丢失通常会导致 200ms
到 3s
的额外延迟,因此这可能是延迟问题的一个常见原因。
网络吞吐量
由于 Cassandra 对传出带宽限制很敏感,因此有时确定网络吞吐量是否受限很有用。一个方便的工具是 iftop,它可以一目了然地显示带宽使用情况和连接信息。一个显示针对本地 ccm
集群进行压力测试期间流量的示例。
$ # remove the -t for ncurses instead of pure text
$ sudo iftop -nNtP -i lo
interface: lo
IP address is: 127.0.0.1
MAC address is: 00:00:00:00:00:00
Listening on lo
# Host name (port/service if enabled) last 2s last 10s last 40s cumulative
--------------------------------------------------------------------------------------------
1 127.0.0.1:58946 => 869Kb 869Kb 869Kb 217KB
127.0.0.3:9042 <= 0b 0b 0b 0B
2 127.0.0.1:54654 => 736Kb 736Kb 736Kb 184KB
127.0.0.1:9042 <= 0b 0b 0b 0B
3 127.0.0.1:51186 => 669Kb 669Kb 669Kb 167KB
127.0.0.2:9042 <= 0b 0b 0b 0B
4 127.0.0.3:9042 => 3.30Kb 3.30Kb 3.30Kb 845B
127.0.0.1:58946 <= 0b 0b 0b 0B
5 127.0.0.1:9042 => 2.79Kb 2.79Kb 2.79Kb 715B
127.0.0.1:54654 <= 0b 0b 0b 0B
6 127.0.0.2:9042 => 2.54Kb 2.54Kb 2.54Kb 650B
127.0.0.1:51186 <= 0b 0b 0b 0B
7 127.0.0.1:36894 => 1.65Kb 1.65Kb 1.65Kb 423B
127.0.0.5:7000 <= 0b 0b 0b 0B
8 127.0.0.1:38034 => 1.50Kb 1.50Kb 1.50Kb 385B
127.0.0.2:7000 <= 0b 0b 0b 0B
9 127.0.0.1:56324 => 1.50Kb 1.50Kb 1.50Kb 383B
127.0.0.1:7000 <= 0b 0b 0b 0B
10 127.0.0.1:53044 => 1.43Kb 1.43Kb 1.43Kb 366B
127.0.0.4:7000 <= 0b 0b 0b 0B
--------------------------------------------------------------------------------------------
Total send rate: 2.25Mb 2.25Mb 2.25Mb
Total receive rate: 0b 0b 0b
Total send and receive rate: 2.25Mb 2.25Mb 2.25Mb
--------------------------------------------------------------------------------------------
Peak rate (sent/received/total): 2.25Mb 0b 2.25Mb
Cumulative (sent/received/total): 576KB 0B 576KB
============================================================================================
在本例中,我们可以看到带宽在许多对等方之间相当均匀地分配,但是如果总带宽接近 NIC 的额定容量或集中在单个客户端上,这可能表明问题所在。
高级工具
有时作为操作员,您可能需要深入研究。这就是高级操作系统工具派上用场的地方。
bcc-tools
大多数现代 Linux 发行版(内核版本高于 4.1
)支持 bcc-tools 用于深入研究性能问题。首先安装 bcc-tools
,例如在 Debian 上使用 apt
安装。
$ apt install bcc-tools
然后,您可以使用 bcc-tools
包含的所有工具。其中一个最有用的工具是 cachestat
(cachestat 示例),它允许您准确地确定发生了多少操作系统页面缓存命中和未命中。
$ sudo /usr/share/bcc/tools/cachestat -T 1
TIME TOTAL MISSES HITS DIRTIES BUFFERS_MB CACHED_MB
18:44:08 66 66 0 64 88 4427
18:44:09 40 40 0 75 88 4427
18:44:10 4353 45 4308 203 88 4427
18:44:11 84 77 7 13 88 4428
18:44:12 2511 14 2497 14 88 4428
18:44:13 101 98 3 18 88 4428
18:44:14 16741 0 16741 58 88 4428
18:44:15 1935 36 1899 18 88 4428
18:44:16 89 34 55 18 88 4428
在本例中,页面缓存 MISSES
不太多,这表明缓存大小合理。这些指标是您 Cassandra 节点“热”数据集的最直接衡量指标。如果您没有足够的缓存,MISSES
将很高,性能将很慢。如果您有足够的缓存,MISSES
将很低,性能将很快(因为几乎所有读取都从内存中提供)。
您还可以使用 biolatency
(biolatency 示例) 测量磁盘延迟分布,以了解当读取错过操作系统页面缓存并必须访问磁盘时 Cassandra 的速度有多慢。
$ sudo /usr/share/bcc/tools/biolatency -D 10
Tracing block device I/O... Hit Ctrl-C to end.
disk = 'sda'
usecs : count distribution
0 -> 1 : 0 | |
2 -> 3 : 0 | |
4 -> 7 : 0 | |
8 -> 15 : 0 | |
16 -> 31 : 12 |****************************************|
32 -> 63 : 9 |****************************** |
64 -> 127 : 1 |*** |
128 -> 255 : 3 |********** |
256 -> 511 : 7 |*********************** |
512 -> 1023 : 2 |****** |
disk = 'sdc'
usecs : count distribution
0 -> 1 : 0 | |
2 -> 3 : 0 | |
4 -> 7 : 0 | |
8 -> 15 : 0 | |
16 -> 31 : 0 | |
32 -> 63 : 0 | |
64 -> 127 : 41 |************ |
128 -> 255 : 17 |***** |
256 -> 511 : 13 |*** |
512 -> 1023 : 2 | |
1024 -> 2047 : 0 | |
2048 -> 4095 : 0 | |
4096 -> 8191 : 56 |***************** |
8192 -> 16383 : 131 |****************************************|
16384 -> 32767 : 9 |** |
在本例中,数据驱动器 (sdc
) 上的大多数 IO 速度很快,但许多需要 8 到 16 毫秒。
最后,biosnoop
(示例) 可用于更深入地研究并查看每个 IO 的延迟。
$ sudo /usr/share/bcc/tools/biosnoop | grep java | head
0.000000000 java 17427 sdc R 3972458600 4096 13.58
0.000818000 java 17427 sdc R 3972459408 4096 0.35
0.007098000 java 17416 sdc R 3972401824 4096 5.81
0.007896000 java 17416 sdc R 3972489960 4096 0.34
0.008920000 java 17416 sdc R 3972489896 4096 0.34
0.009487000 java 17427 sdc R 3972401880 4096 0.32
0.010238000 java 17416 sdc R 3972488368 4096 0.37
0.010596000 java 17427 sdc R 3972488376 4096 0.34
0.011236000 java 17410 sdc R 3972488424 4096 0.32
0.011825000 java 17427 sdc R 3972488576 16384 0.65
... time passes
8.032687000 java 18279 sdc R 10899712 122880 3.01
8.033175000 java 18279 sdc R 10899952 8192 0.46
8.073295000 java 18279 sdc R 23384320 122880 3.01
8.073768000 java 18279 sdc R 23384560 8192 0.46
使用 biosnoop
,您可以看到每个 IO 以及它们花费的时间。这些数据可用于构建 biolatency
中的延迟分布,但也可用于更好地了解磁盘延迟如何影响性能。例如,此特定驱动器需要大约 3 毫秒才能完成内存映射读取,这是由于 read_ahead_kb
的默认值 (128kb
) 很大。为了提高点读取性能,您可能希望在快速数据卷(例如 SSD)上降低 read_ahead_kb
,同时保持较高的值,例如 128kb
的值可能适合 HDD。这涉及权衡,有关更多信息,请参阅 queue-sysfs 文档,但无论如何,biosnoop
有助于了解 Cassandra 如何使用驱动器。
vmtouch
有时了解操作系统缓存了多少 Cassandra 数据文件很有用。一个很好的工具可以回答这个问题,那就是 vmtouch。
首先安装它。
$ git clone https://github.com/hoytech/vmtouch.git
$ cd vmtouch
$ make
然后在 Cassandra 数据目录上运行它。
$ ./vmtouch /var/lib/cassandra/data/
Files: 312
Directories: 92
Resident Pages: 62503/64308 244M/251M 97.2%
Elapsed: 0.005657 seconds
在本例中,几乎整个数据集都在操作系统页面缓存中处于热状态。一般来说,除非读取错过缓存(例如,cachestat),否则百分比并不重要,在这种情况下,增加内存可能有助于读取性能。
CPU 火焰图
Cassandra 通常使用大量 CPU,但很难确定它在做什么。分析 Cassandra CPU 时间的最佳方法之一是使用 CPU 火焰图,它以一种有用的方式显示 Cassandra 代码的哪些区域正在使用 CPU。这可能有助于将压缩问题缩小到“压缩问题丢弃墓碑”,或者只是帮助您缩小 Cassandra 在出现问题时正在执行的操作范围。要获取 CPU 火焰图,请按照 Java 火焰图 的说明操作。
一般来说
-
在 Cassandra 的
jvm.options
配置文件中启用-XX:+PreserveFramePointer
选项。这会对性能造成微不足道的负面影响,但允许您实际看到 Cassandra 在做什么。 -
运行
perf
以获取一些数据。 -
将这些数据通过 FlameGraph 工具集中的相关脚本发送,并将数据转换为漂亮的火焰图。在浏览器或其他图像浏览器中查看生成的 SVG 图像。
例如,直接从 github 克隆,我们首先将 perf-map-agent
安装到我们的 JVM 的位置(假设为 /usr/lib/jvm
)。
$ sudo bash
$ export JAVA_HOME=/usr/lib/jvm/java-8-oracle/
$ cd /usr/lib/jvm
$ git clone --depth=1 https://github.com/jvm-profiling-tools/perf-map-agent
$ cd perf-map-agent
$ cmake .
$ make
现在要获取火焰图。
$ git clone --depth=1 https://github.com/brendangregg/FlameGraph
$ sudo bash
$ cd FlameGraph
$ # Record traces of Cassandra and map symbols for all java processes
$ perf record -F 49 -a -g -p <CASSANDRA PID> -- sleep 30; ./jmaps
$ # Translate the data
$ perf script > cassandra_stacks
$ cat cassandra_stacks | ./stackcollapse-perf.pl | grep -v cpu_idle | \
./flamegraph.pl --color=java --hash > cassandra_flames.svg
生成的 SVG 可搜索、可缩放,并且通常易于使用浏览器进行内省。
数据包捕获
有时您需要了解 Cassandra 节点现在正在执行哪些查询才能解决问题。对于这些情况,可靠的数据包捕获工具(如 tcpdump
和 Wireshark)非常有助于分析数据包捕获。Wireshark 甚至具有本机 CQL 支持,尽管它有时与较新的 Cassandra 协议版本存在兼容性问题。
要获取数据包捕获,首先捕获一些数据包。
$ sudo tcpdump -U -s0 -i <INTERFACE> -w cassandra.pcap -n "tcp port 9042"
现在使用 wireshark 打开它。
$ wireshark cassandra.pcap
如果您没有看到类似 CQL 的语句,请尝试通过右键单击发送到 9042 的数据包 → Decode as
→ 从 9042 端口的下拉菜单中选择 CQL 来告诉它以 CQL 解码。
如果您不想手动执行此操作或使用 GUI,您还可以使用类似 cqltrace 的工具来简化获取和解析 CQL 数据包捕获。