ShardingSphere-Proxy 数据库协议交互解读

news2024/9/21 12:24:21

数据库协议对于大部分开发者来说算是比较冷门的知识,一般的用户、开发者都是通过现成的数据库客户端、驱动使用数据库,不会直接操作数据库协议。不过,对数据库协议的特点与流程有一些基本的了解,有助于开发者在排查数据库功能、性能问题的过程中提供一些发现问题的思路。

本文将简要介绍常用的 MySQL、PostgreSQL 等开源数据库协议的特点,并大致解读 ShardingSphere-Proxy 与客户端在数据库协议层面的交互。

文章目录

    • ShardingSphere 接入端介绍
    • 数据库协议特点简要介绍
      • MySQL 协议
      • PostgreSQL 协议
      • openGauss 协议
    • ShardingSphere-Proxy 前端交互流程解读
      • ShardingSphere-Proxy 与数据库协议的关系
      • 接入端整体流程
      • ShardingSphere-Proxy 前端流程
    • 如何向 ShardingSphere 社区反馈疑似 Proxy 协议问题?
      • 问题复现方式简单的可提供 Demo
      • 直接提交问题修复 PR
      • 使用抓包工具捕获客户端与 Proxy 的通讯流量

ShardingSphere 接入端介绍

Apache ShardingSphere 由 ShardingSphere-JDBC 和 ShardingSphere-Proxy 这 2 款既能够独立部署,又支持混合部署配合使用的产品组成。它们均提供标准化的基于数据库作为存储节点的增量功能,可适用于如 Java 同构、异构语言、云原生等各种多样化的应用场景。

在这里插入图片描述

ShardingSphere-JDBC 是一套基于 Java 开发的、实现了标准 JDBC 的 SDK,具备轻量级、高性能等特点,但局限性同样也很明显。不过,ShardingSphere-JDBC 在接入方面的局限性,在接入端 ShardingSphere-Proxy 得以解决:

  • ShardingSphere-Proxy 理论上支持通过任何数据库客户端、数据库驱动连接,不受限于 Java 等基于 JVM 的语言;
  • 简化数据管理。尤其在使用数据分片或加密等功能的场景,使用 ShardingSphere-Proxy 作为统一入口操作数据,无须考虑数据实际存储的节点或手动进行解密等;
  • 提供统一运维管控能力。集群模式下,可以使用 ShardingSphere-Proxy 统一管理 ShardingSphere 规则与配置;
  • 可执行重量级操作。ShardingSphere-JDBC 与应用在同一进程内,重量级计算和 I/O 操作可能会影响应用性能;而 ShardingSphere-Proxy 作为独立进程启动,支持水平扩展,执行重量级操作不影响应用性能。

数据库协议特点简要介绍

目前互联网上已有不少关于 MySQL 或 PostgreSQL 协议的具体解读,本文不再详细介绍,本节主要介绍各数据库协议的特点,例如协议对 Pipelining 的支持、批量操作在协议的体现等。

MySQL 协议

MySQL 协议是典型的“一问一答”协议,例如使用 Prepared Statement 执行一条 SQL,在协议层面需要分别执行 COM_STMT_PREPARECOM_STMT_EXECUTE
在这里插入图片描述

图片来源 MySQL 文档 https://dev.mysql.com/doc/dev/mysql-server/latest/mysqlx_protocol_use_cases.html

MySQL 自 5.7.12 起增加了一个 X Plugin,让 MySQL 在保持原本关系型存储的基础上,增加了文档类型存储的支持。
X Plugin 使用了一套新的通讯协议 X Protocol,默认使用端口 33060,协议支持 pipelining,即客户端一次可以发送一批命令给客户端,减少“一问一答”的模式带来的 RTT(Round-trip time,来回通讯延时)。例如使用 Prepared Statement 执行一条 SQL,在协议层面分为 Prepare 和 Execute 步骤,但在网络传输层面上,这两个步骤可以合并发送。相比原来的协议,理论上能够减少一次 RTT。
在这里插入图片描述
图片来源 MySQL 文档 https://dev.mysql.com/doc/dev/mysql-server/latest/mysqlx_protocol_use_cases.html

