作者:客如云 BigData Infra Team
客如云成立于 2012 年,是全球领先、 国内最大的 SaaS 系统公司。 目前面向餐饮、 零售等服务业商家, 提供软硬一体的新一代智能化前台、收银等 SaaS 云服务,包括预订、排队、外卖、点餐、收银、会员管理、进销存等系统服务,并将数据实时传达云端。我们是客如云的大数据基础架构组,负责公司的大数据架构和建设工作,为公司提供大数据基础数据服务。
3. 餐饮行业有明显的业务访问高峰时间,高峰期期间数据库会出现高并发访问,而有些业务,比如收银,在高峰期出现任何 RDS 抖动都会严重影响业务和用户体验。
大数据的 ODS(Operational Data Store) 以前选型的是 MongoDB,ODS 与支持 SaaS 服务的 RDS 进行数据同步。初期的设想是线上的复杂 SQL、分析 SQL,非核心业务 SQL 迁移到大数据的 ODS层。同时 ODS 也作为大数据的数据源,可以进行增量和全量的数据处理需求。但是由于使用的MongoDB,对业务有一定侵入,需要业务线修改相应查询语句,而这点基本上遭到业务线的同学不同程度的抵制。同时目前大数据使用的是 Hadoop + Hive 存储和访问方案,业务线需要把历史明细查询迁移到 Hadoop ,然后通过 Impala、Spark SQL、Hive SQL 进行查询,而这三个产品在并发度稍微高的情况下,响应时间都会很慢,所以大数据组在提供明细查询上就比较麻烦。
同时更为棘手的是,面对客户查询服务(历史细则、报表等),这类查询的并发会更高,而且客户对响应时间也更为敏感,我们首先将处理后的数据(历史细则等)放在了 MongoDB 上(当时 TiDB 1.0 还没有 GA ,不然就使用 TiDB 了),然后针对 OLAP 查询使用了 Kylin ,先解决了明细查询的问题。 但是由于业务很复杂, 数据变更非常频繁,一条数据最少也会经过五六次变更操作。报表展现的不仅是当天数据,涉及到挂账、跨天营业、不结账、预定等复杂状况,生产数据的生命周期往往会超过一个月以上。所以当前的 OLAP 解决方案还有痛点,所以后续我们要把 OLAP 查询移植一部分到 TiDB 上面去,来减轻 Kylin 的压力并且支持更加灵活的查询需求,这个目前还在论证当中。
同时,我们发现 TiDB 有一个子项目 TiSpark, TiSpark 是建立在 Spark 引擎之上,Spark 在机器学习领域里有诸如 MLlib 等诸多成熟的项目,算法工程师们使用 TiSpark 去操作 TiDB 的门槛非常低,同时也会大大提升算法工程师们的效率。我们可以使用 TiSpark 做 ETL,这样我们就能做到批处理和实时数仓,再结合 CarbonData 可以做到非常灵活的业务分析和数据支持,后期根据情况来决定是否可以把一部分 Hive 的数据放在 TiDB 上。
新老框架如下图:
阿里云服务器:
目前我们将线上 RDS 中三个库的数据通过 Binlog 同步到 TiDB ,高峰期 QPS 23k 左右,接入了业务端部分查询服务;未来我们会将更多 RDS 库数据同步过来,并交付给更多业务组使用。因为 TiDB 是新上项目,之前的业务线也没有线上 SQL 迁移的经历,所以在写入性能上也没有历史数据对比。
(1)查询一个索引后的数字列,返回 10 条记录,测试索引查询的性能。
(2)查询两个索引后的数字列,返回 10 条记录(每条记录只返回 10 字节左右的 2 个小字段)的性能,这个测的是返回小数据量以及多一个查询条件对性能的影响。
(3)查询一个索引后的数字列,按照另一个索引的日期字段排序(索引建立的时候是倒序,排序也是倒序),并且 Skip 100 条记录后返回 10 条记录的性能,这个测的是 Skip 和 Order 对性能的影响。
(4)查询 100 条记录的性能(没有排序,没有条件),这个测的是大数据量的查询结果对性能的影响。
(5)TiDB 对比 MySQL 复杂 SQL 执行速率:
a. 对应 SQL:
SELECT sum(p.exempt_amount) exempt_amount FROM table1 p JOIN table2 c ONp.relate_id=c.id AND p.is_paid = 1
andp.shop_identy in(BBBBB)
andp.brand_identy=AAAAA
andp.is_paid=1 AND p.status_flag=1 AND p.payment_type!=8
WHEREc.brand_identy = AAAAA
ANDc.shop_identy in(BBBBB)
ANDc.trade_type in(1,3,4,2,5)
ANDc.recycle_status=1
AND c.trade_statusIN (4,5,10)
ANDp.payment_time BETWEEN '2017-08-11 16:56:19' AND '2018-01-13 00:00:22'
ANDc.status_flag = 1
ANDc.trade_pay_status in(3,5)
AND c.delivery_type in(1,2,3,4,15)
b. 对应 SQL:
SELECT sum(c.sale_amount)tradeAmount,sum(c.privilege_amount) privilege_amount,sum(c.trade_amount)totalTradeAmount,sum(c.trade_amount_before) tradeAmountBefore
FROM (SELECTc.sale_amount,c.privilege_amount,c.trade_amount,c.trade_amount_before
FROM table1p
JOIN table2c ON p.relate_id=c.id
andp.shop_identy in(BBBBB)
andp.brand_identy=AAAAA
andp.is_paid=1 AND p.status_flag=1 AND p.payment_type!=8
and c.brand_identy = AAAAA
ANDc.shop_identy in(BBBBB)
ANDc.trade_type in(1,3,4,2,5)
ANDc.recycle_status=1 AND c.trade_statusIN (4,5,10)
ANDp.payment_time BETWEEN '2017-07-31 17:38:55' AND '2018-01-13 00:00:26'
ANDc.status_flag = 1
ANDc.trade_pay_status in(3,5)
ANDc.delivery_type in(1,2,3,4,15)
ANDp.payment_type not in(4,5,6,8,9,10,11,12)
GROUP BY p.relate_id ) c
c. 对应 SQL:
SELECT SUM(if(pay_mode_id=-5 or pay_mode_id = -6,0,IFNULL(pi.face_amount, 0) - IFNULL(pi.useful_amount, 0) -IFNULL(pi.change_amount, 0))) redundant
FROM table2c
JOIN table1 p ON c.id = p.relate_id AND c.brand_identy=p.brand_identy
JOIN table3pi ON pi.payment_id=p.id AND pi.pay_status in (3,5,10)
AND pi.brand_identy=p.brand_identy ANDpi.pay_mode_id!=-23
andp.shop_identy in(BBBBB)
andp.brand_identy=AAAAA
andp.is_paid=1 AND p.status_flag=1 AND p.payment_type!=8
WHEREc.brand_identy = AAAAA
ANDc.shop_identy in(BBBBB)
ANDc.trade_type in(1,3,4,2,5)
ANDc.recycle_status=1
AND c.trade_statusIN (4,5,10)
ANDp.payment_time BETWEEN '2017-07-31 17:38:55' AND '2018-01-13 00:00:26'
ANDc.status_flag = 1
ANDc.trade_pay_status in(3,5)
AND c.delivery_type in(1,2,3,4,15)
d. 对应 SQL:
SELECT t.id tradeId,sum(t.trade_amount - t.trade_amount_before) AS roundAmount, sum(-p.exempt_amount) AS exemptAmount
FROM table2t
LEFT JOINtable1 p ON p.relate_id = t.id
LEFT JOINtable3 pi ON pi.payment_id = p.id
WHEREt.brand_identy =AAAAA AND t.trade_status IN (4,5,10)
ANDt.trade_pay_status IN (3,4,5,6,8) ANDp.payment_type IN (1,2)
ANDpi.pay_mode_id !=-23 ANDp.is_paid=1 AND t.status_flag=1
AND t.shop_identy IN(<123个商户号码>)
GROUP BY t.id
e. 对应 SQL:
SELECT t.id tradeId,
sum(t.trade_amount- t.trade_amount_before) AS roundAmount,
sum(-p.exempt_amount)AS exemptAmount
FROM table2t
JOIN table1 p ON t.id = p.relate_id
WHERE t.brand_identy = AAAA
ANDt.trade_status IN(4,5,10)
ANDt.trade_pay_status IN (3,4,5,6,8)
ANDp.is_paid=1 AND t.status_flag=1
group by t.id ;
(6)OLTP 对比测试结果:
(7)简单测试结论:
目前线上已经存储超过 6 个月的数据,总数据量几 T,支持线上的查询和分析需求,很多一般复杂度 OLAP 查询都能够在秒级返回结果。TiSpark 我们也调试通过,准备移植一些支持 OLAP 的 ETL 应用做到实时 ETL。目前 TiDB 生产还有很多优化的空间,比如系统参数,SQL 的使用姿势,索引的设计等等。
感谢 TiDB 的厂商的人员给予了我们巨大的支持,希望我们能够提供给 TiDB 一些有意义的信息和建议,在 TiDB 成长的路上添砖加瓦。
延展阅读
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。