假如让你来设计数据库中间件 (假如让你来设计2020年全国爱眼日的主题你会如何设计)

教程大全 2025-07-20 15:31:51 浏览

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

一、总体目标

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

二、实现的功能

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

(1)统一接入入口

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

而只有

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

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

而只有

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

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

ROAD-MAP规划如下:

(2)保持访问接口

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

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

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

(3)屏蔽读写分离

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

(4)支持的分库

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

db.table会水平拆分为:

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

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

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

(5)高可用性的支持

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

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

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

(6)可运维性的支持

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

三、设计折衷

假如让你来设计2020年全国爱眼日的主题你会如何设计

(1)协议与整体架构

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

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

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

(2)架构细节

总体架构细节图如上。

(2.1)上游

(2.2)下游

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

(2.3)中间层-ConfigMgr

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

从配置文件可以看出,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:数据库项,可以理解为一个分区上的一个读库或者写库,这个对上游也是透明的

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

(2.4)中间层-MysqlServerPart

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

这一层次面临这些细节:

(2.5)中间层-MysqlClientPart

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

这一层次面临这些细节:

(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的种类有限,故只需解析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:

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

(2.8)中间层-SqlRouter

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

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

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

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

(2.9)中间层-ResultSetMerger

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

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

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

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

(2.10)其他组件

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

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


excel中这个函数是什么意思呢=IF(G1="","",SUMIF(表1!$D$3:$D$3059,G70,表2!$E$3:$E$3059))

如果G1单元格为空则显示为空,否则按给定条件对指定单元格求和。

如果A1和A2都是空值,刚A3就为空值,怎么写IF函数?

题出的不明确啊 呵呵如果A1和A2都为空,则A3为空,否则A3应该怎么样。 按照 czh 同学回答,如果A2不为空,A3就是返回错误。 且是A1 和A2 同时为空,还是A1 为空或A2为空。 A1 A2同时为空的情况=IF(and(A1=,A2=),,要怎么样)A1 A2只有一个为空情况 =IF(OR(A1=,A2=),,要怎么样)

sql 计算出某个时间的到期日?

select p_id,p_sdate,case when year(DateAdd(mm,6,p_sdate))<=year(getdate()) then dateadd(mm,6,p_sdate) else cast(cast(year(p_sdate)+1 as char(4))+-02-28 as datetime) endas p_edate,case when dateadd(mm,6,p_sdate))

本文版权声明本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,请联系本站客服,一经查实,本站将立刻删除。

发表评论

热门推荐