KingbaseES 物理备库影响主库的性能与垃圾回收
前言
KingbaseES 物理备库有些配置可能影响到主库性能,或者反过来说主库某些配置也会影响到备库。终极原因还是heap tuple 和dead tuple放在一起导致的。
首先,原理上讲,物理备库就是基于KingbaseES WAL流式复制。物理备库在物理层面与主库完全一致,每一个数据块都一样。物理备库允许在实时恢复的同时,对外提供只读的功能。通常生产环境很多部署读写分离集群。这就会带来我们熟知的备库的查询冲突问题。
问题来了,只读操作可能和恢复会发生冲突,比如用户正在备库读某个数据块的数据,与此同时,实时恢复进程读取到WAL的记录,发现需要修改这个数据块的数据。此时恢复就与只读发生了冲突。
为了避免冲突,数据库有哪些方式呢?
- 主库配置
1.1 vacuum_defer_cleanup_age
设置主库垃圾回收的延迟,例如配置为1000,表示垃圾版本将延迟1000个事务再被回收,默认为0。
- 备库配置
2.1 hot_standby_feedback
如果设置为ON,备库在执行QUERY时会通知主库,哪些版本需要被保留,不能被VACUUM。
2.2 max_standby_archive_delay, max_standby_streaming_delay
表示当备库的QUERY与恢复进程发生冲突时,恢复进程最长的等待时间,当恢复进程从被冲突堵塞开始等待时间超过以上设置时,会主动KILL与之发生冲突的QUERY,然后开始恢复,直到catch up,才允许QUERY与恢复进程再次发生冲突。
问题分析
以上配置,要么影响主库,要么影响备库。都是有一定代价的。
- vacuum_defer_cleanup_age > 0
代价1,主库膨胀,因为垃圾版本要延迟若干个事务后才能被回收。
代价2,重复扫描垃圾版本,重复耗费垃圾回收进程的CPU资源。(n_dead_tup会一直处于超过垃圾回收阈值的状态,所以autovacuum 不断唤醒worker进行回收动作)。
当主库的 autovacuum_naptime=很小的值,同时autovacuum_vacuum_scale_factor=很小的值时,尤为明显,对性能影响更大。
代价3,如果期间发生大量垃圾,垃圾版本可能会在事务到达并解禁后,爆炸性的被回收,产生大量的WAL日志,从而造成WAL的写IO问题,这也是主题中提到的造成IO的性能问题。
- hot_standby_feedback=on
如果备库出现了LONG QUERY,或者Repeatable Read的长事务,并且主库对备库还需要或正查询的数据执行了更新并产生了垃圾时,主库会保留这部分垃圾版本(与vacuum_defer_cleanup_age效果类似)。
代价,与vacuum_defer_cleanup_age > 0 类似。
- max_standby_archive_delay, max_standby_streaming_delay
代价,如果备库的QUERY与APPLY(恢复进程)冲突,那么备库的apply会出现延迟,也许从备库读到的是N秒以前的数据。
影响主库的问题复现
前面分析了,当主库设置了vacuum_defer_cleanup_age > 0或者备库设置了hot_standby_feedback=on同时有LONG QUERY时,都可能造成主库的3个问题。
这个问题很容易复现。
复现方法1 备库hot_standby_feedback=on
开启主库的自动垃圾回收,同时设置为很小的唤醒时间,以及很小的垃圾回收阈值。
这样设置是为了防止膨胀,但是也使得本文提到的问题更加的明显。
test=# show autovacuum_naptime ;
-[ RECORD 1 ]------+---
autovacuum_naptime | 1s
test=# show autovacuum_vacuum_scale_factor ;
-[ RECORD 1 ]------------------+-------
autovacuum_vacuum_scale_factor | 0.0002
- 创建测试表
test=# create table test(id int , info text, crt_time timestamp);
- 插入1000万测试数据
test=# insert into test select 1,md5(random()::text),now() from generate_series(1,10000000);
- 在hot standby上开启一个repeatable read事务,执行一笔QUERY,查询test的全表
test=# begin transaction isolation level repeatable read;
BEGIN
test=# select count(*) from test ;
count
----------
10000000
(1 row)
- 在主库更新test全表
test=# update test set info=info;
- 查询test表当前的统计信息,有1000万条dead tuple
test=# select * from pg_stat_all_tables where relname ='test';
-[ RECORD 1 ]-------+------------------------------
relid | 17621
schemaname | public
relname | test
seq_scan | 1
seq_tup_read | 10000000
idx_scan |
idx_tup_fetch |
n_tup_ins | 10000000
n_tup_upd | 10000000
n_tup_del | 0
n_tup_hot_upd | 0
n_live_tup | 10000000
n_dead_tup | 10000000
- 造成的影响,读IO巨大(扫描test表,试图回收垃圾,但是回收未成功),以及autovacuum worker的CPU开销很大。
因为autovacuum worker process 不停被唤醒,扫描垃圾数据,但是不能对其进行回收,所以n_dead_tup一直不会下降,循环往复,autovacuum worker不断被唤醒。极端情况cpu会被占满。
问题处理
- 备库设置参数hot_standby_feedback=off
hot_standby_feedback = off
reload
问题马上解除,垃圾被回收掉了。
test=# select * from pg_stat_all_tables where relname ='test';
-[ RECORD 1 ]-------+------------------------------
relid | 17621
schemaname | public
relname | test
seq_scan | 1
seq_tup_read | 10000000
idx_scan |
idx_tup_fetch |
n_tup_ins | 10000000
n_tup_upd | 10000000
n_tup_del | 0
n_tup_hot_upd | 0
n_live_tup | 10000000
n_dead_tup | 0
autovacuum worker不会再被唤醒,所以主库的CPU马上下降。
同时注意垃圾回收会带来一次很大的WAL写IO。
- max_standby_archive_delay, max_standby_streaming_delay起作用是,备库的事务在apply冲突超时后,被强制kill
test=# show hot_standby_feedback;
hot_standby_feedback
----------------------
off
(1 row)
test=# select count(*) from test ;
count
----------
10000000
(1 row)
test=# select * from test limit 10;
FATAL: terminating connection due to conflict with recovery
DETAIL: User query might have needed to see row versions that must be removed.
HINT: In a moment you should be able to reconnect to the database and repeat your command.
server closed the connection unexpectedly
This probably means the server terminated abnormally
before or while processing the request.
The connection to the server was lost. Attempting reset: Succeeded.
复现方法2 主库vacuum_defer_cleanup_age > 0
略,复现方法一样。
小结与优化
为了尽量的避免物理备库的QUERY与apply的冲突,KingbaseES提供了几种方法,但是这些方法要么影响主库,要么影响备库。都有一定代价。
上例已描述代价。
引申,还有一些行为可能会导致垃圾记录(dead tuple)无法被回收,一旦dead tuple无法被回收,那么每次autovacuum worker都是无用功。同样会引发和本文类似的问题(autovacuum不停被唤醒)。 例如
主库有LONG XACT,无法回收该事务ID后产生的垃圾。(9.6可以设置snapshot too old,针对只读事务,如果事务超过配置的时间(或者XID),不好的是可能遇到快照过旧的错误,好处是避免一直无法垃圾回收的问题。)
主库有LONG 2PC XACT,无法回收该事务ID后产生的垃圾。(9.6可以设置snapshot too old,针对只读事务,如果事务超过配置的时间(或者XID),不好的是可能遇到快照过旧的错误,好处是避免一直无法垃圾回收的问题。)
紧急解决这个问题的办法很简单,cancel long query,xact,2pc xact即可。
- 如果复制槽失效,在主备切换后有可能导致此问题,那么就会导致主库有大量dead tuple无法回收。
优化建议
不建议设置 vacuum_defer_cleanup_age > 0
如果备库有LONG query,同时需要实时性,可以设置hot_standby_feedback=on,同时建议将主库的autovacuum_naptime,autovacuum_vacuum_scale_factor设置为较大值(例如60秒,0.1),主库的垃圾回收唤醒间隔会长一点,但是如果突然产生很多垃圾,可能会造成一定的膨胀。
如果备库有LONG QUERY,并且没有很高的实时性要求,建议设置设置hot_standby_feedback=off, 同时设置较大的max_standby_archive_delay, max_standby_streaming_delay。
以上优化各有利弊,我还是觉得最好是把主库dml和备库query分开不同时间执行。
建议参数如下:
hot_standby_feedback = off
autovacuum_naptime=45s
vacuum_freeze_min_age = 50000000
vacuum_freeze_table_age = 1300000000
vacuum_multixact_freeze_min_age = 50000000
vacuum_multixact_freeze_table_age = 1300000000
autovacuum_freeze_max_age = 1500000000
autovacuum_multixact_freeze_max_age = 1500000000
- 备库配置recovery.conf中如果设置了使用SLOT,也可能导致主库wal堆积,导致主库的dead tuple不清理(对应SLOT备库需要的不清理)。
Replication slots provide an automated way to ensure that the master does not remove WAL segments until they have been received by all standbys, and that the master does not remove rows which could cause a recovery conflict even when the standby is disconnected.
KingbaseES 物理备库影响主库的性能与垃圾回收的更多相关文章
- DG之主库、备库切换(物理备库)
DG之主库.备库切换 一.开库与关库顺序 开库顺序 先启备库,再启主库(启动监听.打开告警日志) 关库顺序 先关主库,再关备库 二.主备库切换 1.操作过程一览 步骤1:启动备库.监听.告警: 步骤2 ...
- Flashing Back a Failed Primary Database into a Physical Standby Database(闪回FAILOVER失败的物理备库)
文档操作依据来自官方网址:https://docs.oracle.com/cd/E11882_01/server.112/e41134/scenarios.htm#SBYDB4888 闪回FAILOV ...
- 【Oracle】DG中物理备库、快照备库的相互转换
一.物理备库切换快照备库 1. 如果正在运行日志应用,先停止 ALTER DATABASE RECOVER MANAGED STANDBY DATABASE CANCEL; 2. 确保数据库为MOUN ...
- 深入理解JAVA虚拟机之JVM性能篇---垃圾回收
一.基本垃圾回收算法 1. 判断对象是否需要回收的方法(如何判断垃圾): 1) 引用计数(Reference Counting) 对象增加一个引用,即增加一个计数,删除一个引用则减少一个计数.垃圾回 ...
- Android性能调优篇之探索垃圾回收机制
开篇废话 如果我们想要进行内存优化的工作,还是需要了解一下,但这一块的知识属于纯理论的,有可能看起来会有点枯燥,我尽量把这一篇的内容按照一定的逻辑来走一遍.首先,我们为什么要学习垃圾回收的机制,我大概 ...
- pgsql物理复制(pgsql 备库的搭建以及角色互换,提升)
结构图如下: Postgresql早在9.0版本开始支持物理复制,也称为流复制,通过从实例级复制出一个与主库一模一样的备库.流复制同步方式有同步,异步两种,如果主节点和备节点不是很忙,通常异步模式下备 ...
- dataguard 归档丢失(主库中无此丢失归档处理),备库基于SCN恢复
dataguard 归档丢失(主库中无此丢失归档处理),备库基于SCN恢复 环境: OS: CentOS 6.5 DB: Oracle 10.2.0.5 1.主备库环境 主库: SQL> sel ...
- Oracle 物理和逻辑备库健康监測的一个根据
以以下keyword眼为例: 1 物理备库健康检查根据: Tue Apr 22 16:44:51 CST 2014Media Recovery Log /data/CMS/arch_log/1_583 ...
- [Oracle] Data Guard 系列(5) - 创建逻辑备库
在创建逻辑备库之前,必须得先创建物理备库,关于如何创建物理备库,请参考<Data Guard 系列(4) - 在不停主库的情况下创建物理备库>. 1. 在物理备库上停止日志应用服务 SYS ...
- Data Guard 主备库角色转换
1. switchover操作 1.1 备库先关闭实时日志应用 standby>alter database recover managed standby database cancel; 1 ...
随机推荐
- C++ 快速加载 Dll 里的 API
最近项目里要重新编写程序加载器,也就是编译出一个可执行文件,在 Windows 上是 .exe 为什么要程序加载器? 个人理解是,可执行文件大小最好是越小越好,功能都可以由 dll 文件执行 而程序加 ...
- win32-如何识别哪个静态控件被点击
创建多个具体SS_NOTIFY样式的static controls 根据文档显示,当用户单击具有SS_NOTIFY样式的静态控件时,将发送STN_CLICKED通知代码.控件的父窗口通过WM_COMM ...
- [Android逆向]Exposed 破解 jwxdxnx02.apk
使用exposed 遇到了一些坑,这里记录一下 源码: package com.example.exposedlesson01; import de.robv.android.xposed.IXpos ...
- go-ini解析ini文件
文档 https://github.com/go-ini/ini https://ini.unknwon.io/docs/intro/getting_started go get -u gopkg.i ...
- Go语言实现记账本
使用面向过程思想实现 package main import ( "fmt" ) func main(){ key := "" //设置初始金额 sum := ...
- 在矩池云使用Llama2-7B的方法
今天给大家分享如何在矩池云服务器使用 Llama2-7b模型. 硬件要求 矩池云已经配置好了 Llama 2 Web UI 环境,显存需要大于 8G,可以选择 A4000.P100.3090 以及更高 ...
- 影刀rpa:第二个项目学习心得
教程有说到元素的关联操作,教程说自上而下的html路径,一时之间没弄清楚,索性就去看了下网页的html源码,才弄清楚到底是咋回事: 我是先选中了列表子元素的价格字段,选择两次以后就能选择到所有列表子元 ...
- Java面向对象(下)--static/final/代码块/抽象/接口/内部类
目录 1 关键字:static 2 理解main方法的语法 3 类的成员之四:代码块 4关键字:final 5 抽象类与抽象方法 6 接口(interface) 7 类的成员之五:内部类 static ...
- 一款开源、免费、跨平台的Redis可视化管理工具
前言 经常有小伙伴在技术群里问:有什么好用的Redis可视化管理工具推荐的吗?, 今天大姚给大家分享一款我一直在用的开源.免费(MIT License).跨平台的Redis可视化管理工具:Anothe ...
- 使用fastJson中的JSONObject对象简化POST请求传参-2022新项目
一.业务场景 Java项目开发中,经常会用到远程调用,不管是POST请求,Feign远程调用,还是使用Resttemplate中的POST方法等等都需要传递参数. 可是如何更好的传递参数呢?之前自己开 ...