最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

深度解析 PostgreSQL Protocol v3.0(一)

2023-08-30 11:35 作者:KaiwuDB  | 我要投稿

引言

PostgreSQL 使用基于消息的協(xié)議在前端(也可以稱為客戶端)和后端(也可以稱為服務(wù)器)之間進行通信。該協(xié)議通過 TCP/IP 和 Unix 域套接字支持。

《深度解析?PostgreSQL Protocol v3.0》系列技術(shù)貼,將帶大家深度了解 PostgreSQL Protocol 3.0 版本(在 PostgreSQL 7.4 及更高版本中實現(xiàn),有關(guān)早期協(xié)議版本的描述請參考 PostgreSQL 文檔的早期版本,該系列文章不予贅述)相關(guān)的消息傳輸格式和格式碼消息支持的數(shù)據(jù)類型消息的格式、協(xié)議交互流程錯誤消息和通知消息、支持的子協(xié)議等,相關(guān)的代碼解讀基于 PostgreSQL 代碼倉庫的 REL_14_STABLE 分支。

PostgreSQL 單個服務(wù)器可以支持多個協(xié)議版本,可以接收和處理多個不同版本協(xié)議的客戶端的請求消息。初始啟動請求消息告訴服務(wù)器、客戶端嘗試使用的協(xié)議版本

  • 如果客戶端請求的主要版本不受服務(wù)器支持,則連接將被拒絕(例如,如果客戶端請求協(xié)議版本 4.0,而服務(wù)器端支持的協(xié)議版本不存在 4.0,此時就會發(fā)生這種情況);

  • 如果服務(wù)器不支持客戶端請求的次要版本(例如,客戶端請求版本為 3.1,但服務(wù)器僅支持 3.0,不支持 3.1 版本,此時就會發(fā)生這種情況),則服務(wù)器可以拒絕連接,或者可以使用包含其支持的最高次要協(xié)議版本的 NegotiateProtocolVersion 消息進行響應(yīng)。

客戶端可以選擇使用服務(wù)器端指定的協(xié)議版本繼續(xù)連接或中止連接。為了高效地為多個客戶端提供服務(wù),服務(wù)器為每個客戶端啟動一個新的進程進行請求處理。在當前實現(xiàn)中,在服務(wù)器檢測到客戶端的 Socket 連接后立即創(chuàng)建新的子進程進行后續(xù)的處理,比如 SSL 通信加密協(xié)商、啟動消息、身份認證等流程。

一、消息傳輸?shù)母袷?/h1>

客戶端和服務(wù)器所有的交互都是通過消息流進行的。每一條消息主要由三部分組成:

  • 消息類型

用于標記消息的類型,是單個字符或者 1 位的數(shù)字。消息類型長度占用 1 個字節(jié)。

  • 消息長度

消息中除了消息類型之外的字節(jié)長度。消息長度占用 4 個字節(jié)。消息長度的值包含了消息長度本身的 4 個字節(jié)長度。計算方法:

(1)消息字節(jié)總長度減去 1 字節(jié)的消息類型的長度;

(2)消息內(nèi)容字節(jié)總長度加上消息長度本身占用的字節(jié)數(shù) 4。

  • 消息體

消息的具體 payload 內(nèi)容,例如簡單查詢的 SQL 內(nèi)容。

需要注意的是,由于歷史原因,客戶端發(fā)送的第一條消息(啟動消息)沒有消息類型的 1 個字節(jié)。服務(wù)器和客戶端為了避免與消息流失去同步,通常在嘗試處理消息內(nèi)容之前將整個消息讀入緩沖區(qū)(使用字節(jié)計數(shù))。

如果在處理消息內(nèi)容時檢測到錯誤,就可以輕松恢復(fù)。在極端情況下(例如沒有足夠的內(nèi)存來緩沖消息),接收器可以使用字節(jié)計數(shù)來確定在恢復(fù)讀取消息之前要跳過多少輸入字節(jié)長度。服務(wù)器和客戶端都必須注意不要發(fā)送不完整的消息。這通常是通過在開始發(fā)送之前在緩沖區(qū)中編碼整個消息來完成的。

如果在發(fā)送或接收消息的過程中發(fā)生通信故障,那么唯一明智的做法是斷開連接,因為恢復(fù)消息邊界同步的希望很小。

二、消息支持的數(shù)據(jù)類型

PostgreSQL Protocol v3.0 的消息中支持的數(shù)據(jù)類型只有以下 4 種:

  • Intn(i)

n?位二進制表示的整數(shù),為網(wǎng)絡(luò)字節(jié)順序(最高有效字節(jié)優(yōu)先,MSB),n?表示該值占用的位數(shù)。

