最近在网上逛的时候看到一篇关于数据库中间件设计的文章,嗯,讲的还比较详细,转载之,再附上自己的一点点感想,原文出自《假如让你来设计数据库中间件》,原文如下:

13年底负责数据库中间件设计时的设计文档,拿出来和大家分享:

  • 可以了解下数据库中间件技术

  • 可以了解下架构师系统设计的思路

一、总体目标

数据库中间层项目背景不再展开,根据前期的调研以及和公司同事的讨论,中间层的核心目标主要有两个:

  • db虚拟化:让db对业务线透明(本文的db均指mysql),业务线不再需要知道db的真实ip,port,主从关系,读写关系,高可用等

  • 分库的支持:让db的分库对业务线透明

二、实现的功能

上述目标相对比较宽泛,具体来说,数据库中间层需要实现以下功能。

(1)统一接入入口

如果统一接入入口,从今以后,不再有

db1.58.com:3306

db2.58.com:3306

im.58.com:3306

jiaoyou.58.com:3306

只有

db.58.com:3306

所有的业务线,对db的访问,都只有一个入口,由数据库中间层来进行权限验证,由中间件来路由请求,这是一种完美的情况。

当然,统一一个总入口目标有点宏大,可以循序渐进,先各业务线统一读写访问入口,故折衷的目标可以是,从今以后,不再有

im.read.db1.58.com:3306

im.read.db2.58.com:3306

im.write.db.58.com:3306

而只有

im.58.com:3306

im业务对db的访问,统一到一个入口上来了,由中间层来对请求进行智能路由。

更简化的,甚至可以初期同一个业务线的db读写都不对业务线透明,数据库中间层只做简单的请求转发,先初步的把数据库访问入口收拢到数据库中间层来,为后续的统一,再统一打下基础。

ROAD-MAP规划如下:

  • 业务线入口统一(中转请求)

  • 业务线入口统一(智能路由)

  • 全局入口统一

(2)保持访问接口

原来db的访问方式主要有以上三种:

  • 手工用mysql客户端连mysql,直连数据库执行命令

  • java使用jdbc连接数据库

  • c/c++使用libmysqlclient.a来对mysql进行访问

所谓保持访问接口,是指上游对数据库的访问接口完全不用变,中间件服务对上游来说,就是数据库。

由于SQL协议是非常复杂的,在db的客户端与服务器插入了一个中间层之后,不一定能对所有的SQL功能都进行支持,支持哪些SQL是需要慎重考虑的。

(3)屏蔽读写分离

业务层不需要在关注读写分离,由中间件来进行读写请求路由。

(4)支持的分库

58的db的水平扩展,基本是用的分库的方式(分库比较好,很容易实现实例的扩容),即:

db.table会水平拆分为:

db1.table

db2.table

db3.table

db4.table

这样的话,dao层对于table就只有一个table实例了,比较方便。

根据前期与各业务线同学的沟通,58在分库上的业务访问需求为(这个调研的周期比较长,和很多业务线进行了沟通):

  • patition key普通查询

  • patition key上的IN查询

  • 非patition key上的查询

  • 有限功能的排序+分页查询

故对分库上的分布式SQL功能,数据库中间层只需要支持上上述四项即可。

(5)高可用性的支持

高可用的支持又分为两个部分:

第一部分,故障自动发现:下游数据库挂了,能够自动发现问题,并报警周知相关人员。

第二部分,故障自动转移:

  • 主库挂了,能够自动切换,或者屏蔽写请求

  • 从库挂了,能够自动自动切换读请求量流量

  • 中间件挂了,自动切换中间件流量,高可用

(6)可运维性的支持

  • 支持一些统计数据的展现

  • 支持一些管理命令

  • 支持页面话的运维

however,只要总的框架设计具备可扩展性,这些功能可以循序渐进,逐步添加。

三、设计折衷

(1)协议与整体架构

既然选择了mysql client server protocol作为业务层与中间层之间的协议,那么中间层必然是作为mysql-server接收上游的请求作为mysql-client向真正的mysql发送请求的,中间层的整体结构如下:

这样的话,需要对mysql client server protocol做详尽的研究,了解:

  • 连接的建立过程

  • 权限认证的过程

  • 压缩解压缩的过程

  • 请求响应二进制协议各种细节

协议这一块的掌握必须详尽,好在官方文档相对比较全面:

http://dev.mysql.com/doc/internals/en/client-server-protocol.html

(2)架构细节

总体架构细节图如上。

(2.1)上游

  • mysql客户端,java使用jdbc作为上游连接,c/c++使用libmysql.a作为上游连接,使用的是Mysql Client Server协议

  • DBA亦可以向中间件发送一些管理命令,或者查看一些统计信息,使用的是自己定义的内部协议