不过,目前 MySQL 的 X Plugin 看起来并没有流行的趋势,大多数场景下客户端和服务端还是基于原本的 MySQL 协议进行通讯。
在批量操作的场景下,MySQL 协议执行 Prepared Statement 语句的命令 COM_STMT_EXECUTE 每次只能发送一组参数,“一问一答”的方式显得效率有些低下:
在这里插入图片描述
图片来源 MySQL 文档 https://dev.mysql.com/doc/dev/mysql-server/latest/mysqlx_protocol_use_cases.html

协议本身设计对批量操作的不支持,只能在客户端层面对批量操作进行优化。

以 MySQL Connector/J 为例,参数 rewriteBatchedStatements 启用后,MySQL Connector/J 内部会把通过 addBatch 方法设置的多组参数,合并 insert values 或将 update / delete 组成多语句,在协议层面一次性发送。通过增加少量 CPU 的开销,换取 RTT 的减少。

例如,对一个 Prepared Statement insert 语句,添加多组参数执行:

INSERT INTO tbl VALUES (?, ?, ?);
addBatch [1, "foo", "bar"]
addBatch [2, "baz", "fuz"]

MySQL Connector/J 实际执行的语句:

INSERT INTO tbl VALUES (1, "foo", "bar"),(2, "baz", "fuz");

对于批量 update / delete,MySQL Connector/J 会通过 COM_QUERY 执行多语句,例如:

UPDATE tbl SET name = ? WHERE id = ?;
addBatch ["foo", 1]
addBatch ["bar", 2]

MySQL Connector/J 实际执行的语句:

UPDATE tbl SET name = "foo" WHERE id = 1;UPDATE tbl SET name = "bar" WHERE id = 2;

PostgreSQL 协议

与 MySQL 协议相比,PostgreSQL 协议定义看起来会更简单一些,而且 PostgreSQL 协议支持 Pipelining。
PostgreSQL 的 Extended Query 将 SQL 执行拆解为多个步骤,常用的几个操作有:

  • Parse:SQL 解析为 Prepared Statement;
  • Describe:获取 Prepard Statement 或 Portal 的元数据;
  • Bind:Prepared Statement 绑定实际参数,产生可执行的 Portal;
  • Execute:执行 Portal;
  • Close:关闭 Prepared Statement 或 Portal。

PostgreSQL JDBC 与数据库的协议交互示例如下:
在这里插入图片描述

在批量操作的场景下,客户端可以将多组参数以连续的 Bind、Execute 一次性发送,虽然在协议层上是多个数据包,但在 TCP 传输层面,每次可以发送一批数据包出去。
在这里插入图片描述

支持 Pipelining 的协议,结合 I/O 多路复用,在吞吐量上存在一定的优势。例如基于多路复用 I/O 的数据库驱动 Vert.x PostgreSQL 曾在 TechEmpower Benchmark 第 15 轮测试的 Single Query 场景(数据库点查)得到第一名的成绩。
在这里插入图片描述
图片来源 https://www.techempower.com/benchmarks/#section=data-r15&test=db

openGauss 协议

openGauss 在沿用 PostgreSQL Protocol 3.0 的情况下,增加了一个 Batch Bind 的消息。PostgreSQL 协议的 Bind 消息一次只能发送一组参数,openGauss 新增的 Batch Bind 支持同时发送多组参数。
在这里插入图片描述
另外,openGauss 在认证安全性方面进行了增强。协议总体流程与 PostgreSQL 一致。

ShardingSphere-Proxy 前端交互流程解读

ShardingSphere-Proxy 与数据库协议的关系

数据库协议如同 HTTP 等协议,是客户端与服务端之间通讯的标准。每个数据库都定义了自己的协议,例如 MySQL 数据库定义了一套自己的协议,还有基于 Protobuf 的 X Protocol;PostgreSQL 也定义了一套自己的协议……

