0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

数据库的中间件有啥用?

数据分析与开发 来源:Coder的技术之路 作者:Coder的技术之路 2021-06-21 16:16 次阅读

Part1 数据库中间件有啥用

有一天,你去三亚玩耍,就想玩个冲浪,即时你不差钱,难道还要自己采买快艇、滑板等等装备来满足这为数不多的心血来潮么。租一个就行了嘛。这其实就是连接池的作用。

数据库中间件可以理解为是一种具有连接池功能,但比连接池更高级的、带很多附加功能的辅助组件,不仅可以租冲浪板,还可以提供地点推荐、上保险等等各类服务。

从网上的资料看,zdal应该算是半开源的,好像是之前开源过,但后续没有准备维护,然后就删除了,不过github被fork下来好多,随便一搜就是一片,当前,只是老的版本。目前蚂蚁内部的zdal好像已经更新到zdal5了吧,那咱可就看不到了。

越复杂的系统,数据库中间件的作用越大。就拿zdal来说,它提供分库分表,结果集合并,sql解析,数据库failover动态切换等数据访问层统一解决方案。下面就一起来看下,其内部实现是怎么样的。

Part2 架构剖析之高屋建瓴

c87433b8-d145-11eb-9e57-12bb97331649.png

2.1 整体概述

如上图所示,zdal有四个重要的组成部分:

价值体现--客户端Client包。对外暴露基本操作接口,用于业务层简单黑盒的操作数据源;业务只和client交互,动态切换/路由等逻辑只需要进行规则配置,相关逻辑由zdal实现。

核心功能--连接管理datasource包。最核心的能力,提供多种类型数据库的连接管理;不管功能多花哨,最终目的还是为了解决数据库连接的问题。

关键能力--SQL解析parser包。基础SQL解析能力;解析sql类型、字段名称、数据库等等,配合规则进行路由

扩展能力--库表路由rule包。根据parser解析出的字段确定逻辑库表和物理库表。

2.2 组件图看架构

组件图对整体架构和各组件及相互联系的理解可以起到很好的帮助。一个简版的组件图画了好久,还有不少错,不过大概是这么个意思,哎,基本功要丢~

c8833368-d145-11eb-9e57-12bb97331649.png

对照上图可以比较清晰的看到:

Client包对应用层暴露的数据源、负责监听配置动态变更的监听组件、负责加载组织各部分的配置组件、负责加载spring bean 和库表规则的配置组件;

Client中加载了规则组件,实现逻辑表和数据库的路由规则。

Client中的库表配置调用datasource中的数据源管理服务并构建连接池的连接池;

Client中的SqlDispatcher服务调用SQL解析组件实现SQL解析。

Part3 细节剖析之一叶知秋

3.1 配置加载和bean初始化

大部分情况下,我们使用如mybatis这样的ORM框架来进行数据库操作,其实不管是ORM还是其他方式,应用层都需要对数据源进行配置。

所以,client对外暴露了一个符合JDBC标准的datasource数据源,用来满足应用层ORM等框架配置数据源的要求--ZdalDataSource

c89b1afa-d145-11eb-9e57-12bb97331649.png

//只提供了一个init方法,这也是spring启动时时,必须要调用的初始化方法,所有功能,都从这里开始
public class ZdalDataSource extends AbstractZdalDataSource implements DataSource{
    public void init() {
        try {
            super.initZdalDataSource();
        } catch (Exception e) {
            CONFIG_LOGGER.error("...");
            throw new ZdalClientException(e);
        }
    }

ZdalDataSource#init()方法即为配置加载的核心入口,init中负责加载spring配置,根据配置初始化数据源,并创建连接池,同时,将逻辑表和物理库的对应关系都维护起来供后续路由调用。

/*父类的init方法*/
protected void initZdalDataSource() {
    /*用FileSystemXmlApplicationContext方式加载配置文件中的数据源和规则,转化成zdalConfig对象*/
    this.zdalConfig = ZdalConfigurationLoader.getInstance().getZdalConfiguration(appName,dbmode, appDsName, configPath);
    this.dbConfigType = zdalConfig.getDataSourceConfigType();
   this.dbType = zdalConfig.getDbType();
   //初始化数据源
   this.initDataSources(zdalConfig);
   this.inited.set(true);
    }
}

