• pg ash自制版 pg_active_session_history


    一、 实现功能

            由于pgsentinel插件存在严重的内存占用问题,本篇改为自行实现,但其语句仍可以参考pgsentinel插件。PostgreSQL ash —— pgsentinel插件 学习与踩坑记录_CSDN博客

            v1.0 根据pg 14版本设计及测试,仅支持收集主库信息。默认每10秒收集一次 active与idle in transaction 状态会话信息,保留两个月。

    二、 历史会话与阻塞信息

           参考 pgsentinel插件的pg_active_session_history视图及pg pg_stat_activity视图,根据不同版本,其中部分字段的值可能为空。

    pg_ash表

    列名

    数据类型

    字段含义

    ash_timetimestamp with time zone采样时间
    datidoid会话连接的dbid
    datnamename会话连接的DB名
    pidinteger会话进程ID
    leader_pidinteger并行进程leader id,pg 13新增
    usesysidoiduser id
    usenamename用户名
    application_nametext应用程序名
    client_addrinet客户端ip
    client_hostnametext客户端主机名
    client_portinteger客户端端口
    backend_starttimestamp with time zone会话连接到服务器的时间
    xact_starttimestamp with time zone当前事务开始的时间,若无活跃事务则为 NULL
    query_starttimestamp with time zone当前活跃查询的开始时间。如果state不为active,则表示上个查询的开始时间
    state_changetimestamp with time zonestate上次更改的时间
    wait_event_typetext正在等待的事件类型(如果有)
    wait_eventtext正在等待的事件名(如果有)
    statetext当前会话状态
    backend_xidxid该会话的顶层事务id(如果有)
    backend_xminxid该会话的xmin horizon
    querytext

    active状态下,为当前正在执行的查询;其他状态下,表示最后执行的查询。

    默认情况下,查询文本被截断为 1024 字节(由参数track_activity_query_size控制)

    query_idbigint查询id,类似Oracle的sql_id,pg 14新增
    backend_typetext当前会话类型,例如client backend, checkpointer, startup, walreceiver... pg 10新增
    blockersinteger阻塞者数量
    blockerpidinteger阻塞者进程id
    blocker_statetext阻塞者状态

    三、 表结构创建

    1. 按月进行分区

    1. CREATE TABLE public.pg_ash (
    2.     ash_time timestamp with time zone,
    3.     datid oid,
    4.     datname name,
    5.     pid integer,
    6.     leader_pid integer,
    7.     usesysid oid,
    8.     usename name,
    9.     application_name text,
    10.     client_addr inet,
    11.     client_hostname text,
    12.     client_port integer,
    13.     backend_start timestamp with time zone,
    14.     xact_start timestamp with time zone,
    15.     query_start timestamp with time zone,
    16.     state_change timestamp with time zone,
    17.     wait_event_type text,
    18.     wait_event text,
    19.     state text,
    20.     backend_xid xid,
    21.     backend_xmin xid,
    22.     query text,
    23.     query_id bigint,
    24.     backend_type text,
    25.     blockers integer,
    26.     blockerpid integer,
    27.     blocker_state text
    28. ) PARTITION BY RANGE(ash_time);
    29. -- 索引创建
    30. CREATE INDEX idx_pg_ash_n1 ON pg_ash(ash_time);
    31. -- 分区创建,超出最大范围的值会落入默认的final分区
    32. CREATE TABLE pg_ash_history PARTITION OF pg_ash DEFAULT;
    33. CREATE TABLE pg_ash_202310 PARTITION OF pg_ash FOR VALUES FROM ('2023-10-01'TO ('2023-11-01');
    34. CREATE TABLE pg_ash_202311 PARTITION OF pg_ash FOR VALUES FROM ('2023-11-01'TO ('2023-12-01');
    35. CREATE TABLE pg_ash_202312 PARTITION OF pg_ash FOR VALUES FROM ('2023-12-01'TO ('2024-01-01');

    2. 定期自动新增分区

    vi  auto_create_partiton.sh

    1. #!/bin/bash
    2. source ~/.bash_profile
    3. # 分区表主表名
    4. MAIN_TABLE_NAME="pg_ash"
    5. # 待新增分区表名
    6. NEXT_MONTH=`date -d '+1 months' +%Y%m`
    7. TABLE_NAME=${MAIN_TABLE_NAME}_${NEXT_MONTH}
    8. # 分区范围
    9. NEXT_MONTH_FIRST_DAY=`date -d '+1 months' +%Y%m01`
    10. NEXT_2_MONTH_FIRST_DAY=`date -d '+2 months' +%Y%m01`
    11. SQL="CREATE TABLE IF NOT EXISTS $TABLE_NAME (LIKE $MAIN_TABLE_NAME INCLUDING INDEXES); ALTER TABLE $MAIN_TABLE_NAME ATTACH PARTITION $TABLE_NAME FOR VALUES FROM ('$NEXT_MONTH_FIRST_DAY') TO ('$NEXT_2_MONTH_FIRST_DAY');"
    12. #echo $SQL;
    13. psql -c "$SQL"

    chmod +x  auto_create_partiton.sh

    每月1号00:00 自动新建下月分区

    crontab -e

    00 00 01 * * /data/postgres/home/postgres/auto_create_partiton.sh

    3. 自动清理旧分区

    以保留两个月数据为例

    vi  auto_drop_old_partiton.sh

    1. #!/bin/bash
    2. source ~/.bash_profile
    3. # 分区表主表名
    4. MAIN_TABLE_NAME="pg_ash"
    5. # 待新增分区表名
    6. NEXT_MONTH=`date -d '+1 months' +%Y%m`
    7. TABLE_NAME=${MAIN_TABLE_NAME}_${NEXT_MONTH}
    8. # 分区范围
    9. NEXT_MONTH_FIRST_DAY=`date -d '+1 months' +%Y%m01`
    10. NEXT_2_MONTH_FIRST_DAY=`date -d '+2 months' +%Y%m01`
    11. SQL="CREATE TABLE IF NOT EXISTS $TABLE_NAME (LIKE $MAIN_TABLE_NAME INCLUDING INDEXES); ALTER TABLE $MAIN_TABLE_NAME ATTACH PARTITION $TABLE_NAME FOR VALUES FROM ('$NEXT_MONTH_FIRST_DAY') TO ('$NEXT_2_MONTH_FIRST_DAY');"
    12. #echo $SQL;
    13. psql -c "$SQL"

    chmod +x  auto_drop_old_partiton.sh

    每月30号23:00 自动删除旧分区

    crontab -e

    00 23 30 * * /data/postgres/home/postgres/auto_drop_old_partiton.sh

    四、 数据插入

    vi pg_ash.sh

    1. #!/bin/bash
    2. . ~/profile << EOF
    3. 5432
    4. EOF
    5. psql << EOF
    6. insert into pg_ash
    7. select now(), act.datid, act.datname, act.pid, act.leader_pid, act.usesysid, act.usename,
    8.  act.application_name, act.client_addr, act.client_hostname,
    9.  act.client_port, act.backend_start, act.xact_start, act.query_start,
    10.  act.state_change, act.wait_event_type, act.wait_event, act.state, act.backend_xid,
    11.  act.backend_xmin,act.query,act.query_id,act.backend_type,cardinality(pg_blocking_pids(act.pid))
    12.  as blockers,(pg_blocking_pids(act.pid))[1] as blockerpid ,blk.state as blocker_state
    13.  from pg_stat_activity act left join pg_stat_activity blk
    14.  on (pg_blocking_pids(act.pid))[1] = blk.pid
    15.  where act.state in ('active', 'idle in transaction') and act.pid != pg_backend_pid();
    16. EOF

    五、 设置定时执行

    由于crontab最小只能按分钟执行,这里利用while true+sleep实现每十秒执行。

    vi run.sh   与pg_ash.sh放在相同目录

    1. #!/bin/bash
    2. source .bash_profile
    3. while [ true ]
    4. do
    5. sh ./pg_ash.sh
    6. sleep 10
    7. done

    后台运行run.sh

    nohup ./run.sh &

    六、 测试运行效果

    1. pgbench压测

    • 初始化数据
    1. -bash-4.2$ createdb pgbench
    2. -bash-4.2$ pgbench -i pgbench
    3. dropping old tables...
    4. NOTICE: table "pgbench_accounts" does not exist, skipping
    5. NOTICE: table "pgbench_branches" does not exist, skipping
    6. NOTICE: table "pgbench_history" does not exist, skipping
    7. NOTICE: table "pgbench_tellers" does not exist, skipping
    8. creating tables...
    9. generating data (client-side)...
    10. 100000 of 100000 tuples (100%) done (elapsed 0.23 s, remaining 0.00 s)
    11. vacuuming...
    12. creating primary keys...
    13. done in 0.49 s (drop tables 0.00 s, create tables 0.01 s, client-side generate 0.27 s, vacuum 0.11 s, primary keys 0.10 s).
    14. -bash-4.2$
    15. -bash-4.2$ psql
    16. psql (14.0)
    17. Type "help" for help.
    18. postgres=# \l
    19. List of databases
    20. Name | Owner | Encoding | Collate | Ctype | Access privileges
    21. -----------+----------+----------+------------+------------+-----------------------
    22. pgbench | postgres | UTF8 | en_US.utf8 | en_US.utf8 |
    23. postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 |
    24. template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres +
    25. | | | | | postgres=CTc/postgres
    26. template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | =c/postgres +
    27. | | | | | postgres=CTc/postgres
    28. testdb | postgres | UTF8 | en_US.utf8 | en_US.utf8 |
    29. (5 rows)
    30. postgres=# \c pgbench
    31. You are now connected to database "pgbench" as user "postgres".
    32. pgbench=# \d
    33. List of relations
    34. Schema | Name | Type | Owner
    35. --------+------------------+-------+----------
    36. public | pgbench_accounts | table | postgres
    37. public | pgbench_branches | table | postgres
    38. public | pgbench_history | table | postgres
    39. public | pgbench_tellers | table | postgres
    40. (4 rows)
    • 压测脚本

    vi test.sql

    1. \set aid random(1, 100000 * :scale)
    2. \set bid random(1, 1 * :scale)
    3. \set tid random(1, 10 * :scale)
    4. \set delta random(-5000, 5000)
    5. BEGIN;
    6. UPDATE pgbench_accounts SET abalance = abalance + :delta WHERE aid = :aid;
    7. SELECT abalance FROM pgbench_accounts WHERE aid = :aid;
    8. UPDATE pgbench_tellers SET tbalance = tbalance + :delta WHERE tid = :tid;
    9. UPDATE pgbench_branches SET bbalance = bbalance + :delta WHERE bid = :bid;
    10. INSERT INTO pgbench_history (tid, bid, aid, delta, mtime) VALUES (:tid, :bid, :aid, :delta, CURRENT_TIMESTAMP);
    11. END;
    • 执行压测
    pgbench -c 4 -t 30000 pgbench -r -f test.sql

    2. 运行ash脚本

    nohup ./run.sh &

    3. 查询ash数据

    1. postgres=# select * from pg_ash;
    2. -[ RECORD 1 ]----+-----------------------------------------------------------------------
    3. ash_time | 2023-10-12 05:44:07.152751+08
    4. datid | 41585
    5. datname | pgbench
    6. pid | 1530
    7. leader_pid |
    8. usesysid | 10
    9. usename | postgres
    10. application_name | pgbench
    11. client_addr |
    12. client_hostname |
    13. client_port | -1
    14. backend_start | 2023-10-12 05:44:04.461672+08
    15. xact_start | 2023-10-12 05:44:07.144351+08
    16. query_start | 2023-10-12 05:44:07.145214+08
    17. state_change | 2023-10-12 05:44:07.145215+08
    18. wait_event_type | Lock
    19. wait_event | transactionid
    20. state | active
    21. backend_xid | 677819
    22. backend_xmin | 677814
    23. query | UPDATE pgbench_branches SET bbalance = bbalance + 3177 WHERE bid = 1;
    24. query_id | -6995838559535145041
    25. backend_type | client backend
    26. blockers | 1
    27. blockerpid | 1533
    28. blocker_state | active
    29. -[ RECORD 2 ]----+-----------------------------------------------------------------------
    30. ash_time | 2023-10-12 05:44:07.152751+08
    31. datid | 41585
    32. datname | pgbench
    33. pid | 1531
    34. leader_pid |
    35. usesysid | 10
    36. usename | postgres
    37. application_name | pgbench
    38. client_addr |
    39. client_hostname |
    40. client_port | -1
    41. backend_start | 2023-10-12 05:44:04.463697+08
    42. xact_start | 2023-10-12 05:44:07.151628+08
    43. query_start | 2023-10-12 05:44:07.152311+08
    44. state_change | 2023-10-12 05:44:07.152312+08
    45. wait_event_type | Lock
    46. wait_event | transactionid
    47. state | active
    48. backend_xid | 677821
    49. backend_xmin | 677817
    50. query | UPDATE pgbench_tellers SET tbalance = tbalance + 1637 WHERE tid = 8;
    51. query_id | -9151069917332221911
    52. backend_type | client backend
    53. blockers | 1
    54. blockerpid | 1530
    55. blocker_state | active
    56. ...

    参考:

    PostgreSQL Observability

    GitHub - pgsentinel/pgsentinel: postgresql extension providing Active session history

  • 相关阅读:
    kube-scheduler源码分析(2)-核心处理逻辑分析
    Linux|centos7下部署安装alertmanager并实现邮箱和微信告警
    yangwebrtc x86_64环境搭建
    39 vue.js
    Vite + Vue3 实现前端项目工程化
    安装yolov3(Anaconda)
    [论文必备]最强科研绘图分析工具Origin(1)——安装教程
    威固新能源GO野 伊士曼旗下品牌威固加速布局新能源车后市场
    深度学习(14)—— 关于Tensorboard
    从零开始,打造自己的专属游戏世界!
  • 原文地址:https://blog.csdn.net/Hehuyi_In/article/details/90671173