一般用户或开发者都是使用现成的客户端或相应的驱动,协议对于他们来说相对透明。因此,ShardingSphere-Proxy 实现数据库协议并以此对外提供服务,对于用户来说,使用 ShardingSphere-Proxy 就如同使用数据库一样。

目前,ShardingSphere-Proxy 支持的数据库协议具体版本为:

  • MySQL Protocol 4.1(自 MySQL 4.1 起)
  • PostgreSQL Protocol 3.0(自 PostgreSQL 7.4 起)
  • openGauss Protocol 3.00 / 3.50 / 3.51

接入端整体流程

ShardingSphere-Proxy 与 ShardingSphere-JDBC 共用 ShardingSphere 内核模块,对用户提供了不同的接入方式。ShardingSphere-Proxy 是一个独立进程存在,以数据库协议对外提供服务;ShardingSphere-JDBC 是一套 SDK,用户直接通过代码调用。
在这里插入图片描述

ShardingSphere-Proxy 前端流程

ShardingSphere-Proxy 前端使用 Netty 实现数据库协议。基于 Netty 事件驱动的方式处理前端连接,让 ShardingSphere-Proxy 前端可以维护较大数量的客户端连接。协议的拆包、编码逻辑主要在 Netty EventLoop 线程内执行。由于 ShardingSphere-Proxy 后端仍然使用 JDBC 与数据库交互,为避免 Netty EventLoop 线程阻塞,协议数据拆包后,会使用专门的线程池执行 ShardingSphere 内核逻辑、数据库交互。
在这里插入图片描述

PacketCodec 主要进行数据的拆包和编码。在前面的数据库协议介绍提到,PostgreSQL 协议支持 pipelining,能够一次发送一批数据包。

示例:下图是 PostgreSQL 客户端使用 Prepared Statement 执行 select current_schema() 语句所对应的请求协议。Prepared Statement 的 SQL 解析、执行等步骤,由客户端一次性发送给服务端执行。
在这里插入图片描述
服务端接收到的就是一串字节流,如何能够把这一串字节流拆分为多个协议包?

以 PostgreSQL 协议格式为例,除了 Startup Message,每个协议包的格式都是 1 字节消息类型 + 4 字节数据长度(包含长度自身)+ 数据,结构如下:
在这里插入图片描述
MySQL 协议数据包格式与此相似。

PacketCodec 只需遵循协议格式定义,即可把接收到的字节流正确拆分。

字节流拆分后,剩余的步骤就是按照数据库协议解析数据,得到要执行的 SQL 与参数。有了 SQL 与参数后,剩余的执行流程就与通过 ShardingSphere-JDBC 执行 SQL 基本一致。

ShardingSphere-Proxy 后端通过 JDBC 执行 SQL 后,得到的结果集为 Java 对象,PacketCodec 会调用具体的编码逻辑,将 Java 对象按照数据库协议转换为字节流,组装成数据包后响应客户端。

在这里插入图片描述
以上就是 ShardingSphere-Proxy 前端数据库协议交互的大致流程。

如何向 ShardingSphere 社区反馈疑似 Proxy 协议问题?

由于 ShardingSphere-Proxy 与数据库的计算能力存在差异,Proxy 对数据库协议的实现尚未达到 100% 的支持度,在使用过程中难免会存在一些不支持的情况,且不支持的情况在不同的数据库客户端、数据库驱动之间存在一定差异。

当用户在使用 Proxy 的过程中,遇到疑似 Proxy 协议实现不完善导致的问题,本文给出一些反馈问题的建议。

问题复现方式简单的可提供 Demo

如果遇到的问题,能够通过构造出简单的代码复现(例如只需使用 Python 语言并安装一些简单的依赖),可以在 issue 中直接提供复现问题的代码与步骤。