如果指定了?i則?i?是將出現(xiàn)的確切值;如果未指定?i?值,該值是可變的。例如,Int16 表示一個值未指定的占用 16 位二進制位的整數(shù)(占用長度為 2 個字節(jié),占用 16 位二進制);Int32 (42) 表示一個值為 42 的占用 32 位二進制位的整數(shù)(占用長度為 4 個字節(jié),占用 32 位二進制)。

  • Intn[k]

由?k?個?n?位二進制表示的整數(shù)組成的數(shù)組。數(shù)組長度?k?始終由消息中較早的字段確定。

  • String(s)

以空結(jié)尾的字符串(C-style 字符串)。字符串沒有特定的長度限制。

如果指定了?s,則?s?是將出現(xiàn)的確切值;如果未指定?s?值,該值是可變的。例如,String?表示一個值未指定的字符串;String("user")?表示值為?user?的字符串。

需要注意的是,服務(wù)器可以返回的字符串長度沒有預(yù)定義長度的限制,因此客戶端比較好的編碼策略是使用可擴展緩沖區(qū),以便可以接收適合內(nèi)存大小的內(nèi)容。如果這不可行,請讀取整個字符串并丟棄不適合固定大小緩沖區(qū)的尾隨字符。

  • Byten(c)

n?個字節(jié)。如果字段寬度?n?不是常數(shù),則它總是可以從消息中較早的字段確定。如果指定了?c,則?c?為該字段的精確值。例如,Byte2 表示值未指定的 2 個字節(jié),Byte1 ('\n') 表示值為 '\n' 的 1 個字節(jié)。

除了以上四種數(shù)據(jù)類型,其他數(shù)據(jù)類型在 PostgreSQL Protocol v3.0 的消息中均不支持。

三、消息傳輸?shù)母袷胶透袷酱a

在 Postgresql Protocole 中,特定數(shù)據(jù)類型的數(shù)據(jù)可以用幾種不同格式中的任何一種傳輸。

從 PostgreSQL 7.4(PostgreSQL Protocol v3.0)開始,協(xié)議支持的數(shù)據(jù)傳輸支持的格式是?text(文本)和?binary(二進制),該協(xié)議為將來的擴展做好了準備。任何值傳輸?shù)母袷接筛袷酱a指定。

客戶端可以為每個傳輸?shù)膮?shù)值和查詢結(jié)果的每一列指定格式代碼。text?的格式代碼為?0,binary?的格式代碼是?1,所有其他格式代碼都保留以供將來定義。

值的?text?表示是輸入 / 輸出轉(zhuǎn)換函數(shù)為特定數(shù)據(jù)類型生成 / 接受的字符串。在傳輸?text?的表示中,沒有結(jié)尾空字符;如果客戶端想要將接收到的值作為 C 風格字符串處理,則客戶端必須自行將其加 1 個空字符。需要注意的是,text?傳輸格式的值不允許內(nèi)嵌空字符。

整數(shù)的 binary 表示使用網(wǎng)絡(luò)字節(jié)順序(最高有效字節(jié)優(yōu)先,MSB)。

值得特別注意的是,復(fù)雜數(shù)據(jù)類型的 binary 表示可能會在服務(wù)器版本之間發(fā)生變化;因此 text 格式通常是更便攜更通用的選擇。


四、消息的交互流程

PostgreSQL Protocol v3.0 的交互流程主要包括以下幾種流程:

1. 啟動流程

要開始會話,客戶端將打開與服務(wù)器的連接并發(fā)送啟動消息 StartupMessage。啟動消息包括用戶的名稱、用戶想要連接到的數(shù)據(jù)庫的名稱和要使用的特定協(xié)議版本(啟動消息可以包括運行時參數(shù)的其他設(shè)置,但是這些參數(shù)都是可選的)。

接著,服務(wù)器使用這些信息及其配置文件(如 pg_hba.conf)的內(nèi)容來確定連接是否暫時可接受,以及需要什么附加身份驗證(如果有的話)。

然后,服務(wù)器發(fā)送適當?shù)纳矸蒡炞C請求消息,客戶端必須用適當?shù)纳矸菡J證響應(yīng)消息(如密碼)回復(fù)該消息。

對于除 GSSAPI、SSPI 和 SASL 之外的所有身份驗證方法,最多只有一個請求和一個響應(yīng)。在某些方法中,客戶端不需要響應(yīng),因此不會發(fā)生身份驗證請求。對于 GSSAPI、SSPI 和 SASL,可能需要多次交換數(shù)據(jù)包才能完成身份驗證。

2. 簡單查詢流程

一個簡單查詢的周期由客戶端端向服務(wù)器端發(fā)送查詢消息來啟動。該消息包括一個以文本字符串表示的 SQL 命令。然后,服務(wù)器根據(jù)查詢命令字符串的內(nèi)容進行執(zhí)行,執(zhí)行完成發(fā)送一條或多條響應(yīng)消息,最后發(fā)送 ReadyForQuery 響應(yīng)消息。

