周三是新年的天,所以周三和周五的文字调换一下,所以postgresql 高可用的文字要在周四发布,敬请见谅。
还能怪谁,谁用的怪谁呗 使用过 PostgreSQL 的对比其他的数据库,都会怕一件事,explosion. 此时的postgresql 就像一个充了气的娃娃,能将你已经预估好的数据的存储空间,完全填满,系统可能会停止运行,或者你的老板会给你在早晨 big morning call。
当然可以谴责postgresql 的“不靠谱”,或者不如先问,是不是.......
到底是为什么会这样,(之前写过两篇文字关于vacuum可以翻翻哈),那就是MVCC,因为要结合自身,以及实现RDS数据库都有的MVCC ,在一群不大理解此事情的使用者“光顾” 后,postgresql 就变成了充气娃娃。
通过保持每行的多个版本,MVCC减少了放置在数据库行上的独占锁的数量。
我们可以来看看下面的例子,建立一个十分 清纯的表
CREATE TABLE exploded (
id SERIAL PRIMARY KEY,
x INTEGER NOT NULL
);
然后就插入 100万条记录
INSERT INTO exploded (x) VALUES (generate_series(1,1000000));
然后我们查看这100万条记录占用了35MB 的空间
UPDATE exploded SET x = x + 1;
SELECT pg_size_pretty(pg_relation_size('exploded'));
我们可以看一下在update 后这个表变成了69MB
我们将实验继续下去, 再次update 如果按照逻辑思维,表应该继续膨胀到 100MB 左右,但实际上,没有,压根就没有变化。
到这里的捋一捋,"充气娃娃"到底什么时候充气,什么时候就不膨胀了.
先问个问题,其他的数据库为什么不会这样,例如ORACLE ,MYSQL ,事实上是这样的吗,你何曾听过POSTGRESQL 有 REDO , UNDO ,而 ORACLE ,MYSQL 都有 UNDO log 这就是不同的数据库实现 MVCC 的手法不一样,ORACLE MYSQL 是去膨胀他的UNDO LOG ,而Postgresql 是在行设计来完成部分的UNDO LOG 的功能。所以mysql 需要进行purge, postgresql 需要 vacuum.
那到底为什么第二次不膨胀了的问题我想就很好回答了,如果你在ORACLE ,MYSQL 里面执行一个事务结束后,在执行一个事务,UNDO LOG 大部分可能性会复用空间来解决,所以POSTGRESQL 也会将不再使用的“死行”进行回收,我们也叫 vacuum. 来保证表空间不会无序大量的进行膨胀。
那问题剩下就是,怎么会导致无法vacuum(画外音,我这出事了,别讲大道理,赶紧给我解决方法) OK ,下面只说怎么和充气娃娃处
1 autovacuum 运行了吗 ? 通过查看 pg_stat_user_tables 可以看到 exploed 表 已经 autovacuum_count 两次了。
2 是否有长时间运行的语句
SELECT pid, datname, usename, state, backend_xmin,query,backend_type,query_start,client_addr
FROM pg_stat_activity
WHERE backend_xmin IS NOT NULL
ORDER BY age(backend_xmin) DESC;
3 您老人家是否开了复制槽,并且接收方已经“玩失踪了”
SELECT
slot_name, slot_type,
database
, xmin
FROM
pg_replication_slots
ORDER
BY
age(xmin)
DESC
;
4 两段式提交中,prepare操作操作由于某些原因 迟迟不能commit (参见分布式数据库概念)
SELECT
gid, prepared, owner,
database
,
transaction
AS
xmin
FROM
pg_prepared_xacts
ORDER
BY
age(
transaction
)
DESC
;
5 长时间不提交的事务,有没有
select datname,application_name,client_addr,backend_start,xact_start,query,state,backend_xid,backend_xmin
from pg_stat_activity
where (state = 'idle in transaction')
and xact_start is not null;
OK 在过滤了这些问题后,如果你的问题还没有解决的情况,应该不会太大
当然你也可以通过下面的方法来看看到底有多少表在你的数据库中有猫腻,有多少行没有被vacuum。
SELECT schemaname, relname, n_live_tup, n_dead_tup, last_autovacuum
FROM pg_stat_all_tables
ORDER BY n_dead_tup
/ (n_live_tup
* current_setting('autovacuum_vacuum_scale_factor')::float8
+ current_setting('autovacuum_vacuum_threshold')::float8)
DESC
LIMIT 10;
至于上面的那些问题怎么解决,KILL 连接(参见另一篇 KILL -9 客户连接,你胆真肥的那篇,你可千万别弄巧成拙),或者是在出现问题,需要大量的整体的full vacuum,请参见 repack 那篇,基本上这样的问题就都解决了。
postgresql (参见数据库简史 1那篇),可以算是数据库界的元老了,能活这么长时间,也是有自己的优点的,所以在某些坛子看见提出 POSTGRESQL VACUUM 以及提出PG数据库原理是怪胎,可以考虑另一个问题,postgresql 事务回滚怎么比 某些数据库要快?
不限制数据库种类,可以讨论,学习各种数据库的一个群,期待,其中有一些文件,可以随意自取,另外还会不断添加。