(2.2)下游

处于系统体系结构中的最后端,系统中间件的下游就是mysql集群了,中间件与mysql之间使用的也是Mysql Client Server协议。

(2.3)中间层-ConfigMgr

中间层配置文件管理组件ConfigMgr是中间层中非常重要的一个部分,请求的转发,读写分离,分库功能的支持,都需要通过配置来完成。

<mysql>

<db id=0 logic_db="im"type=1>

<item ip="10.58.1.100" port=3306 name="im" />

</db>

<db id=1 logic_db="umc"type=2 patition_count=2 key="uid" hash="mod">

   <patition id=0>

       <item ip="10.58.1.100" port=3306 role="w" />

       <item ip="10.58.1.101" port=3306 role="r" />

       <item ip="10.58.1.102" port=3306 role="r" />

   </patition>

   <patition id=1>

       <item ip="10.58.1.100" port=3316 role="w" />

       <item ip="10.58.1.101" port=3316 role="r" />

       <item ip="10.58.1.102" port=3316 role="r" />

   </patition>

</db>

</mysql>

从配置文件可以看出,ConfigMgr需要管理的mysql配置类型有两种:

type=1请求转发

<db id=0 logic_db="im"type=1>

       <item ip="10.58.1.100" port=3306 name="im" />

</db>

配置的含义是,上游如果访问逻辑数据库logic_db=”im”,中间件则将请求转发到实际的后端数据库item,item中配置了后端数据库的ip/port/name。

type=2分库支持

解释分库支持的配置之前,先说明一下数据库的层次结构LOGIC_DB、PARTITION、ITEM。

LOGIC_DB:逻辑数据库,面向上游,例如umc

PARTITION:数据库分区,可以理解为分库,例如umc0和umc1,这个对上游是透明的

ITEM:数据库项,可以理解为一个分区上的一个读库或者写库,这个对上游也是透明的

上例中对应的配置文件为:

<db id=1 logic_db="umc"type=2 patition_count=2 key="uid" hash="mod">

   <patition id=0>

       <item ip="10.58.1.100" port=3306 role="w" />

       <item ip="10.58.1.101" port=3306 role="r" />

       <item ip="10.58.1.102" port=3306 role="r" />

   </patition>

   <patition id=1>

       <item ip="10.58.1.100" port=3316 role="w" />

       <item ip="10.58.1.101" port=3316 role="r" />

       <item ip="10.58.1.102" port=3316 role="r" />

   </patition>

</db>

  • LOGIC_DB:需要关注partition-key-column,也需要关注partition算法,它要实现对PARTITION的请求路由以及结果集的汇总

  • PARTITION:需要关注ITEM的读写特性,它要实现对ITEM的读写分离

  • ITEM:是最终的数据库,和它相关的配置是数据库ip/port/name/wr-type

(2.4)中间层-MysqlServerPart

中间层服务端组件MysqlServerPart是中间层中非常重要的一个部分,它负责端口的监听+请求接收与返回(服务端网络IO),MysqlProtocol的解析。根据其功能,MysqlServerPart组件又主要分为两个组件ServerIOMgr组件(服务端IO管理),MysqlProtocolAnalyzer组件(Mysql协议分析)。

这一层次面临这些细节:

  • server网络框架的选取:建议使用异步server

  • 并发模型的选取:建议使用IO-thread + multi-work-thread的并发模型

  • 内存管理模型的选取:建议使用内存池

  • 连接上下文管理,最容易想到的上下文,一个数据库连接是和一个逻辑库LOGIC_DB绑定的

  • Mysql如何建立数据库连接:需要考察Mysql协议

  • Mysql协议的细化解析:需要考察Mysql协议

(2.5)中间层-MysqlClientPart

中间层客户端组件MysqlClientPart是中间层中非常重要的一个部分,它负责中间件对mysql的连接池管理,以及返回结果集的解析。根据其功能,MysqlClientPart组件又主要分为两个组件ClientConnPoolMgr组件(客户端连接池管理),ResultSetAnalyzer组件(返回结果集分析)。

这一层次面临这些细节:

  • 数据库连接池的实现

  • 数据库连接模型的选型:建议前期使用同步模型

  • 连接上下文管理,最容易想到的上下文,一个数据库连接是和一个ITEM绑定的

  • Mysql结果集的细化解析:需要考察Mysql协议

(2.6)中间层-SqlParser

中间层Sql分析组件SqlParser是中间层中非常重要的一个部分,它负责对sql语句的语法分析与语义分析。

为什么要进行Sql语法语义分析?需要解析出什么东东?

分为两种情况:

type=1请求转发

