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ā)送來(lái)的日志消息,處理打印邏輯。在大循環(huán)中同時(shí)也根據(jù)時(shí)間和大小,來(lái)判斷是否進(jìn)行日志輪轉(zhuǎn)。
日志消息通信
PG 的其余進(jìn)程如果有需要打印的日志,通常會(huì)調(diào)用 elog 或者 ereport 來(lái)打印。而這兩個(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 說明日志消息來(lái)源于同一進(jìn)程,將其組裝起來(lái),當(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è)置了,那么接下來(lái)做幾道題檢驗(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)問接下來(lái)要寫的日志文件是什么?
- 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)問接下來(lái)要寫的日志文件是什么?
- 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)問接下來(lái)要寫的日志文件是什么?
- 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)是日志出來(lái)的即時(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 中的單引號(hào)與雙引號(hào)用法說明
這篇文章主要介紹了PostgreSQL 中的單引號(hào)與雙引號(hào)用法說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2021-02-02PostgreSQL中查看當(dāng)前時(shí)間和日期的幾種常用方法
在 PostgreSQL 中,有多個(gè)函數(shù)可以用來(lái)查看當(dāng)前時(shí)間和日期,這些函數(shù)在處理時(shí)間戳、日期和時(shí)間的計(jì)算時(shí)非常有用,以下是幾種常用的查看當(dāng)前時(shí)間和日期的函數(shù)及示例,需要的朋友可以參考下2024-10-10postgresql數(shù)據(jù)庫(kù) timescaledb 時(shí)序庫(kù) 把大數(shù)據(jù)量表轉(zhuǎn)換為超表的問題
這篇文章主要介紹了postgresql數(shù)據(jù)庫(kù) timescaledb 時(shí)序庫(kù) 把大數(shù)據(jù)量表轉(zhuǎn)換為超表,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02PostgreSQL常用字符串函數(shù)與示例說明小結(jié)
文章介紹了PostgreSQL中常用字符串函數(shù)的使用方法,包括空值處理、字符串位置查詢、長(zhǎng)度計(jì)算、大小寫轉(zhuǎn)換、去除空格、連接、替換、匹配、拆分和截取等操作,感興趣的朋友跟隨小編一起看看吧2024-11-11pgsql 如何刪除仍有活動(dòng)鏈接的數(shù)據(jù)庫(kù)
這篇文章主要介紹了pgsql 刪除仍有活動(dòng)鏈接的數(shù)據(jù)庫(kù)操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2021-01-01PGSQL 實(shí)現(xiàn)把字符串轉(zhuǎn)換成double類型(to_number())
這篇文章主要介紹了PGSQL 實(shí)現(xiàn)把字符串轉(zhuǎn)換成double類型(to_number()),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧2020-12-12PostgreSQL教程(十四):數(shù)據(jù)庫(kù)維護(hù)
這篇文章主要介紹了PostgreSQL教程(十四):數(shù)據(jù)庫(kù)維護(hù),本文講解了恢復(fù)磁盤空間、更新規(guī)劃器統(tǒng)計(jì)、VACUUM和ANALYZE的示例、定期重建索引等內(nèi)容,需要的朋友可以參考下2015-05-05PostgreSQL進(jìn)行重置密碼的方法小結(jié)
今天想測(cè)試一個(gè)PostgresSQL語(yǔ)法的 SQL,但是打開PostgresSQL之后沉默了,密碼是什么?日長(zhǎng)月久的,漸漸就忘記了,于是開始了尋找密碼的道路,所以本文介紹了Postgresql忘記密碼,如何重置密碼,需要的朋友可以參考下2024-05-05PostgreSQL12.5中分區(qū)表的一些操作實(shí)例
PostgreSQL支持通過表繼承進(jìn)行分區(qū),下面這篇文章主要給大家介紹了關(guān)于PostgreSQL12.5中分區(qū)表的一些操作的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-08-08