dram.me

阅读PostgreSQL代码

PostgreSQL的代码可读性很高,文档和代码注释也很详尽,另外社区发展也很健康,所以考虑读一读代码。

统计了当前版本(REL_10_BETA4)的代码量,C代码有70万行,非常庞大的。考虑看早期版本(PG95-1_01),因为从版本发布说明来看,早期版本也已经有很高的成熟度,很多工具和概念一直沿用至今,这个版本的C代码量为9万行。

PG95的目录结构很清晰(当前版本与此没有大的改动),主要包括以下几部分:

历史说明中可以看到,psql工具是Postgres95引入的,替换了之前的客户端工具monitor,那么代码阅读也可以由此开始。阅读时可以参考早期的psql文档。

CLIPS连接PostgreSQL数据库

CLIPS自身由于考虑可移植性,并没有包含网络接口,这增加了极大的不便利性。但和这里的思路类似,可以通过socat规避。

具体实现见如下示例代码:

#!/bin/sh

ROOT="$(dirname "$(readlink -f "$0")")"

PG_DATA="$ROOT/data"

socat -d -d -v -x "PIPE:pg-out.pipe,nonblock!!PIPE:pg-in.pipe" "UNIX-CONNECT:$PG_DATA/.s.PGSQL.5432"

echo "Connection closed"

其中-d -d选项用于显示调试信息,-v -x显示数据交互。另外nonblock参数是为让socat预先将pg-in.pipe管道也创建好,而不是等待在pg-out.pipe对端连接。

之后CLIPS先打开pg-out.pipe管道,写入启动信息,之后PostgreSQL服务端响应后,CLIPS可以打开pg-in.pipe管道并读取。

模板系统设计

最近考虑在CLIPS中实现一个模板系统,以便做Web应用相关开发。

最开始考虑参考ctemplatemustache实现,两者的理念是呈现和逻辑的绝对分离。

但从当前Web开发的发展来说,呈现端是需要逻辑的,如若不然,逻辑和呈现间很难有清晰的接口分界。例如Angular就是在浏览器端实现了完整的MVC框架,Angular和后端通过RESTful API通信。

之后由此展开,看了Zope的TAL系统,以及XQuery标准的发展,有个细节,XQuery也不支持嵌套序列,这一点与CLIPS类似。

进而又了解了BaseXeXist这两个开源的XML Database,以及PostgreSQL 10对于SQL标准XMLTABLE的支持。

可以看到,传统的数据库正在往多元化的方向发展。

RDBMS和多进程多线程

补遗

  1. Uber的一篇文章中也提到了数据库多进程多线程的问题,另外一位PostgreSQL咨询公司的回应slide也有提及。—— 2017-09-13

在PostgreSQL的手册1.2. Architectural Fundamentals中提到,PostgreSQL是传统的多进程C/S架构,而从网上的讨论中有看到,MySQL是基于多线程(未确定)的。

不管是哪一种情况,都可以看到这样的架构设计无法支持大规模的客户端连接。所以OpenStack中有Conductor服务的存在(虽然文档说是出于安全的考虑,防止计算节点直接访问数据库)。假使没有nova-conductor,在使用PostgreSQL时,如果有100个计算节点,就会存在100个或成倍的数据库连接。

有一个疑问是,多个进程访问数据库时,需要加锁防止竞争,这样是不是存在性能瓶颈?细化的数据库锁、表锁和行锁,具体又是如何实现的?

PostgreSQL多实例运行

补遗

  1. PostgreSQL在初始化的时候会生成一个默认数据库postgres(另外还有两个模板库template0template1,可以通过psql -l查看。详见文档),所以如果只是生成单数据库环境,初始化时可以省去createdb的过程。—— 2017-09-15

  2. 在Cygwin环境中运行PostgreSQL依赖于Cygserver提供的共享内存服务,如何配置详见文档(注意需要以管理员身份运行Terminal后执行相关命令)。—— 2017-09-15

虽然众多RDBMS设计之初就是向着多数据库多用户的方向发展的(SQLite是一个例外),但并不是说不能各用户独立实例使用。例如KDE就可以使用MySQL存储用户数据。

以下脚本是对在Debian中运行多实例PostgreSQL功能的简单封装,其他平台应该做小的调整也可使用。

#!/bin/sh

ROOT="$(dirname "$(readlink -f "$0")")"

DATABASE=foo

PG_BIN=/usr/lib/postgresql/9.6/bin/
PG_DATA="$ROOT/data"
PG_LOG="$PG_DATA/postgresql.log"
PG_OPTIONS="-c listen_addresses= -c unix_socket_directories='$PG_DATA'"

case $1 in
    init)
	$PG_BIN/pg_ctl init -D "$PG_DATA"
	$PG_BIN/pg_ctl start -D "$PG_DATA" -l "$PG_LOG" -o "$PG_OPTIONS"
	while [ ! -S "$PG_DATA/.s.PGSQL.5432" ]
	do
	    sleep 1
	done
	$PG_BIN/createdb -h "$PG_DATA" $DATABASE
	;;
    shell)
	$PG_BIN/psql -h "$PG_DATA" $DATABASE
	;;
    start)
	$PG_BIN/pg_ctl start -D "$PG_DATA" -l "$PG_LOG" -o "$PG_OPTIONS"
	;;
    stop)
	$PG_BIN/pg_ctl stop -D "$PG_DATA"
	;;
    *)
	echo "Unknown command"
	;;
esac

← older posts newer posts →