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

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

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

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

