PostgreSQL技术内幕10:PostgreSQL事务原理解析-日志模块介绍

news2024/9/19 9:27:26

文章目录

    • 0.简介
    • 1.PG日志介绍
    • 2.事务日志介绍
    • 3.WAL分析
      • 3.1 WAL概述
      • 3.2 WAL设计考虑
        • 3.2.1 存储格式
        • 3.2.2 实现方式
        • 3.2.3 数据完整性校验
        • 3.3 check ponit
    • 4.事务提交日志(CLOG)
      • 4.1 clog存储使用介绍
      • 4.2 slru缓冲池并发控制

0.简介

本文将延续上一篇文章内容,上一篇介绍了PG事务涉及到的模块,本文介绍日志模块,主要介绍PG包含的日志分类,和WAL日志、CLOG的详细介绍。

1.PG日志介绍

在PG中,日志包含三种:

1)pg_log:数据库运行日志,一般用于记录数据库服务状态、sql执行情况和一些错误信息,警告信息。
2)pg_xlog:WAL(Write Ahead Log),即预写日志,记录事务日志信息。
3)pg_clog:事务提交日志,记录事务的元数据。

2.事务日志介绍

常见的事务日志分为两类,即Redo Log和Undo Log,其区别如下:
1)Redo Log:记录修改前的值,Replay时用旧值覆盖当前值,用于回滚。
2)Undo Log:记录修改后的值,Replay时用新值覆盖当前值,用于重做。
事务日志需要在数据真正修改发生之前来做记录,且Replay操作需要保证幂等性,对于PG来说,回滚并不涉及到Undo日志,而是用MVCC来处理,在下一篇会介绍PG的MVCC实现。

3.WAL分析

3.1 WAL概述

如果每次的数据修改都直接去写表文件,那么更新的代价是比较大的,需要去做硬盘随机写入且修改可能是没有顺序的,多次随机寻址和更新页面信息,所以一般会引入Buffer Pool,将数据写入内存,但是面临的问题就是如果在没有刷盘前发生系统故障,就会造成数据丢失,所以需要日志记录,相较于直接更行表文件,WAL Log代价更小。
写入顺序为:先写入WAL Log,在更新内存。在这种情况下,断电或系统故障都能准确恢复数据。
另外,现在WAL Log还可以用来做主从同步,数据备份等。

3.2 WAL设计考虑

对于WAL的设计,下面将介绍一般考虑的点和PG对应的实现

3.2.1 存储格式

数据库中的数据一般分为元数据和数据,元数据和数据可以分开存储,也可以一起存储,如下图:
在这里插入图片描述
对于PG,其WAL被分为多个文件,被称为WAL segment file,每个文件最大是16M。其命名规则是,24个字符被分为三部分:TimeLineID、逻辑文件ID、物理文件ID。每个八位,取值都是0x00000000到0xFFFFFFFF(实际上物理文件id到不了0xFFFFFFFF)。
寻址规则是:32bit的逻辑文件id+8bit的物理文件id+16M的24bit地址,组成一共64bit地址。
其内部层级如下:
在这里插入图片描述
文件中包含N个大小为8K的page,其中有两种page header,一种是XLogLongPageHeaderData,另一种是XLogPageHeaderData,除了第一个page header是XLogLongPageHeaderData,其余都是XLogPageHeaderData。


typedef struct XLogPageHeaderData
{
  uint16    xlp_magic;    /* magic value for correctness checks */
  uint16    xlp_info;    /* flag bits, see below */
  TimeLineID  xlp_tli;    /* TimeLineID of first record on page */
  XLogRecPtr  xlp_pageaddr;  /* XLOG address of this page */

  /*
   * When there is not enough space on current page for whole record, we
   * continue on the next page.  xlp_rem_len is the number of bytes
   * remaining from a previous page; it tracks xl_tot_len in the initial
   * header.  Note that the continuation data isn't necessarily aligned.
   */
  uint32    xlp_rem_len;  /* total len of remaining data for record */
} XLogPageHeaderData;

typedef struct XLogLongPageHeaderData
{
  XLogPageHeaderData std;    /* standard header fields */
  uint64    xlp_sysid;    /* system identifier from pg_control */
  uint32    xlp_seg_size;  /* just as a cross-check */
  uint32    xlp_xlog_blcksz;  /* just as a cross-check */
} XLogLongPageHeaderData;

可以看到XLogLongPageHeaderData成员除了XLogPageHeaderData还有三个成员。xlp_sysid对应的是pg_control中的system identifier,而剩下的xlp_seg_size和xlp_xlog_blcksz为固定大小,分别为segment文件的大小(16M)和page的大小(8K)。
在一个page中,page header之后是N个XLog record。XLog record的布局和结构体信息如下:


