做者:Mobike / 技术研发部 / 基础平台中心 丁宬杰 胡明
摩拜单车于 2015 年 1 月成立,2016 年 4 月 22 日地球日当天正式推出智能共享单车服务,截至 2017 年 11 月中旬,已前后进入国内外超过 180 个城市,运营着超过 700 万辆摩拜单车,为全球超过 2 亿用户提供着智能出行服务,日订单量超过 3000 万,成为全球最大的智能共享单车运营平台和移动物联网平台。摩拜天天产生的骑行数据超过 30TB,在全球拥有最为全面的骑行大数据,飞速增加的业务使摩拜面临数据库扩展与运维的巨大挑战。数据库
面对飞速增加的并发数与数据量,单机数据库终将因没法支撑业务压力而罢工。在摩拜正式上线以来,咱们就在不断思考数据库扩展和运维的将来,近年来业内对数据库进行扩展的常见的方案是经过中间件把数据库表进行水平拆分,将表内数据按照规则拆分到多个物理数据库中。使用这样的中间件方案,在数据库扩容时须要先停下业务,再重构代码,以后进行数据迁移,对于摩拜这样与时间赛跑的创业公司来说代价巨大,中间件方案对业务过强的侵入性,不支持跨分片的分布式事务,没法保证强一致性事务的特性都使咱们望而却步。后端
摩拜单车于 2017 年初开始使用 TiDB,从最先的 RC三、RC四、PreGA、到如今的 1.0 正式版,一步步见证了 TiDB 的成熟和稳定。目前支撑着摩拜内部的实时分析和部分线上业务,同时正在规划迁移更多的线上业务至 TiDB。安全
目前,TiDB 在摩拜部署了数套集群,近百个节点,承载着数十 TB 的各种数据。服务器
在摩拜,TiDB 是一个核心的数据交易与存储支撑平台,引入它的主要目的是用来解决海量数据的在线存储、大规模实时数据分析和处理。架构
在咱们看来,TiDB 的好处主要有:并发
下面介绍 TiDB 的应用场景:运维
场景一:开关锁日志成功率统计分布式
开关锁成功率是摩拜业务监控的重点指标之一。高并发
在每次开、关锁过程当中,用户和锁信息会在关键业务节点产生海量日志,经过对线上日志的汇总分析,咱们把用户的行为规整为人和车两个维度,经过分布式、持久化消息队列,导入并存放到 TiDB 里。在此过程当中,经过对不一样的实体添加不一样的标签,咱们就能方便地按照地域、应用版本、终端类型、用户、自行车等不一样的维度,分别统计各个类别的开锁成功率。工具
按照咱们的估计,这个业务一年的量在数百亿,因此使用单机的 MySQL 库须要频繁的进行归档,特别是遇到单机数据库瓶颈的状况下,扩容更是带来了很是大的挑战,这在咱们有限的人力状况下,彻底是个灾难。因此要支撑整个 Mobike 的后端数据库,咱们必需要寻找简单易用的方案,极大地减小在单个业务上的人力成本开销。其次,根据咱们以前使用分库分表的经验,对于这类须要频繁更新表结构进行 DDL 操做的业务,一旦数据量过大,很很容易出现数据库假死的状况,不只影响服务的可用性,更严重的是极可能致使数据不一致的状况出现。最后,咱们但愿无论从此的业务量如何激增,业务需求如何变化,均可以保持业务逻辑能够很方便地升级支持。
在方案设计时,咱们进行考察了 MySQL 分库分表的方案和 TiDB 方案的对比。
咱们先估计了可能的状况:
考虑到这些状况,MySQL 分库分表的方案就出现了一些问题,首先频繁变更表结构就比较麻烦,而 TiDB 能够进行在线 DDL。数据生命期比较长,能够设计之初作一个比较大的集群,可是弹性就比较差,针对这个问题,TiDB 能够根据须要,弹性的增长或者减小节点,这样的灵活性是 MySQL 分库分表没有的。另外,数据要支持频繁的复杂关联查询,MySQL 分库分表方案彻底没办法作到这一点,,而这偏偏是 TiDB 的优点,经过以上的对比分析,咱们选择了 TiDB 做为开关锁日志成功率统计项目的支撑数据库。
目前,大体能够将到端到端的延时控制在分钟级,即,如有开锁成功率降低,监控端可即时感知,此外,还能经过后台按用户和车查询单次故障骑行事件,帮助运维人员快速定位出故障的具体位置。
场景二:实时数据分析
数据分析场景中,TiDB 能够从线上全部的 MySQL 实例中实时同步各种数据,经过 TiDB 周边工具 Syncer 导入到 TiDB 进行存储。
这个业务的需求很简单,咱们线上有数十个 MySQL 集群,有的是分库分表的,有的是独立的实例。这些孤立的数据要进行归集以便供业务方进行数据分析。咱们一开始计划把这些库同步到 Hive 中,考察了两种方式,一种是每日全量同步,这么作,对线上的库压力以及 Hive 的资源开销都会愈来愈大。另外一种是增量同步,这种方式很是复杂,由于 HDFS 不支持 update,须要把每日增量的部分和以前的部分作 merge 计算,这种方法的优势是在数据量比较大的状况下,增量同步对比全量同步要更快、更节省空间,缺点是占用至关一部分Hadoop 平台的计算资源,影响系统稳定性。
TiDB 自己有不少不错的工具,能够和 MySQL 的生态方便的链接到一块儿。这里咱们主要使用了 TiDB 的 syncer 工具,这个工具能够方便的把 MySQL 实例或者 MySQL 分库分表的集群都同步到 TiDB 集群。由于 TiDB 自己能够 update,因此不存在 Hive 里的那些问题。同时有 TiSpark 项目,数据进入 TiDB 之后,能够直接经过 Spark 进行很是复杂的 OLAP 查询。有了这套系统,运营部门提出的一些复杂在线需求,都可以快速简洁的完成交付,这些在 Hadoop 平台上是没法提供这样的实时性的。
目前,该集群拥有数十个节点,存储容量数十 T,受益于 TiDB 自然的高可用构架,该系统运行稳定,往后集群规模日益变大也仅需简单增长 x86 服务器便可扩展。后台开发、运维、业务方等均可以利用 TiDB 的数据聚合能力汇总数据,进行数据的汇总和分析。
场景三:实时在线 OLTP 业务
如前所述,对比传统的分库分表方案,TiDB 的灵活性和可扩展性在实时在线业务上优点更加明显。
根据咱们的测试,TiDB 在数据量超过 5 千万时,对比 MySQL 优点较大,同时协议层高度兼容 MySQL,几乎不用修改业务代码就能直接使用,因此 TiDB 集群对于数据量大的实时在线业务很是适合。
目前,摩拜主要上线了两套在线 OLTP 业务,分别是摩豆信用分业务和摩豆商城业务。
摩豆信用分业务
摩拜单车信用分业务与用户骑行相关,用户扫码开锁时先行查询用户信用积分判断是否符合骑行条件,待骑行完成后,系统会根据用户行为进行信用分评估并进行修改。当单车没法骑行,上报故障核实有效后增长信用分、举报违停核实有效后下降信用分;可是若是不遵照使用规范,则会扣除相应的信用分;例如用户将自行车停在禁停区域内,系统就会扣除该用户的部分信用分做为惩罚,并存档该违停记录。当用户的信用分低于 80 分时,骑行费用将会大幅上升。
摩豆商城业务(APP 中的摩拜成就馆)
魔豆商城业务即摩拜成就馆,用户的每一次骑行结束后,系统会根据骑行信息赠送数量不等的省时币、环保币、健康币做为积分,经过积累这些积分能够在摩拜成就馆内兑换相应积分的实物礼品。
这些业务的共同特色:
因为是典型 OLTP 场景,可选项并很少,并且数据量增加极快,这些数据库的数据在一年内轻松达到数百亿量级。这些场景在咱们有了 TiDB 的使用经验之后,发现 TiDB 的全部特性都很是契合这种海量高并发的 OLTP 场景。TiDB 的容量/并发可随意扩展的特性不在赘述,支持在线 DDL 这个特性特别适合这些业务,有须要业务更改不会阻塞业务,这是咱们业务快速迭代比较须要的特性。
目前,这两个在线 OLTP 集群拥有数十个节点,百亿级数据,上线之后很是稳定,PingCAP 客户支持团队也协助咱们进行该集群的平常运维工做。
场景四:违章停车记录/开锁短信库等日志归集库
相对于传统的针对不一样的业务分别部署 MySQL 集群的方案,TiDB 在可扩展性和在线跨库分析方面有较大优点。
在部署 TiDB 以前,摩拜面对新增的业务须要对其进行单独的规划和设计,并根据业务的数据量,增速以及并发量设计 MySQL 的分库分表方案,这些重复的预先设计工做在所不免。另外一方面,不一样业务之间每每是有关联的,当运营部门须要不一样业务的汇总数据时,就变得异常麻烦,须要新建一个临时的数据汇总中心,例如新建一套 MySQL 分库分表的集群,或者临时向大数据组申请 Hive 的空间,这都让数据提供的工做变得麻烦。
有了 TiDB 之后,此类业务的开发和数据提供都变得很是简单,每次新需求下来,只须要按照新增数据量增长 TiKV 节点的数量便可,由于整个集群变得比较大,并发承载能力很是强,基本不须要考虑并发承载能力。特别的好处是,由于这些业务有相关性的业务,放在一个独立的数据库中,运营须要提供某几类某段时间的数据时就变得极为方便。
基于 TiSpark 项目,Spark 集群能够直接读取 TiDB 集群的数据,在一些运营须要实时数据提供的场景,再也不须要按照原有的提供数据到大数据平台,设计 ETL 方案,运营再去大数据部门沟通运算逻辑。而是直接在 TiDB 现有数据的基础上,直接提出复杂的分析需求,设计 Spark 程序进行在线的直接分析便可。这样作,咱们很是容易就能够实现一些实时状态的分析需求,让数据除了完成本身的工做,还能更好的辅助运营团队。
在说优化问题以前,先看 TiDB 的架构图,整个系统大体分为几个部分。
其中:
在使用过程当中,遇到过很多问题,可是在我方和 PingCAP 技术团队的充分交流和协做下,都获得了比较完善的解决,下面挑选最为重要的资源隔离与优化展开。
TiKV 中数据存储的基本单位是 Region,每一个 Region 都会按顺序存储一部分信息。当一个 Region 包含多个表的数据,或一台机器上有多个 Region 同时为热点数据时,就容易产生资源瓶颈。
PD 在设计之初考虑了这方面的问题(专门设计了 HotRegionBalance),可是,它的调度粒度是单个 Region,而且,整个调度基于这样的假设:即每一个 Region 的资源消耗对等,不一样 Region 之间没有关联,同时尽可能保持 Region 均摊在全部 Store。
但当一个集群同时承载多个库,或一个库中包含多个表时,发生资源瓶颈的几率会明显提高。
针对这个问题,咱们和 PingCAP 技术团队合做,对 TiDB 作了如下优化。
优化一:基于 Table 的分裂
这个修改的目的是解决小表数据的相互影响的问题。
当有新表数据插入某一 Region 时,TiKV 会根据当前 Region 的 Key Range 计算出 tableID,若是发现插入的 Key 不在这个 KeyRange 中,会对这个 Region 提早分裂,这就保证了每一个 Region 只包含一个表的数据。
优化二:表级别的资源隔离
与此同时,咱们在 PD 增长了 TableID 和 Namespace 之间的映射关系以及 NameSpace 和 TiKV Store 的映射关系,经过把上述关系持久化到 eEtcd 里,保证该映射关系的安全。
当数据插入时,能够在 TiDB 层面拿到 TableID,进而从 PD 找出目标 Region 所在的 TiKV,保证新插入的数据不会放到其余 TiKV。
另外,咱们还与 PingCAP 团队共同开发实现了一个 NameSpace 调度器,把未规整的 Region 调度回它应在的 TiKV 里,进而在表级别保证数据不会相互干扰。
优化三:管理工具
最后的问题是管理 NameSpace 的问题。
好在 TiDB 在早期设计时保留了足够的灵活性,经过 TiDB 原有接口,咱们只须要调用相关 API 即能经过表名拿到 TableID。
同时咱们在 PD 的命令行管理台 pc-ctl 中增长了 HTTP 接口,管理确认 Table Name 和 Table ID 之间的对应关系。
部署 TiDB 近一年来,摩拜单车经历了用户数量近十倍,日骑行数据数十倍的增加,依靠 TiDB 在线扩容的能力,咱们完成了屡次数据库扩容与服务器更换,并且这些操做对业务是彻底透明的,咱们能够更专一于业务程序的开发与优化,而无须了解数据库的分片规则,对于快速成长的初创公司,这有着很强的借鉴意义。另外深度参与 TiDB 的开发并和开源社区紧密的互动,也使咱们得到了不少有益的反馈,极大下降了代码维护成本。
将来,咱们会联合 PingCAP 进一步丰富多集群的管理工具,进行更深刻的研究和开发,持续提高 TiDB 的性能,将 TiDB 应用到更多的业务中。