PostgreSQL?Log日志模塊原理及存在的問題詳解
背景
PG 的日志模塊是一個(gè)相對(duì)獨(dú)立的模塊,主要功能就是打印用戶的操作日志以及一些異常報(bào)錯(cuò)信息。本文僅講述 logging_collector 參數(shù)開啟的情況。
日志模塊原理
Syslogger 核心模塊
PG 有各種各樣的進(jìn)程,其中 syslogger 進(jìn)程專門用于打印日志信息。
而其余進(jìn)程打印日志的方法如出一轍:將需要打印的信息發(fā)送給 syslogger 進(jìn)程,由其統(tǒng)一負(fù)責(zé)打印。

syslogger 的大體邏輯如下圖所示:

- postmaster 進(jìn)程在 SysLogger_Start 函數(shù)完成部分初始化;
- 由 postmaster 進(jìn)程 fork 出 syslogger 進(jìn)程;
- 進(jìn)入 syslogger 的主邏輯函數(shù) SysLoggerMain 中,大循環(huán)監(jiān)聽其他進(jìn)程發(fā)送來的日志消息,處理打印邏輯。在大循環(huán)中同時(shí)也根據(jù)時(shí)間和大小,來判斷是否進(jìn)行日志輪轉(zhuǎn)。
日志消息通信
PG 的其余進(jìn)程如果有需要打印的日志,通常會(huì)調(diào)用 elog 或者 ereport 來打印。而這兩個(gè)函數(shù)會(huì)將日志消息分成若干個(gè) chunk 發(fā)送給 syslogger 進(jìn)程,每個(gè) chunk 的結(jié)構(gòu)可參考下圖(源碼中的 PipeProtoChunk 結(jié)構(gòu))