/*
 * The overall layout of an XLOG record is:
 *    Fixed-size header (XLogRecord struct)
 *    XLogRecordBlockHeader struct
 *    XLogRecordBlockHeader struct
 *    ...
 *    XLogRecordDataHeader[Short|Long] struct
 *    block data
 *    block data
 *    ...
 *    main data
 */
typedef struct XLogRecord
{
  uint32    xl_tot_len;    /* total len of entire record */
  TransactionId xl_xid;    /* xact id */
  XLogRecPtr  xl_prev;    /* ptr to previous record in log */
  uint8    xl_info;    /* flag bits, see below */
  RmgrId    xl_rmid;    /* resource manager for this record */
  /* 2 bytes of padding here, initialize to zero */
  pg_crc32c  xl_crc;      /* CRC for this record */

  /* XLogRecordBlockHeaders and XLogRecordDataHeader follow, no padding */

} XLogRecord;

typedef struct XLogRecordBlockHeader
{
  uint8    id;        /* block reference ID */
  uint8    fork_flags;    /* fork within the relation, and flags */
  uint16    data_length;  /* number of payload bytes (not including page
                 * image) */

  /* If BKPBLOCK_HAS_IMAGE, an XLogRecordBlockImageHeader struct follows */
  /* If BKPBLOCK_SAME_REL is not set, a RelFileLocator follows */
  /* BlockNumber follows */
} XLogRecordBlockHeader;

typedef struct XLogRecordDataHeaderShort
{
  uint8    id;        /* XLR_BLOCK_ID_DATA_SHORT */
  uint8    data_length;  /* number of payload bytes */
}      XLogRecordDataHeaderShort;

typedef struct XLogRecordDataHeaderLong
{
  uint8    id;        /* XLR_BLOCK_ID_DATA_LONG */
  /* followed by uint32 data_length, unaligned */
}      XLogRecordDataHeaderLong;
3.2.2 实现方式

实现方式分为Undo和Redo方式,对于PG来说,记录的是Redo日志。

3.2.3 数据完整性校验

对应数据完整性的校验,使用的是循环校验码的方式,这种方式可以有两种实现方式,一种是对整个日志块进行校验,优势的话就是速度快,缺点有一个记录损坏的话恢复代价大,要整块处理;另外一种是分段校验,对于校验速度比第一种稍慢,但出问题更容易找到出问题的小段来进行恢复,对于PG来说,可以看到,每个XLog Record都有自己的循环校验码。

3.3 check ponit

对于WAL文件和WAL buffer,在执行的过程中,数据量一直在增加,如果数量过多,会影响系统性能,PG清理机制依赖于checkpoint,其主要作用就是脏数据的写回,xlog的回收和更新Redo point(恢复启动的起点)等信息到pg_control文件中。

4.事务提交日志(CLOG)

4.1 clog存储使用介绍

CLOG日志记录的是事务的状态,在内存中是由使用SLRU作为淘汰算法的缓冲池进行缓存,由CLOG日志管理器来进行管理。
在PG事务模块一共定义了事务的四种状态:

#define TRANSACTION_STATUS_IN_PROGRESS    0x00 //事务正在运行中
#define TRANSACTION_STATUS_COMMITTED    0x01 //事务已提交
#define TRANSACTION_STATUS_ABORTED      0x02 //事务被终止
#define TRANSACTION_STATUS_SUB_COMMITTED  0x03 //事务的子事务已提交

可以看到,事务的状态只有四种,使用2byte就可以记录一个事务状态,一个page(8k)可以记录32k个日志记录。其存储文件以4位的16进制数字命名,位于PGDATA/pg_act目录下,内部内容如下:

/* We need two bits per xact, so four xacts fit in a byte --*/
#define CLOG_BITS_P ER_XACT	2  ---个事务占用2个bit位
#define CLOG_XACTS_PER_BYTE 4      --一个字节可以存放4个事务状态
#define CLOG_XACTS_PER_PAGE (BLCKSZ * CLOG_XACTS_PER_BYTE)--一个页块可以存放多少个事务状态
#define CLOG_XACT_BITMASK	((1 << CLOG_BITS_PER_XACT) - 1)