ReadyForQuery 通知客戶端,可以安全地發(fā)送新命令。(客戶端實際上不需要在發(fā)出另一個命令之前等待 ReadyForQuery,但客戶端必須負責弄清楚如果前一個命令失敗,而已經(jīng)發(fā)出的后一個命令成功,會發(fā)生什么情況。因此,建議的做法是客戶端接收到 ReadyForQuery 消息之后再發(fā)送新命令。)

簡單查詢的交互流程中,也會出現(xiàn)一些異常情況,會得到異常的響應(yīng)。例如,查詢 SQL 為空字符串,則響應(yīng)為 EmptyQueryResponse,后跟 ReadyForQuery。發(fā)生錯誤時,發(fā)出 ErrorResponse,然后發(fā)出 ReadyForQuery。ErrorResponse 會中止對查詢字符串的所有進一步處理。

3.?擴展查詢

擴展查詢協(xié)議將上述簡單查詢協(xié)議分解為多個步驟。為了提高效率,可以多次重復(fù)使用 Prepare 步驟的結(jié)果。

此外,還提供了其他功能,例如可以將數(shù)據(jù)值作為單獨的參數(shù)提供,而不必將它們直接插入到查詢字符串中。擴展查詢一般需要經(jīng)過 Parse, Bind 和 Execute 步驟,中間有一些可選步驟如 Describe,Close 和 Flush。

4. Pipelining

擴展查詢協(xié)議的使用允許流水線,這意味著發(fā)送一系列查詢而無需等待較早的查詢完成。流水線減少了完成給定系列操作所需的網(wǎng)絡(luò)往返次數(shù)。

但是,如果其中一個步驟失敗,用戶必須仔細考慮所需的處理,因為稍后的查詢已經(jīng)在發(fā)送到服務(wù)器。

5. 函數(shù)調(diào)用(Function Call)流程

函數(shù)調(diào)用 (Function Call) 子協(xié)議允許客戶端請求直接調(diào)用數(shù)據(jù)庫的 pg_proc 系統(tǒng)目錄中存在的任何函數(shù)。客戶端必須具有函數(shù)的執(zhí)行權(quán)限。

函數(shù)調(diào)用子協(xié)議是一個較早版本的遺留功能,在新代碼 / 新版本中最好避免使用。類似的結(jié)果可以通過設(shè)置執(zhí)行 SELECT function ($1, …) 的準備語句的值來實現(xiàn)。然后可以用 Bind/Execute 代替函數(shù)調(diào)用周期。

函數(shù)調(diào)用周期由客戶端向端發(fā)送 FunctionCall 消息來啟動。服務(wù)端根據(jù)函數(shù)調(diào)用的結(jié)果發(fā)送一條或多條響應(yīng)消息,最后發(fā)送 ReadyForQuery 響應(yīng)消息。ReadyForQuery 通知客戶端它可以安全地發(fā)送新的查詢或函數(shù)調(diào)用。

6. 取消執(zhí)行中的請求流程

在處理查詢期間,客戶端可能會請求取消查詢。出于實現(xiàn)效率的原因,取消請求不會直接通過正在執(zhí)行查詢的連接發(fā)送到服務(wù)端:不希望服務(wù)端在查詢處理過程中不斷檢查來自客戶端的新輸入。取消請求應(yīng)該是相對較少的,所以我們讓取消流程稍微麻煩一些,以避免在正常情況下發(fā)生錯誤。

要發(fā)出取消請求,客戶端應(yīng)該打開到服務(wù)器的新連接并發(fā)送一條 CancelRequest 消息,而不是通常通過新連接發(fā)送的 StartupMessage 消息。服務(wù)器將處理此請求,然后關(guān)閉連接。出于安全原因,不直接回復(fù)取消請求消息。

7. 結(jié)束流程

正常、友好的終止過程是客戶端發(fā)送 Terminate 終止消息并立即關(guān)閉連接。服務(wù)端收到此 Terminate 消息后,關(guān)閉連接并終止。

在極少數(shù)情況下(如管理員通過命令關(guān)閉數(shù)據(jù)庫),服務(wù)器端可能會在沒有任何客戶端請求的情況下斷開連接。在這種情況下,服務(wù)器端將嘗試在關(guān)閉連接之前發(fā)送錯誤或通知消息,給出斷開連接的原因。

8. COPY 操作

COPY 命令允許客戶端與服務(wù)器之間進行高速批量數(shù)據(jù)傳輸。COPY IN 和 COPY OUT 操作都會將連接切換到不同的子協(xié)議中,該子協(xié)議將持續(xù)到操作完成。