- 開頭兩個(gè) \0 ,表示是日志開頭
- length:用于記錄當(dāng)前 chunk 的長(zhǎng)度
- pid:發(fā)送該 chunk 的進(jìn)程號(hào)
- is_last:是否是本條日志消息的最后一個(gè) chunk;
- data:具體的日志消息。
- chunk 大?。篜IPE_CHUNK_SIZE ,源碼 define 出的一個(gè)值,由 OS 的 PIPE_BUF 決定。具體細(xì)節(jié)可參考這部分定義的代碼。
注: PG 15 在 pipe 協(xié)議格式中做了一些變化,由 flags 代替 is_last 標(biāo)記。
syslogger 在接收到日志消息后,將其按照 pid 進(jìn)行分組,相同的 pid 說明日志消息來源于同一進(jìn)程,將其組裝起來,當(dāng)收到包含 is_last 標(biāo)記的最后一個(gè) chunk 后,將整條日志消息打印到日志文件。
日志輪轉(zhuǎn)
所謂日志輪轉(zhuǎn),指的就是不想繼續(xù)寫當(dāng)前日志文件了,需要新找一個(gè)日志文件繼續(xù)寫日志。
PG 的日志輪轉(zhuǎn)是一個(gè)坑非常多的地方,因?yàn)樗上旅嫠膫€(gè)參數(shù)同時(shí)控制:
- log_filename :日志文件格式,我們以其設(shè)定為 postgres_%d_%h 為例,某個(gè)月 14 號(hào) 15 點(diǎn)的日志文件名就是 postgres_14_15.log
- log_rotation_age:如果距離當(dāng)前日志文件已經(jīng)超過設(shè)定的時(shí)間,那么就新開一個(gè)日志文件;
- log_rotation_size:如果距離當(dāng)前日志文件還沒有超過 log_rotation_age 設(shè)定的時(shí)間,但是已經(jīng)超過了 log_rotation_size 設(shè)定的大小,那么就新開一個(gè)日志文件;
- log_truncate_on_rotation:是否在按時(shí)間輪轉(zhuǎn)后做截?cái)?。即如果下一個(gè)日志文件的同名文件已經(jīng)存在了,是否直接清空該文件并從頭開始寫;
這幾個(gè)參數(shù)的具體使用可參考 PG 官方文檔??赐晟厦娴慕榻B,想必大家已經(jīng)精通日志參數(shù)設(shè)置了,那么接下來做幾道題檢驗(yàn)自己的學(xué)習(xí)成果。
假如,我們按照以下值設(shè)定日志相關(guān)參數(shù)
log_filename='postgres_%d_%h.log' log_rotation_age = 2h log_rotation_size = 10MB log_truncate_on_rotation = on
問題一
- Q:此時(shí)時(shí)間剛到 14 號(hào)下午 17 點(diǎn) ,日志文件為 postgres_14_16.log,且大小為 5MB,請(qǐng)問接下來要寫的日志文件是什么?
- A:postgres_14_16.log 。因?yàn)榇藭r(shí)距離 15 點(diǎn)僅過了 1h,沒有超過 log_rotation_age;大小并沒有超過 log_rotation_size ,所以并不發(fā)生輪轉(zhuǎn)。
問題二
- Q:此時(shí)時(shí)間為 14 號(hào)下午 16 點(diǎn) 30 分 ,日志文件為 postgres_14_16.log,且大小剛剛超過 10MB 到達(dá) 10.9MB,請(qǐng)問接下來要寫的日志文件是什么?
- A:postgres_14_16.log 。因?yàn)?log_filename 參數(shù)的最小精度值就到小時(shí),哪怕當(dāng)前日志文件大小變成 1TB 也只會(huì)繼續(xù)追加寫這個(gè)文件。
問題三
- Q:此時(shí)時(shí)間剛到 14 號(hào)下午 17 點(diǎn) ,日志文件為 postgres_14_16.log,且大小剛剛超過 10MB 到達(dá) 10.9MB,請(qǐng)問接下來要寫的日志文件是什么?
- A:postgres_14_17.log 。因?yàn)闈M足 log_rotation_size 的輪轉(zhuǎn)條件了。
問題四
- Q:此時(shí)時(shí)間剛到 14 號(hào)下午 17 點(diǎn) ,日志文件為 postgres_14_16.log,且大小剛剛超過 10MB 到達(dá) 10.9MB,但是名為 postgres_14_17.log 的文件已經(jīng)存在了(上個(gè)月日志創(chuàng)建的),那么是追加寫還是覆蓋寫該文件?
- A:追加寫,因?yàn)檫@是按大小輪轉(zhuǎn)。
問題五
- Q:此時(shí)時(shí)間剛到 14 號(hào)下午 18 點(diǎn) ,日志文件為 postgres_14_16.log,且大小只有 0.1MB。但是名為 postgres_14_18.log 的文件已經(jīng)存在了,那么是追加寫還是覆蓋寫該文件?
- A:覆蓋寫,log_rotation_age 強(qiáng)制觸發(fā)按時(shí)間輪轉(zhuǎn)邏輯。
上面問題都能搞懂,基本也沒什么坑了。
存在的問題
刷盤性能
當(dāng)前情況下,在 log_statement 參數(shù)設(shè)置成 all 時(shí),性能下降會(huì)非常厲害。因?yàn)?PG 的日志在刷盤時(shí)的默認(rèn)策略為:每寫一行就刷盤。Linux 提供的刷盤模式可分為以下三種:
- _IOFBF:全緩沖模式,緩沖區(qū)寫滿后才刷盤
- _IOLBF:行緩沖模式,一行寫滿就刷盤
- _IONBF:不緩沖,直接刷
當(dāng)前 PG 采用第二種行緩沖模式,優(yōu)點(diǎn)是日志出來的即時(shí)性更高,缺點(diǎn)就是對(duì)性能有不小的影響。
日志輪轉(zhuǎn)
日志輪轉(zhuǎn)的邏輯設(shè)計(jì)雖然勉強(qiáng)算是合理的(不會(huì)丟日志),但是理解成本很高,且有可能出現(xiàn)某個(gè)日志文件存在了非常非常久(上一節(jié)問題 4 的變種),一直沒被刪掉,需要依賴人工手動(dòng)刪除。
參考資料
- [1] https://www.postgresql.org/docs/current/logfile-maintenance.html
- [2] https://github.com/postgres/postgres
總結(jié)
到此這篇關(guān)于PostgreSQL Log日志模塊原理及存在的問題詳解的文章就介紹到這了,更多相關(guān)PostgreSQL Log日志模塊內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
PostgreSQL中rank()窗口函數(shù)實(shí)用指南與示例
在數(shù)據(jù)分析和數(shù)據(jù)庫(kù)管理中,經(jīng)常需要對(duì)數(shù)據(jù)進(jìn)行排名操作,PostgreSQL提供了強(qiáng)大的窗口函數(shù)rank(),可以方便地對(duì)結(jié)果集中的行進(jìn)行排名,本文將詳細(xì)介紹rank()函數(shù)的使用方法,并通過多個(gè)實(shí)用示例展示其在不同場(chǎng)景下的應(yīng)用,需要的朋友可以參考下2025-07-07
將PostgreSQL的數(shù)據(jù)實(shí)時(shí)同步到Doris的技巧分享
眾所周知,在兩個(gè)毫不相干的數(shù)據(jù)管理系統(tǒng)之間進(jìn)行數(shù)據(jù)同步,特別是實(shí)時(shí)同步,其復(fù)雜程度足以讓高級(jí)DBA腦瓜疼,本文給大家介紹了將PostgreSQL的數(shù)據(jù)實(shí)時(shí)同步到Doris的技巧分享,需要的朋友可以參考下2024-03-03
解決sqoop import 導(dǎo)入到hive后數(shù)據(jù)量變多的問題
這篇文章主要介紹了解決sqoop import 導(dǎo)入到hive后數(shù)據(jù)量變多的問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-12-12
Postgresql限制用戶登錄錯(cuò)誤次數(shù)的實(shí)例代碼
這篇文章主要介紹了Postgresql限制用戶登錄錯(cuò)誤次數(shù)的實(shí)例代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03
PostgreSQL 重復(fù)數(shù)據(jù)處理的操作方法
這篇文章主要介紹了PostgreSQL 重復(fù)數(shù)據(jù)處理的操作方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12
postgresql數(shù)據(jù)添加兩個(gè)字段聯(lián)合唯一的操作
這篇文章主要介紹了postgresql數(shù)據(jù)添加兩個(gè)字段聯(lián)合唯一的操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-02-02

