PostgreSQL码农集散地

重新发现PostgreSQL之美 - 12 serverless & SaaS行业 & 多租户 & 资源隔离 & 捣蛋鬼,你揍开

标签

PostgreSQL , login hook , 进程模型 , plpythonu , cgroup , serverless


背景

视频回放: https://www.bilibili.com/video/BV1SQ4y1X7oC/

场景:

  • 游戏、SaaS行业. serverless 场景: 在一个企业内部, 业务线非常多,

  • 在同一个实例中有多个业务共同使用时,

  • 分析师、DBA或者运营人员有偶尔使用数据库的需求.

挑战:

  • 为每个业务分配一个数据库实例存在的问题: 资源浪费(每个实例在内存、空间方面的浪费)、弹性较差(创建资源慢、扩容缩容慢).

  • 多个业务共享一个实例存在的问题: 资源争抢、干扰、抖动、安全风险增加,

  • DBA或分析师人为的大查询可能将资源耗光, 影响在线业务

PG 方案:

  • 按来源IP、USER、DBNAME、application_name等信息来区分用户和业务

  • 结合cgroup隔离业务的cpu、io、网络等资源使用率, 防止干扰

例子

cgroup 配置举例

限制组cgroupA的任务最多可以使用8核资源

限制组cgroupB的任务最多可以使用16核资源

加载CPU子系统,创建子资源分区

mkdir -p /cgroup/cpu      
mount -t cgroup -o cpu cpu /cgroup/cpu
cd /cgroup/cpu
mkdir cgroupA
mkdir cgroupB

配置资源配比(以100为基数,核数乘以100即得到cpu.shares)

cd cgroupA      
echo 800 > cpu.shares
echo 1000000 > cpu.cfs_period_us
echo 8000000 > cpu.cfs_quota_us

cd ../cgroupB
echo 1600 > cpu.shares
echo 1000000 > cpu.cfs_period_us
echo 16000000 > cpu.cfs_quota_us

将PID放入某个cgroup组

创建一个shell将PID放入某个cgroup组

/home/digoal/cpu_cgroup.sh PID GROUPNAME

脚本内容略

配置允许PG进程的启动账号sudo执行该命令

202011/20201107_03.md 《Linux : 使用 sudoedit 配置 - 允许普通用户a以另一个用户b或组g执行某些特定命令》

在数据库中创建plpythonu, 调用shell, 将当前会话PID放入对应cgroup

create extension plpythonu;  

create or replace function exec_cmd2(cmd text) returns setof text as $$
import os
v = os.popen('/home/digoal/cpu_cgroup.sh ' + cmd)
return v
$$ language plpythonu;

以下例子, 简单粗暴的逻辑,

  • postgres 用户登陆后, 会话对应的backend PID 会塞入cgroupA

  • digoal 用户登陆后, 会话对应的backend PID 会塞入cgroupB

实际使用中可以配置一个映射表, 从映射表里面获取规则.

create or replace function exec_cmd() returns void as $$    
declare
pid int := pg_backend_pid();
begin
case current_user
when 'postgres' then perform exec_cmd2(format('%s %s',pid, 'cgroupA'));
when 'digoal' then perform exec_cmd2(format('%s %s',pid, 'cgroupB'));
else raise notice 'not mapping users cgroup';
end case;
end;
$$ language plpgsql strict;

配置login hook, 创建会话时, 自动执行以上函数

postgresql.conf  

session_preload_libraries = 'session_exec'
session_exec.login_name = 'exec_cmd'

postgres 用户登陆后, 会话对应的backend PID 会塞入cgroupA
digoal 用户登陆后, 会话对应的backend PID 会塞入cgroupB

更复杂的逻辑

限制逻辑还可以更复杂一点, 例如, 根据:

  • 来源IP

  • 登陆的用户

  • 登陆的数据库

  • application_name(用户在连接URL里面可以设置, 用来区分不同的业务)

  • 登陆的时间

  • 当前实例级资源使用率

  • 当前各个cgroup的资源使用率

  • 当前映射的cgroup的资源使用率

实施动作:

  • 将当前会话的PID放入某个cgoup组进行限制

  • 扩大或缩小某个cgroup的限制上限. 例如凌晨放大BI业务的限制, 白天缩小BI业务的限制.

其他cgoup可以限制的指标:

  • io, 读写吞吐, 网络流量, 内存等

参考

https://github.com/okbob/session_exec

202007/20200727_02.md 《PostgreSQL 登录(新建会话)hook - login "trigger"插件》
201710/20171023_01.md 《在PostgreSQL中使用 plpythonu 调用系统命令》
201606/20160613_01.md 《Linux cgroup - cpu与cpuset子系统讲解》
201606/20160611_01.md 《Linux cgroup资源隔离各个击破之 - io隔离》
202011/20201107_03.md 《Linux : 使用 sudoedit 配置 - 允许普通用户a以另一个用户b或组g执行某些特定命令》

欢迎关注我的github (https://github.com/digoal/blog) , 学习数据库不迷路.  

近期正在写公开课材料, 未来将通过视频号推出.