当前位置:   article > 正文

进阶数据库系列(二十四):PostgreSQL 数据库日志与日常巡检

postgres日志

点击下方名片,设为星标

回复“1024”获取2TB学习资源!

前面介绍了 PostgreSQL 基于 pgpool 实现读写分离实践数据库备份与恢复主从数据目录同步工具 pg_rewind数据库作业调度工具性能优化等相关的知识点,今天我将详细的为大家介绍 PostgreSQL 数据库日志与日常巡检相关知识,希望大家能够从中收获多多!如有帮助,请点在看、转发支持一波!!!

PostgreSQL 服务器日志

开启审计日志

编辑 $PGDATA/postgresql.conf文件

  1. vi $PGDATA/postgresql.conf
  2. # 做以下修改,下面2部分未提及的全部备注掉
  3. # - Where to Log -
  4. log_destination = 'csvlog' # 日志输出格式
  5. logging_collector = on # 日志收集器,打开后某些不会出现在审计日志中的日志会被重定向到审计日志
  6. log_directory = 'pg_log' # 相对于 $PGDATA 的相对路径,全路径即为 $PGDATA/pg_log
  7. # 保留近7天的审计日志,轮询替换
  8. log_filename = 'postgresql.%a' #日志名称
  9. log_file_mode = 0600 # 只有postgres有读写权限
  10. log_truncate_on_rotation = on # 覆盖同名日志
  11. log_rotation_size = 0 # 不限制日志大小
  12. log_min_messages = warning # 控制哪些消息级别被写入到审计日志
  13. log_min_error_statement = error # 控制哪些导致一个错误情况的 SQL 语句被记录在服务器日志中
  14. log_min_duration_statement = 0 # 记录所有sql运行时长,可以查慢sql
  15. # - What to Log -
  16. log_duration = on # 导致每一个完成的语句的持续时间被记录
  17. log_lock_waits = on # 等锁超时记录日志,超时时间参数 deadlock_timeout
  18. log_statement = 'mod' # mod记录所有ddl语句,外加数据修改语句例如INSERT, UPDATE、DELETE、TRUNCATE, 和COPY FROM
  19. log_replication_commands = off # 不记录流复制命令
  20. log_timezone = 'Asia/Shanghai' # 时区,查看操作系统时区 timedatectl | grep "Time zone"

重启数据库

pg_ctl restart -mf

更多关于 PostgreSQL 系列的学习文章,请参阅:PostgreSQL 数据库,本系列持续更新中。

sql直接读取日志

安装 file_fdw 插件

create extension file_fdw;