对于请求的中转,上游一个数据库连接对应一个逻辑库LOGIC_DB,由ConfigMgr可以知道对应下游一个真实的ITEM(ip/port/db),此时直接转发请求即可,无需解析Sql语句。

type=2分库支持

对于分库的支持,解析Sql语句可能需要得到这些问题的答案:Sql是否带了partition-key-column?partition-key-column的值是多少?

例如一条Sql语句:select * from user where uid=123456;

就必须将“uid”列属性,以及uid的列属性值“123456”解析出来,以用作后续请求路由。

注意:更细的情况是,针对每个表,分库partition-key-column都是不一样的,上例中还需要将表名user也解析出来。

这一层次面临这些细节:

  • 如何解析Sql语句:可以参考mysql源码对SQL语句的解析,亦可参照cober对SQL语句的解析方法;

注:由于我们只需要支持多库,数据库库名信息是在“连接”这一层获取的,又我们支持的分布式Sql的种类有限,故只需解析partition-key-column,offset/limit等少数信息即可。

(2.7)中间层-SqlModifier

中间层Sql修改组件SqlModifier是中间层中非常重要的一个部分,它负责对sql语句改写。

为什么要对Sql语句进行改写?

type=1的请求转发,无需修改Sql,但对于type=2的分库支持,有些Sql语句就必须进行改写。

例如:select * from user where uid in(1,2,3,4,5,6);

假设PARTITION分了0和1奇偶两个分区,则sql应该分别被改写为:

select * from user where uid in(2,4,6); => 路由给0库;

select * from user where uid in(1,3,5); => 路由给1库;

又例如:select * from user limit 1000,10;

则sql可能会被改写为:

select * from user limit 0,1010; => 分别路由到两个库,收集完结果集共2020条记录,再排序取其中1000-1010这10条。

哪些Sql需要改写,如何改写?

结合我们需要实现的四类分布式Sql:

  • patition key普通查询

  • patition key上的IN查询

  • 非patition key上的查询

  • 有限功能的排序+分页查询

只有(2)和(4)两项需要改写,改写方法上文已述,其中(4)的改写效率较低,使用起来要谨慎。

(2.8)中间层-SqlRouter

中间层Sql路由组件SqlRouter是中间层中非常重要的一个部分,它负责对sql语句进行路由。

哪些Sql需要路由,如何路由?

结合我们需要实现的四类分布式Sql:

  • patition key普通查询

  • patition key上的IN查询

  • 非patition key上的查询

  • 有限功能的排序+分页查询

只有(1)和(2)两项需要路由,(3)和(4)需要将请求分发至所有的PARTITION。

(2.9)中间层-ResultSetMerger

中间层结果集合并组件ResultSetMerger是中间层中非常重要的一个部分,它负责对结果集进行合并,筛选。

哪些Sql需要合并结果集,筛选结果集?

结合我们需要实现的四类分布式Sql:

  • patition key普通查询

  • patition key上的IN查询

  • 非patition key上的查询

  • 有限功能的排序+分页查询

其中(2)和(3)类查询需要将结果集进行合并,(4)不但要合并结果集,还需要将结果集在本地进行排序,然后再筛选出真正的结果集。

(2.10)其他组件

  • AdminServer:监听一个新端口,接收数据库管理员命令的server

  • AdminMgr:实现管理员命令的组件

  • MonitorMgr:实现监控报警的组件

  • StatisticsMgr:实现数据统计功能的组件

上述组件可循序渐进,逐步添加,故一期需要实现的组件及架构图为:

感谢看完,说明你对数据库中间件感兴趣,建议在PC上细看3遍,一定更有收获,谢转。

=======================================分割线============================================

1,每条业务线每张table的分片方式可能都不一样,只有实际的业务线才知道自己的分片需求,可以出台一个比较通用的规范/约束,每条业务线按照这个规范push自己的配置到配置管理器中,中间件在启动的时候加载这些配置

2,中间件proxy要具有HA的能力

3,是否需要支持分布式事务,根据业务需求决定

4,最好是能够动态在线扩容,借鉴codis的扩容方案?

