PostgreSQL 网络延迟 瓶颈定量分析
背景
在使用sysbench或者pgbench测试数据库性能时,连unix socket, loop address性能差异是非常大的,特别是非常小的事务,例如基于KEY的查询,或者select 1这样的简单查询。
原因是这种查询在数据库端的处理非常快,从而网络延迟在整个耗时占比上就会比较大。
还有一种场景结果集比较大,网络延迟在整个耗时占比上也会比较大。
那么如何来定量分析呢?
1. 分析包的大小,可以通过tcpdump抓包,取得数据库请求过程中传输的包大小和数量。
2. 或者从PostgreSQL源码中,根据实际的查询计算对应的包大小,例如libpq。
网络延迟的定量分析
以 select 1; 为例分析。
如何计算出一个请求在数据库处理的耗时,以及在网络传输段的耗时?
网络传输端的耗时,可以通过前面拿到的包大小,然后使用网络延迟分析工具例如 qperf 得到。
例子:
假设通过tcpdump得到的 select 1; 的包大小为16字节(去除TCP包头)。
使用qperf测试单会话下的16字节包tcp延迟。
启动qperf服务端
yum install -y qperf
qperf -lp 8888 &
测试回环地址8-16字节 TCP包延迟
qperf 127.0.0.1 -lp 8888 -t 6 -oo msg_size:8:64:*2 -v tcp_lat &
latency = 5.16 us
msg_rate = 194 K/sec
msg_size = 16 bytes
time = 6 sec
loc_cpus_used = 86.8 % cpus
rem_cpus_used = 86.8 % cpus
测试 select 1 的qps
vi test.sql
select 1;
pgbench -M prepared -n -r -P 1 -f ./test.sql -c 1 -j 1 -T 10 -h 127.0.0.1
tps = 36938.282331 (including connections establishing)
根据以上QPS以及qperf测出来的网络延迟,计算出select 1的数据库处理时延,注意需要计算回包的时间,所以TCP延迟*2
(1000000/36938.03) - (5.16*2) = 16.75 us
同局域网主机的延迟测试
qperf xxx.xxx.xxx.xxx -lp 8888 -t 6 -oo msg_size:8:64:*2 -v tcp_lat &
tcp_lat:
latency = 13.6 us
msg_rate = 73.8 K/sec
msg_size = 16 bytes
time = 6 sec
loc_cpus_used = 8.67 % cpus
rem_cpus_used = 9.5 % cpus
使用以上值,以及前面得到的数据库处理延迟,计算理论上在这台机器连接到数据库服务器进行tps测试的结果应该是
1000000 / (16.75 + 13.6*2) = 22753 tps
实际测试得到的tps, 基本一致
pgbench -M prepared -n -r -P 1 -f ./test.sql -c 1 -j 1 -T 10 -h xxx.xxx.xxx.xxx
tps = 24724.666217 (including connections establishing)
并发情况下的网络延迟分析。
启动多个qperf服务端
qperf -lp 8888 &
qperf -lp 8889 &
qperf -lp 8890 &
qperf -lp 8891 &
qperf -lp 8892 &
qperf -lp 8893 &
qperf -lp 8894 &
qperf -lp 8895 &
qperf -lp 8896 &
qperf -lp 8897 &
qperf -lp 8898 &
qperf -lp 8899 &
qperf -lp 8900 &
qperf -lp 8901 &
qperf -lp 8902 &
qperf -lp 8903 &
qperf -lp 8904 &
qperf -lp 8905 &
qperf -lp 8906 &
qperf -lp 8907 &
qperf -lp 8908 &
qperf -lp 8909 &
qperf -lp 8910 &
qperf -lp 8911 &
qperf -lp 8912 &
qperf -lp 8913 &
qperf -lp 8914 &
qperf -lp 8915 &
qperf -lp 8916 &
qperf -lp 8917 &
qperf -lp 8918 &
qperf -lp 8919 &
qperf -lp 8920 &
qperf -lp 8921 &
qperf -lp 8922 &
qperf -lp 8923 &
qperf -lp 8924 &
qperf -lp 8925 &
qperf -lp 8926 &
qperf -lp 8927 &
qperf -lp 8928 &
qperf -lp 8929 &
qperf -lp 8930 &
qperf -lp 8931 &
qperf -lp 8932 &
qperf -lp 8933 &
qperf -lp 8934 &
qperf -lp 8935 &
qperf -lp 8936 &
qperf -lp 8937 &
qperf -lp 8938 &
qperf -lp 8939 &
qperf -lp 8940 &
qperf -lp 8941 &
qperf -lp 8942 &
qperf -lp 8943 &
qperf -lp 8944 &
qperf -lp 8945 &
qperf -lp 8946 &
qperf -lp 8947 &
qperf -lp 8948 &
qperf -lp 8949 &
qperf -lp 8950 &
qperf -lp 8951 &
并发测试延迟
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8888 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8889 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8890 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8891 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8892 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8893 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8894 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8895 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8896 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8897 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8898 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8899 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8900 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8901 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8902 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8903 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8904 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8905 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8906 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8907 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8908 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8909 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8910 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8911 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8912 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8913 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8914 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8915 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8916 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8917 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8918 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8919 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8920 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8921 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8922 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8923 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8924 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8925 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8926 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8927 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8928 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8929 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8930 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8931 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8932 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8933 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8934 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8935 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8936 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8937 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8938 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8939 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8940 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8941 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8942 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8943 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8944 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8945 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8946 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8947 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8948 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8949 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8950 tcp_lat &
qperf 127.0.0.1 -t 6 -oo msg_size:16:16:*2 -v -lp 8951 tcp_lat &
回环地址,64个并发的延迟约11.8us
latency = 11.8 us
测试64个并发的tps,并计算出数据库端的耗时(64核的机器)
pgbench -M prepared -n -r -P 1 -f ./test.sql -c 64 -j 64 -T 10 -h 127.0.0.1
tps = 1575989.161924 (including connections establishing)
计算出数据库的RT
与单进程的RT基本一致,说明现在PostgreSQL在高并发下的处理能力已经非常强大了,充分利用了CPU的多核,并且性能是线性的。
(1000000/(1575989.161924/64)) - (11.8*2) = 17 us
在远端主机测试网络延迟
从测试结果来看,已经大大超出了数据库本地处理的时间,网络成了最大的瓶颈
qperf xxx.xxx.xxx.xxx -t 6 -oo msg_size:16:16:*2 -v -lp 8888 tcp_lat &
...
qperf xxx.xxx.xxx.xxx -t 6 -oo msg_size:16:16:*2 -v -lp 8951 tcp_lat &
latency = 61.8 us
推算出64并发的TPS
(1000000/(17 + 61.8*2)) * 64 = 455192
推算出来的TPS与实际测出来的TPS基本一致
pgbench -M prepared -n -r -P 1 -f ./test.sql -c 64 -j 64 -T 10 -h xxx.xxx.xxx.xxx
tps = 466737.781999 (including connections establishing)
以上是网络延迟的定量分析,网络延迟在高并发的数据库应用中,影响还是非常大的。
参考
1. man tcpdump
2. man qperf
3. man iperf
4. http://blog.yufeng.info/archives/2234