创建外部表

  1. drop foreign table if exists pg_log_mon;
  2. create foreign table pg_log_mon(
  3.      log_time timestamp
  4.     ,user_name text
  5.     ,database_name text
  6.     ,process_id integer
  7.     ,connection_from text
  8.     ,session_id text
  9.     ,session_line_num bigint
  10.     ,command_tag text
  11.     ,session_start_time timestamp
  12.     ,virtual_transaction_id text
  13.     ,transaction_id bigint
  14.     ,error_severity text
  15.     ,sql_state_code text
  16.     ,message text
  17.     ,detail text
  18.     ,hint text
  19.     ,internal_query text
  20.     ,internal_query_pos integer
  21.     ,context text
  22.     ,query text
  23.     ,query_pos integer
  24.     ,location text
  25.     ,application_name text 
  26. ) server pg_file_server options(
  27.      filename '/data/pgdata/pg_log/postgresql.Mon.csv'
  28.     ,format 'csv'
  29.     ,header 'false'
  30.     ,delimiter ','
  31.     ,quote '"'
  32.     ,escape '"'
  33. );
  34. comment on foreign table pg_log_mon is '每周一当天审计日志';
  35. comment on column pg_log_mon.log_time is '日志时间';
  36. comment on column pg_log_mon.user_name is '用户名';
  37. comment on column pg_log_mon.database_name is '数据库名';
  38. comment on column pg_log_mon.process_id is '进程id';
  39. comment on column pg_log_mon.connection_from is '客户端ip:端口';
  40. comment on column pg_log_mon.session_id is '会话id';
  41. comment on column pg_log_mon.session_line_num is '当前会话的第几次查询';
  42. comment on column pg_log_mon.command_tag is '命令类型';
  43. comment on column pg_log_mon.session_start_time is '会话开始时间';
  44. comment on column pg_log_mon.virtual_transaction_id is '虚拟事务id';
  45. comment on column pg_log_mon.transaction_id is '事务id';
  46. comment on column pg_log_mon.error_severity is '错误级别';
  47. comment on column pg_log_mon.sql_state_code is 'sql状态代码';
  48. comment on column pg_log_mon.message is '信息';
  49. comment on column pg_log_mon.detail is '详细信息';
  50. comment on column pg_log_mon.hint is '提示信息';
  51. comment on column pg_log_mon.query is '查询的sql';
  52. comment on column pg_log_mon.application_name is '应用名(客户端名)';
  53. drop foreign table if exists pg_log_tue;
  54. create foreign table pg_log_tue(
  55.      log_time timestamp
  56.     ,user_name text
  57.     ,database_name text
  58.     ,process_id integer
  59.     ,connection_from text
  60.     ,session_id text
  61.     ,session_line_num bigint
  62.     ,command_tag text
  63.     ,session_start_time timestamp
  64.     ,virtual_transaction_id text
  65.     ,transaction_id bigint
  66.     ,error_severity text
  67.     ,sql_state_code text
  68.     ,message text
  69.     ,detail text
  70.     ,hint text
  71.     ,internal_query text
  72.     ,internal_query_pos integer
  73.     ,context text
  74.     ,query text
  75.     ,query_pos integer
  76.     ,location text
  77.     ,application_name text 
  78. ) server pg_file_server options(
  79.      filename '/data/pgdata/pg_log/postgresql.Tue.csv'
  80.     ,format 'csv'
  81.     ,header 'false'
  82.     ,delimiter ','
  83.     ,quote '"'
  84.     ,escape '"'
  85. );
  86. comment on foreign table pg_log_tue is '每周二当天审计日志';
  87. comment on column pg_log_tue.log_time is '日志时间';
  88. comment on column pg_log_tue.user_name is '用户名';
  89. comment on column pg_log_tue.database_name is '数据库名';
  90. comment on column pg_log_tue.process_id is '进程id';
  91. comment on column pg_log_tue.connection_from is '客户端ip:端口';
  92. comment on column pg_log_tue.session_id is '会话id';
  93. comment on column pg_log_tue.session_line_num is '当前会话的第几次查询';
  94. comment on column pg_log_tue.command_tag is '命令类型';
  95. comment on column pg_log_tue.session_start_time is '会话开始时间';
  96. comment on column pg_log_tue.virtual_transaction_id is '虚拟事务id';
  97. comment on column pg_log_tue.transaction_id is '事务id';
  98. comment on column pg_log_tue.error_severity is '错误级别';
  99. comment on column pg_log_tue.sql_state_code is 'sql状态代码';
  100. comment on column pg_log_tue.message is '信息';
  101. comment on column pg_log_tue.detail is '详细信息';
  102. comment on column pg_log_tue.hint is '提示信息';
  103. comment on column pg_log_tue.query is '查询的sql';
  104. comment on column pg_log_tue.application_name is '应用名(客户端名)';
  105. drop foreign table if exists pg_log_wed;
  106. create foreign table pg_log_wed(
  107.      log_time timestamp
  108.     ,user_name text
  109.     ,database_name text
  110.     ,process_id integer
  111.     ,connection_from text
  112.     ,session_id text
  113.     ,session_line_num bigint
  114.     ,command_tag text
  115.     ,session_start_time timestamp
  116.     ,virtual_transaction_id text
  117.     ,transaction_id bigint
  118.     ,error_severity text
  119.     ,sql_state_code text
  120.     ,message text
  121.     ,detail text
  122.     ,hint text
  123.     ,internal_query text
  124.     ,internal_query_pos integer
  125.     ,context text
  126.     ,query text
  127.     ,query_pos integer
  128.     ,location text
  129.     ,application_name text 
  130. ) server pg_file_server options(
  131.      filename '/data/pgdata/pg_log/postgresql.Wed.csv'
  132.     ,format 'csv'
  133.     ,header 'false'
  134.     ,delimiter ','
  135.     ,quote '"'
  136.     ,escape '"'
  137. );
  138. comment on foreign table pg_log_wed is '每周三当天审计日志';
  139. comment on column pg_log_wed.log_time is '日志时间';
  140. comment on column pg_log_wed.user_name is '用户名';
  141. comment on column pg_log_wed.database_name is '数据库名';
  142. comment on column pg_log_wed.process_id is '进程id';
  143. comment on column pg_log_wed.connection_from is '客户端ip:端口';
  144. comment on column pg_log_wed.session_id is '会话id';
  145. comment on column pg_log_wed.session_line_num is '当前会话的第几次查询';
  146. comment on column pg_log_wed.command_tag is '命令类型';
  147. comment on column pg_log_wed.session_start_time is '会话开始时间';
  148. comment on column pg_log_wed.virtual_transaction_id is '虚拟事务id';
  149. comment on column pg_log_wed.transaction_id is '事务id';
  150. comment on column pg_log_wed.error_severity is '错误级别';
  151. comment on column pg_log_wed.sql_state_code is 'sql状态代码';
  152. comment on column pg_log_wed.message is '信息';
  153. comment on column pg_log_wed.detail is '详细信息';
  154. comment on column pg_log_wed.hint is '提示信息';
  155. comment on column pg_log_wed.query is '查询的sql';
  156. comment on column pg_log_wed.application_name is '应用名(客户端名)';
  157. drop foreign table if exists pg_log_thu;
  158. create foreign table pg_log_thu(
  159.      log_time timestamp
  160.     ,user_name text
  161.     ,database_name text
  162.     ,process_id integer
  163.     ,connection_from text
  164.     ,session_id text
  165.     ,session_line_num bigint
  166.     ,command_tag text
  167.     ,session_start_time timestamp
  168.     ,virtual_transaction_id text
  169.     ,transaction_id bigint
  170.     ,error_severity text
  171.     ,sql_state_code text
  172.     ,message text
  173.     ,detail text
  174.     ,hint text
  175.     ,internal_query text
  176.     ,internal_query_pos integer
  177.     ,context text
  178.     ,query text
  179.     ,query_pos integer
  180.     ,location text
  181.     ,application_name text 
  182. ) server pg_file_server options(
  183.      filename '/data/pgdata/pg_log/postgresql.Thu.csv'
  184.     ,format 'csv'
  185.     ,header 'false'
  186.     ,delimiter ','
  187.     ,quote '"'
  188.     ,escape '"'
  189. );
  190. comment on foreign table pg_log_thu is '每周四当天审计日志';
  191. comment on column pg_log_thu.log_time is '日志时间';
  192. comment on column pg_log_thu.user_name is '用户名';
  193. comment on column pg_log_thu.database_name is '数据库名';
  194. comment on column pg_log_thu.process_id is '进程id';
  195. comment on column pg_log_thu.connection_from is '客户端ip:端口';
  196. comment on column pg_log_thu.session_id is '会话id';
  197. comment on column pg_log_thu.session_line_num is '当前会话的第几次查询';
  198. comment on column pg_log_thu.command_tag is '命令类型';
  199. comment on column pg_log_thu.session_start_time is '会话开始时间';
  200. comment on column pg_log_thu.virtual_transaction_id is '虚拟事务id';
  201. comment on column pg_log_thu.transaction_id is '事务id';
  202. comment on column pg_log_thu.error_severity is '错误级别';
  203. comment on column pg_log_thu.sql_state_code is 'sql状态代码';
  204. comment on column pg_log_thu.message is '信息';
  205. comment on column pg_log_thu.detail is '详细信息';
  206. comment on column pg_log_thu.hint is '提示信息';
  207. comment on column pg_log_thu.query is '查询的sql';
  208. comment on column pg_log_thu.application_name is '应用名(客户端名)';
  209. drop foreign table if exists pg_log_fri;
  210. create foreign table pg_log_fri(
  211.      log_time timestamp
  212.     ,user_name text
  213.     ,database_name text
  214.     ,process_id integer
  215.     ,connection_from text
  216.     ,session_id text
  217.     ,session_line_num bigint
  218.     ,command_tag text
  219.     ,session_start_time timestamp
  220.     ,virtual_transaction_id text
  221.     ,transaction_id bigint
  222.     ,error_severity text
  223.     ,sql_state_code text
  224.     ,message text
  225.     ,detail text
  226.     ,hint text
  227.     ,internal_query text
  228.     ,internal_query_pos integer
  229.     ,context text
  230.     ,query text
  231.     ,query_pos integer
  232.     ,location text
  233.     ,application_name text 
  234. ) server pg_file_server options(
  235.      filename '/data/pgdata/pg_log/postgresql.Fri.csv'
  236.     ,format 'csv'
  237.     ,header 'false'
  238.     ,delimiter ','
  239.     ,quote '"'
  240.     ,escape '"'
  241. );
  242. comment on foreign table pg_log_fri is '每周五当天审计日志';
  243. comment on column pg_log_fri.log_time is '日志时间';
  244. comment on column pg_log_fri.user_name is '用户名';
  245. comment on column pg_log_fri.database_name is '数据库名';
  246. comment on column pg_log_fri.process_id is '进程id';
  247. comment on column pg_log_fri.connection_from is '客户端ip:端口';
  248. comment on column pg_log_fri.session_id is '会话id';
  249. comment on column pg_log_fri.session_line_num is '当前会话的第几次查询';
  250. comment on column pg_log_fri.command_tag is '命令类型';
  251. comment on column pg_log_fri.session_start_time is '会话开始时间';
  252. comment on column pg_log_fri.virtual_transaction_id is '虚拟事务id';
  253. comment on column pg_log_fri.transaction_id is '事务id';
  254. comment on column pg_log_fri.error_severity is '错误级别';
  255. comment on column pg_log_fri.sql_state_code is 'sql状态代码';
  256. comment on column pg_log_fri.message is '信息';
  257. comment on column pg_log_fri.detail is '详细信息';
  258. comment on column pg_log_fri.hint is '提示信息';
  259. comment on column pg_log_fri.query is '查询的sql';
  260. comment on column pg_log_fri.application_name is '应用名(客户端名)';
  261. drop foreign table if exists pg_log_sat;
  262. create foreign table pg_log_sat(
  263.      log_time timestamp
  264.     ,user_name text
  265.     ,database_name text
  266.     ,process_id integer
  267.     ,connection_from text
  268.     ,session_id text
  269.     ,session_line_num bigint
  270.     ,command_tag text
  271.     ,session_start_time timestamp
  272.     ,virtual_transaction_id text
  273.     ,transaction_id bigint
  274.     ,error_severity text
  275.     ,sql_state_code text
  276.     ,message text
  277.     ,detail text
  278.     ,hint text
  279.     ,internal_query text
  280.     ,internal_query_pos integer
  281.     ,context text
  282.     ,query text
  283.     ,query_pos integer
  284.     ,location text
  285.     ,application_name text 
  286. ) server pg_file_server options(
  287.      filename '/data/pgdata/pg_log/postgresql.Sat.csv'
  288.     ,format 'csv'
  289.     ,header 'false'
  290.     ,delimiter ','
  291.     ,quote '"'
  292.     ,escape '"'
  293. );
  294. comment on foreign table pg_log_sat is '每周六当天审计日志';
  295. comment on column pg_log_sat.log_time is '日志时间';
  296. comment on column pg_log_sat.user_name is '用户名';
  297. comment on column pg_log_sat.database_name is '数据库名';
  298. comment on column pg_log_sat.process_id is '进程id';
  299. comment on column pg_log_sat.connection_from is '客户端ip:端口';
  300. comment on column pg_log_sat.session_id is '会话id';
  301. comment on column pg_log_sat.session_line_num is '当前会话的第几次查询';
  302. comment on column pg_log_sat.command_tag is '命令类型';
  303. comment on column pg_log_sat.session_start_time is '会话开始时间';
  304. comment on column pg_log_sat.virtual_transaction_id is '虚拟事务id';
  305. comment on column pg_log_sat.transaction_id is '事务id';
  306. comment on column pg_log_sat.error_severity is '错误级别';
  307. comment on column pg_log_sat.sql_state_code is 'sql状态代码';
  308. comment on column pg_log_sat.message is '信息';
  309. comment on column pg_log_sat.detail is '详细信息';
  310. comment on column pg_log_sat.hint is '提示信息';
  311. comment on column pg_log_sat.query is '查询的sql';
  312. comment on column pg_log_sat.application_name is '应用名(客户端名)';
  313. drop foreign table if exists pg_log_sun;
  314. create foreign table pg_log_sun(
  315.      log_time timestamp
  316.     ,user_name text
  317.     ,database_name text
  318.     ,process_id integer
  319.     ,connection_from text
  320.     ,session_id text
  321.     ,session_line_num bigint
  322.     ,command_tag text
  323.     ,session_start_time timestamp
  324.     ,virtual_transaction_id text
  325.     ,transaction_id bigint
  326.     ,error_severity text
  327.     ,sql_state_code text
  328.     ,message text
  329.     ,detail text
  330.     ,hint text
  331.     ,internal_query text
  332.     ,internal_query_pos integer
  333.     ,context text
  334.     ,query text
  335.     ,query_pos integer
  336.     ,location text
  337.     ,application_name text 
  338. ) server pg_file_server options(
  339.      filename '/data/pgdata/pg_log/postgresql.Sun.csv'
  340.     ,format 'csv'
  341.     ,header 'false'
  342.     ,delimiter ','
  343.     ,quote '"'
  344.     ,escape '"'
  345. );
  346. comment on foreign table pg_log_sun is '每周日当天审计日志';
  347. comment on column pg_log_sun.log_time is '日志时间';
  348. comment on column pg_log_sun.user_name is '用户名';
  349. comment on column pg_log_sun.database_name is '数据库名';
  350. comment on column pg_log_sun.process_id is '进程id';
  351. comment on column pg_log_sun.connection_from is '客户端ip:端口';
  352. comment on column pg_log_sun.session_id is '会话id';
  353. comment on column pg_log_sun.session_line_num is '当前会话的第几次查询';
  354. comment on column pg_log_sun.command_tag is '命令类型';
  355. comment on column pg_log_sun.session_start_time is '会话开始时间';
  356. comment on column pg_log_sun.virtual_transaction_id is '虚拟事务id';
  357. comment on column pg_log_sun.transaction_id is '事务id';
  358. comment on column pg_log_sun.error_severity is '错误级别';
  359. comment on column pg_log_sun.sql_state_code is 'sql状态代码';
  360. comment on column pg_log_sun.message is '信息';
  361. comment on column pg_log_sun.detail is '详细信息';
  362. comment on column pg_log_sun.hint is '提示信息';
  363. comment on column pg_log_sun.query is '查询的sql';
  364. comment on column pg_log_sun.application_name is '应用名(客户端名)';
  365. create or replace view pg_log as 
  366. select * from pg_log_mon
  367. union all
  368. select * from pg_log_tue
  369. union all
  370. select * from pg_log_wed
  371. union all
  372. select * from pg_log_thu
  373. union all
  374. select * from pg_log_fri
  375. union all
  376. select * from pg_log_sat
  377. union all
  378. select * from pg_log_sun;

