查看原文
其他

mycat实践篇-分表分库案例

2016-06-27 IT哈哈

SAAS多租户案例


SAAS多租户的案例是Mycat粉丝的创新性应用案例之一,思路巧妙并且实现方式简单。

SAAS应用中,不同租户的数据是需要进行相互隔离的,比较常用的一种方式是不同的租户采用不同的Database存放业务数据,常规的做法是应用程序中根据租户ID连接到相应的Database,通常是需要启动多个应用实例,每个租户一个,但这种模式消耗的资源比较多,而且不容易管理,还需要开发额外的功能,以对应租户和部署的应用实例。

在Mycat出现以后,有人利用Mycat的SQL拦截功能,巧妙的实现了SAAS多租户特性,传统应用仅做少量的改动,就直接进化为多租户的SAAS应用,下面的内容是Mycat用户提供的具体细节:


单租户就是传统的给每个租户独立部署一套web + db 。由于租户越来越多,整个web部分的机器和运维成本都非常高,因此需要改进到所有租户共享一套web的模式(db部分暂不改变)。基于此需求,我们对单租户的程序做了简单的改造实现web多租户共享。具体改造如下:  1.web部分修改:      a.在用户登录时,在线程变量(ThreadLocal)中记录租户的id      b.修改 jdbc的实现:在提交sql时,从ThreadLocal中获取租户id,  添加sql 注释,把租户的schema 放到注释中。例如:/*!mycat :  schema = test_01 */ sql ;  2.在db前面建立proxy层,代理所有web过来的数据库请求。proxy层是用mycat实现的,web提交的sql过来时在注释中指定schema, proxy层根据指定的schema 转发sql请求。


此方案有几个关键点: 

- ThreadLocal变量的巧妙使用,与Hibernate的事务管理器一样的机制,线程的一个ThreadLocal变量中保留当前线程涉及到的数据库连接、事务状态等信息,当Service的某个事务托管的业务方法被调用时,Hibernate自动完成数据库连接的建立或重用过程,当此方法结束时,自动回收数据库连接以及提交事务。在这里,操作数据库的线程中以ThreadLocal变量方式放入当前用户的Id以及对应的数据库Schema(Database),则此线程随后的整个调用方法堆栈中的任何一个点都能获取到用户对应的Schema,包括在JDBC的驱动程序中。 

- Mycat的SQL拦截机制,Mycat提供了强大的SQL注解机制,可以用来影响SQL的路由,用户可以灵活扩展。在此方案中,:/*!mycat : schema = test_01 */ 这个注解就表明此SQL将在test_01这个Schema(Database)中执行 

- 改造MySQL JDBC 驱动,MySQL JDBC驱动是开源的项目,在这里实现对SQL的拦截改造,比在程序里实现,要更加安全和可靠 



每天2亿数据的实时查询案例


某移动项目中,每天的账单结算业务数据估计高峰期为每天2亿,需要能够响应快速查询,查询性能要求控制在3秒内,80%的查询是根据用户手机号来查询当天或者最近几天的交易流水,此外还有供内部运维人员的查询条件,根据交易的某个内部流水号查询,由于并非单纯的主键查询,所以普通的Key-Value系统就难以应付,因此首先想到用分布式内存数据库系统,后来知道了Mycat,于是开始评估测试Mycat+MySQL内存表的可能性,经过详细的分析测试对比,发现MySQL内存表方式与InnoDB的查询性能差异并不大,因为有索引的情况下,单条或少量结果集的查询,所耗费的磁盘IO并不大,而内存表的全表锁定问题会导致到数据录入和查询线程之间的竞争,其结果很不确定,可能导致查询的响应时间达到几十秒,另外,2个亿的数据要全部装入内存,则计算需要16G以上内存,要保持1个月的数据,则需要差不多500G内存,而现网的机器也还没有那么大内存,最终经过详细的对比测试,采用了InnoDB表的方式,测试署环境:Mycat一个+MySQL一个,测试客户端也在本机,硬件为笔记本工作站:CPU 酷睿4800 核心数量: 四核心,8线程, 内存16G,硬盘SSD混合硬盘。


MySQL 5.6参数设置如下:[mysqld]tmp_table_size=0Mmax_connections =2100innodb_buffer_pool_size=4Ginnodb_file_per_table=1innodb_use_sys_malloc =0innodb_undo_tablespaces=64innodb_open_files=1024table_open_cache=1024innodb_autoextend_increment=128innodb_max_dirty_pages_pct=90innodb_log_file_size =128Minnodb_log_buffer_size=16Minnodb_log_files_in_group=8innodb_flush_log_at_trx_commit=2enforce-gtid-consistency=true


