微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

PostgreSQL数据库 OLTP高并发请求性能优化

在多核系统中,一般TPS会随并发数的增加而提升,但是当并发数超过一定的数值(如cpu核数的2到3倍以后),性能开始下降,并发数越高,下降越严重。
例子:
更新500万记录表中的1条随机记录。开8000个并发。

create table test_8000 (id int primary key, cnt default 0);
insert into test_8000 select generate_series(15000000);
vi t.sql
\setrandom id 1@H_404_81@5000000
updateset cnt=cnt+where id=:id;
update test_8000 2;

每次加载80个并发,循环100次,一共加载8000个并发。
vi testsh
@H_404_135@#!/bin/bash
@H_404_135@for ((i=0;i<100;i++))
@H_404_135@do
sleep pgbench -M simple n r f ./tsql c 80 j T 100000U postgres &
done

开始

testsh

当连接数达到8000后,观察TPS,我们可以使用PG的统计信息表来计算QPS。
postgres=@H_404_135@# select count(*) from pg_stat_activity;
@H_404_135@count
@H_404_135@-------
@H_404_135@ 8002
@H_404_135@(1 row)
# select timestamptz '2015-10-08 17:01:24.203089+08' - timestamptz '2015-10-08 17:01:16.574076+08';
@H_404_135@ ?column?
@H_404_135@-----------------
@H_404_135@00:00:07.629013
@H_404_135@# select 43819090-43749480;
@H_404_135@?column?
@H_404_135@----------
@H_404_135@ 69610
@H_404_135@# select 69610/07.629013;
@H_404_135@ ?column?
@H_404_135@-----------------------
@H_404_135@(1 row)

8000个并发的时候,更新TPS约9124。大部分时间可能浪费在cpu调度上了。

另一种场景,
如果有8000个并发是空闲连接,只有10个在执行更新,性能是这样的:
先制造8000个空闲连接:
select pg_sleep100000done
sh
然后开启10个连接执行更新操作。
M prepared P 10@H_404_81@1000U postgres postgres
progress:@H_404[email protected] s29429.2 tps lat 0.336 ms stddev 0.109

这种方法性能约6万 qps。
优化思路:
排队处理用户请求。类似pgbouncer或Oracle的shared server机制,真实处理请求的进程数有限。
使用Postgresql的advisory函数可以模拟这种排队机制:
create or replace function updl intv_id ) returns voidas $$
declare
begin
LOOP
if pg_try_advisory_xact_locklthen--只有获得这个应用级锁才执行更新,否则就等待。
update test_8000 v_id returnelse
perform pg_sleep30*random());随机等待时间
endifEND LOOP;
end$$ language plpgsql strict 增加一个随机变量l,用来表示应用所的号码,也就是说模拟10个同时在更新的操作,其他的都在等待。
这个是没有经过优化的排队机制,因为不是独立的进程处理用户请求,依旧是backend process在处理用户请求,依旧有8000个进程。
5000000
\setrandom l 10
select(:sh
@H_404_135@#!/bin/bash
@H_404_135@for ((i=0;i<100;i++))
@H_404_135@do
;
&
done
sh

测试结果比较理想,已经提升了1倍性能
# select Now(),n_tup_upd+n_tup_hot_upd from pg_stat_all_tables where relname='test_8000'; Now |?column -------------------------------+----------- @H_404_81@2015-1008@H_404_81@19:0637.951332221045069 row)
------------------------------+----------- @H_404_81@0746.46325222879057 # select timestamptz '2015-10-08 19:07:46.46325+08' - timestamptz '2015-10-08 19:06:37.951332+08'; ----------------- @H_404_81@000108.511918 # select 222879057-221045069; ---------- @H_404_81@1833988 # select 1833988/68.5; -------------------- @H_404[email protected] )

模拟结果,相比不排队,有1倍以上的性能提升。
TOP
top 0937 up 119 days359 users load average0.960.981.01
Tasks8872 total 5 running8866 sleeping stopped0 zombie
cpus):@H_404[email protected]%us0.8sy0.0ni93.9wahisist
Mem132124976k@H_404_81@118066688k used14058288k free316752k buffers
Swap2097144k 148k@H_404_81@2096996k@H_404_81@63702028k cached

advisory lock是PG提供的一种轻量级的面向用户的锁(当然比LWLOCK是要重的),我之前在秒杀场景的优化中也有叙述,可以达到每秒处理19万次的单条记录更新请求的性能,并且保持1毫秒以内的RT。请参考。
http://blog.163.com/digoal@126/blog/static/16387704020158149538415/
把这种优化思路加入到Postgresql的内核中是比较靠谱的,最终实现的效果会和Oracle的shared server非常类似。
阿里云PG内核组的小鲜肉和老腊肉们,优化开始搞起吧。
在没有优化前,还是使用pgbouncer这种连接池吧。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