PostgreSQL技术内幕(九)libpq通信协议

news2024/12/23 22:44:52

 

libpq通信协议是基于TCP/IP 协议的一套消息通信协议,它允许 psql、JDBC、PgAdmin等客户端程序传递查询给PostgreSQL后端服务器,并接收返回查询的结果。

在这次的直播中,我们为大家介绍了libpq通信协议的实现原理和执行机制,以下内容根据直播文字整理而成。

libpq通信协议简介

通信协议,是指通信双方按控制信息交换规则的标准、约定的集合,即网络上的传输规则。两个实体要成功地通信,必须“说同样的语言”。

libpq协议在TCP/IP模型网络分层中,属于应用层协议的一种。在进行libpq协议通信之前,要先完成连接的建立。libpq协议描述了交互所需的认证握手过程、数据请求应答过程与错误处理过程。

从交互层次来看,libpq通信协议包括建立连接、数据查询、终止链接阶三个阶段, 接下来我们将围绕这三个阶段不同的状态和模式展开阐述。

建立连接阶段(starup阶段)

用户使用libpq 驱动创建与数据库的连接,并发送授权信息,如果一切正常,服务端会反馈状态信息,连接成功创建。

 客户端connect和服务端accept过程示意图

如上图所示,libpq建立连接阶段大致分为三个步骤:连接建立阶段、加密协商阶段、认证协商阶段,其中连接建立阶段是tpc协议的内容,对应代码实现就是connect 和 accept函数。加密协商和认证协商是libpq通信建立连接阶段的重要流程。

建立连接

用户使用libpq创建连接的流程,从代码阶段主要分为三步:

1.创建 PGconn 类型连接对象 conn;

2.连接数据库(通过接口 PQconnectdb /PQconnectdbParams/ PQsetdbLogin);

3.判断连接对象 conn 的状态,若为 CONNECTION_OK ,则连接成功。

用户通过 libpq 与 server 建立连接的过程,主要涉及到两种状态类型:

轮询状态类型PostgresPollingStatusType和连接状态类型ConnStatusType。

  • 轮询状态:

轮询主要是用于等待 conn 对象创建 socket 、写入连接参数、等待 server 返回结果、等待连接认证等。此过程中 conn 对象已经创建,但未完成与 server 的服务连接过程。

连接不是瞬间完成的,需要有一系列的处理过程,在此过程中的等待流程由轮询控制,是一个短暂的过程。PGRES_POLLING_FAILED 和 PGRES_POLLING_OK 为轮询终止的状态条件, PGRES_POLLING_READING,PGRES_POLLING_WRITING 为需要持续询问当前 conn 的状态条件。

在空的conn 对象建立后,轮询进入初始状态 PGRES_POLLING_WRITING,调用 PQconnectPoll 询问到是否需要等待 conn 建立完成。若仍需等待,则继续等待和状态轮询直到连接建立完成,否则错误返回。

  • 连接状态:

PQconnectPoll函数会为客户端连接推进连接状态机,为CONNECTION_MADE状态进行处理,这里的主要工作就是启动认证请求。

在连接过程的任何时候,都可以通过调用PQstatus 来检查连接的状态。如果此时调用返回CONNECTION_BAD,则连接过程失败;如果调用返回 CONNECTION_OK,则连接准备就绪。这两种状态都可以从 PQconnectPoll 的返回值中检测到。

在异步连接过程期间(并且仅在期间)也可能出现其他状态,比如writing ,代表客户端要给服务端发送认证、协商信息;reading 代表等待服务端返回信息包。

加密协商

加密协商阶段是在连接建立后进行的第一个阶段,为了保证后续的认证协商阶段中会话信息不会泄漏,需要先对连接进行通信加密。

加密协商阶段是可选的,只有开启GSSAPI认证或者SSL认证才会执行。在这一阶段,客户端调用PQconnectPoll函数中,ConnStatusType连接状态处于CONNECTION_NEEDED,然后调用connect函数去连接服务端,连接状态会转变为CONNECTION_STARTED。

这个时候,服务端postmaster会执行如下调用:StreamConnection函数会使用服务器端口创建与客户端的新连接,将 port->sock 设置为新连接的 FD。连接新建成功后,postmaster会调用BackendStartup为该客户端连接创建postgres后端服务子进程。

下一步,PQconnectPoll函数会尝试为此连接推进状态机,为CONNECTION_MADE状态进行处理,启动认证请求,并构建启动包。