更多关于 PostgreSQL 系列的学习文章,请参阅:PostgreSQL 数据库,本系列持续更新中。

备份策略

每天00:30备份前一天的审计日志

shell脚本实现备份
  1. #! /bin/bash
  2. #备份日期默认昨天,也是备份日期上限
  3. BAKUP_DATE_UPPER=`date '+%Y%m%d' -d '-1 day'`
  4. BAKUP_DATE_FLOOR=`date '+%Y%m%d' -d '-6 day'`
  5. BAKUP_DATE=${BAKUP_DATE_UPPER}
  6. showuseage() {
  7.     echo "程序功能:在数据库中备份昨天的pg审计日志
  8.   Useage: [backup_pglog -h 20220830]
  9.        -h [:可选,指定备份日期,可选范围${BAKUP_DATE_FLOOR}-${BAKUP_DATE_UPPER},其他默认昨天]"
  10. }
  11. # /home/postgres/backup_pglog.sh
  12. # 每天备份昨天的数据
  13. while getopts h: OPTS; do
  14.     case "$OPTS" in
  15.         h)  
  16.             if [ $OPTARG -ge ${BAKUP_DATE_FLOOR} -a $OPTARG -le ${BAKUP_DATE_UPPER} ]; then 
  17.                 BAKUP_DATE=$OPTARG
  18.             fi
  19.             ;;
  20.         :)  
  21.             echo "$0 必须为 -$OPTARG 添加一个参数!"
  22.             exit 1
  23.             ;;
  24.         ?)
  25.             showuseage
  26.             exit 1
  27.            ;;
  28.     esac
  29. done            
  30. BAKUP_SQL="
  31.     create table if not exists pg_log_:bak_log_span as 
  32.     select 
  33.          :today::varchar(8) as bak_date
  34.         ,*
  35.     from pg_log
  36.     where 1 = 2
  37.     ;
  38.     delete from pg_log_:bak_log_span where to_char(log_time,'yyyymmdd')::numeric = ${BAKUP_DATE}
  39.     ;
  40.     insert into pg_log_:bak_log_span
  41.     select :today::varchar as bak_date ,* 
  42.     from pg_log
  43.     where to_char(log_time,'yyyymmdd')::numeric = ${BAKUP_DATE}
  44.     ;
  45.     "
  46. echo `date '+%Y-%m-%d %H:%m:%S'`"|INFO|备份数据日期:${BAKUP_DATE}"
  47. echo `date '+%Y-%m-%d %H:%m:%S'`"|INFO|审计日志备份开始"
  48. BAKUP_SQL_EXEC_DATE=`date '+%Y%m%d%H%m%S'`
  49. psql <<EOF > /tmp/bakup_sql_exec_${BAKUP_SQL_EXEC_DATE}.log 2>&1 
  50. \i ~/var/${BAKUP_DATE}.sql
  51. ${BAKUP_SQL}
  52. \q
  53. EOF
  54. EXECLOG=`cat /tmp/bakup_sql_exec_${BAKUP_SQL_EXEC_DATE}.log`
  55. rm -f /tmp/bakup_sql_exec_${BAKUP_SQL_EXEC_DATE}.log
  56. echo `date '+%Y-%m-%d %H:%m:%S'`"|INFO|审计日志备份结束"
  57. # 错误
  58. ERRORNUM=`echo "${EXECLOG}" | grep -i 'ERROR' | wc -l`
  59. if [ ${ERRORNUM} -eq 0 ]
  60. then 
  61.     # 发短信通知备份成功
  62.     echo `date '+%Y-%m-%d %H:%m:%S'`"|INFO|审计日志备份成功"
  63.     exit 0
  64. else
  65.     # 发短信通知备份失败
  66.     echo "请及时重新执行备份脚本进行备份" | mail -s "审计日志备份失败" 1445471277@qq.com
  67.     echo `date '+%Y-%m-%d %H:%m:%S'`"|ERROR|审计日志备份失败"
  68.     exit 1
  69. fi
  1. chmod +x /home/postgres/backup_pglog.sh
  2. crontab -e 
  3. 30 0 * * * . /home/postgres/backup_pglog.sh >> /home/postgres/backup_pglog.log  2>&1
