PostgreSQL内核打印调试的几种方案
目的
向系统内核源码中添加打印语句
日志模块剖析
log架构
基础
log路径、开关等配置在postgresql.conf,有DN、CN等log,也有/data/pg_log目录下的log。
日志配置在postgresql.conf中,每个参数的介绍可以参考http://www.postgres.cn/docs/9.4/runtime-config-logging.html#GUC-LOGGING-COLLECTOR
三种log
pg_log记录各种Error信息,以及服务器与DB的状态信息,可由用户随意更新删除
pg_xlog与pg_clog记录数据库的事务信息,不得随意删除更新,做物理备份时要记得备份着两个日志。
pg_log
该文件夹中的日志一般用来记录服务器与DB的状态,如各种Error信息,定位慢查询SQL,数据库的启动关闭信息,发生checkpoint过于频繁等的告警信息等。linux自带的路径一般在/var/log/postgres下面。该日志有.csv格式和.log。这种日志是可以被清理删除不影响DB的正常运行。
当我们有遇到DB无法启动或者更改参数没有生效时,第一个想到的就是查看这个日志。
如果服务无法启动,该日志文件夹下的日志没有记录,建议查看操作系统的事件查看器的日志。有助于快速定位问题。
pg_xlog
该文件夹中的日志是记录的Postgresql的WAL信息,也就是一些事务日志信息(transaction log),默认单个大小是16M,源码安装的时候可以更改其大小。这些信息通常名字是类似'000000010000000000000013'这样的文件,这些日志会在 定时回滚恢复(PITR), 流复制(Replication Stream)以及归档时能被用到,这些日志是非常重要的,记录着数据库发生的各种事务信息,不得随意删除或者移动这类日志文件,不然你的数据库会有无法恢复的风险
当归档或者流复制发生异常的时候,事务日志会不断地生成,有可能会造成磁盘空间被塞满,最终导致DB挂掉或者起不来。遇到这种情况不用慌,可以先关闭归档或者流复制功能,备份pg_xlog日志到其他地方,但请不要删除。然后删除较早时间的的pg_xlog,有一定空间后再试着启动Postgres。
pg_clog
pg_clog这个文件也是事务日志文件,但与pg_xlog不同的是它记录的是事务的元数据(metadata),这个日志告诉我们哪些事务完成了,哪些没有完成。这个日志文件一般非常小,但是重要性也是相当高,不得随意删除或者对其更改信息。
内核角度
elog(LOG, "aclparse: input = "%s"", s);
ereport(LOG, (errmsg("AIO Startup, Completer thread id =%d try times=%d, error=%d", i, try_times, error)));
fprintf(stdout, "%s %lu %lu LOG: [GSSAPI] %s, detail:%s:%s.n",
StringInfo log = makeStringInfo();
appendStringInfo(log, "remove all cbm pages of rel %u/%u/%u forknum %d",
使用角度
开启SQL语句log
1. 进入/opt//data目录,找到postgresql.conf,修改如下配置参数
log_statement = 'all'
logging_collector=on
2. 进入/opt//app目录,执行如下语句
su - a
gs_ctl reload -D /opt//data
如果返回"Server Signaled"说明reload失败,需执行以下命令重启,并重启AC
gs_ctl restart -D /opt//data
3. 进入/opt//data/pg_log目录
tail -f 最新的log查看sql记录
超过一定时间的耗时SQL语句记录
我们主要使用的配置有两项:
log_min_duration_statement:
如果某个语句的持续时间大于或者等于这个毫秒数,那么在日志行上记录该语句及其持续时间。 设置为零将打印所有查询和他们的持续时间。设置为-1(缺省值)关闭这个功能。比如, 如果你把它设置为250ms,那么所有运行时间等于或者超过 250ms 的 SQL 语句都会被记录。
开发经常有需求查看所有操作日志,将这个值设置为0即可(要在主站点修改)。
修改完之后需要在dbuser用户下gs_ctl reload使配置生效(所有.conf配置文件修改都需要执行该语句生效)
printf风格的字符串配置
log_line_prefix:
这是一个printf风格的字符串,在日志的每行开头输出。 %字符开始"转义序列"被如下所述状态信息替换。 无法识别的转义被忽略。其它字符都直接拷贝到日志行中。 有些转义只被会话进程识别,被后端进程看做空,比如主服务器进程。 通过在%之后该选项之前声明有一个数字文字,状态信息可以左对齐或者右对齐。 负值将会使得该状态信息在右侧补齐空白到最小宽度, 正直将在左侧补齐空白。补齐可以有助于帮助人们读取日志文件。
转义
影响
仅用于会话
%a
应用名
是
%u
用户名
是
%d
数据库名
是
%r
远程主机名或IP地址和远程端口
是
%h
远程主机名或IP地址
是
%p
进程 ID
否
%t
没有毫秒的时间戳
否
%m
有毫秒的时间戳
否
%i
命令标签:会话的当前命令的类型
是
%e
SQLSTATE 错误代码
否
%c
会话 ID:见下文
否
%l
每个会话或进程的日志行数,从1开始
否
%s
进程开始的时间戳
否
%v
虚拟事务 ID (backendID/localXID)
否
%x
事务 ID (如果没有分配则为0)
否
%q
不产生输出,但是告诉非会话的进程在字符串的这个点停止; 被会话进程忽略
否
%%
文字 %
否
开发可以根据需求自行设置prefix。
关键日志过滤。
sql慢操作过滤
日志中会将操作时长duration打印出来,可以通过 zgrep duration * 以及其他过滤条件筛选出操作日志耗时长的语句看是否可优化。
数据库中出现锁等待、死锁查询:
zgrep “check statement timeout“ *
锁等待每隔一段时间(可在配置文件配置)打印一次check timeout,直到不再等待锁。
- 死锁查询:
zgrep “deadlock” *
出现死锁日志中会出现deadlock detected,同时释放死锁