#define TransactionIdToPage(xid)	((xid) / (TransactionId) CLOG_XACTS_PER_PAGE) --事务存放在第几页
#define TransactionIdToPgIndex(xid) ((xid) % (TransactionId) CLOG_XACTS_PER_PAGE) --页内的偏移量
#define TransactionIdToByte(xid)	(TransactionIdToPgIndex(xid) / CLOG_XACTS_PER_BYTE)  --页内的第几个字节
#define TransactionIdToBIndex(xid)	((xid) % (TransactionId) CLOG_XACTS_PER_BYTE)  --字节内的偏移量
    可以看到,有一个事务id之后,可以计算得到页,页内偏移,页内字节和字节内偏移量,从而找到事务状态。

4.2 slru缓冲池并发控制

因为slru(最近最少使用)的概念是比较容易理解的,下面主要描述PG在slru的缓冲池上实现并发控制的方式。
对于SLRU缓冲池,PG使用了两种锁来进行并发控制。
1)ControlLock:整个缓冲区的控制锁(读写锁)。
2) buffer_locks:每个缓冲区页面锁(读写锁)。
一次读取到slru的流程
获取ControlLock的全局锁-》挑选出替换的缓存,更新缓存的状态为正在读-》获取缓存的写锁-》释放ControlLock的全局锁,因为刷新磁盘的时间会很长,这里释放全局锁提高并发性能-》从文件中读取数据到缓存-》重新获取ControlLock全局锁,因为接下来要修改缓存的状态-》设置缓存的状态为有效状态-》释放ControlLock全局锁-》释放缓存的写锁,并且设置缓存为最近访问。
可以看到PG采用了分页控制的方式提高了并发操作的性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2146005.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

好用的网页翻译插件

软件介绍 「火山翻译&#xff0c;开箱即用免配置&#xff0c;完全免费无广告&#xff0c;开发的多语言翻译插件&#xff0c;基本涵盖众多小语种及国际通用语言的翻译&#xff0c;支持网页一键翻译、划词翻译、英语词典、生词本、吐司弹词记忆等丰富能力。 下载方式 请看文章…

【AprilTag】视觉定位实战 | 使用 ROS 驱动的 USB 摄像头进行相机标定与 AprilTag 识别

写在前面&#xff1a; &#x1f31f; 欢迎光临 清流君 的博客小天地&#xff0c;这里是我分享技术与心得的温馨角落。&#x1f4dd; 个人主页&#xff1a;清流君_CSDN博客&#xff0c;期待与您一同探索 移动机器人 领域的无限可能。 &#x1f50d; 本文系 清流君 原创之作&…

Matlab进行频率切片小波变换

Matlab进行频率切片小波变换(FSWT)源代码&#xff0c;将一维信号生成时频图。 输入信号可以是任何一维信号&#xff0c;心电信号、脑电信号、地震波形、电流电压数据等。 相比连续小波变换(CWT)&#xff0c;频率切片小波变换(Frequency Slice Wavelet Transform,FSWT)是一种更具…

C# 使用代码清理 以及禁用某个代码清理

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 源码指引&#xff1a;github源…

鸿蒙Harmony应用开发,数据驾驶舱 项目结构搭建

对于一个项目而言&#xff0c;在拿到我们的开发任务后&#xff0c;我们最重要的就是技术的选型。选型定下来了之后我们便开始脚手架的搭建&#xff0c;然后开始撸代码&#xff0c;开搞. 首先我们需要对一些常见依赖库的引入 我们需要再oh-package.json5的dependencies节点下面…

strlen和sizeof

在 C 语言中&#xff0c;strlen 和 sizeof 是两个非常常用的操作符&#xff0c;但它们的作用和用途有很大的不同。下面详细解释这两个操作符&#xff1a; strlen strlen 是一个函数&#xff0c;定义在 <string.h> 头文件中&#xff0c;用于计算一个以空字符&#xff08…

华为OD机试 - 字符串划分(Java 2024 E卷 100分)

华为OD机试 2024E卷题库疯狂收录中&#xff0c;刷题点这里 专栏导读 本专栏收录于《华为OD机试&#xff08;JAVA&#xff09;真题&#xff08;E卷D卷A卷B卷C卷&#xff09;》。 刷的越多&#xff0c;抽中的概率越大&#xff0c;私信哪吒&#xff0c;备注华为OD&#xff0c;加…

注意,传统的提示工程对新模型o1可能失效:来自OpenAI官方的4条提示词建议!

大家好&#xff0c;我是木易&#xff0c;一个持续关注AI领域的互联网技术产品经理&#xff0c;国内Top2本科&#xff0c;美国Top10 CS研究生&#xff0c;MBA。我坚信AI是普通人变强的“外挂”&#xff0c;专注于分享AI全维度知识&#xff0c;包括但不限于AI科普&#xff0c;AI工…

Flink系列知识之:Checkpoint原理