案例:社区同学曾经提交过一个 Django.db 连接 ShardingSphere-Proxy MySQL 的事务问题 https://github.com/apache/shardingsphere/issues/18461

作者在 issue 中提供了复现的方式,为 ShardingSphere 团队修复该问题提供了帮助。

直接提交问题修复 PR

对于一些相对简单的问题,ShardingSphere 团队可以提供修复的思路,有条件的社区同学可以考虑直接提交 PR 修复。

案例:社区同学反馈了一个通过 Python asyncpg 连接 ShardingSphere-Proxy 报错的问题:https://github.com/apache/shardingsphere/issues/23885

该问题为 Python asyncpg 数据库驱动在向 ShardingSphere-Proxy 发送 client_encoding 时,在编码名称上增加了引号。由于 ShardingSphere-Proxy PostgreSQL 没有考虑到编码名称包含引号的情况(PostgreSQL 数据库支持这种情况),导致编码识别报错。
Issue 作者已经具备了复现问题的条件,加上作者具备修复该问题的技能,便在 ShardingSphere 团队的指导下,直接提交了 PR 修复该问题。

使用抓包工具捕获客户端与 Proxy 的通讯流量

对于一些使用异构语言的用户,在使用 ShardingSphere-Proxy 过程中可能会遇到和具体功能不相关、疑似协议层面的问题。由于用户与 ShardingSphere 团队存在技术栈上的差异,ShardingSphere 团队可能无法快速在本地完成问题的复现。此时可以考虑通过捕捉客户端与 ShardingSphere-Proxy 之间网络流量的方式,向 ShardingSphere 社区反馈问题。

抓包工具可以选择 Wireshark 或 tcpdump。工具的使用互联网上有大量资料,本文不展开介绍。

案例:社区同学前段时间提交了一个 .NET MySqlConnector 使用 ShardingSphere-Proxy 报错的问题:
https://github.com/apache/shardingsphere/issues/23857

Issue 中反馈了一个 .NET 连接 ShardingSphere-Proxy 报错的问题,根据堆栈,该报错是在 TryResetConnectionAsync 期间导致的,而且最后抛出异常的地方是在 Protocol 相关代码下,所以这可能是一个 ShardingSphere-Proxy 协议实现与 MySQL 表现不一致导致的问题。

    An error occurred using the connection to database .....

 MySqlConnector.MySqlProtocolException: Packet received out-of-order. Expected 1; got 2.
         at MySqlConnector.Protocol.Serialization.ProtocolUtility.<DoReadPayloadAsync>g__AddContinuation|5_0(ValueTask`1 readPacketTask, BufferedByteReader bufferedByteReader, IByteHandler byteHandler, F
unc`1 getNextSequenceNumber, ArraySegmentHolder`1 previousPayloads, ProtocolErrorBehavior protocolErrorBehavior, IOBehavior ioBehavior) in /_/src/MySqlConnector/Protocol/Serialization/ProtocolUtility.cs:
line 476
         at MySqlConnector.Core.ServerSession.ReceiveReplyAsyncAwaited(ValueTask`1 task) in /_/src/MySqlConnector/Core/ServerSession.cs:line 943
         at MySqlConnector.Core.ServerSession.TryResetConnectionAsync(ConnectionSettings cs, MySqlConnection connection, IOBehavior ioBehavior, CancellationToken cancellationToken) in /_/src/MySqlConnect
or/Core/ServerSession.cs:line 616

由于该问题的复现具备一定的环境搭建成本,不便于 ShardingSphere 团队在本地复现问题,社区同学也提供了客户端与 Proxy 之间协议通讯流量。

在这里插入图片描述

根据协议抓包结果,ShardingSphere 团队立即确认了该问题为 ShardingSphere-Proxy MySQL 数据包编码逻辑实现问题。


🔗 官方网站:
https://shardingsphere.apache.org

🔗 GitHub:
https://github.com/apache/shardingsphere

🔗 Slack:
https://apacheshardingsphere.slack.com

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

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

相关文章