COPY IN 是將數(shù)據(jù)從客戶端傳輸?shù)椒?wù)器端,COPY OUT 是將數(shù)據(jù)從服務(wù)器端傳輸?shù)娇蛻舳恕_€有另一種與 COPY 相關(guān)的模式,稱為 “雙向復(fù)制”,它允許客戶端與服務(wù)器之間的雙向高速批量數(shù)據(jù)傳輸。

9. 異步操作

有幾種情況下,服務(wù)器端將向客戶端發(fā)送客戶端命令沒有特別請求的消息??蛻舳吮仨氹S時準備好處理這些消息,即使這些消息不是為了響應(yīng)查詢請求。

因此,客戶端在開始讀取查詢響應(yīng)之前,至少應(yīng)該檢查這些情況。服務(wù)端異步發(fā)送給客戶端的消息主要有兩種類型:NoticeResponse 消息和 ParameterStatus 消息。

五、錯誤消息和通知消息

錯誤消息 ErrorResponse 和通知消息 NoticeResponse,通常是在服務(wù)器端處理失敗或者發(fā)生異常場景時,通知客戶端執(zhí)行失敗或者服務(wù)器端異常原因的消息。

錯誤消息和通知消息中可能出現(xiàn)的每個字段類型都有一個單字節(jié)標識,并且任何給定的字段類型在每條消息中最多出現(xiàn)一次。錯誤消息和通知消息中可能出現(xiàn)的字段及其含義如下表所示。


客戶端負責格式化顯示錯誤消息和通知消息的信息以滿足其需要??蛻舳藨?yīng)該根據(jù)需要進行換行等,錯誤消息字段中出現(xiàn)的換行符應(yīng)視為段落分隔符,而不是換行符。

六、其他子協(xié)議簡介

1.?流復(fù)制協(xié)議(Streaming Replication Protocol)和邏輯流復(fù)制協(xié)議(Logical Streaming Replication Protocol)

要啟動流復(fù)制,客戶端在啟動消息中發(fā)送?replication?參數(shù)。replication?參數(shù)為布爾值,值為 true(或 on,yes,1)告訴服務(wù)器端進入物理復(fù)制 walsender 模式,其中可以發(fā)出一組復(fù)制命令,而不是 SQL 語句。

將 database 作為?replication?參數(shù)的值傳遞,指示服務(wù)器端進入邏輯復(fù)制 walsender 模式,連接到 dbname 參數(shù)中指定的數(shù)據(jù)庫。在邏輯復(fù)制 walsender 模式下,可以發(fā)出復(fù)制命令以及正常的 SQL 命令。在物理復(fù)制或邏輯復(fù)制 walsender 模式中,只能使用簡單的查詢協(xié)議。

這兩種協(xié)議,主要應(yīng)用于主備服務(wù)器數(shù)據(jù)同步的場景。流復(fù)制也叫物理復(fù)制,是基于對文件塊的流復(fù)制,邏輯復(fù)制是基于對數(shù)據(jù)元組按照一定格式進行復(fù)制。

2. 加密協(xié)議

(1)SSL 會話加密

如果 PostgreSQL 的構(gòu)建選項使用了 SSL,那么客戶端和服務(wù)器端通信可以使用 SSL 加密。SSL 會話加密在攻擊者可能能夠捕獲會話流量的環(huán)境中提供了通信安全性。

(2)GSSAPI 會話加密

如果 PostgreSQL 的構(gòu)建選項是使用了 GSSAPI,則可以使用 GSSAPI 加密客戶端和服務(wù)器端的通信流量。這在攻擊者可能能夠捕獲會話流量的環(huán)境中提供了通信安全性。

本篇技術(shù)貼中第四、五、六章節(jié)的相應(yīng)內(nèi)容,會在后續(xù)推出的《深度解析 PostgreSQL Protocol v3.0》系列文章中為大家進行詳細展開,對本系列感興趣的小伙伴歡迎關(guān)注我們,第一時間獲取更新內(nèi)容噢。

深度解析 PostgreSQL Protocol v3.0(一)的評論 (共 條)

分享到微博請遵守國家法律
呼和浩特市| 松江区| 乌什县| 轮台县| 繁昌县| 三江| 阳谷县| 太和县| 丰原市| 界首市| 乾安县| 确山县| 康乐县| 延边| 乳源| 樟树市| 宝山区| 嘉鱼县| 湘乡市| 嘉荫县| 克拉玛依市| 明溪县| 澜沧| 宁明县| 桃江县| 连州市| 灌阳县| 安平县| 鸡西市| 都江堰市| 闽侯县| 区。| 万年县| 贺兰县| 永登县| 扶余县| 赤城县| 五莲县| 井陉县| 五大连池市| 新竹市|