0%

切记:永远不要手工删除postgresql数据库目录下的文件。

一个测试库,因为开启了归档,而归档命令又失败了,导致归档日志暴涨,把根文件系统撑爆了,因为只是测试库,所以没在意,从配置文件中关了归档,
直接去pg_xlog目下手工干掉了所有的归档日志,然后问题就来了。

重新启动postgresql服务失败,错误日志:

1
2
3
4
5
6
2016-11-26 13:47:53 CST \[24422-1\] LOG: database system was shut down at 2016-11-26 13:42:38 CST
2016-11-26 13:47:53 CST \[24422-2\] LOG: invalid primary checkpoint record
2016-11-26 13:47:53 CST \[24422-3\] LOG: invalid secondary checkpoint record
2016-11-26 13:47:53 CST \[24422-4\] PANIC: could not locate a valid checkpoint record
2016-11-26 13:47:53 CST \[24421-1\] LOG: startup process (PID 24422) was terminated by signal 6: Aborted
2016-11-26 13:47:53 CST \[24421-2\] LOG: aborting startup due to startup process failure

检查点丢失了,只好reset log

1
2
$ sudo -u postgres ./pg_resetxlog /var/lib/postgresql/9.4/main/
Transaction log reset

如果不行,请加-f参数强制reset

然后再启动,提示:

1
2
3
4
5
2016-11-26 13:55:24 CST \[27330-1\] LOG: database system was shut down at 2016-11-26 13:54:28 CST
2016-11-26 13:55:24 CST \[27330-2\] PANIC: too many replication slots active before shutdown
2016-11-26 13:55:24 CST \[27330-3\] HINT: Increase max_replication_slots and try again.
2016-11-26 13:55:24 CST \[27329-1\] LOG: startup process (PID 27330) was terminated by signal 6: Aborted
2016-11-26 13:55:24 CST \[27329-2\] LOG: aborting startup due to startup process failure

因为以前添加了复制槽,现在max_replication_slots又设置成了0,所以出错了,重新修改配置文件:

1
2
archive_moe=archive
max_replication_slots=5

启动后删除replication slots:
[sql]
=> select pg_drop_replication_slot(‘slotname’);
[/sql]

这样关闭归档参数就没问题了。

再一次,永远不要手工删除postgresql数据目录下的文件,归档日志太多撑爆了硬盘,postgresql panic,是因为归档命令或者复制槽出问题了,因此数据库无法自动清理wal日志。
如果故障无法排除,可以首先将pg_xlog目录下的文件拷贝到其他地方,然后使用pg_archivecleanup命令来清理归档日志。

迫不得已,实在每办法了,再reset log,但是这时的数据库状态是不对的,不应该再使用了。如果有其他备份,请恢复这些备份。
没有的话,可以先pg_dump,然后停止数据库,重新initdb初始化数据库,然后再pg_restore。

References:
[1]How can I solve postgresql problem after deleting wal files?

===
[erq]

1
2
3
$ vim --version grep clipboard
-clipboard
-xterm_clipboard

debian系统终端下面的vim默认编译选项并不支持系统剪贴板,所以如果需要与系统剪贴板交互需要使用gvim,当然鼠标中键一直是可以用的,不过,用vim不就是为了丢掉效率地下的鼠标吗?

References:
[1]:help registers
[2]Vim中寄存器的使用
===
[erq]

CPU负载居高不下,可以从这几方面入手查找原因,一个比较大的可能是有查询在长期占用CPU资源。

查看当前连接数

1
2
=> SELECT count(*) FROM pg_stat_activity;
=> select client_addr, count(*) from pg_stat_activity group by client_addr;

可以查看总的连接数,以及每个客户端的连接数,判断是否有客户端泄露连接。

查看连接状态

1
=> SELECT state, count(*) FROM pg_stat_activity GROUP BY state;

连接有以下几种状态:

  • idle
    连接对应的后端进程处于空闲状态
  • actvie
    连接对应的后端进程正在执行查询
  • idle in transaction
    连接对应的后端进程在一个事务中,但当前并没有执行查询
  • idle in transaction (aborted)
    在一个事务中,但是事务中的语句出现了错误,事务没有正确回滚
  • fastpath function call
    正在执行fastpath函数调用
  • disabled
    后端进程被配置为禁止跟踪

等待锁的连接

1
=> SELECT count(distinct pid) FROM pg_locks WHERE granted = false;

查看是否有连接在等待排它锁导致效率低下

查看事务最大执行时间

1
=> SELECT max(now() -xact_start) FROM pg_stat_activity WHERE state IN ('idle in transaction','active'); 