假如让你来设计数据库中间件相关推荐

  1. 2.4.1 数据库中间件设计篇

    目录 2.4.1.1 数据库中间件设计理论 1.为什么需要数据库中间件? 1.1.数据库存储的数据量不是很大,但并发的读写操作超过数据库服务器的处理能力 1.2.应用的业务模块很多,总的数据量很大,并 ...

  2. 数据库中间件设计理论

    为什么需要消息中间件 高并发.海量数据的情况下: 1 .数据库存储的数据量不是很大,但并发的读写操作都很大,超过数据库服务器的处理能力. 2.应用的业务模块很多,总得数据量很大,并发读写操作均超过单个 ...

  3. 4.1.2 数据库中间件设计要点

    文章目录 数据库中间件设计要点 数据库拆分 数据库拆分 - 垂直拆分 数据库拆分 - 水平拆分 水平拆分 - 分片规则 分库分表的技术难点 数据库中间件的两种实现模式 常用数据库中间件简介 数据库中间 ...

  4. 【干货】浅谈分布式数据库中间件之分库分表

    分库分表,顾名思义就是把原本存储于一个库的数据分块存储到多个库上,把原本存储于一个表的数据分块存储到多个表上.那么关于分库分表,你了解多少呢?接下来,我们将从什么是数据分片及如何进行分片两方面对DDM ...

  5. 手把手带你用数据库中间件Mycat+SpringBoot完成分库分表

    一.背景 随着时间和业务的发展,数据库中的数据量增长是不可控的,库和表中的数据会越来越大,随之带来的是更高的磁盘.IO.系统开销,甚至性能上的瓶颈,而一台服务的资源终究是有限的,因此需要对数据库和表进 ...

  6. mysql为什么需要中间件_究竟为什么要引入数据库中间件

    不少朋友经常会问我以下问题: 58到家有没有使用数据库中间件 使用了什么数据库中间件,是自研,还是第三方 怎么实现的,是基于客户端的中间件,还是基于服务端的中间件 使用中间件后,join/子查询/集函 ...

  7. mysql分布式数据库中间件对比

    目前数据库中间件有很多,基本这些中间件在下都有了解和使用,各种中间件优缺点及使用场景也都有些心的.所以总结一个关于中间件比较的系列,希望可以对大家有帮助. 1. 什么是中间件 传统的架构模式就是 应用 ...

  8. 轻量级数据库中间件利器Sharding-JDBC深度解析(有彩蛋)

    讲师介绍 张亮 当当架构部总监 负责分布式中间件和私有云平台建设 目前主导开源项目:Elastic-Job及Sharding-JDBC 主题简介: 1.关系型数据库中间件核心功能介绍 2.Shardi ...

  9. 如何写一个数据库中间件以及需要准备的知识储备

    什么是数据库中间件 1.透明化使用方无感知,或者尽量少感知.通过现有的接入端接入已有服务 2.增量服务不改变数据库本身功能的前提下,提供额外的功能与服务一个原则不破坏原有逻辑,并且让用户基于之前的经验 ...

最新文章

  1. 【观点】智能制造:新时代智能产业革命的基石|王飞跃
  2. 前端开发工具 vscode 使用技巧篇:控制台由powershell切换为cmd方法,windows下新旧版控制台cmd与powershell互切方法
  3. Kafka是如何实现高吞吐率的
  4. A strange lift HDU - 1548(基础广搜)
  5. Luogu P2055 [ZJOI2009]假期的宿舍
  6. 【渝粤题库】陕西师范大学800005 人文地理学
  7. 第一讲 数学方法论引论
  8. 淘宝/天猫api 收货地址列表 API接口
  9. 两种有趣的排序方法:睡眠排序、猴子排序(golang版本)
  10. 第九届信号与图像处理国际学术研讨会(CSIP 2022)
  11. 程序猿面试八股文分享~
  12. 导出单帧图片以及时间线介绍(PR)
  13. centos mysql 大小写_linux 、centos 安装MySQL及踩坑大小写敏感
  14. 综合实践计算机的入门知识教学设计,3-6年级综合实践活动3.我是电脑小画家_教案、教学设计_市级优课(0001)【信息技术】.doc...
  15. 解决html在手机和PC端显示效果不一致的问题
  16. java 校验网站域名格式是否为(xxx.xxx.xxx/xxx/xxx..)正则
  17. 森林图怎么分析_图说meta十一:森林图暨RevMan软件使用方法简介
  18. iview自定义表单验证
  19. window对象的方法
  20. mysql docker oom_如何让docker容器不会被oomkill掉设置oomkilldisable

热门文章

  1. android论坛功能开发教程,Android教程 如何免费生成论坛App
  2. 系统的版本说明 VOL OEM VLK FPP RTM RC
  3. 律师学python有什么用呢_律的解释|律的意思|汉典“律”字的基本解释
  4. js代码实现繁体字切换效果
  5. s3c4510 烧写flash
  6. java在哪一年面世_显示java时候
  7. 设计模式03:装饰模式
  8. shell小技巧(七十七)搜索文件并将其权限修改为644
  9. 百度央视春晚秀自动驾驶技术,无人车队驶上港珠澳大桥
  10. 问题 A: 数据结构作业(可选)-- 约瑟环问题