Fabric磁盘扩容后数据迁移

线上环境原来的磁盘比较小&#xff0c;随着业务数据的增多&#xff0c;磁盘需要扩容&#xff0c;因此需要把原来docker数据转移至新的数据盘。 数据迁移 操作系统&#xff1a; centOS 7   docker默认的数据目录为/var/lib/docker   创建一个新的目录/opt/dockerdata&…

Halcon转OpenCV实例--OCR字符识别(附源码)

导 读 本文主要介绍Halcon转OpenCV实例--OCR字符识别(附源码)。 实例来源 实例来源于51Halcon论坛的帖子,原贴地址: https://www.51halcon.com/forum.php?mod=viewthread&tid=889 Halcon实现 测试图: 实现代码与效果: read_image (Image, ET.png)decompose3…

智慧园区解决方案

智慧园区解决方案 智慧园区是以互联网为载体&#xff0c;“互联网产业”融合产业模式为手段&#xff0c;面向园区提供全产业链支撑服务的解决方案。能够帮助园区在信息化方面建立统一的组织管理协调架构&#xff0c;业务管理平台和对内对外服务运营平台。将相关资源形成紧密联…

Java最新学习路线

Java语言是目前流行的互联网等企业的开发语言&#xff0c;是市面上很多程序员喜欢并且在用的程序设计语言。关于学习java&#xff0c;有一部分人是为了就业或自己创业&#xff0c;而大多数人是希望使用java这个开发语言用来工作&#xff0c;开发出计算机后端系统&#xff0c;利…

python带你采集回车桌面高清写真壁纸

前言 大家早好、午好、晚好吖 ❤ ~ 壁纸嘛~大家都在用&#xff0c;每个人喜欢的壁纸类型也不同 那今天来教大家怎么批量保存一批高质量壁纸~ 开发环境: Python 3.8 Pycharm 模块使用: requests >>> pip install requests 数据请求 parsel >>> pip instal…

soapui + groovy 接口自动化测试