格式符说明
  1. %a  #星期的英文单词的缩写:如星期一, 则返回 Mon
  2. %A  #星期的英文单词的全拼:如星期一,返回 Monday
  3. %b  #月份的英文单词的缩写:如一月, 则返回 Jan
  4. %B  #月份的引文单词的缩写:如一月, 则返回 January
  5. %c  #返回datetime的字符串表示,如03/08/15 23:01:26
  6. %d  #返回的是当前时间是当前月的第几天
  7. %f  #微秒的表示: 范围: [0,999999]
  8. %H  #以24小时制表示当前小时
  9. %I  #以12小时制表示当前小时
  10. %j  #返回 当天是当年的第几天 范围[001,366]
  11. %m  #返回月份 范围[0,12]
  12. %M  #返回分钟数 范围 [0,59]
  13. %P  #返回是上午还是下午–AM or PM
  14. %S  #返回秒数 范围 [0,61]。。。手册说明的
  15. %U  #返回当周是当年的第几周 以周日为第一天
  16. %W  #返回当周是当年的第几周 以周一为第一天
  17. %w  #当天在当周的天数,范围为[06],6表示星期天
  18. %x  #日期的字符串表示 :03/08/15
  19. %X  #时间的字符串表示 :23:22:08
  20. %y  #两个数字表示的年份 15
  21. %Y  #四个数字表示的年份 2015
  22. %z  #与utc时间的间隔 (如果是本地时间,返回空字符串)
  23. %Z  #时区名称(如果是本地时间,返回空字符串)
