本文将与大家分享饿了么作为快速成长的互联网公司之一,数据库技术如何在发展过程中紧随公司发展,不断满足业务需求。分享内容大致涉及以下五点:数据库架构如何满足业务,支撑业务发展?如何提高数据库的可用性?如何对数据流进行相应的控制和保护?未来如何提高数据库运维效率?总结首先简单介绍一下饿了么的概况。点过外卖的同学应该知道饿了么?饿了么发展最快的阶段是最近四五年。我是2015年加入饿了么,那时候每天只有几十万单,服务器也不多。到2016年,日订单达数百万,商户更多;而2017年的订单量和出货量订单均超过千万,至今仍在高速增长。这么多数据的产生,对底层的数据存储是一个非常大的挑战,而且当时要应对业务在很短时间内的爆发式增长,所以当时的底层技术挑战也是非常大的。大的。数据库架构的垂直拆分也是数据库架构初期比较原始的阶段。一开始是一主多从的架构;后来发现订单数据库已经不能满足业务增长的需要了。百万master之后,slave再多也难以满足业务的需求(因为write太大了),面临拆分的需求。热点业务需要单独拆分,将一套数据库拆分成多套。进行垂直业务拆分。数据库架构——垂直拆分的原理是什么?如何预估订单库当前架构能承载多少TPS和QPS?我们结合订单量,对应的QPS,TPS数据,然后根据半年后的增长情况来计算每个业务会产生多少QPS和TPS。然后再结合每组集群能够承载的TPS和QPS数量(根据压测),可以估算出需要拆分成什么样的结构,大概每组TPS和QPS多少(经过半年)拆分后需要携带。当时,按照业务垂直拆分后,这套解决方案承载了200万到300万单的规模。垂直拆分的好处是成本小见效快(业务代码改动不大),可以快速有效的支撑业务。虽然横向拆分已经按照纵向结构进行了拆分,但热点仍然是热点。例如,随着订单量的增加,订单仍然会成为一个很大的瓶颈。那么如何突破瓶颈呢?我们需要将订单的热点拆分成多个集合。Databasearchitecture-horizo??ntal就是业界常说的“横向拆分”。原来的订单表在底层拆分成1000个小表,放在不同的集群上。这样即使这个订单的量很大,也可以通过不断的横向扩容机器,将压力分摊到更多的集群上,从而满足热点的性能负载。我们可以通过压测计算出每个集群可以承载多少QPS和TPS,然后结合当前的业务情况来预估多少QPS和TPS对应会产生多少订单。另外,你也可以知道有多少套集群可以拆分成多少业务量,所以你也知道需要扩容多少台机器来满足半年或者一年的业务增长。如果底层实现了扩容的sharding策略,但是这种变化对业务是不透明的,意味着业务需要做大量的改造来适应底层的sharding逻辑,这对于一般业务来说是比较困难的。所以我们的水平拆分是为了对业务透明,我们需要搭建一个代理层(我们称之为DAL),代理层会帮助业务代码实现对数据库底层拆分逻辑的透明访问,而业务看到同样的订单表,但是底层已经变成了1000表。横向扩展完成后,基本上所谓的热点不会有太大的瓶颈。如果向上生长,还可以继续拆解变小,增加更多的机器来承载。多活架构垂直拆分后,性能就没有瓶颈了吗?其实机房也会成为我们的瓶颈。一般来说,企业向供应商租用机房。一个机房能装多少台机器是没有限制的,供应商也不可能给你预留太多的位置。当你的服务所在的机房放不下机器时,你会发现虽然技术架构可以满足水平扩展,但物理上无法再添加更多的机器,性能瓶颈还是会来。为了打破单个机房面临的容量瓶颈,我们需要扩展到更多的机房,所以我们打造了“多活架构”。数据库架构-每个机房的多活数据库是一个简单的主从结构。下单时,北京用户可以在第一机房下单,上海用户可以在第二机房下单。这样一来,下单的峰值压力会被分散到多个点,在两个机房部署同一套集群,也就意味着负载的性能会提升。这时候机器可以放在两个机房。如果一个机房的机器太满,我们可以将流量分流到另一个机房,扩展另一个机房的容量,从而打破单个机房的容量限制。我们的多活逻辑是根据用户所在的位置来决定他下订单的是哪个机房。可能他今天在北京,明天在上海,订单放在了不同的机房。为了让用户看到所有的数据,数据必须双向流通。因此,数据在多个机房之间的相互流通是数据库活跃的必要条件。做热备份的公司有很多。他们只是在一侧下订单,而另一侧则处于备用状态。一旦这里出现问题,他们就会切换到另一边。这种架构无法解决性能问题,资源利用率很低。(有多少公司敢砍题?)。并且我们的多活架构可以同时在两个机房下单,可以显着提高性能、资源利用率和可靠性。数据库架构层次从垂直拆分、水平拆分到多活后,基本可以满足大部分企业的业务发展。其中,我们有两个组件起着重要的作用,我们将它们一起介绍。①DAL代理层(DAL),最直观的要求就是能够做分库分表,可以做读写分离,还可以做资源隔离,连接数隔离,连接管理等等,等等重要的是,它还可以对数据库保护进行相应的操作。外卖业务大部分人在中午下单,所以11点左右是饿了么的业务高峰期。为了减轻数据库的压力,我们会通过DAL层进行调峰处理。当流量过大时,我们会将用户消息排队,从而缓解瞬间对数据库的影响。如果流量特别大,也可以进行限流熔断。还有黑白名单机制。懂数据库运维的就知道,如果研发写的SQL有问题,放到数据库中的风险会比较高。如果他现在发SQL命令删除表,是有风险的,我们的DAL会拒绝这种列入黑名单的SQL。一个更高级的功能是多维分表和全局表MapTable的功能。一些配置表希望所有机房都有,可以在DAL上实现GlobalTable功能,可以保证所有节点的数据相同。当然,DAL在完成这些功能后,对SQL也有一定的限制。比如事务,下单的时候不能跨服务切片做事务。许多传统的应用程序业务逻辑将许多东西包装在一个事务中,但互联网服务应该尽量减少此类应用程序。底层分片后,业务交易不能完全靠数据库中的交易来保证。有可能每个表的sharding维度不一样,会导致数据分布到不同的机器上。这就需要跨服务器事务一致性的保证,业务不能再依赖数据库事务,需要通过其他机制来保证。Orderby和Groupby也有限制。如果您检查Top10,DAL只会在一个切片上为您提供Top10,而不是全局。尽管有这些限制,但与DAL相比的好处是完全可以接受的。②DRC数据同步组件DRC,实现的功能是接受一个机房的变更日志,并将变更日志传送到其他机房,其他机房就可以应用变更。为什么使用DRC组件而不是MySQL原生复制?因为我们的链路是跨机房、跨地域的,在上海和北京的长距离传输下,使用原生复制缺乏灵活性。比如MySQL会产生各种消息,尤其是在维护操作的时候需要增加字段,会产生大量的变更日志,这时候直接投递会直接阻塞网络。当北京和上海的带宽只有5-10G时,100G的DDL变更表就会把带宽占满,容易造成重大故障。而且DRC可以做的事情还有很多:比如过滤无用消息,MySQL通常会生成很多通知消息,而我们只需要数据变化消息,只需要传输变化信息即可。它可以压缩数据包和过滤维护操作。维护操作可同时在两个机房进行,不希望通过复制方式传送。这样就避免了维护中大量的变更消息,造成网络拥塞等问题。再比如如何处理数据冲突?以及如何避免数据循环。如果变更日志A写在上海机房,但是A的变更传到北京机房后,北京机房的日志会更新,A会通过北京机房的变化。这是一个循环。DRC会标注对应的变更源,从而可以控制数据不返回到生成的机房。数据库高可用的下一步是如何提高数据库的可用性。整个网站的可用性是由多个部分来完成的,而数据库只是其中的一个部分,所以数据库的可用性应该高于整体的可用性。比如要做到网站可用性的三个九,底层需要四个九,甚至五个九的可用性来保证。架构我们都知道物理故障是不可避免的,任何机器、任何设备都可能发生故障,所以我们需要针对可能发生故障的地方有相应的高可用解决方案。当EMHA的一台Master机器出现故障时,我们的HA是基于开源MHA的EMHA。在每个机房,当每个机房的Master发生故障时,EMHA负责管理倒换。它不仅负责故障的切换,还要求切换时间控制在30s左右,同时将故障抛给其他需要通知的地方。比如master挂了之后,agent需要知道新的master是谁。因此,EMHA在切换时,需要将信息进行传播,使所有需要信息的组件和链路都能接收到信息。这样,当主库挂起时,对业务的影响很小(业务可能察觉不到),同时自动完成DB的切换。切割组件的对接,从而提高可用性。多分片方案如果订单业务没有办法保证机器不出故障,但又希望出故障的影响很小,可以采用分片方案。比如分成10片,放在10台机器上。这时一台机器故障会影响1个分片,整体只会影响十分之一的业务。如果把切片分成足够小的块,影响的范围就会变小。对重点业务进行更细粒度的切片。如果一个切片坏了,只能影响1/n个业务。异地多活异地多活后,机房出现问题影响不大,因为机房的切换时间在几分钟内就可以完成,可以大大提高系统在线时间。另外,在进行重要维护时,可以将一个机房的流量全部切断,在没有流量的机房进行相应的维护动作。维护完成后,可以切换流量,再操作其他机房。这是一个特别高风险的维护操作。无需关闭车站。一般较大的网站做一次停机维护需要很长时间;以上几点可以从架构的角度逐层提高可用性。下面我们从故障发现和处理的角度来看如何提高可用性。故障可用性也很重要——既然故障是不可避免的,那么我们必须追求如何快速发现和解决问题。Trace从应用(appid)到DB的全链路跟踪,包括接入层、应用层、中间层、服务层、代理层、缓存层、数据库层等串联。TraceID可以提供正向和反向的异常互推能力:ID会从上到下依次序列化,无论你发现哪一层有问题,都可以查看链路上哪些环节有问题(哪个环节耗时最长或异常),所以以便及时定位问题。如果每个地方都单独查找,会耗费很长时间。有了Trace系统,定位问题的效率会大大提高。另外,在数据库层面,80%到90%的问题都是SQL问题。如果能及时获取问题SQL,判断SQL来源,限制或阻断某些非关键问题SQL的访问,隔离问题SQL的影响,减少DB故障。VDBA我们在数据库层开发了一个VDBA自动处理程序,它会根据我们制定的规则不断扫描所有的数据库并判断状态。如果SlowSQL出现问题,会根据异常程度进行限流。杀死、拒绝等操作。当然,VDBA不仅可以处理SlowSQL,还可以处理系统拥塞、未提交的事务、复制中断、Blocked,以及大到无法清理的binlog。很多事情由VBDA自动处理后,不仅效率提高了,而且人为操作的风险也大大降低了。在故障处理过程中加快故障定位时间和故障自动处理机制后,可用性将得到显着提高。数据流控制数据流控制也依赖于刚才提到的一些组件。作为数据管理者,理论上应该有自己的手段来控制什么样的数据可以进入,什么样的SQL可以通过,以什么样的方式存储。控制并不意味着你可以通过写文件来控制它,你需要有相应的强制手段和工具。每个业务可以用多少个连接访问数据库,需要什么样的账号权限才能有比较规范的控制,让所有的数据进来的时候都在DBA的掌控之中。数据进来之后,需要生产和存储,落地后的数据也需要传输到其他地方,这些都需要相应的控制。比如现在大数据需要获取数据,我们可以通过DRC消息推送到大数据,这样就不需要扫描数据库获取数据了。原来通过Sqoop任务的大数据是隔天、每小时拉取数据,现在可以实现实时数据传输,在做营销活动的时候可以实时看到营销效果。数据生成后,可能还需要对外提供。比如将生产数据同步到测试环境和开发环境;这时候,DataBus就可以帮你同步数据。对外传输生产数据(尤其是手机号、身份证号)需要进行数据脱敏和清洗操作。以前比较繁琐,现在研发只需要管理同步配置信息,组件会自动脱敏清除,非常方便,符合安全规范。提升运维效率专注于提升运维效率:在研发人员几千人的公司,如果只有一堆规范文档维护规则,很难管控,因为有离职人员,新员工等进入的人,不可能推广给所有人,所以必须要有一个平台来管控。SQL治理首先,当SQL发布时,我们平台上的发布工具会嵌入需要遵循的标准。如果表格创建时不符合标准,则无法制作和提交。这将迫使规则和标准变得僵化。要求,SQL也能自动审计,节省DBA大量时间。另外,一旦生产中出现慢SQL,监控系统会第一时间推送消息给研发。如果影响生产运行,直接拒收或杀掉。比如我们定义超过30秒的SQL是不允许在线产生的,这种SQL会直接kill掉,这样可以大大降低生产的风险。自发布许多公司的DBA大部分时间都花在reviewSQL和发布SQL上,而我们的SQL是通过研发自发布的,DBA不用操心。本平台支持原生、PT执行、mm-ost执行(饿了么自改数据库多机房同步发布工具)。发布平台会帮他们计算你的发布需要多长时间,甚至让你判断什么时候是业务的低峰(那个时候开发布会比较好),这样研发对自己的发布有更多的控制权。自助归档也是一个相对频繁的需求。一旦产生大量数据,就需要将冷热数据分离,剔除不需要经常使用的数据。原来这个操作比较费力,需要DBA跟进,做很多事情,而现在只需要自己开发解决就行了。如果你的表超过1000万,你需要部署归档任务。这个时候会发消息给R&D,告诉他你的表超标了,需要部署归档任务。研发可以在平台填写表的归档规则。,审批完成后,后台会自动帮你完成。还有关于数据库备份和恢复。数据库部署到生产后,后台系统会自动部署备份和恢复任务,并自动为您检查可用性。您也可以在平台上完成数据回滚。一旦数据刷错或写错,可以通过平台找回。为了数据保护和迁移,DBA需要将一个数据库从本机迁移到另一台机器,将一个大表拆分成多个小表,类似的动作都需要迁移数据。我们创建了一个数据迁移工具。您只需要进行配置。配置完成后,可以自动迁移数据,这样也会减少很多DBA的工作量。云练习你现在饿了吗?所有的开发和测试环境都在云端,比自己搭建环境效率高很多。需要的时候拿,用完了就放。弹力也可以做到。弹性伸缩比较难,目前我们还没有完全实现,但是我们正在朝这个方向努力。我们业务的曲线是午峰和晚峰。这个时候流量很大。灵活调度需要在业务高峰时段增加机器,在业务低峰时段回收机器,以提高机器利用率。后面的云机房会承载我们的主要交通。云机房的优势在于底层管理无需自己负责,扩展资源更方便,可以提高交付效率。云上机房可以灰度引流。一开始,我们可以用少量的流量来做。当我们觉得稳定的时候,我们就可以慢慢的把流量上移。这样,我们就可以逐步发挥云平台的优势,在控制风险的同时,使资源动态化、可扩展地利用起来。因此,利用云来提高运维效率是一个很好的方式。建议原则总结一下,我个人觉得从我们做的这些事情中提炼出哪些点比较重要?①最小可用性原则应该对账户处理、连接处理、SQL标准有比较严格的限制。使用太多资源,不应该占用太多资源。最小可用原则就是你平时只用20个连接,我给你40个,还有双倍波动的余地。还有账号权限只需要添加、修改、勾选权限,这样就不会给你删除权限了。②DesignforFailure这是我们CTO常说的。无论是运维规划还是代码环节,设计过程都要考虑接受失败。无论是物理层面还是架构层面,基础设施肯定会出现问题。这时候,一个好的架构必须要考虑处理错误情况,保证这样的波动和瞬态问题能够容错和隔离,不会导致整体崩溃。同时能够快速恢复。③标准、流程、自动化(辅助)、量化,一开始就制定标准,然后把标准拆解成流程,再把流程做成自动化、自助化处理,保持整体标准不变形,提高同时。效率的目的应尽可能量化。例如,去年我们需要两个DBA来维护100个数据库实例。今年效率提升后,一个可能就够了。量化还可以提高运维效率(可以知道哪些环节最耗人力物力,针对性优化后效率是提高的)。④灰阶、限流、熔丝、隔离变化是影响系统稳定性的主要变量。如果要提高整体的可用性,就必须对变更过程有严格的限制。比如我们要求所有的release都必须先灰度化。灰度完成后会在一旁的机房发布,然后全量化,一定要有快速回滚的方法;然后程序需要过载保护处理,有限流、熔断、隔离。措施。⑤稳定性、效率、成本三点应该是企业对技术部门的核心诉求,也是有追求的技术团队继续努力的方向。⑥需要方向,但更重要的是,经历过今天介绍的内容的人都知道,每一步都不容易。对于基础设施薄弱的企业来说,最重要的是考虑他们能用什么。第一,要有立足点,甚至从最基本的问题出发,把问题一一解决。然后逐步完善和改变,真正让用户和企业感受到团队的价值。所以说了这么多,最重要的还是落实。郭国飞,饿了么数据技术部负责人。从事数据库行业十余年,专注于MySQL、PGSQL、MSSQL等数据库领域的管理、研究和平台开发。目前在饿了么主要负责数据库及相关中间件的管理、开发和维护。
