假如让你来设计数据库中间件

13年底,负责数据库中间件的设计,当时的设计文档,拿出来和大家分享:
(1)可以了解下数据库中间件技术;
(2)可以了解下架构系统设计的思路;
画外音:后面项目没落地。
 
一、总体目标
数据库中间层项目背景不再展开,根据前期的调研以及和公司同事的讨论,中间层的核心目标主要有两个:
(1)db虚拟化:让db对业务线透明(本文的db均指mysql),业务线不再需要知道db的真实ip,port,主从关系,读写关系,高可用等;
(2)无限容量(分库)的支持:让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规划如下:
(1.1)业务线入口统一(中转请求);
1.2)业务线入口统一(智能路由);
1.3)全局入口统一;
 
(2)保持访问接口
假如让你来设计数据库中间件
原来db的访问方式主要有以上三种:
(2.1)手工用mysql客户端连mysql,直连数据库执行命令;
2.2)java使用jdbc连接数据库;
2.3)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在分库上的业务访问需求为(这个调研的周期比较长,和很多业务线进行了沟通):
(4.1)patition key普通查询;
4.2)patition key上的IN查询;
4.3)非patition key上的查询;
4.4)有限功能的排序+分页查询;
故对分库上的分布式SQL功能,数据库中间层只需要支持上上述四项即可。
 
(5)高可用性的支持
高可用的支持又分为两个部分:
第一部分,故障自动发现:下游数据库挂了,能够自动发现问题,并报警周知相关人员。
第二部分,故障自动转移
(5.1)主库挂了,能够自动切换,或者屏蔽写请求;
5.2)从库挂了,能够自动自动切换读请求量流量
5.3)中间件挂了,自动切换中间件流量,高可用;
 
(6)可运维性的支持
(6.1)支持一些统计数据的展现;
(6.2)支持一些管理命令;
(6.3)支持页面上的运维;
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是中间层中非常重要的一个部分,请求的转发,读写分离,分库功能的支持,都需要通过配置来完成。

       

 

key="uid" hash="mod">

   

       

       

       

   

   

       

       

       

   

 
从配置文件可以看出,ConfigMgr需要管理的mysql配置类型有两种:
type=1请求转发

       

配置的含义是,上游如果访问逻辑数据库logic_db=”im”,中间件则将请求转发到实际的后端数据库item,item中配置了后端数据库的ip/port/name。
 
type=2分库支持
解释分库支持的配置之前,先说明一下数据库的层次结构LOGIC_DB、PARTITION、ITEM。
假如让你来设计数据库中间件
LOGIC_DB:逻辑数据库,面向上游,例如umc
PARTITION:数据库分区,可以理解为分库,例如umc0和umc1,这个对上游是透明的
ITEM:数据库项,可以理解为一个分区上的一个读库或者写库,这个对上游也是透明的
 
上例中对应的配置文件为:

key="uid" hash="mod">

   

       

       

       

   

   

       

       

       

   

 - 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:实现数据统计功能的组件
上述组件可循序渐进,逐步添加,故一期需要实现的组件及架构图为:
假如让你来设计数据库中间件
感谢看完,说明你对数据库中间件感兴趣,希望大家有,谢转。
相关文章:
关于MySQL,这篇都没人赞,太没天理了!

发布者:糖太宗,转载请注明出处:https://www.qztxs.com/archives/science/technology/5950

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022年5月11日 下午8:53
下一篇 2022年5月11日 下午8:54

相关推荐

  • 某手v8.x版本抓包分析

    快手升级到v8.x版本以后,会发现直接用Charles、Fiddler等抓包工具抓包的时候,抓不到包了。这是因为快手用了quic协议,下面就具体讲一下分析过程和解决方案。 一、分析过程 我曾经在分析sig参数的时候看到过有一个方法入参是okhttp3.Request,我们就直接从这里入手。 用Frida hook一下,打印request看一下。 var s ...

    2022年6月2日
    7200
  • 为啥大中型公司都热衷于造轮子?

    为啥大厂热衷于造轮子?首先造轮子的事情比比皆是,随便截几个图看看。             其实不只是大厂,中型公司亦有不少造轮子的,俗话说人上一百形形色色。造轮子的原因大抵总结下面几类。   1、别人的轮子不好用 开源产品不少轮子已经齐备,但是往往存在满足80%-90%的需求的情况,为了...

    2022年5月18日
    2400
  • 渗透测试流程

    总结,持续更新 渗透千万条,安全第一条。渗透不授权,亲人泪两行! 白帽子要有自己的原则和底线,即使数据再诱人,也千万不要去拿任何数据! 是要在客户允许的范围内进行测试,白帽子需要有白帽子的底线! 0x00 前言 渗透测试是指渗透人员在不同的位置(比如从内网、从外网等位置)利用各种手段对某个特定网络进行测试,以期发现和挖掘系统中存在的漏洞,然后输出渗透测试报告...

    技术 2022年5月28日
    3100
  • CVE-2019-0708 批量检测

    0x01 前言 项目地址:https://github.com/Pa55w0rd/CVE-2019-0708 CVE-2019-0708 Windows RDP 远程命令执行漏洞 Windows系列服务器于2019年5月15号,被爆出高危漏洞,该漏洞影响范围较广,windows2003、windows2008、windows2008 R2、windows x...

    2022年6月13日
    5800
  • 帖子中心,1亿数据,架构如何设计?

    帖子中心,是互联网业务中,一类典型的“1对多”业务,即:一个用户能发布多个帖子,一个帖子只有一个发布者。   随着数据量的逐步增大,并发量的逐步增大,帖子中心这种“1对多”业务,架构应该如何设计,有哪些因素需要考虑,是本文将要系统性讨论的问题。 什么是x对x? 所谓的“1对1”,“1对多”,“多对多”,来自数据库设计中的“实体-关系”ER模型,用来描述实体之...

    2022年5月14日
    2100

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信