消息严重级别
2bb98e5d29e0aa8028264140d7d68062.png

更多关于 PostgreSQL 系列的学习文章,请参阅:PostgreSQL 数据库,本系列持续更新中。

Postgresql 数据库巡检

主机信息
CPU
  1. mpstat | sed -n '3,$p' | awk -F' ' '{print $13}'
  2. echo 'CPU CORE' && cat /proc/cpuinfo|grep processor|wc -l
  • 正常:空闲cpu大于20%;

  • 异常处理:排查问题,杀掉cpu高进程,top 按c;

检查内存
free -m
  • 正常:空闲内存大于30%;

  • 异常处理:排查问题,杀掉内存高进程,top 按c;

检查磁盘空间
df -lh
  • 正常:磁盘空间已用空间小于70%;

  • 异常处理:增加硬盘或者删除无用的数据;

检查IO
iostat -x | sed -n '6,$p' | awk -F' ' '{print $1,$13,$14}'
  • 正常:磁盘空间已用空间小于70%;

  • 异常处理:增加硬盘或者删除无用的数据;

检查端口
netstat -tanp | grep 'LISTEN' | grep '5432'
  • 正常:tcp4和tcp6正常监听;

  • 异常处理:排查数据库是否正常启动,排查数据库配置文件的端口参数是否为5432;

检查postgres进程
ps -ef | grep "checkpointer|background writer|walwriter|autovacuum launcher|archiver|stats collector|logical replication launcher|logger" | grep -v grep
  • 正常:进程都在;

  • 异常处理:重启数据库;