1.操作excel的groovy脚本 package pubimport jxl.* import jxl.write.Label import jxl.write.WritableWorkbookclass ExcelOperation {def xlsFiledef workbookdef writableWorkbookdef ExcelOperation(){}//设置xlsFile文件路径def ExcelOperation(xlsFile){this.xlsFile x…

景联文科技:您的模型性能问题需要标注数据来解决

为什么需要重新考虑模型开发当人们想到人工智能时&#xff0c;他们的脑海中常常充满对未来世界幻想的画面&#xff0c;在这个世界中&#xff0c;算法为机器人提供动力&#xff0c;这些机器人负责处理他们的日常职责。他们的虚拟助手为他们提供建议并管理他们的日程安排&#xf…

数组的复制与二维数组的用法

今天学习的主要内容有 数组的复制 数组的复制 利用循环进行数组的复制 import java.util.Arrays; public class Main3 {public static void main(String[] args) {int []arr new int[]{1,2,3,4,5,6};int []arr1 new int[arr.length];for (int i 0; i < arr.length; i…

SpringBoot 整合 Redis 缓存

文章目录前言1、缓存 概念知识1.1、什么是缓存1.2、缓存的优缺点1.3、为什么使用缓存2、Redis 概念知识2.1、Redis 简介2.2、为什么用 Redis 作为缓存2.3、Redis 支持的数据类型2.3、Redis是如何判断数据是否过期2.4、过期的数据的删除策略2.5、Redis 事务2.6、Redis 持久化机制…

Windows软件界面字体和图标太小的解决办法

有时候我们装好软件之后&#xff0c;打开软件会发现部分字体变得非常小&#xff0c;难以看清屏幕中的文字&#xff0c;如图所示&#xff1a; 下面小编在这里以Windows 11系统&#xff08;其余版本Windows系统的设置步骤没有改变&#xff0c;只是部分选项的位置有所改变&#xf…

开发不停机的服务程序

使用守护进程、心跳机制、调度程序实现服务程序永不死机。 调度程序:启动服务程序&#xff0c;服务程序死掉后调度程序休眠n秒再次调度。 进程心跳:使用共享内存维护自己的心跳信息&#xff0c;当前时间减去最新时间如果大于超时时间就认为故障了&#xff0c;守护进程就会遍历…

共享模型之不可变

1.日期转换的问题 1>.代码示例 Slf4j public class TestDateFormatDemo1 {public static void main(String[] args) {SimpleDateFormat sdf new SimpleDateFormat("yyyy-MM-dd");for (int i 0; i < 10; i) {//多个线程调用日期格式化对象的方法new Thread(…

kafka监控工具安装和使用

1. KafkaOffsetMonitor 该监控是基于一个jar包的形式运行&#xff0c;部署较为方便。只有监控功能&#xff0c;使用起来也较为安全(1)消费者组列表 (2)查看topic的历史消费信息. (3)每个topic的所有parition列表(topic,pid,offset,logSize,lag,owner) (4)对consumer消费情况进…

使用Eureka搭建单击模拟到集群模拟

首先讲讲什么是Eureka:1.Eureka是Netflix的子模块&#xff0c;同样也是核心模块之一&#xff0c;Eureka是基于REST的服务&#xff0c;用于定位服务&#xff0c;以实现云端中间件层服务发现和故障转移&#xff0c;服务注册与发现对于微服务来说是非常重要的&#xff0c;有了服务…

vue项目第三天

论坛项目动态路由菜单以及渲染用户登录全局前置拦截器获取用户的菜单以及接口执行过程解析菜单数据&#xff0c;渲染伟动态路由。菜单数据将数据源解析为类似路由配置对象的格式&#xff08;./xxx/xxx 这种格式&#xff09;。下方是路由实例的代码,后面封装了很多方法这里也需要…

RFID服装吊牌材质分类

1、吊牌常见材质 铜版纸&#xff1a;最常用&#xff0c;分单铜纸、双铜纸 白卡纸&#xff1a;厚度较厚 黑卡纸&#xff1a;黑卡纸常用于烫金、烫银工艺 牛皮纸&#xff1a;韧度较高、色彩单一 塑料材料&#xff1a;一般一些比较高档的品牌会选塑料材质&#xff0c;成本比铜…

电商CRM的作用和用途

数据显示&#xff0c;使用电商CRM客户管理系统后&#xff0c;企业销售额提高了87%&#xff0c;客户满意度提高了74%&#xff0c;业务效率提高了73%。要在竞争激烈的电商市场取得成功&#xff0c;与目标受众的有效沟通是有效的方法。下面说说什么是电商CRM系统&#xff1f;电商C…

Docker镜像和容器操作,ლ(´ڡ`ლ)好吃的.

文章目录1.镜像操作1.镜像命令2.情景1&#xff1a;拉取镜像3.情景2&#xff1a;保存导入镜像2.容器操作1.容器命令2.情景1&#xff1a;创建并运行一个容器3.情景2&#xff1a;进入容器&#xff0c;修改文件3.结语halo&#xff0c;大家好&#xff0c;这次我带来的是Docker的一些…

SATA SSD需要NCQ开启吗?

一、故事开篇最近有同学在咨询&#xff0c;SATA SSD是否需要NCQ功能&#xff1f;借此机会&#xff0c;今天我们来聊聊这个比较古老的话题&#xff0c;关于SATA协议的NCQ的故事。首先我们先回顾下SATA与NCQ的历史&#xff1a;2003年&#xff0c;SATA协议1.0问世&#xff0c;传输…

微服务中API网关的作用是什么?

目录 什么是API网关&#xff1f; 为什么要用API网关&#xff1f; API网关架构 API网关是如何实现这些功能的&#xff1f; 协议转换 链式处理 异步请求 什么是API网关&#xff1f; Api网关是微服务的重要组成部分&#xff0c;封装了系统内部的复杂结构&#xff0c;客户端…