当前位置: 首页 > 科技观察

基于订单系统的分库分表实战,让应用飞起来

时间:2023-03-17 10:15:52 科技观察

前言大家好,这是分库分表实战的第一篇。》设计思路和内容。本次实战的重点是分库分表的实战,比较适合有1到3年工作经验的程序员朋友。实战主要是接外卖订单在外卖APP作为本次实战的核心业务,如园技术团队基于外卖订单业务,开发了外卖订单项目,通过该项目逐步分析随着订单数据量逐渐增加,系统会遇到哪些问题。以这些问题为线索,逐步分析在分库分表之前是否有一些解决方案可以初步解决这些问题,随着订单数据量的增加,这些解决方案为什么会失效,最后导致分库分表。以及分库分表方案如何设计?设计完成后,应该如何实现?引入分库分表后会带来哪些新的问题abase和分表方案?这些问题都可以在这场实战中得到解答。熟悉单数据库版本的订单系统。一开始,订单系统是用单一数据库运行的。随着数据量的不断增加,系统会采取各种措施逐步优化,比如索引和SQL优化,增加缓存,上传读写分离和垂直分库等方案,分库分表只会如果结局无法忍受,则进行。从单库版本到分库分表版本的整个优化过程的基础是单库版本的外卖订单系统。儒猿技术团队提前使用Spring+SpringMVC+MyBatis开发并实现了外卖订餐系统。单库版订单系统整体架构图如下:上图是单库版订单系统的逻辑架构图和技术架构图比较订单系统分为三层,即接入层、服务层和数据层。1、接入层:是调用后台服务的入口。这里直接使用postman调用,因为重点是分库分表方案的实现,比较后端,所以直接使用postman作为请求入口非常方便。2、服务层:是整个订单系统的核心。提供外卖订餐系统的核心功能,如用户下单、用户查询订单列表、商户订单接收等核心功能;为了实现这些功能,使用了一些技术。比如使用Tomcat作为服务器对外提供服务,使用SpringWebMVC作为web开发框架,使用SpringIOC管理bean,使用MyBatis操作数据库,使用logback记录日志等。3、数据层:主要用于存储外卖订单数据,这里使用的数据库是MySQL。业务快速增长,驱动系统架构不断演进。这是一个背景。外卖订餐系统定位于一家初创互联网公司。目前累计用户约10万,日活跃用户约2万。订单量也是20,000。简单估算一下,一年的订单数据量在七八百万左右,单个数据库可以轻松抵挡。索引和sql优化,但是创业型公司发展比较迅速。如果踩对了风口,用户数量将呈现爆发式增长。订单20万,订单表从之前的几百万迅速达到了2000万的水平,如下图:令人担忧的是,随着时间的推移,订单表中的数据会不断增长迅速。这个时候sql查询的性能开始慢慢下降,是时候优化sql了。至此,从索引和sql优化入手,展示sql优化的大致流程。这里会有2个案例。隐式转换导致索引失败。对于MySQL来说,数据库资源使用率非常高,降低了MySQL的查询性能,最后导致ordersql查询突然增加到2s。为了解决这个问题,引入了缓存,如下图所示:说白了就是用缓存来承担大部分的查询请求,让很少的请求到达数据库,资源占用率数据库的性能会稳定在一个正常的范围内,这样ordersql的查询效率不会受到很大的影响。介绍读写分离方案的优化案例——由于促销活动,大量下单的用户会不断刷新页面查看订单信息,比如查看订单是否已经开始发货,这会导致对MySQL的大量请求。此时单体数据库无法抵抗这样的读请求,导致数据库负载过高,严重降低订单sql的查询效率,最终导致订单sql的查询时间突然增加到2.5促销活动期间。促销活动期间的订单操作是典型的读多写少的场景。为了解决这个问题,引入了读写分离的方案,如下图所示:即写数据请求到主库,读数据请求到从库。由于有2个从库,可以共同抵御大量的读请求,ordersql的查询效率可以得到显着提升。引入数据库垂直分区方案和引入读写分离方案后,可能会遇到另一个问题,即商品模块、订单模块、用户模块都部署在同一个物理数据库上,即主库.物理数据库的CPU、内存和网络负载能力由产品模块、订单模块和用户模块共享。比如有一天,产品模块做一些活动,产品模块会接受大量的读请求。比较尴尬的是product模块没有读写分离。此时产品模块所在的物理数据库,其CPU、内存和网络负载都会很高。关键是数据库的资源是有限的。商品模块已经占用了大量的数据库资源,而订单模块可用的数据库资源变得非常有限。这时候写入订单数据的SQL执行时间可能突然增加到2s,这对订单来说是绝对不能接受的。因此,为了避免其他业务模块对订单模块的影响,将进行数据库垂直划分的改造,如下图:垂直数据库划分后,每个业务都有自己独立的物理服务器,并且之前相互占用资源的问题不复存在,最终完美解决了顺序写入数据时间突然增加的问题。因为随着时间的推移,订单表的数据量必然会越来越大,订单sql查询的时间也会越来越慢。为了提高sql的查询效率,也为了更好的扩展性,最终还是有必要引入这套分库分表的方案。看一下分库分表版本的订单系统架构。引入分库分表方案后,外卖订餐系统的系统架构如下:整个层没有变化。分库分表分三层后,分别是访问层、服务层和数据层,仍然从上到下一一介绍:1.访问层:访问层仍然使用postman,还有这一层没有变化。2、服务层:增加了根据路由键重写sql的功能,因为分库分表后会有多个数据库和表,比如订单数据库分为order_db_0和order_db_1。每个数据库中有多个订单表,如order_db_0中的order_info_0和order_info_1。这时候如果要往数据库中插入一个订单或者查询一个订单,为了判断数据落在哪个数据库的哪个表,就需要使用routingkey来重写sql,而重写根据路由键的sql是通过ShardingSphere实现的。新增数据迁移功能,因为分库分表后,需要将之前单库中的数据迁移到新的数据库表中。比如这里分了8库8表,原来单库的数据会迁移到新的8库8表中,数据迁移会用到全量同步、增量同步、数据校验等功能。数据迁移功能会用到canal和RocketMQ。3.数据层:还是用MySQL,但是会用ShardingSphere做SQL重写和读写分离,然后在数据层引入缓存,缓存用Redis实现。结语本节主要对整个外卖订餐系统的背景、系统演进过程、单库版系统架构和分库分表版系统架构进行了简单的介绍,以及后续将围绕单库版本的订单系统进行分步优化,最终优化组件库分表版本的系统架构。为了更好的阅读后续连载内容,建议读者仔细查看单库版和分库分表版的系统架构图,了解当前的订单系统架构是什么样子的,订单是什么系统最终会形成一个整体的样子。认识。