从上面的类图和这里的两个入口方法大概了解到zdal配置加载的启动流程。下面我们就来详细看一下,读写分离和分库分表的规则是怎么被加载,怎么起作用的。

3.2 细说读写分离

读写分离配置的加载

首先,我们需要有数据源的相关配置,如下图:

c8b7a6b6-d145-11eb-9e57-12bb97331649.png

此XML配置会在init方法被调用时,被初始化,解析成ZdalConfig类的属性,ZdalConfig类的主要成员见下面代码:

public class ZdalConfig {
    /** key=dsName;value=DataSourceParameter 所有物理数据源的配置项,比如用户名,密码,库名等 */
    private Map dataSourceParameters = new ConcurrentHashMap();
    /** 逻辑数据源和物理数据源的对应关系:key=logicDsName,value=physicDsName */
    private Map              logicPhysicsDsNames  = new ConcurrentHashMap();
    /** 数据源的读写规则,比如只读,或读写等配置*/
    private Map              groupRules           = new ConcurrentHashMap();
    /** 异常转移的数据源规则*/
    private Map              failoverRules        = new ConcurrentHashMap();
    //一份完整的读写分离和分库分表规则配置
    private AppRule                          appRootRule;

可以看到,xml中的规则,被解析到xxxRules里。这里以groupRules为例,failover同理。

下一步则是通过解析得到的zdalConfig 来初始化数据源:

protected final void initDataSources(ZdalConfig zdalConfig) {
    //DataSourceParameter中存的是数据源参数,如用户名密码,最大最小连接数等
    for (Entry entry : zdalConfig.getDataSourceParameters().entrySet()) {
        try {
           //初始化连接池
           ZDataSource zDataSource = new ZDataSource(/*设置最大最小连接数*/createDataSourceDO(entry.getValue(),zdalConfig.getDbType(), appDsName + "." + entry.getKey()));
           this.dataSourcesMap.put(entry.getKey(), zDataSource);
        } catch (Exception e) {
            //...
        }
   }
  //其他分支略,只看最简单的分组模式
  if (dbConfigType.isGroup()) {
       //读写配置赋值
       this.rwDataSourcePoolConfig = zdalConfig.getGroupRules();
       //初始化多份读库下的负载均衡
       this.initForLoadBalance(zdalConfig.getDbType());
  }
  //注册监听:为了满足动态切换
  this.initConfigListener();
}

initForLoadBalance的方法如下:

private void initForLoadBalance(DBType dbType) {
    Map dsSelectors = this.buildRwDbSelectors(this.rwDataSourcePoolConfig);
    this.runtimeConfigHolder.set(new ZdalRuntime(dsSelectors));
    this.setDbTypeForDBSelector(dbType);
}

可以看到,首先构建出了DB选择器,然后赋值给了runtimeConfigHolder供运行时获取。而构建DB选择器的时候,其实是按读写两个维度,把所有数据源都构建了一遍,即group_r和group_w下都包含5个数据源,只不过各自的权重不一样:

//比如按上面的配置写库只有一个,但是也会包含全数据源

group_0_w_0 :< bean:read0DataSource , writeWeight:0>
group_0_w_1 :< bean:writeDataSource , writeWeight:10>
group_0_w_2 :< bean:read1DataSource , writeWeight:0>
group_0_w_3 :< bean:read2DataSource , writeWeight:0>
group_0_w_4 :< bean:read3DataSource , writeWeight:0>

//上述就是写相关的DBSelecter的内容。

读写分离怎么起作用

以delete为例,更新删除是要操作写库的

 public void delete(ZdalDataSource dataSource) {
     String deleteSql = "delete from test";
     Connection conn = null;
     PreparedStatement pst = null;
     try {
        conn = dataSource.getConnection();
        pst = conn.prepareStatement(deleteSql);
        pst.execute();
     } catch (Exception e) {
            //...
     } finally {
           //资源关闭
     }
 }

getConnection会从上文中提到的runtimeConfigHolder中获取DBSelecter,然后执行execute方法