如果编译宏参数ENABLE_GSS 或者USE_SSL开启,则进行加密协商。

加密协商过程如下:

client->server(协议版本信息)

加密协商阶段是在连接建立后进行的第一个阶段,为了保证后续的认证协商阶段中会话信息不会泄漏,需要先对连接进行通信加密。

server处理流程:

ServerLoop->BackendStartup->BackendInitialize->ProcessStartupPacket(处理加密)

认证协商

当加密协商阶段完成或跳过后,libpq 协议将开始进行认证阶段。认证阶段由 Startup message 消息开始,消息格式以消息长度开始,随后紧跟协议版本号,然后是键值对形式的连接信息,如用户名、数据库以及其他 GUC 参数和值。

前端发出Startup message 消息后,后端会进行认证应答,认证应答信息的类型为“R ”,其内容大致分为 3 种情况:完成认证(相当于不需要认证,此时用户不需要验证密码)、提供认证方式与所需的参数、认证错误。

前端通过认证应答信息提供的认证方式(如果有的话)向后端发送认证请求,

认证请求消息中包含后端所需要的认证参数,例如密码或密码的MD5 值等。

认证错误消息ErrorResponse 会导致后端直接关闭连接,停止认证协商。

认证请求的类型为“ P ”,其内容需要根据上下文进行推断,例如之前认证应答消息中的认证方式为 MD5,则认证请求消息中的内容就为密码的 MD5 值。

前端向后端发送认证请求后,后端会再次根据认证请求中的内容进行认证应答,直到认证完成或认证错误。所以,认证阶段完成的标志是:后端发送的内容为认证完成的认证应答消息或者发送了ErrorResponse 的认证错误消息。

当认证完成时,后端会在认证应答信息后发送一些其他协议,来通知前端一些必要的参数,其中有:

  • 类型为“ S ”的 ParameterStatus :是一个 Key-value 对,进行参数设置;
  • 类型为“ K ”的 BackendKeyData:描述了一个取消请求的 Key,主要用户在开始阶段时 Cancel request 需要的 Key 值,用于在一个新建会话中中断另一个会话中阻塞操作;
  • 类型为“ Z ”的 ReadyForQuery:代表后端已经准备好开始一个新的数据请求。

  • 至此,一个建立连接的过程已经完全准备完成。建立连接的状态图如下:

连接建立流程逻辑示意图 

数据查询阶段(normal阶段)

数据查询阶段,客户端和服务端所有通信都通过消息流进行。消息的第一个字节标识消息类型,随后四个字节标识消息内容的长度(该长度包括这四个字节本身),具体的消息内容由消息类型决定。


服务端支持消息类型为PostgresMain 函数;客户端支持处理消息类型为pqParseInput3 函数。数据查询阶段常用的通信模式有三种,分别为Simple query、Extended query和Copy data。

Simple query模式:客户端通过 Query 消息发送一个文本命令给服务端,服务端处理请求,回复查询结果。查询结果通常包括两部分内容:结构和数据。结构通过 RowDescription 消息传递,包括列名、类型 OID 和长度等;数据通过 DataRow 消息传递,每个 DataRow 消息中包含一行数据。

每个命令的结果发送完成之后,服务端会发送一条CommandComplete 消息,表示当前命令执行完成。客户端的一条查询请求可能包含多条 SQL 命令,每个 SQL 命令执行完都会回复一条 CommandComplete 消息,查询请求执行结束后会回复一条 ReadyForQuery 消息,告知客户端可以发送新的请求。消息流如下:

Simple query消息流示意图 

Extended query模式:Extended query 协议将以上 Simple query 的处理流程分为若干步骤,每一步都由单独的服务端消息进行确认。Extended query 协议通常包括5个步骤,分别是 Parse、Bind、Describe、Execute 和 Sync,这里不再展开讲述。

Extended query 协议可以使用服务端的 prepared-statement 功能,即先发送一条参数化 SQL,服务端收到 SQL(Statement)之后对其进行解析、重写并保存,这里保存的 Statement 也就是Prepared-statement,可以被复用;执行 SQL 时,直接获取事先保存的 Prepared-statement 生成计划并执行,避免对同类型 SQL 重复解析和重写;随后,服务端会在适当的条件下缓存计划,以备后续复用。

