背景
分库分表这个词相信很多人都不陌生,在互联网公司数据到达一定规模的时候,多数都会对数据进行分库分表,或者也有人叫分片,英文翻译为Sharding;更加准确来说我们常常关心的是水平分片,即单个业务的某些表到达一定规模后,即使建立索引也无法从根本上带来很大的性能提升,这时我们会考虑把单表拆分,以MySQL为例,B+树索引的深度会随着记录的增多而逐渐加深,根据索引查询的开销也会越来越大,而单表拆分成多个表之后,B+树深度降低,每个单表独立查询的速度也会加快,如果同时还分库的话,并且在不同的实例上,大量的查询压力也会分担到不同的机器上,这对单个数据库机器减压也带来好处。
分库分表的技术方案总体上来讲分为两大类:应用层依赖类中间件、中间层代理类中间件。
应用层依赖类中间件
这类分库分表中间件的特点就是和应用强耦合,需要应用显示依赖相应的jar包(以Java为例),比如知名的TDDL、当当开源的sharding-jdbc、蘑菇街的TSharding、携程开源的Ctrip-DAL、支付宝开源但比较低调的zdal等。
此类中间件的基本思路就是重新实现JDBC的API,通过重新实现DataSource、PrepareStatement等操作数据库的接口,让应用层在基本(注意:这里用了基本)不改变业务代码的情况下透明地实现分库分表的能力。中间件给上层应用提供熟悉的JDBC API,内部通过sql解析、sql重写、sql路由等一系列的准备工作获取真正可执行的sql,然后底层再按照传统的方法(比如数据库连接池)获取物理连接来执行sql,最后把数据结果合并处理成ResultSet返回给应用层。
此类中间件的优点很明显,就是无需额外部署,只要和应用绑定一起发布即可,但是缺点也很明显,就是不能跨语言,比如Java写的sharding-jdbc显然不能用在C#项目中,所以携程的dal也要重新写一套C#的客户端。
中间层代理类中间件
这类分库分表中间件的核心原理是在应用和数据库的连接之间搭起一个代理层,上层应用以标准的MySQL协议来连接代理层,然后代理层负责转发请求到底层的MySQL物理实例,这种方式对应用只有一个要求,就是只要用MySQL协议来通信即可,所以用MySQL Workbench这种纯的客户端都可以直接连接你的分布式数据库,自然也天然支持所有的编程语言。比较有代表性的产品有开创性质的Amoeba、阿里开源的Cobar、社区发展比较好的Mycat 等。
在技术实现上除了和应用层依赖类中间件基本相似外,代理类的分库分表产品必须实现标准的MySQL协议,某种意义上讲数据库代理层转发的就是MySQL协议请求,就像Nginx转发的是Http协议请求。
上述无论哪种类型的产品,除了实现分库分表这一主要功能外,都会额外实现一些其他很有实用价值的功能,比如读写分离、负载均衡等。