背景

书接上文,我们很好的理解了xmin和xid的区别。我们继续上文《KingbaseESV8R6不同隔离级下xmin的区别》来讨论 snapshot too old 的功能。

当kingbaseES中有事务长时间持有backend_xmin,就会通过参数old_snapshot_threshold把快照中的lsn和当前事务数据块中的lsn做对比判断快照是否过旧。

它并不关心是否存在backend_xid。

[](javascript:void(0)

test=# show old_snapshot_threshold ;
old_snapshot_threshold
------------------------
-1
(1 row) test=# alter system set old_snapshot_threshold= 1;
ALTER SYSTEM

[](javascript:void(0)

修改后重启数据库生效

第一种情况: 包含xmin,没有申请xid的只读事务

当持有xmin的query执行时间超过old_snapshot_threshold设置的阈值,并且读取到数据块的LSN大于快照存储的LSN时,报snapshot too old错误。

[](javascript:void(0)

test=# create table e1(id int);
CREATE TABLE
test=# insert into e1 select generate_series(1,10000);
INSERT 0 10000
test=# create index idx_e1 on e1(id);
CREATE INDEX session A:
test=# begin transaction isolation level repeatable read;
BEGIN
1号数据块的数据
test=# select ctid,* from e1 where id=2;
ctid | id
-------+----
(0,1) | 2
(1 row)
另一个数据块的数据
test=# select ctid,* from e1 where id=800;
ctid | id
--------+------
(3,122) | 800
(1 row) session B:
更新1号数据块的某条记录
test=# update e1 set id=0 where id=2 returning ctid,*;
ctid | id
---------+----
(44,57) | 0
(1 row)
UPDATE 1 1分钟后
session A:
访问未发生变化的数据块正常(因为id=1000走索引,所以不会扫描变更的数据块,这也是前面测试要建立索引的原因)
test=# select ctid,* from e1 where id=800;
ctid | id
--------+------
(3,122) | 800
(1 row)
访问发生变化的数据块, 报错snapshot too old
test=# select ctid,* from e1 where id=6;
ERROR: snapshot too old
test=# end;
ROLLBACK

[](javascript:void(0)

第二种情况:已申请xid的写,在隔离级别repeatable read/serializable事务,由于持有了xmin,并且repeatable read隔离级别,事务只要不结束,xmin不会变化。这种情况一样可能出现snapshot too old。

[](javascript:void(0)

session A:
test=# begin transaction isolation level repeatable read;
BEGIN
test=# insert into e1 values (1) returning ctid,*;
ctid | id
---------+----
(44,60) | 1
(1 row) session B:
修改10号数据块的记录,导致10号数据块LSN变大
test=# update e1 set id=1 where ctid::text ~ '^\(10,' returning ctid,*;
ctid | id
----------+----
(44,60) | 1
(44,61) | 1
(44,62) | 1
(44,63) | 1
......
UPDATE 226 1分钟后
session A:
访问变更的数据块,报错
test=# select * from e1 where ctid::text ~ '^\(10,';
ERROR: snapshot too old
test=# end;
ROLLBACK

[](javascript:void(0)

第三种情况:已申请xid的,在隔离级别read committed写事务,由于query开始时会重新生成快照,所以通常query持有的快照lsn大于或等于访问到的PAGE的LSN,则不会出现snapshot too old。因为这种情况不用去读取快照

[](javascript:void(0)

session A:
test=# begin transaction isolation level read committed;
BEGIN
test=# insert into e1 values (1) returning ctid,*;
ctid | id
----------+----
(46,1) | 1
(1 row) session B:
修改44号数据块的记录,导致44号数据块LSN变大
test=# update e1 set id=2 where ctid::text ~ '^\(44,' returning ctid,*;
ctid | id
----------+----
(45,60) | 2
(45,61) | 2
(45,62) | 2
(45,63) | 2
......
UPDATE 225 1分钟后
session A:
访问变更的数据块,不会报错
test=# select * from e1 where ctid::text ~ '^\(44,';
id
----
0
0
0
0
0
...... 但是如果QUERY本身访问时间长,并且访问到了快照创建以后被修改的页,还是会报错的。也就是访问到被修改的块的时候发现快照号lsn大于数据块lsn。这时候再去找以前的快照lsn已经发现超过1min过于旧。
模拟长SQL
session A:
with t as (select pg_sleep(100) ) select * from e1,t; 立即执行如下
session B:
test=# update e1 set id=7 where ctid::text ~ '^\(4,' returning ctid,*;
ctid | id
----------+----
(47,59) | 7
(47,60) | 7
(47,61) | 7
........
UPDATE 226
长SQL报错
session A:
ERROR: snapshot too old

[](javascript:void(0)

总结

哪些情况可能导致snapshot too old

包含了backend_xmin的事务,SQL的执行时间超过old_snapshot_threshold阈值,并且该SQL读取到了LSN超过快照存储的LSN的数据块时。

\1. snapshot too old报错通常出现在非常耗时的SQL,同时读取的数据块在不断的变化。当读取时间在10点,但10:03分另外的事务更改了查询中的某个数据块,这时候,查询进行到10:04分时候发现这个数据块中的lsn大于快照中的lsn,就要去快照中读取过去版本,这是为了保证一致性读,如果查询开始到这个时刻超过snapshot too old就会报snapshot too old报错。

\2. snapshot too old也可能出现在sys_dump备份数据库时,因为sys_dump使用的是repeatable read隔离级别,快照是在事务启动后的第一条SQL创建的,备份时间长的话,极有可能在备份过程中读取到LSN大于快照LSN的数据块,导致snapshot too old报错。

快照与隔离级别

  • 已提交读:在该事务的每条SQL执行之前都会重新获取一次快照
  • 可重复读和可串行化:该事务只在第一条SQL执行之前获取一次快照

最后我们比对理解oracle中undo机制和kingbaseES中的snapshot too old。

undo表空间的其中一个功能就是实现一致性读,当我在15:00开始查询,15:00的SCN号记录假设为100。那么在15:00这个时刻100就是最大的SCN,

这里需要引入一个ITL的概念,ITL全称为 Interested Transaction List,是Oracle中数据块的组成部分,用来记录在这个数据块上发生的所有事务,一个ITL可以记录一个事务不论这个事务是否已经提交,一个数据块可以有多个ITL。如果这个事务已经提交了那么这个ITL的位置就可以被反复使用了,因为ITL类似记录,所以,有的时候也叫ITL槽位。ITL槽中会记录对应undo块的地址。可以说上面记录的100SCN号在15:00的时候大于所有的数据块上ITL记录的SCN(多个ITL取最大SCN)

执行查询时,服务器进程扫描这个表中的数据块时,会把每个数据块ITL槽中最大的SCN与100进行比较,如果比100小则说明这个数据块没有被修改服务器进程直接进行数据读取即可。如果数据块ITL槽中的SCN大于100那么说明这个数据块在发起查询后被修改了,需要借助undo去获取15:00那个时刻数据块的数据。

根据上面的例子,我是在15:00开始的查询,而数据是在15:03的时候被修改(这里不用考虑有没有提交,因为ITL只要数据块被修改就会有记录,那么这个查询就会去读undo数据块)。我们假设这个被修改的数据块是n号数据块,修改后n号数据块的ITL中记录的SCN是120,当服务器进程扫描到这个数据块进行SCN比较时发现这个数据块的SCN要大于100,服务器进程就知道了这个数据块在发起查询后被修改了,于是服务器进程到n号数据块的头部找到120对应的ITL槽,然后找到对应undo块的位置。将undo块中所存放的n号块修改前的数据取出再结合n号块里的当前数据行进而构建15:00这个时间点未被修改的数据块,这个被新构建的数据块被称为CR块(Consistant Read)。然后服务器进程扫描这个块,得到15:00一致性的数据,返回正确的数据。这就是一致性读

因为我们的修改操作是delete,那么undo中对应的信息就是insert,insert将被删除的数据插入到CR块中,实现一致性读。undo记录的是buffer_cache中对应修改的前镜像,所以undo记录buffer修改的反向操作。

好了,我们把undo中记录的事务槽中scn号比作snapshot中的记录lsn号。结合案例3,第三种情况最符合oracle中的场景应用,因为我们数据库默认的隔离级别也是read committed。如果QUERY时间很长,也就是访问到被修改的块的时候发现快照号lsn大于数据块lsn。也就是相当于oracle中buffer_cache中数据块的scn大于undo中对应这条记录的scn,就需要读取前镜像,在我们数据库就需要读取snapshot。而snapshot保存多久靠old_snapshot_threshold这个参数设置,在oracle中undo表空间保留策略靠undo_retention参数,默认15分钟。

下文我们讨论垃圾回收受到参数old_snapshot_threshold参数的影响。

KingbaseESV8R6 snapshot too old的配置和测试的更多相关文章

  1. 四步完成NodeJS安装,配置和测试

    四步完成NodeJS安装,配置和测试 NodeJS 官网地址: http://nodejs.org/ 第一步:在官网点击 ’ INSTALL ’,下载相应的版本(我的机器是Win7专业版 64bit) ...

  2. WIN7环境下CUDA7.5的安装、配置和测试(Visual Studio 2010)

    以下基于"WIN7(64位)+Visual Studio 2010+CUDA7.5". 系统:WIN7,64位 开发平台:Visual Studio 2010 显卡:NVIDIA ...

  3. freeRadius 基础配置及测试

    国内私募机构九鼎控股打造APP,来就送 20元现金领取地址:http://jdb.jiudingcapital.com/phone.html 内部邀请码:C8E245J (不写邀请码,没有现金送) 国 ...

  4. myBatis 基础测试 表关联关系配置 集合 测试

    myBatis 基础测试 表关联关系配置 集合 测试 测试myelipse项目源码 sql 下载 http://download.csdn.net/detail/liangrui1988/599388 ...

  5. ubuntu10.10 tftp安装,配置,测试

    ubuntu10.10 tftp安装,配置,测试 成于坚持,败于止步 虽然ubuntu/centos/redhat都是linux,但是内核其中存在一定的修改,所以对于tftp服务器的安装存在不同的命令 ...

  6. 大数据测试之hadoop集群配置和测试

    大数据测试之hadoop集群配置和测试   一.准备(所有节点都需要做):系统:Ubuntu12.04java版本:JDK1.7SSH(ubuntu自带)三台在同一ip段的机器,设置为静态IP机器分配 ...

  7. Oracle RAC 11g DG Broker配置和测试

    Oracle RAC 11g DG Broker配置和测试 之前在<RHEL6.4 + Oracle 11g DG测试环境快速搭建参考>已经简单说过. 本篇在实验环境中实际配置 环境: R ...

  8. Eclipse For JavaEE安装、配置、测试

    Eclipse For JavaEE安装.配置.测试(win7_64bit) 目录 1.概述 2.本文用到的工具 3.安装与配置 4.JavaSE开发测试(确保JDK已正确安装) 5.JavaEE开发 ...

  9. Genymotion安卓模拟器和VirtualBox虚拟机安装、配置、测试

    Genymotion安卓模拟器和VirtualBox虚拟机安装.配置.测试(win7_64bit) 目录 1.概述 2.本文用到的工具 3.VirtualBox虚拟机安装 4.Genymotion安卓 ...

随机推荐

  1. C#判断数组或集合中是否含有属性值为value的对象

    /// <summary> /// 判断list中是否有某个对象的Id_srvplan为value /// </summary> /// <param name=&quo ...

  2. 一图读懂k8s informer client-go

    概述 为什么要有k8s informer 我们都知道可以使用k8s的Clientset来获取所有的原生资源对象,那么怎么能持续的获取集群的所有资源对象,或监听集群的资源对象数据的变化呢?这里不需要轮询 ...

  3. gitlab和jenkins做持续集成构建教程

    背景介绍 上一个轮回,我花了三篇文章的时间着重向大家介绍了在条件有限的情况下,如果优雅地进行前端发版和迭代.庆七一,热烈庆祝香港回归,人民生活水平越来越好,昨天上午我自掏腰包买了台服务器,决定由冷兵器 ...

  4. 梯度下降GD,随机梯度下降SGD,小批量梯度下降MBGD

    阅读过程中的其他解释: Batch和miniBatch:(广义)离线和在线的不同

  5. 6 zookeeper实现分布式锁

    zookeeper实现分布式锁 仓库地址:https://gitee.com/J_look/ssm-zookeeper/blob/master/README.md 锁:我们在多线程中接触过,作用就是让 ...

  6. Linux系列之添加和删除软件命令

    前言 在基于Debian的Linux发行版中,默认的软件管理器是Advanced Packaging Tool, 也就是apt.本文将简单介绍下面有关添加和删除软件的命令: apt-cache sea ...

  7. 基于yarn1.x的monorepo实践分享

    背景介绍 几天前,晓东船长微信问我,你们团队有没有monorepo的实践,我很遗憾的告诉他没有,但这在我心里播下了一颗探索的种子,刚好最近老总要搞内蒙古的新项目,我和另一个前端兄弟组成双枪敢死队进行保 ...

  8. 使用 Abp.Zero 搭建第三方登录模块(三):网页端开发

    ​简短回顾一下网页端的流程,总的来说网页端的职责有三: 生成一个随机字符作为鉴权会话的临时Token, 生成一个小程序码, Token作为参数固化于小程序码当中 监控整个鉴权过程状态,一旦状态变为AU ...

  9. Hbase学习(三)过滤器 java API

    Hbase学习(三)过滤器 HBase 的基本 API,包括增.删.改.查等. 增.删都是相对简单的操作,与传统的 RDBMS 相比,这里的查询操作略显苍白,只能根据特性的行键进行查询(Get)或者根 ...

  10. sql语句实现每日资格设置

    CREATE TABLE 'iDayAuth'( 'openid' VARCHAR(16) NOT NULL , 'iStamp' INT(10) NOT NULL, 'iDayAuth' SMALL ...