上述设置,没有开启bin-log(只对主从同步有效),innodb_buffer_pool_size设置的比较大,日志相关的缓存也优化,每个表一个独立表空间(innodb_file_per_table=1),只有操作系统崩溃的时候才可能丢失1秒的数据(innodb_flush_log_at_trx_commit=2),这些配置对于非交易型数据是最佳配置。 

查询2小时内的某个电话号码的交易信息(排序),限制为20条

select * from opp_call where calldate in (2014020100,2014020101) and phone = ${phone(139-189)} order by callminutes desc limit 20;

finishend:200000 failed:0 qps:8338.87,query time min:0ms,max:941ms,avg:11.99

finishend:200000 failed:0 qps:8338.87,query time min:0ms,max:941ms,avg:11.99

上述100个并发随机查询20万次,平均响应时间是12ms,最大<1S

总结:采用calldate的时间分片算法,每个分片保留1小时的记录,最多保留31天的数据,总共774个分片,均匀分布到后端4-10台物理机上,数据库建立合适的索引并做优化,满足查询响应时延<2S的实时查询。


物联网26亿数据的案例


此案例由某研究所提供,场景是采集分布于不同点的探头数据并且保存到数据库中,提供实时查询,最终测试并通过了10000个网关并行插入采集数据的同时,进行界面查询的验收测试标准。

数据库分表:通过Mycat分库,3台物理机,共100个数据库,每个库一张表。


从测试结果可以看出,通过性能优化后,一万个网关同时插入数据,当数据库存量在10亿以内时,吞吐量为1500条/秒,10个用户并发查询1万条记录的时间为1.1s左右;当数据库存量扩展到26.1亿时,吞吐量降为1000条/秒,20个用户并发查询1万条记录的时间为1.4s左右,完全符合预计的目标。


大型分布式零售系统案例


此案例为大型分布式零售系统,支持全国2万多家门店的使用,系统部署在北京、深圳多个机房,备用和容灾用,每月订单量千万级,最大的表10亿以上。该系统中五个子系统用到mycat。

系统拆分步骤

1. 寻找大表。对某个子系统中所有表做数据量评估,这个可以找这个业务领域有经验的同事,或者有现有数据的可以根据现有数据量做评估,如评估一个表一年的记录条数、磁盘占用量,3年的、五年的。


这个步骤是为了找出系统中的大表,根据自己定的单表最大量来确定是否要拆分,如超过800万的表都要拆分。

1. 扩大拆分表范围。扩大拆分表指的是有些表虽然量级没达到800万,但是他与第一步选出的大表有关联查询,这些表也一起找出来,然后统筹一起定分片算法和拆分策略。

扩大拆分范围时常用全局表、相同拆分策略等方式。具体见后文第三章 Mycat实施指南中的数据拆分原则。

1. 定分片策略。这个根据业务不同可能差异很大,需要对mycat支持的分片算法都了解清楚,同时对业务系统的业务要非常清楚(即这个工作是需要2个人来一起完成的,一个懂mycat的,一个懂业务的,如果这两个都懂的就更好了)。

我们的数据拆分方式使用

系统拆分按照后文mycat实施指南中的数据拆分原则进行,单表的数据量控制在800万以内。

针对零售的业务特点,我们的系统中可用的拆分维度有:经营区域(华东、华北、西北、华中等)、订货单位、管理城市、经营城市、店铺、时间范围等。

联合冗余字段的分片使用

在拆分过程中碰到一个场景,无法满足拆分原则,通过引入联合冗余字段,达到了拆分目的,场景如下:

某几个表业务上都与经营区域相关,但是所有经营区域只有10多个,按照数据量预估这个表会有10亿的量,按照经营区域拆分,单表能达到1亿,如果考虑高峰区域和冷门区域问题,这个峰值会更大,可能2亿都有可能。但是又没有其他好的拆分维度可以用,后来想到这个表中还有一个日期字段,查询时都可以加上时间区域的限制,但是如果按照自然月拆分会如何呢?单表也会超过800万,最后确定如果联合这两个字段,多大的数据量都能拆开了,弄出了一个联合字段zone_yyyymm,表示区域+自然月,1年12个月,10多个区域,能够拆分成100多个分片,这下来再大的数据量也能拆分开了。


您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存