PGQUERY_EXTENDED查询协议将一个SQL的执行过程拆分成三个层次,相邻的两个层次间抽象出statement和portal对象,每个层次允许单独重复调用,并且在当前连接的生命周期内,也允许再次调用,使整个SQL的执行过程具有了可重复利用性,对中间结果的保存减少了重复调用,节省了执行开销,也提高了执行速度。Extended query 完整消息流如下图所示:

 Extended query消息流示意图

Copy data 模式:为高效地导入/导出数据,libpq 支持 Copy 命令,Copy操作会将当前连接切换至一种截然不同的消息通信方式。

Copy data对应三种模式:copy-in 导入数据,对应命令 COPY FROM STDIN;copy-out 导出数据,对应命令 COPY TO STDOUT;copy-both 用于 walsender,在主备间批量传输数据。

以copy-in 为例,服务端收到 COPY 命令后,进入 COPY 模式,并回复 CopyInResponse。随后客户端通过 Copydata 消息传输数据,CopyComplete 消息标识数据传输完成,服务端收到该消息后,发送 CommandComplete 和 ReadyForQuery 消息,消息流如下图所示:

Copy data消息流示意图 

终止阶段

这一阶段流程相对简单,客户端请求结束后,可以主动发送消息断开连接。服务端接收到客户端的终止消息后,直接退出进程。


总结

通过 libpq 与 PostgreSQL 建立连接是一个比较复杂的过程,主要通过 libpq 所在的 client 端进行驱动:发起请求,等待响应。

在建立连接轮询状态机、建立连接流程状态机和设置环境变量状态机中,有些状态会存在多次转换以完成连接建立的过程。经过连接建立、加密协商、认证协商三个阶段之后,一个连接到PostgreSQL 的 PGconn 连接对象就准备完成,应用程序可以通过该对象进行后续各种业务的执行,向 Server 发起请求,并解析返回结果。

本次分享为大家介绍了如何使用 libpq 建立与 PostgreSQL Server 的连接,并使用连接发送业务请求。对libpq协议感兴趣的同学可关注HashData公众号,了解更多libpq通信协议技术细节。

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

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

相关文章

发挥AMS、PMS和WMS在框架层服务作用,简化开发过程

Framework底层服务是Android操作系统提供的一组核心服务和功能,用于支持应用程序的开发和运行。这些底层服务提供了许多功能和特性,帮助开发者构建稳定、高效和功能丰富的Android应用程序。 Framework底层服务作用: 管理应用程序的生命周期…

小白到运维工程师自学之路 第五十一集 (三剑客之sed)

一、概述 sed是一个流式文本编辑器,可以对文本进行搜索、替换、删除等操作。它是一个非交 互式的命令行工具,通常用于处理大量的文本数据。sed的工作方式是逐行读取输入文 本,按照预定义的命令对每一行进行处理,并输出结果。它…

[Linux] 最基础简单的线程池 及其 单例模式的实现

本篇文章主要用到线程相关内容, 下面是博主关于线程相关内容的文章: [Linux] 线程同步分析:什么是条件变量?生产者消费者模型是什么?POSIX信号量怎么用?阻塞队列和环形队列模拟生产者消费者模型 [Linux] 线程互斥分析: 多线程的问…

Python接口自动化测试--requests高级进阶