Flink系列知识之&#xff1a;Checkpoint原理 在介绍checkpoint的执行流程之前&#xff0c;需要先明白Flink中状态的存储机制&#xff0c;因为状态对于检查点的持续备份至关重要。 State Backends分类 下图显示了Flink中三个内置的状态存储种类。MemoryStateBackend和FsState…

linux设置常见开机自启动命令

本文介绍了三种开机自启的方式&#xff0c;重点介绍使用systemctl的方式自启动的 方式一、修改 /etc/rc.d/rc.local 文件 /etc/rc.d/rc.local 文件会在 Linux 系统各项服务都启动完毕之后再被运行。所以你想要自己的脚本在开机后被运行的话&#xff0c;可以将自己脚本路径加到…

Kubernetes从零到精通(12-Ingress、Gateway API)

Ingress和Gateway API都是Kubernetes中用于管理外部访问集群服务的机制&#xff0c;但它们有不同的设计理念和适用场景。它们的基本原理是通过配置规则&#xff0c;将来自外部的网络流量路由到Kubernetes集群内部的服务上。 Ingress/Gateway API和Service Ingress/Gateway API…

边缘计算智能网关的功能应用与优势-天拓四方

在物联网的世界中&#xff0c;数以亿计的设备不断产生、传输和处理数据。然而&#xff0c;传统的云计算架构在面对这些实时性要求高、数据量庞大的物联网数据时&#xff0c;常常面临着网络延迟、带宽限制和安全风险等问题。这时&#xff0c;边缘计算智能网关作为一种新兴的技术…

图书馆座位预约系统小程序的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;用户管理&#xff0c;图书馆管理&#xff0c;座位信息管理&#xff0c;预约选座管理&#xff0c;签到信息管理&#xff0c;系统管理 微信端账号功能包括&#xff1a;系统首页&#xff0c;论坛&#xf…

【Harmony】轮播图特效,持续更新中。。。。

效果预览 swiper官网例子 Swiper 高度可变化 两边等长露出&#xff0c;跟随手指滑动 Swiper 指示器导航点位于 Swiper 下方 一、官网 例子 参考代码&#xff1a; // xxx.ets class MyDataSource implements IDataSource {private list: number[] []constructor(list: nu…

python:Django与Celery配合实现定时任务

Celery是一个基于python开发的分布式任务队列&#xff0c;而做python WEB开发最为流行的框架莫属Django&#xff0c;但是Django的请求处理过程都是同步的无法实现异步任务&#xff0c;若要实现异步任务处理需要通过其他方式&#xff08;前端的一般解决方案是ajax操作&#xff0…

监控网线和电话线水晶头

监控网线 1、网络摄像机网线接口的线序与B类网线的对应关系&#xff08;表格从左到右代表线序1-8&#xff09; 表格解读&#xff1a; &#xff08;1&#xff09;请先查看摄像机网线对应的颜色&#xff0c;确定是第一种还是第二种摄像机类型 &#xff08;2&#xff09;确定好…

计算机网络基础 - 应用层(3)

计算机网络基础 应用层P2P 应用P2P 体系结构的扩展性BitTorrent 协议torrenl 洪流BitTorrent 运行的过程 P2P文件共享应用非结构化 P2PDHT 结构化 P2P&#xff08;了解&#xff09; 视频流和内容分发网视频流化服务HTTP 流和 DASH内容分发网 CDN面临挑战CDN 概述CDN 操作过程集…

MFC获取网页的html文本

使用 CInternetSession 类和 CHttpFile 类&#xff1b; 在stdafx.h中加入 #include <afxinet.h> &#xff1b; 基本的代码如下&#xff0c; void CMFCApplication3Dlg::OnBnClickedButton1() {// TODO: 在此添加控件通知处理程序代码try{CInternetSession session;CH…

4.事件组

事件组的本质:一个整数 里面的每一个bit,表示一类事件 任务A:可以等待这个整数的"bitx,bity,bitz....."都被设置为1. 这就是"AND"的关系 也可以等待这个整数的"bitx bity bitz..."任意一个被设置为1. 事件组有一个特别的地方在于: 1.假设任…

【QML 基础】QML ——描述性脚本语言,用于用户界面的编写

文章目录 1. QML 定义 1. QML 定义 &#x1f427; QML全称为Qt Meta-Object Language&#xff0c;QML是一种描述性的脚本语言&#xff0c;文件格式以.qml结尾。支持javascript形式的编程控制。QML是Qt推出的Qt Quick技术当中的一部分&#xff0c;Qt Quick是 Qt5中用户界面的涵…