1.总体目标数据库中间层项目后台不再展开。根据之前和公司同事的研究和讨论,中间层主要有两个核心目标:db虚拟化:让db对业务线透明(本文中的db指的是mysql),以及业务line不再需要知道真实的ip,端口,主从关系,读写关系,分库的高可用支持:让db的分库支持业务线透明2.实现的功能上述目标比较宽泛。具体来说,数据库中间层需要实现以下功能。1.统一访问入口如果有统一访问入口,以后就没有db1.58.com:3306db2.58.com:3306im.58.com:3306jiaoyou.58.com:3306只有db.58。com:3306所有业务线只有一次访问db,数据库中间层做授权校验,中间件路由请求。这是绝对的情况。当然,统一一个总入口的目标有点宏大,还是可以循序渐进的。首先,所有业务线统一读写访问入口,所以折衷的目标可以是以后不再有im.read.db1.58.com:3306im.read.db2.58.com:3306im.write.db.58.com:3306和im.58.com:3306im业务访问db统一到一个入口,中间层智能路由请求。更简化一点,即使是前期同一业务线的db读写,对业务线也不透明,数据库中间层只做简单的请求转发,初步收集数据库访问入口到中间层数据库,为后续统一,再统一基础。ROAD-MAP规划如下:统一业务线入口(中转请求)统一业务线入口(智能路由)统一全局入口连接数据库,执行命令java使用jdbc连接数据库c/c++使用libmysqlclient。由于SQL协议非常复杂,db的client和server插入一个中间层后,不一定能支持所有的SQL功能,支持哪些SQL需要慎重考虑。3.屏蔽读写分离业务层无需关注读写分离,由中间件进行读写请求路由。4.支持的分库58的db的水平扩展基本都是采用分库的方式(分库比较好,方便扩展实例),即:db.table会被水平拆分成:db1.tabledb2.以tabledb3.tabledb4.table为例,dao层对于表只有一个表实例,比较方便。根据前期与各业务线同学的沟通,58对分库的业务接入需求如下(本次研究周期比较长,业务线沟通较多):patitionkeygeneralqueryINqueryonpatitionkeynon-patitionkey上面的查询只有排序+分页查询的功能有限,所以对于分库上的分布式SQL功能,数据库中间层只需要支持以上四项即可。5、高可用支持高可用支持分为两部分:***部分,故障自动检测:当下游数据库宕机时,能自动发现问题并通知相关人员。第二部分,自动故障转移:主库宕机,可以自动切换,或者写请求阻塞,从库宕机,可以自动切换读请求流量,中间件宕机,自动切换中间件流量,高可用(6)可操作性的支持,支持一些统计数据的展示,支持一些管理命令的运维,支持页面的运维。但是,只要整体框架设计具有可扩展性,这些功能是可以逐步添加的。三、设计折衷1、协议及总体架构由于选择mysql客户端服务器协议作为业务层与中间层之间的协议,因此中间层必须以mysql-server的身份接收上游请求,以mysql的身份向真正的mysql发送请求-client用于发送请求,中间层整体结构如下:这种情况需要对mysql客户端服务器协议做详细研究了解:连接建立过程权限认证过程压缩解压过程请求响应二进制protocol各种细节...protocolOne一定要详细掌握,幸好官方文档比较全面:http://dev.mysql.com/doc/internals/en/client-server-protocol.html2.架构详细信息总体架构详细信息如上所示。(1)上游mysql客户端,java使用jdbc作为上游连接,c/c++使用libmysql.a作为上游连接,使用MysqlClientServer协议DBA也可以向中间件发送一些管理命令,或者查看一些统计信息信息,它使用自定义的内部协议(2)下游在系统架构的顶端,系统中间件的下游是mysql集群,中间件和mysql之间使用MysqlClientServer协议。(3)中间层-ConfigMgr中间层配置文件管理组件ConfigMgr是中间层非常重要的一个部分。请求转发、读写分离、支持分库功能都需要通过配置来完成。从配置文件可以看出ConfigMgr需要管理的mysql的配置有两种:a.type=1请求转发配置的意思是,如果上游访问逻辑数据库logic_db="im",中间件会将请求转发给实际的后端数据库项,ip/port/nameb。后台数据库的type=2在item中配置。分库支持在讲解分库支持的配置之前,先解释一下数据库LOGIC_DB、PARTITION、ITEM的层次结构。LOGIC_DB:逻辑数据库,面向上游,如umcPARTITION:数据库分区,可以理解为分库,如umc0、umc1,对上游透明。ITEM:databaseitem,可以理解为一个分区上的读库或者写库,对上游也是透明的。上例对应的配置文件为:LOGIC_DB:需要关注partition-key-column,还需要关注分区算法,需要实现对PARTITION的请求路由和结果集的汇总PARTITION:需要注意ITEM的读写特性,需要实现ITEM的读写分离ITEM:是最终的数据库,其相关配置是数据库ip/port/name/wr-type(4)中间层-MysqlServerPart中间层服务器组件MysqlServerPart是中间层中很重要的一个部分,它负责e用于端口监听+请求接收以及返回(服务器端网络IO),MysqlProtocol的解析MysqlServerPart组件根据其功能主要分为两个组件:ServerIOMgr组件(服务器端IO管理)、MysqlProtocolAnalyzer组件(Mysql协议解析)。这一层面临这些细节:服务器网络框架的选择:建议使用异步服务器并发模型的选择:建议使用IO线程+多工作线程并发模型内存管理模型的选择:建议使用使用内存池连接上下文管理,最容易想到的上下文是一个数据库连接是Mysql绑定到一个逻辑库LOGIC_DB。如何建立数据库连接:需要考察Mysql协议。Mysql协议详解:需要考察Mysql协议...(5)Middlelayer-MysqlClientPart中间层客户端端组件MysqlClientPart是中间层非常重要的一个部分,负责连接池的管理通过中间件对mysql进行分析,并对返回的结果集进行分析。MysqlClientPart组件根据其功能主要分为ClientConnPoolMgr组件(客户端连接池管理)、ResultSetAnalyzer组件(返回结果集分析)两个组件。这一层面临这些细节:数据库连接池的实现数据库连接模型的选择:建议前期使用同步模型连接上下文管理。最容易想到的上下文,一个数据库连接就是对一个ITEM绑定的Mysql结果集的细化分析:需要考察Mysql协议...(6)Middlelayer-SqlParser中间层Sql分析组件SqlParser是中间层的一个非常重要的部分,负责SQL语句的语法分析和语义分析。为什么要分析Sql的语法和语义?需要解析什么?有两种情况:a.type=1requestforwarding请求转发,上游的一个数据库连接对应一个逻辑库LOGIC_DB,ConfigMgr可以知道对应下游的是真正的ITEM(ip/port/db),直接转发即可请求不解析sql语句。b.type=2分库支持对于分库支持,解析Sql语句可能需要回答这些问题:DoesSqlhavepartition-key-column?分区键列的值是多少?比如一条Sql语句:select*fromuserwhereuid=123456;必须解析出“uid”列属性和uid列属性值“123456”,以便后续请求路由。注意:更详细的情况是对于每张表,分库的partition-key-column是不一样的。上面的例子中,还需要解析出表名user。这个级别面临这些细节:如何解析Sql语句:可以参考mysql源码对SQL语句的解析,也可以参考cober对SQL语句的解析方法;注意:由于我们只需要支持多数据库,数据库名称信息在“Connection”层,我们支持的分布式Sql类型有限,所以只需要partition-key-column,offset/limit,等需要解析。(7)中间层-SqlModifier中间层Sql修改组件SqlModifier是中间层非常重要的一个部分,负责重写sql语句。为什么要重写Sql语句?type=1的请求转发不需要修改Sql,但是对于type=2的分库支持,需要重写部分Sql语句。例如:select*fromuserwhereuidin(1,2,3,4,5,6);假设PARTITION分为0和1校验分区,则sql应该改写为:select*fromuserwhereuidin(2,4,6);=>路由到图书馆0;select*fromuserwhereuidin(1,3,5);=>路由到图书馆1;另一个例子:select*fromuserlimit1000,10;那么sql可以重写为:select*fromuserlimit0,1010;=>分别路由到两个数据库,收集结果集一共2020条记录后,然后排序从1000-1010取10条记录。需要改写哪个Sql,怎么改写?结合我们需要实现的四种分布式Sql:patitionkeycommonqueryINqueryonpatitionkeyqueryonpatitionkeyqueryonnon-patitionkeylimitedfunctionsorting+pagingqueryonly(2)and(4)两项需要重写。重写的方法上面已经说了。其中,(4)的重写效率较低,需谨慎使用。(8)中间层-SqlRouter中间层Sql路由组件SqlRouter是中间层非常重要的一个部分,负责对sql语句进行路由。需要路由哪个Sql以及如何路由?结合我们需要实现的四种分布式Sql:patitionkeycommonqueryINqueryonpatitionkeyqueryonpatitionkeyqueryonnon-patitionkeylimitedfunctionsorting+pagingqueryonly(1)and(2)两项需要路由,(3)(4)需要将请求分发给所有的PARTITION。(9)中间层-ResultSetMerger中间层结果集合并组件ResultSetMerger是中间层中非常重要的一个部分,负责对结果集进行合并和过滤。哪个Sql需要合并结果集和筛选结果集?结合我们需要实现的四种分布式Sql:patitionkeycommonqueryINqueryonpatitionkeyqueryonpatitionkeylimitedfunctionsorting+pagingquery其中(2)和(3)类查询需要合并结果集,(4)不仅需要合并结果集,还需要在本地对结果集进行排序,然后过滤掉真正的结果集。(10)其他组件AdminServer:监听新的端口,接收数据库管理员命令的服务器AdminMgr:实现管理员命令的组件MonitorMgr:实现监控告警的组件StatisticsMgr:实现数据统计功能的组件以上组件可以逐步添加,因此第一阶段需要实现的组件和架构为:【本文为专栏作者《58神剑》原创稿件,转载请联系原作者】点此查看该作者更多好文