查看当前所有事务中最长事务的执行时间,一般来讲事务应该在数秒内结束,数分钟已经是很长的事务了。如果有事务的执行时间达到了小时的级别,那一定是出现了错误,但是事务还在占用系统资源,应该将其干掉。

查看事务执行时间

1
=> SELECT pid, xact_start FROM pg_stat_activity ORDER BY xact_start ASC;

以事务的起始时间为顺序,如果某事务的运行时间过长,比如达到了小时级别,应该查清原因,然后搞掉它。

杀掉后端进程

1
=> SELECT pg_cancel_backend(1234);

1234就是pg_stat_activity表里的pid,也是postgres进程的系统进程pid,不要用操作系统命令去搞死进程,要用postgresql提供的命令。

References:
[1]28.2. The Statistics Collector
[2]Debug Slow Performance & High Resource Utilisation Issue in PostgreSQL
[3]Find and Kill Long Running Process in PostgreSQL

===
[erq]

fork之后上游可能又有了一些更新,在提交pull request之前最好重新同步一下上游主干,解决可能存在的冲突之后再发起pull request

步骤如下:

1
2
3
4
5
$ git remote add upstream https://github.com/jiangwen365/pypyodbc # 添加上游仓库
$ git fetch upstream # 获取上游最新更新
$ git checkout master # 切换到本地需要更新的分支头,master或者其他名字的分子都行,看需要
$ git merge upstream/master # 合并上游master分支到本地master分支,分支名字根据需要指定,rebase亦可
$ git push # 将更新后的本地分支推送到github

简单明了。

===
[erq]

pypyodbc

pypyodbc是一个使用纯python实现的跨平台odbc模块,其利用了ctypes来访问底层的odbc驱动,支持python2和python3。
虽然跨平台,但其对linux/mac平台上的unixODBC支持存在问题,无法正确显示中文字段名和字段值。

unixODBC

unixODBC有几个函数的ansi版本和宽字符版本返回信息比较古怪。

首先说SQLDescribeCol,其ansi版本,也就是不带后缀W的版本,无论本地locale为何皆直接返回utf-8编码的字符,但是SQLDescribeColW版本在mac平台上返回utf-16编码的字符,linux平台对于中文字符返回的是用zero填充了每一个utf-8编码字节的神一样的编码

如下面所示:

1
'\\xe5\\x00\\x9b\\x00\\xbe\\x00\\xe5\\x00\\xb9\\x00\\x85\\x00\\xe5\\x00\\x8f\\x00\\xb7\\x00\\x00\\x00'

正确的应该是长这样的:

1
'\\xe5\\x9b\\xbe\\xe5\\xb9\\x85\\xe5\\x8f\\xb7\\x00

以utf-8解码后对应的中文字符是”图幅号”

而英文字符返回的是这样的:

1
'B\\x00u\\x00i\\x00l\\x00d\\x00G\\x00e\\x00o\\x00C\\x00o\\x00d\\x00e\\x00\\x00'

仔细看,这串字符实际上就是”BuildGeoCode”,当然也是utf-8编码无疑。返回的编码以’\x00\x00’作为结束符,它是utf-16吗?它是utf-8吗?
这都算天坑了吧,没这样玩的。

SqlGetData则只有一个版本,无论locale为何都是返回utf-8编码的字符。

针对这几点问题制作了一个补丁,放在了github上,准备给原作者发一个pull request。修改后的版本,connect函数无论unicode_results为True或False都可以正确的返回中文字符。

还有一个函数SQLGetInfo(W),当使用SQL_DRIVER_NAME(值为6)调用时,无论调用哪个版本,都返回SQL_ERROR(值为-1)。

mdbtools
mdbtools是unixODBC上的mdb driver,当前只支持读操作,查询数据时尙不支持group by字句,select得到结果后自行排序吧。

UPDATE:
补丁已经迅速进入官方主线

===
[erq]

utf-16(utf-16-be,utf-16-le)是ucs-2的超集,python3中支持的编码格式没有ucs-2,如需处理ucs-2,直接使用utf-16编码即可。

dpkg -s --status package_name显示包的详细信息,或者执行dpkg-query -s --status package_name

运行locate libodbc命令时,提示“locate: warning: database ‘/var/cache/locate/locatedb’ is more than 8 days old (actual age is 22.3 days)”,运行sudo updatedb更新一下数据库即可。

sed的s命令通常使用/作为分隔符,其实并不是只有/可以做分隔符,s命令紧邻其后的任意一个字符都可以作为分隔符,因此如果pattern或repacement中有/,所以可以这样sed 's,bin/bash,,' 也可以这样sed "s@bin/bash@@"

k8s就是指kubernetes,就像i18n是internationalization的缩写一样。