PostgreSQL学徒

日常答疑系列第二期

前言

这几天收集了一下各个交流群里的问题,潜水过程中也学到了很多内容。

tcp_keepalive

首先是关于TCP keepalive的,在PostgreSQL中,也有相关的几个参数用于释放无法继续通讯的空闲连接,默认配置取决于操作系统

postgres=# select name,setting from pg_settings where name like 'tcp%';
          name           | setting 
-------------------------+---------
 tcp_keepalives_count    | 0
 tcp_keepalives_idle     | 0
 tcp_keepalives_interval | 0
 tcp_user_timeout        | 0
(4 rows)

如果通信一方突然崩溃,无法通知对方,此时另一方能做的就只有傻傻等待了,所以引入了keepalive机制,快速感知失败。但是如果服务端正在忙着处理一个长查询,并不会立马注意到死连接直至查询结束,并且尝试给客户端发送执行结果,因此在14中引入了client_connection_check_interval参数来解决这个问题,每隔一段时间检查客户端是否已离线,如果离线则快速结束未完成的查询,防止客户端已离线而数据库继续运行未完成的查询。

让我们回到问题

Image

可以看到,配置了相关参数,但是数据库里显式为0。为什么会这样?其实官网已经有所说明:

“

In sessions connected via a Unix-domain socket, this parameter is ignored and always reads as zero.

如果是通过unix domain socket登录的话,那么始终显式为0。unix domain socket不需要使用传统的IP地址和端口,而是使用文件系统来进行程序之间的数据交互,如果不同主机上的两个进程进行通信,使用传统的TCP/IP协议当然没什么问题。但是,如果只需要在一台机器上的两个不同进程间通信,就有点杀鸡用牛刀的味道了,这便是unix domain socket的缘由。上面图片也很清晰,可以通过psql -h /path/to/socket/directory/ -p port切换其他目录下的socket文件,所以显式为0就不足为奇了。

当然功能类似的还有jdbc中的socket timeout,可以理解成全局的查询时长限制,是通过TCP连接发送数据(SQL)后,等待响应的超时时间,也可以及时发现网络问题,虽然有了keepalive机制,但大多数操作系统的心跳包的间隔时间要么很长,要不默认没有设置,比如Linux下的keepalive的设置是2小时,所以这个参数也可以帮助我们。

“

The timeout value used for socket read operations. If reading from the server takes longer than this value, the connection is closed. This can be used as both a brute force global query timeout and a method of detecting network problems. The timeout is specified in seconds and a value of zero means that it is disabled.

空闲连接

另外一个是关于空闲连接的问题,长链接的危害不言而喻,在14以前是没有参数用于控制空闲连接何时主动超时断开的(不要与tcp keepalive机制搞混),当然你可以通过pg_timeout插件或者自己写脚本来更加细粒度地控制,在14就方便了,idle_session_timeout解千愁。

checkpoint触发机制

这个问题是③群一位朋友问的

Image

当把log_checkpoint参数打开便会有类似日志条目,这种问题其实在代码里根据关键字一搜就知道了

 else
  ereport(LOG,
  /* translator: the placeholders show checkpoint options */
    (errmsg("checkpoint starting:%s%s%s%s%s%s%s%s",
      (flags & CHECKPOINT_IS_SHUTDOWN) ? " shutdown" : "",
      (flags & CHECKPOINT_END_OF_RECOVERY) ? " end-of-recovery" : "",
      (flags & CHECKPOINT_IMMEDIATE) ? " immediate" : "",
      (flags & CHECKPOINT_FORCE) ? " force" : "",
      (flags & CHECKPOINT_WAIT) ? " wait" : "",
      (flags & CHECKPOINT_CAUSE_XLOG) ? " wal" : "",
      (flags & CHECKPOINT_CAUSE_TIME) ? " time" : "",
      (flags & CHECKPOINT_FLUSH_ALL) ? " flush-all" : "")));
}

可以看到触发条件是CHECKPOINT_CAUSE_XLOG,顾名思义,达到了max_wal_size触发的checkpoint

/*
 * OR-able request flag bits for checkpoints.  The "cause" bits are used only
 * for logging purposes.  Note: the flags must be defined so that it's
 * sensible to OR together request flags arising from different requestors.
 */

/* These directly affect the behavior of CreateCheckPoint and subsidiaries */
#define CHECKPOINT_IS_SHUTDOWN 0x0001 /* Checkpoint is for shutdown */
#define CHECKPOINT_END_OF_RECOVERY 0x0002 /* Like shutdown checkpoint, but
                        * issued at end of WAL recovery */

#define CHECKPOINT_IMMEDIATE 0x0004  /* Do it without delays */
#define CHECKPOINT_FORCE  0x0008     /* Force even if no activity */
#define CHECKPOINT_FLUSH_ALL 0x0010  /* Flush all pages, including those
                    * belonging to unlogged tables */

/* These are important to RequestCheckpoint */
#define CHECKPOINT_WAIT   0x0020     /* Wait for completion */
#define CHECKPOINT_REQUESTED 0x0040  /* Checkpoint request has been made */
/* These indicate the cause of a checkpoint request */
#define CHECKPOINT_CAUSE_XLOG 0x0080  /* XLOG consumption */
#define CHECKPOINT_CAUSE_TIME 0x0100  /* Elapsed time */

其他场景比如create database、达到了timeout、手动发起、recovery结束时等等都会触发checkpoint。

逻辑复制

“

这个我经常在开发环境遇到过,他们老是改结果,我搞了个ddl触发器 去消费ddl的变更,老是有问题,原因是在源端执行了ddl过程中有数据产生,就形成了ddl+dml+ddl ,订阅段是直接ddl+ddl ,中间的一个dml就会结构匹配不上而报错

具体内容可以参照 https://blog.csdn.net/dazuiba008/article/details/117670295,这个问题之前我确实没有遇到过,从源头进行了扼制,不允许轻易DDL,在逻辑复制场景下更甚,分多步严格执行。

Image

小结

以上几个问题都比较典型,容易让人混淆。潜水各个交流群的好处体现出来了,不说话也能学到东西。

最近粉丝数涨得挺快,快要5000了。学徒2群也快满了,3群目前160人还可以扫码进,后来的读者感兴趣的可以扫码进来唠唠嗑,日常答疑、吹牛唠嗑都是可以的。若是满了就添加我微信手动拉吧。

Image

参考

https://hackmd.io/@TMSNgCo0TY6IGequcdJLwA/HkpPKG6-v