 public boolean execute() throws SQLException {
    SqlType sqlType = getSqlType(sql);
    // SELECT相关的就选择group_r对应的DBSelecter
   if (sqlType == SqlType.SELECT || sqlType == SqlType.SELECT_FOR_UPDATE|| sqlType == SqlType.SELECT_FROM_DUAL) {
     //略
    return true;
    //update/delete相关的就选择group_w对应的DBSelecter
  } else if (sqlType == SqlType.INSERT || sqlType == SqlType.UPDATE|| sqlType == SqlType.DELETE) {
       if (super.dbConfigType == DataSourceConfigType.GROUP) {
           executeUpdate0();
       } else {
           executeUpdate();
      }
      return false;
  } 
}

如果是读取相关的,那就选_r的DBSelecter,如果是写相关的,那就选_W的DBSelecter。那么executeUpdate0中是怎么执行区分读写数据源的呢,其实就是把这一组的数据源根据权重筛选一遍。

// WeightRandom#select(int[], java.lang.String[])
private String select(int[] areaEnds, String[] keys) {
   //这里的areaEnds数组,是一个累加范围值数据
   //比如三个库权重    10   9   8
   //那么areaEnds就是  10  19  27 是对每个权重的累加,最后一个值是总和
   int sum = areaEnds[areaEnds.length - 1];
   //这样随机出来的数,是符合权重分布的
   int rand = random.nextInt(sum);
   for (int i = 0; i < areaEnds.length; i++) {
       if (rand < areaEnds[i]) {
           return keys[i];
   }
   return null;
}

Part4 总结

本篇文章,把阿里数据库中间件相关的组件和加载流程进行了总结,就一个最基本的分组读写分离的流程,对内部实现进行了阐述。说是解析,其实是提供给大家一种阅读的思路,毕竟篇幅有限,如果对中间件感兴趣的同学,可以fork下代码,按上述逻辑自己阅读下。

看源码时,比如dubbo这些中间件其实是比较容易入手的,因为他们都依托于Spring进行JavaBean的装载,所有,对Spring容器暴露的那些init、load方法,就是很好的切入点。个人思路,希望对大家有所帮助。

责任编辑:lq6

,>,>,>,>,>,>,>,>,>,>
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 中间件
    +关注

    关注

    0

    文章

    62

    浏览量

    18042
  • 数据库
    +关注

    关注

    7

    文章

    3591

    浏览量

    63365

原文标题:一款优秀数据库中间件的不完全解析

文章出处:【微信号:DBDevs,微信公众号:数据分析与开发】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    求助,关于MDK5中间件network静态ip手动配置问题

    最近在研究MDK5的自带的Middleware中间件,其中用到NetWork,ipv4及ipv6各项功能均已调通。发现MDK提供的network并没有提供供用户手动修改设备Ip地
    发表于 04-22 08:09

    中间件厂商中创股份成功上市

    近日,国内领先的基础软件中间件产品与服务提供商——山东中创软件商用中间件股份有限公司(以下简称“中创股份”)在上海证券交易所科创板上市,股票代码为“688695”。这一里程碑事件标志着中创股份在基础软件中间件领域的实力和影响力得
    的头像 发表于 03-14 15:25 373次阅读

    磐石操作系统的2023丨从繁荣生态,走向国产替代

    年完成100%信创国产化改造,替换范围涵盖芯片、操作系统、中间件等。 2023年8月17日,中软国际发布2023中期报告,指出:紧跟国家发展战略,围绕国产服务器、操作系统、数据库中间件等基础软硬件,打造关基行业中国信创方案。
    的头像 发表于 12-22 20:10 643次阅读
    磐石操作系统的2023丨从繁荣生态,走向国产替代

    操作系统技术创新与发展分论坛圆满举办

    操作 系统作为计算机系统的核心,承担链接硬件、数据库中间件及应用软件的重要角色,它是信息技术领域的基石与灵魂。构建繁荣发展的操作系统生态,需要不断推动创新,加强合作与联合,以实现技术与应用的全面
    的头像 发表于 12-22 18:20 277次阅读
    操作系统技术创新与发展分论坛圆满举办

    诚邀报名 | 内核 Hacker 与 Mogul 邀您共论操作系统技术创新与发展

    硬件、数据库中间件及应用软件的重要角色,它是信息技术领域的基石与灵魂。为了构建一个繁荣发展的操作系统生态,并确保我国数字技术基础的自立自强,我们需要不断推动创新,加强合作与联合,以实现技术与应用的全面突破。 在当前人工智能和物联网技术迅猛发展的背景下,操作系统发展和挑战
    的头像 发表于 12-20 17:24 301次阅读
    诚邀报名 | 内核 Hacker 与 Mogul 邀您共论操作系统技术创新与发展

    诚邀报名 | 内核Hacker与Mogul邀您共论操作系统技术创新与发展

    2023开放原子开发者大会 . OPENATOM DEVELOPERS CONFERENCE 操作系统技术创新与发展分论坛 2023.12.17 操作系统作为计算机系统的核心,承担着链接硬件、数据库
    的头像 发表于 12-08 19:40 332次阅读
    诚邀报名 | 内核Hacker与Mogul邀您共论操作系统技术创新与发展

    oracle数据库中间件有哪些

    Oracle数据库中间件是指由Oracle公司开发和提供的一系列软件产品,用于构建、部署和管理企业级应用。它提供了一套完整的解决方案,包括数据库管理、应用服务器、数据集成和开发工具等,
    的头像 发表于 12-05 16:17 631次阅读

    元件数据库

    软件可以识别设备的元件数据库就好了,我们公司的机器数据都是物料编码建立的
    发表于 11-16 14:39

    EDMS中间件集成的未来趋势和探讨

    ETAS Deterministic Middleware Solution (EDMS,前身为AOS)确定性中间件解决方案,是一个中间件框架,旨在面向汽车领域内应用程序的独特挑战和需求,尤其是
    的头像 发表于 09-28 10:03 1475次阅读
    EDMS<b class='flag-5'>中间件</b>集成的未来趋势和探讨

    在FRDM-K64F开发板上开发中间件应用程序

    本教程将指导您在FRDM-K64F开发板上开发中间件应用程序。 该应用程序从MEMS传感器(加速计和磁力计)读取数据,并使用CGI和JavaScript将其显示在网站上。 Web服务器
    发表于 09-04 08:02

    在MDK版本5中使用CMSIS组件创建中间件应用程序

    本研讨会介绍如何使用CMSIS和中间件组件为复杂的微控制器应用程序创建软件框架。 在本研讨会期间,将创建一个实现以下功能的演示应用程序: 从U盘读取“Test.txt”文件的内容。 在图形显示器上显示此内容。 在触摸屏上提供了更新按钮
    发表于 09-04 07:43

    SpringBoot 2种方式快速实现分库分表,轻松拿捏!

    如今的 ShardingSphere 已经不再是单纯代指某个框架,而是一个完整的技术生态圈,由三款开源的分布式数据库中间件 sharding-jdbc、sharding-proxy 和 sharding-sidecar 所构成。
    的头像 发表于 08-26 14:22 482次阅读
    SpringBoot 2种方式快速实现分库分表,轻松拿捏!

    i.MXRT1024 MCU是否有用于NXP WiFi的驱动程序和中间件

    i.MXRT1024 MCU 是否有用于 NXP WiFi 的驱动程序和中间件? MCUXpressoSDK 包含对多个基于 NXP WiFi 的模块以及许多 i.MXRT 处理器和 EVK
    发表于 06-09 07:37

    什么是DDS(数据分发服务)?#软件中间件

    中间件DDS
    北汇信息POLELINK
    发布于 :2023年06月05日 14:50:13

    自动驾驶通信中间件

    中间件”是一个比较抽象和宽泛的概念,它并不特指一种具体的技术,其概念起源于复杂分布式软件系统的开发,其目的是实 现软件组件之间进行数据交换,使软件组件之间实现解耦。这种数据交换通常是通过网络进行
    发表于 06-01 11:32 0次下载
    自动驾驶通信<b class='flag-5'>中间件</b>