数据库
检查安装信息
  1. select 
  2.      to_char(now(),'yyyy-mm-dd hh24:mi:ss'"巡检时间"
  3.     ,to_char(pg_postmaster_start_time(),'yyyy-mm-dd hh24:mi:ss'"pg_start_time(启动时间)"
  4.     ,now()-pg_postmaster_start_time() "pg_running_time(运行时长)"
  5.     --,inet_server_addr() "server_ip(服务器ip)"
  6.     --,inet_server_port() "server_port(服务器端口)"
  7.     --,inet_client_addr() "client_ip(客户端ip)"
  8.     --,inet_client_port() "client_port(客户端端口)"
  9.     ,version() "server_version(数据库版本)"
  10.     ,(case when pg_is_in_recovery()='f' then 'primary' else 'standby' end ) as  "primary_or_standby(主或备)"
  11. ;
  • 正常:数据库正常使用;

  • 异常处理:重装数据库;

检查postgresql.conf文件
  1. select 
  2.      to_char(now(),'yyyy-mm-dd hh24:mi:ss'"巡检时间"
  3.     ,sourceline "sourceline(行号)"
  4.     ,name "para(参数名)"
  5.     ,setting "value(参数值)"
  6. from pg_file_settings
  7. order by "sourceline(行号)";
  • 正常:各项参数设置适合;

  • 异常处理:编辑postgresql.conf文件,修改参数后重启数据库;

  1. vi $PGDATA/postgresql.conf
  2. pg_ctl restart -mf
检查pg_hba.conf文件
  1. select 
  2.      to_char(now(),'yyyy-mm-dd hh24:mi:ss'"巡检时间"
  3.     ,line_number "line_number(行号)"
  4.     ,type "type(连接类型)"
  5.     ,database "database(数据库名)"
  6.     ,user_name "user_name(用户名)"
  7.     ,address "address(ip地址)"
  8.     ,netmask "netmask(子网掩码)"
  9.     ,auth_method "auth_method(认证方式)"
  10. from pg_hba_file_rules
  11. order by "line_number(行号)";
  • 正常:非套接字连接都需要md5认证;

  • 异常处理:编辑pg_hba.conf文件,修改参数后重新加载数据库;

  1. vi $PGDATA/postgresql.conf
  2. pg_ctl reload
检查数据库重要配置
  1. select
  2.      to_char(now(),'yyyy-mm-dd hh24:mi:ss'"巡检时间"
  3.     ,name 
  4.     ,setting
  5. from
  6.     pg_settings a
  7. where a.name in (
  8.   'data_directory',
  9.   'port',
  10.   'client_encoding',
  11.   'config_file',
  12.   'hba_file',
  13.   'ident_file',
  14.   'archive_mode',
  15.   'logging_collector',
  16.   'log_directory',
  17.   'log_filename',
  18.   'log_truncate_on_rotation',
  19.   'log_statement',
  20.   'log_min_duration_statement',
  21.   'max_connections'
  22.   'listen_addresses'
  23. )
  24. order by name;
  • 正常:各项配置都适合;

  • 异常处理:修改不合适的配置;

检查主从WAl状态
  1. select 
  2.     -- pid "pid(进程id)"
  3.     --,usename "username(用户名)"
  4.     --,application_name "application_name(应用名)"
  5.     --,client_addr "client_addr(IP)"
  6.     --,backend_start "backend_start(备份开始时间)"
  7.      state "state(WAL发送状态编码)"
  8. --    ,case 
  9. --        when state = 'startup' then '正在启动'
  10. --        when state = 'catchup' then '追赶主库'
  11. --        when state = 'streaming' then '流传送'
  12. --        when state = 'backup' then '发送备份'
  13. --        when state = 'stopping' then '发送停止'
  14. --     end "statename(WAL状态)"
  15.     ,sync_state "sync_state(同步状态编码)"
  16. --    ,case 
  17. --        when sync_state = 'async' then '异步'
  18. --        when sync_state = 'potential' then '后备失效变同步'
  19. --        when sync_state = 'sync' then '同步'
  20. --        when sync_state = 'quorum' then '候选'
  21. --     end "sync_statename(同步状态名称)"
  22.     --,round(pg_wal_lsn_diff(pg_current_wal_lsn(),replay_lsn) /(1024 * 1024),2) as "slave_latency_mb(同步延迟_MB)"
  23. from pg_stat_replication;
  1. select 
  2.     -- pid "pid(进程id)"
  3.      status "status(WAl接收状态)"
  4.     ,'async' "sync_state(同步状态编码)"
  5.     --,last_msg_send_time "last_msg_send_time(接收到最后的消息发送时间)"
  6.     --,last_msg_receipt_time "last_msg_receipt_time(接收到最后的消息接收时间)"
  7.     --,sender_host "sender_host(主库IP)"
  8. from pg_stat_wal_receiver
  9. ;

更多关于 PostgreSQL 系列的学习文章,请参阅:PostgreSQL 数据库,本系列持续更新中。

检查表空间
  1. select 
  2.      to_char(now(),'yyyy-mm-dd hh24:mi:ss'"巡检时间"
  3.     ,spcname AS "Name(名称)"
  4.     ,pg_catalog.pg_get_userbyid(spcowner) AS "Owner(拥有者)"
  5.     --,pg_catalog.pg_tablespace_location(oid) AS "Location(数据文件目录)"
  6.     --,pg_catalog.array_to_string(spcacl, E'\n') AS "Access privileges(访问权限)"
  7.     --,spcoptions AS "Options(参数)"
  8.     ,pg_catalog.pg_size_pretty(pg_catalog.pg_tablespace_size(oid)) AS "Size(表空间大小)"
  9.     --,pg_catalog.shobj_description(oid, 'pg_tablespace') AS "Description(备注)"
  10. from pg_catalog.pg_tablespace
  11. order by 1;
检查连接数
  1. select
  2.      to_char(now(),'yyyy-mm-dd hh24:mi:ss'"巡检时间"
  3.     ,max_conn "max_conn(最大连接数)"
  4.     ,now_conn "now_conn(当前连接数)"
  5.     ,max_conn - now_conn "remain_conn(剩余连接数)"
  6. from (
  7.     select
  8.          setting::int8 as max_conn
  9.         ,(select count(*) from pg_stat_activity ) as now_conn
  10.     from pg_settings
  11.     where name = 'max_connections' 
  12. ) a
  13. ;
  • 正常:连接数不超过总连接数的90%;

  • 异常处理:超级用户(postgres)杀连接;

  1. --杀掉所有空闲连接
  2. select pg_terminate_backend(pid) from pg_stat_activity WHERE state = 'idle';
检查锁表
  1. select 
  2.      to_char(now(),'yyyy-mm-dd hh24:mi:ss'"巡检时间"
  3.     ,relname "relname(表名)"
  4.     ,b.nspname "shemaname(模式名)"
  5.     ,c.rolname "user(用户名)"
  6.     ,d.locktype "locktype(被锁对象类型)"
  7.     ,d.mode "mode(锁类型)"
  8.     ,d.pid "pid(进程id)"
  9.     ,e.query "query(锁表sql)"
  10.     ,current_timestamp-state_change "lock_duration(锁表时长)"
  11. from pg_class a
  12. inner join pg_namespace b 
  13. on (a.relnamespace = b.oid)
  14. inner join pg_roles c 
  15. on (a.relowner = c.oid)
  16. inner join pg_locks d
  17. on (a.oid = d.relation)
  18. left join pg_stat_activity e 
  19. on (d.pid = e.pid)
  20. where d.mode = 'AccessExclusiveLock'
  21. order by "lock_duration(锁表时长)" desc;
  • 正常:无锁表;

  • 异常处理:取消该进程或杀掉该会话;

  1. --取消该进程
  2. select pg_cancel_backend(pid);
  3. --杀掉该会话
  4. select pg_terminate_backend(pid);
检查空闲连接top5
  1. select 
  2.      to_char(now(),'yyyy-mm-dd hh24:mi:ss'"巡检时间"
  3.     ,a.datname "datname(数据库名)"
  4.     ,a.pid "pid(进程id)"
  5.     ,b.rolname "username(用户名)"
  6.     --,a.application_name "app_name(应用名称)"
  7.     ,a.client_addr "client_ip(客户端ip)"
  8.     --,a.query_start "query_start(当前查询开始时间)"
  9.     ,to_char(a.state_change,'yyyy-mm-dd hh24:mi:ss'"state_change(状态变化时间)"
  10.     --,a.state "state(状态)"
  11.     --,a.query "sql(执行的sql)"
  12.     --,a.backend_type "backend_type(后端类型)"
  13. from pg_stat_activity a
  14. inner join pg_roles b 
  15. on (a.usesysid = b.oid)
  16. where a.state = 'idle'
  17.     and state_change < current_timestamp - interval '30 min'
  18. order by current_timestamp-state_change desc
  19. limit 5
  20. ;
  • 正常:超半小时空闲的连接;

  • 异常处理:杀连接;

select pg_terminate_backend(pid);
检查长事务top5
  1. select 
  2.      to_char(now(),'yyyy-mm-dd hh24:mi:ss'"巡检时间"
  3.     ,a.datname "datname(数据库名)"
  4.     ,a.pid "pid(进程id)"
  5.     ,b.rolname "username(用户名)"
  6.     --,a.application_name "app_name(应用名称)"
  7.     ,a.client_addr "client_ip(客户端ip)"
  8.     --,a.xact_start "xact_start(当前事务开始时间)"
  9.     --,a.query_start "query_start(当前查询开始时间)"
  10.     ,to_char(a.state_change,'yyyy-mm-dd hh24:mi:ss'"state_change(状态变化时间)"
  11.     --,a.state "state(状态)"
  12.     --,a.query "sql(执行的sql)"
  13.     --,a.backend_type "backend_type(后端类型)"
  14. from pg_stat_activity a
  15. inner join pg_roles b 
  16. on (a.usesysid = b.oid)
  17. where a.state in ('idle in transaction','idle in transaction (aborted)')
  18.     and state_change < current_timestamp - interval '30 min'
  19. order by current_timestamp-state_change desc
  20. limit 5;
  • 正常:不存在长事务;

  • 异常处理:杀会话;

select pg_terminate_backend(pid);
检查慢SQLtop5
  1. select 
  2.      to_char(now(),'yyyy-mm-dd hh24:mi:ss'"巡检时间"
  3.     ,a.datname "datname(数据库名)"
  4.     ,a.pid "pid(进程id)"
  5.     ,b.rolname "username(用户名)"
  6.     --,a.application_name "app_name(应用名称)"
  7.     ,a.client_addr "client_ip(客户端ip)"
  8.     --,a.query_start "query_start(当前查询开始时间)"
  9.     ,to_char(a.state_change,'yyyy-mm-dd hh24:mi:ss'"state_change(状态变化时间)"
  10.     --,a.wait_event_type "wait_event_type(等待类型)"
  11.     --,a.wait_event "wait_event(等待事件)"
  12.     --,a.state "state(状态)"
  13.     --,a.query "sql(执行的sql)"
  14.     --,a.backend_type "backend_type(后端类型)"
  15. from pg_stat_activity a
  16. left join pg_roles b 
  17. on (a.usesysid = b.oid)
  18. where a.state = 'active'
  19.     and state_change < current_timestamp - interval '1 hour'
  20.     and a.datname is not null
  21. order by current_timestamp-state_change desc 
  22. limit 5;
  • 正常:不存在慢sql;

  • 异常处理:分析原因,有针对性地杀连接;

select pg_terminate_backend(pid);
检查对象数
  1. --这里需要循环查每个库所有数据然后合并
  2. select to_char(now(),'yyyy-mm-dd hh24:mi:ss'"巡检时间"
  3.     ,current_database()
  4.     ,sum(obj_num) "obj_num(对象数)" 
  5. from (
  6.     select count(1) obj_num from pg_class 
  7.     union all 
  8.     select count(1) from pg_proc 
  9. ) a
  10. ;
  • 正常:总对象数不超过5万;

  • 异常处理:删除无用的对象;

检查表膨胀top5
  1. select
  2.      to_char(now(),'yyyy-mm-dd hh24:mi:ss'"巡检时间"
  3.     ,current_database() current_database 
  4.     ,relname as "table_name(表名)"
  5.     ,schemaname as "schema_name(模式名)"
  6.     ,pg_size_pretty(pg_relation_size('"'||schemaname|| '"."'||relname||'"')) as "table_size(表大小)"
  7.     ,n_dead_tup as "n_dead_tup(无效记录数)"
  8.     ,n_live_tup as "n_live_tup(有效记录数)"
  9.     ,to_char(round(n_dead_tup*1.0/(n_live_tup+n_dead_tup)*100,2),'fm990.00') as "dead_rate(无效记录比例%)"
  10. from
  11.     pg_stat_all_tables
  12. where n_live_tup+n_dead_tup <> 0
  13. ;
  • 正常:不存在表膨胀,因为有自动清理垃圾进程;

  • 异常处理:对膨胀表做vacuum analyze操作;

检查索引膨胀
  1. select
  2.   to_char(now(),'yyyy-mm-dd hh24:mi:ss'"巡检时间",
  3.   current_database() AS db, schemaname, tablename,bs, reltuples::bigint AS tups, relpages::bigint AS pages, otta,
  4.   ROUND(CASE WHEN otta=0 OR sml.relpages=0 OR sml.relpages=otta THEN 0.0 ELSE sml.relpages/otta::numeric END,1) AS tbloat,
  5.   CASE WHEN relpages < otta THEN 0 ELSE relpages::bigint - otta END AS wastedpages,
  6.   CASE WHEN relpages < otta THEN 0 ELSE bs*(sml.relpages-otta)::bigint END AS wastedbytes,
  7.   CASE WHEN relpages < otta THEN $$0 bytes$$::text ELSE (bs*(relpages-otta))::bigint || $$ bytes$$ END AS wastedsize,
  8.   iname, ituples::bigint AS itups, ipages::bigint AS ipages, iotta,
  9.   ROUND(CASE WHEN iotta=0 OR ipages=0 OR ipages=iotta THEN 0.0 ELSE ipages/iotta::numeric END,1) AS ibloat,
  10.   CASE WHEN ipages < iotta THEN 0 ELSE ipages::bigint - iotta END AS wastedipages,
  11.   CASE WHEN ipages < iotta THEN 0 ELSE bs*(ipages-iotta) END AS wastedibytes,
  12.   CASE WHEN ipages < iotta THEN $$0 bytes$$ ELSE (bs*(ipages-iotta))::bigint || $$ bytes$$ END AS wastedisize,
  13.   CASE WHEN relpages < otta THEN
  14.     CASE WHEN ipages < iotta THEN 0 ELSE bs*(ipages-iotta::bigint) END
  15.     ELSE CASE WHEN ipages < iotta THEN bs*(relpages-otta::bigint)
  16.       ELSE bs*(relpages-otta::bigint + ipages-iotta::bigint) END
  17.   END AS totalwastedbytes
  18. FROM (
  19.   SELECT
  20.     nn.nspname AS schemaname,
  21.     cc.relname AS tablename,
  22.     COALESCE(cc.reltuples,0) AS reltuples,
  23.     COALESCE(cc.relpages,0) AS relpages,
  24.     COALESCE(bs,0) AS bs,
  25.     COALESCE(CEIL((cc.reltuples*((datahdr+ma-
  26.       (CASE WHEN datahdr%ma=0 THEN ma ELSE datahdr%ma END))+nullhdr2+4))/(bs-20::float)),0) AS otta,
  27.     COALESCE(c2.relname,$$?$$) AS iname, COALESCE(c2.reltuples,0) AS ituples, COALESCE(c2.relpages,0) AS ipages,
  28.     COALESCE(CEIL((c2.reltuples*(datahdr-12))/(bs-20::float)),0) AS iotta -- very rough approximation, assumes all cols
  29.   FROM
  30.      pg_class cc
  31.   JOIN pg_namespace nn ON cc.relnamespace = nn.oid AND nn.nspname <> $$information_schema$$
  32.   LEFT JOIN
  33.   (
  34.     SELECT
  35.       ma,bs,foo.nspname,foo.relname,
  36.       (datawidth+(hdr+ma-(case when hdr%ma=0 THEN ma ELSE hdr%ma END)))::numeric AS datahdr,
  37.       (maxfracsum*(nullhdr+ma-(case when nullhdr%ma=0 THEN ma ELSE nullhdr%ma END))) AS nullhdr2
  38.     FROM (
  39.       SELECT
  40.         ns.nspname, tbl.relname, hdr, ma, bs,
  41.         SUM((1-coalesce(null_frac,0))*coalesce(avg_width, 2048)) AS datawidth,
  42.         MAX(coalesce(null_frac,0)) AS maxfracsum,
  43.         hdr+(
  44.           SELECT 1+count(*)/8
  45.           FROM pg_stats s2
  46.           WHERE null_frac<>0 AND s2.schemaname = ns.nspname AND s2.tablename = tbl.relname
  47.         ) AS nullhdr
  48.       FROM pg_attribute att 
  49.       JOIN pg_class tbl ON att.attrelid = tbl.oid
  50.       JOIN pg_namespace ns ON ns.oid = tbl.relnamespace 
  51.       LEFT JOIN pg_stats s ON s.schemaname=ns.nspname
  52.       AND s.tablename = tbl.relname
  53.       AND s.inherited=false
  54.       AND s.attname=att.attname,
  55.       (
  56.         SELECT
  57.           (SELECT current_setting($$block_size$$)::numeric) AS bs,
  58.             CASE WHEN SUBSTRING(SPLIT_PART(v, $$ $$, 2) FROM $$#"[0-9]+.[0-9]+#"%$$ for $$#$$)
  59.               IN ($$8.0$$,$$8.1$$,$$8.2$$) THEN 27 ELSE 23 END AS hdr,
  60.           CASE WHEN v ~ $$mingw32$$ OR v ~ $$64-bit$$ THEN 8 ELSE 4 END AS ma
  61.         FROM (SELECT version() AS v) AS foo
  62.       ) AS constants
  63.       WHERE att.attnum > 0 AND tbl.relkind=$$r$$
  64.       GROUP BY 1,2,3,4,5
  65.     ) AS foo
  66.   ) AS rs
  67.   ON cc.relname = rs.relname AND nn.nspname = rs.nspname
  68.   LEFT JOIN pg_index i ON indrelid = cc.oid
  69.   LEFT JOIN pg_class c2 ON c2.oid = i.indexrelid
  70. ) AS sml 
  71. ;
  • 索引膨胀,依赖于统计信息,统计信息未更新,索引膨胀信息不准确。一般每年统一做一次重建索引即可。

  • 异常处理:重建索引;

reindex index 索引名;

更多关于 PostgreSQL 系列的学习文章,请参阅:PostgreSQL 数据库,本系列持续更新中。

参考文章:https://blog.csdn.net/qq_33445829/article/

details/126578647 https://blog.csdn.net/qq_33445829

/article/details/126638945

读者专属技术群

构建高质量的技术交流社群,欢迎从事后端开发、运维技术进群(备注岗位,已在技术交流群的请勿重复添加)。主要以技术交流、内推、行业探讨为主,请文明发言。广告人士勿入,切勿轻信私聊,防止被骗。

扫码加我好友,拉你进群

4a077c6afa13cd98792936c4c9c80930.jpeg

推荐阅读 点击标题可跳转

卸载 Postman!事实证明,它更牛逼。。。

果真有这样的公司,够横!直接干上了热搜

C 盘真的一下子就不红了!微软官方工具就能解决

面试官:如何修改正运行的Docker容器端口映射?

突然,很多人被裁!知名公司遭曝光。。。

不雅信息发到工作群!回应:病毒入侵,已报警!

阿里再次大改革,江湖再无 P8 了。。。

d7400c6aaee9eeb93b9e2070b955b8d6.png

PS:因为公众号平台更改了推送规则,如果不想错过内容,记得读完点一下在看,加个星标,这样每次新文章推送才会第一时间出现在你的订阅列表里。点在看支持我们吧!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/知新_RL/article/detail/922340
推荐阅读
相关标签
  

闽ICP备14008679号