Cookies与会话对象 如果某个响应中包含一些Cookie,你可以快速访问它们: import requests r requests.get(http://www.google.com.hk/) print(r.cookies[NID]) print(tuple(r.cookies)) 要想发送你的cookies到服务器,可以使用 cookies 参…

xShell中使用vim编辑时,无法粘贴外来文本

鼠标右键弹出菜单时,vim直接变成了视图模式了,不能粘贴了。。 好,执行命令 vim ~/.vimrc输入: set mousec即可。 此时便可以粘贴了。

「观察者(Observer)」设计模式 Swift实现

这里写目录标题 介绍设计模式介绍举例 iOS 中已有的 观察者设计模式实现Notification什么是通知机制或者说如何实现通知机制? KVOKVO底层实现如何实现手动KVO? 介绍 设计模式介绍 观察者设计模式(Observer Pattern)是一种行为型…

win10电脑出现网络问题时,如何解决?

我们的Windows可能会出现各种网络连接问题: 尝试连接Wi-Fi网络时出现错误:Windows无法连接到此网络;您可以通过Wifi访问互联网,但通过电缆访问以太网却无法正常工作;尝试通过电缆连接互联网时出现错误: Wi…

图数据库:neo4j学习笔记

参考资料:neo4j 教程_w3cschool Springboot集成Neo4j_喝醉的咕咕鸟的博客-CSDN博客 SpringBoot 整合 Neo4j_springboot neo4j_$懒小猿$的博客-CSDN博客 图数据库Neo4j实战(全网最详细教程)_neo4j使用教程_星川皆无恙的博客-CSDN博客 代码片段…

Flink DataStream之输出数据到File中

新建类 package test01;import org.apache.flink.api.common.serialization.SimpleStringEncoder; import org.apache.flink.configuration.Configuration; import org.apache.flink.configuration.MemorySize; import org.apache.flink.connector.file.sink.FileSink; import…

Model, ViewModel, EnvironmentObject 的使用

1. Model 数据模型的定义与使用 1.1 案例 struct UserModel: Identifiable{let id: String UUID().uuidStringlet dispalyName: Stringlet userName: Stringlet followerCount: Intlet isVerified: Bool }/// 数据模型 struct ModelBootcamp: View {State var users:[Use…

web 禁用 OPTIONS方法启用【原理扫描】

Web服务器上启用了HTTP OPTIONS方法。 OPTIONS方法提供了Web服务器支持的方法列表,它表示对有关由Request-URI标识的请求/响应链上可用的通信选项的信息的请求。 直接在IIS上进行关闭即可:

osg osgDB::readImageFile 返回空指针 解决中

在 osg功能开发中,需要用到 纹理 加载图片,最神奇的之前 好好的。 现在 把osg 编译成了 osg 342vs2013x86 环境 就出现幺蛾子了,之前是使用的 osg364vs2013x86。结果 命令行运行 加载图片 直接 有 warning 提示。还在处理中! 提示 找不到文…

Nginx 的Nacos配置

进入nginx 配置目录 cd /usr/local/nginx/conf 2. 编辑nginx配置文件 vi nginx.conf 3. 增加对Nacos 的代理 upstream nacosServerList {server 192.168.172.102:8848;server 192.168.172.103:8848;server 192.168.172.104:8848; } # Nacos地址服务器寻址配置 server {#监听端…

微信小程序第六节——个体账号如何实现用户自定义内容

📌 微信小程序第一节 ——自定义顶部、底部导航栏及获取胶囊位置信息。 📌 微信小程序第二节 —— 微信小程序第二节 —— 自定义组件。 📌 微信小程序第三节 —— 页面跳转的那些事儿。 📌 微信小程序第四节 —— 网络请求那些事…

matlab GUI入门

matlab GUI入门 两种方法 法一:使用guide 法二:使用appdesigner(推荐,更直观) winopen(cd) 打开当前路径。 ctrlI 代码自动对齐 matlab 导入数据文件 导入图片数据 用imread()函数导入…

第 3 章 Spark 通讯架构

3.1 Spark 通信架构概述 3.1 Spark 通信架构概述 Spark 中通信框架的发展: ➢ Spark 早期版本中采用 Akka 作为内部通信部件。 ➢ Spark1.3 中引入 Netty 通信框架,为了解决 Shuffle 的大数据传输问题使用 ➢ Spark1.6 中 Akka 和 Netty 可以配置使用。…

bug的合规描述

bug的合格描述: 发现问题的版本bug的合格描述: 开发人员需要知道出现问题的版本,才能够获取对应版本的代码来重现故障问题出现的环境 环境分为硬件环境和软件环境,详细的环境描述有利于故障的重现(如果是web项目,需…

到手价的监测要求和方法

品牌在做电商价格监测时,为什么要对到手价进行监测,这其中的原因还是很显现的,各平台的促销信息众多,如果只监测页面价的低价行为,那将有非常多的低价链接不会被发现,而这也会导致品牌做渠道管控时失去公平…

如何随机切换代理IP以避免被封禁?

在网络爬虫和数据抓取的领域,使用代理IP技术是非常常见的做法。使用代理IP可以有效地绕过网站的访问限制,提高访问速度和稳定性。然而,如果我们在访问网站时只使用一个代理IP,那么可能会被网站封禁,从而导致访问失败。…

开源预训练框架 MMPRETRAIN官方文档(高级指南)

1、准备数据集 1、自定义数据集(下面都是分类数据的自定义数据集准备) CustomDataset是一个通用数据集类,供您使用自己的数据集。要使用CustomDataset,您需要根据以下两种格式组织数据集文件: 1、子文件夹格式 在这…