1.背景
Zebra是一个基于JDBC API协议上开发出的高可用、高性能的数据库访问层解决方案。类似阿里的tddl,zebra是一个smart客户端,提供了诸如动态配置、监控、读写分离、分库分表等功能。zebra是由基础架构团队开发和维护,定位是公司统一的数据库访问层组件(Data Access Layer),是新美大DBA团队推荐的官方数据源组件,将来也会以zebra为核心进行数据访问层的演进。
Zebra最初是上海侧数据库访问组件,目前上海侧全量应用使用该组件访问数据库。2016年Q3之后,北京侧逐步放弃使用atlas,外卖配送、酒旅、到餐、猫眼等事业部,都陆陆续续开启接入zebra。 截止2018年6月27日,公司已有8000+应用接入了zebra,整体覆盖率达到94.66%。对于java应用,都建议使用zebra去访问数据库。
简化了读写分离、分库分表的开发工作,使得业务方在分库分库、读写分离的情况下,依然可以像操作单个库那样去操作,屏蔽底层实现的复杂性,对业务透明。提供了从读写分离到分库分表全生命周期的技术支持。
2.组成
zebra主要是以客户端的形式提供服务,客户端又细分为3个组件:zebra-api、zebra-dao、zebra-ds-monitor-client。
- zebra-api(核心)除了监控外,几乎zebra所有核心功能,如读写分离、分库分表、全链路压测、Set化支持、就近路由、流量控制、故障模拟都是通过zebra-api来提供的。
- zebra-ds-monitor-client提供端到端的监控,将监控信息上报到cat、falcon、mtrace。
- zebra-dao对mybatis的轻量级封装,所有mybatis原有的功能都具备,额外提供了异步化接口、分页插件、多数据源等功能。
2.1zebra-api(核心依赖)
2.1.1 读写分离
作为一个访问层组件,读写分离是一个基本要求。
zebra目前支持的如下能力:
- 支持水平扩展从库,灵活的调整各个从库的任意流量比例
- 支持优先就近选择从库进行读取数据,避免跨机房访问
- 灵活的强制走主库策略,支持单条SQL或者整个请求内所有SQL等维度
- ......
2.1.2 分库分表
目前分库分表支持能力如下:
- 同时支持分库和分表,路由策略可以通过groovy脚本进行灵活定制
- 分表键支持 =,in等操作符
- 完善的SQL解析,支持聚合,分组,排序,Limit等语句
- 支持多维度的分表策略
- 配置均集中式配置和存储,简化业务代码的配置文件
- ......
分库分表除了落地到客户端的能力上,zebra还在运维能力上进行持续提升。因次,zebra可以说为分库分表打造了一站式的解决方案,具体包括以下的能力:
- 一键的建库建表和DDL变更操作
- 支持路由结果的可视化查询
- 支持多维度的数据自动化同步
- ......
2.1.3 高可用
高可用架构如下所示:
在整体架构图中可以看到,目前整个数据库的高可用使用到了两个组件,其中一个开源组件是MHA,它来负责主库的检测和切换。另外一个是自研服务,它用来负责从库的可用性检测和故障时从库的摘除。
但是一旦业务的性能差的SQL打到数据库上时,DBA就需要对这条SQL进行处理。目前支持SQL限流和SQL改写两种策略。首先,DBA可以把引发故障的慢SQL在管理端上配置流量进入的比例,这样一来该SQL就不会再打到数据库上从而引发数据库故障。然后,DBA还可以在保证语义完全一样的情况下,在管理端在线对这条SQL进行改写,这样一来客户端发往数据库的将是DBA优化过的SQL了。
2.1.4 全链路压测
能够支持对压测流量中的SQL的数据库表名进行动态改写,从而使得压测流量都落到新的数据库表中,而不影响正常业务的数据库表。这样做的好处是,不用再费事费力去搭建一套性能环境进行压测,而是直接使用的线上的物理设施进行压测,因为这样才能更好的压测出性能瓶颈。
2.1.5 就近路由
为了满足高可用的需求,mysql集群和业务服务器集群一般需要进行多机房/多中心部署,为此会产生跨机房/中心访问的问题。为了平衡跨机房/中心访问带来的延迟问题,需要应用机器能够优先访问部署在同一机房/中心的DB。
2.1.6 故障模拟
业务方有时需要模拟在数据库宕机的情况下服务的可用性。zebra支持模拟主库/从库宕机,以及模拟单个SQL执行失败。
2.1.7 SET化支持
我司外卖业务体量庞大,业务已突破1600W/天。当前,我们通过一个大型分布式集群来支持业务,集群内部进行了大量的拆分(数据库、MQ、缓存等),具备了一定的可扩展性。但是,随着业务量的进一步增长,部分组件的可扩展性遇到了一定问题。同时,随着集群规模的扩大,需要计算资源越来越多,单IDC已不能满足需求,当前架构在IDC扩展时,会遇到一定问题。SET化功能主要是为了在存储层支持单元化架构。
2.1.8 流量控制
在系统访问量较大时,某些库的负载可能非常高,或者因为临时故障或系统bug导致大量异常SQL打到某个库上。为了防止数据库被这些异常流量打垮,需要在数据库访问层上对MySQL进行保护,因此zebra需要提供对某些特定SQL或某个库进行限流的功能。(SQL限流只是用于临时解决问题,事后还需业务方进行优化或扩容)
2.2 zebra-ds-monitor-client
2.2.1 端到端监控
端到端的监控,一端指的是应用服务器,另一端指的是数据库服务器,一次端到端过程,就是一次完整的请求响应过程,中间经历两次来回网络的开销。端到端监控之所以重要,因为它最能够客观的反映SQL的性能。比起MySQL服务端的监控指标,端到端监控还把来回的两次网络开销算了进去。过往的历史经验来看,会经常出现在端到端监控上看到慢查询,但这条慢查询却不能够在MySQL服务器上查出,这是因为有可能这条SQL在网络上多花了开销,或者在MySQL的队列中多等待了一段时间。
因此,端到端的监控是如此的重要!
zebra使用的是cat来进行端到端的监控,也支持把监控指标打到mtrace上。在这些监控平台上,可以明确的看到具体的某条SQL的性能指标,包括平均响应时间、99线、999线等。在CAT上还能够抓取出慢查询报表告诉开发,然后开发对这些慢查询进行优化。
举例来说,上图是CAT上SQL打点的一个截图,从中可以看到以下信息:
- 从连接池拿到连接花了0.01ms(SQL.Conn)
- 整个SQL(UserProfile.loadUserProfile)的执行开始时间(15:13:23.010)和 结束时间(15:13:23.011)
- 这条SQL查询的结果为 0 (SQL.Rows)
- 在dpuser-n1-read数据库上进行了查询Select
- 这条SQL具体的SQL是:SELECT UserID,......,和这条PreparedStatement需要的参数是:115522257
- 这条SQL总共执行了1.48ms
- 整个调用链路上SQL的位置
2.3 zebra-dao
对mybatis的轻量级封装,所有mybatis原有的功能都具备,额外提供了异步化接口、分页插件、多数据源等功能。用法本质上就是mybatis的用法。
2.3.1 异步化接口
一个服务可能包括RPC调用请求、MemCached请求、KV存储请求以及MySQL数据库调用,目前我司其它三种请求的组件都有异步化的接口,但是数据库调用并没有。所以,在这个情况下,开发了这个异步化的DAO。目前,公司内部已有多个业务接入使用,已经接受了线上环境的验证和考验。
2.3.2 分页插件
支持逻辑分页和物理分页
2.3.3 多数据源
支持配置多个数据源,通过注解的方式指应该使用哪个数据源。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。