我们是如何一步一步走到微服务的(一)——架构演进

376 阅读5分钟

一、 前言

在今天,大部分Java后端开发应该都对SpringCloud/Dubbo这样的框架以及生态耳熟能详,“微服务”,“高并发”更是招聘JD上的常客。但是回过头来看一看,我们到底是为什么需要它们呢,它们又是在什么场景下诞生的呢?

二、架构演进

单体架构

Robben是一家公司的后端组长,有一天老板让他负责一条新的产品线。Robben斗志昂扬,键盘哗啦啦作响,一个单体的SpringBoot Backend就搭建好了,他熟稔的按领域建模拆成订单、产品、用户、营销模块分给组员去开发,在团队加班加点的战斗下,系统很快就上线了。运营对新产品的反馈很不错,老板也高兴说:你他娘真是个人才。 系统架构如图:

image.png

应用水平扩容

在运营同学的努力下,公司业绩蒸蒸日上,系统也面临着流量增高的考验。Robben盯着运维的监控数据说:小问题,搞成集群就行了。于是Robben开始将后端服务部署多个,然后通过负载均衡的方式暴露API。这样就就通过水平扩容顶住了应用层海量并发。同时可以在这里引入缓存来缓解数据库压力。 系统架构如图:

image.png

此时系统面临两个问题

  • 集群的负载均衡:这个我们用Nginx就可以搞定。其他的方案还有DNS或者F5硬负载均衡。
  • 分布式Session:这个我们用Redis作为分布式Session就可以搞定。其他的还有JwtToken等方案也可以。
  • 需要缓存分担数据库压力:也用Redis搞定。

数据库读写分离

随着服务层的扩容,数据的压力自然也会增大,电商场景读明显大于写,所以显然robben想到用读写分离来解决这个问题。 搜索引擎在这里也可也引入,本质上搜索引擎就是一个读库。 image.png 带来的问题:

  • 多个数据源配置支持:动态数据源+自定义注解搞定。
  • ES的数据同步:binlog同步,全量同步+mq增量同步。

数据库垂直拆分

随着业务继续增长,虽然有读写分离,可是单Master也已经支撑不住系统的访问量。运维频频向robben投诉说数据库cpu经常90%以上,悄咪咪的说你们开发团队写的代码是不是有问题。在排查了一遍又一遍的慢sql之后,拿着数据库的诊断报告,robben终于申请到经费对数据库进行垂直分库了。

image.png 带来的问题

  • 多个数据源配置支持:多个数据源的配置。
  • 分布式事务:消息补偿。其他还有XA两阶段提交等等,云服务商也提供成熟解决方案。
  • 关联查询:全局表,数据同步,或者在应用层实现join。

数据水平拆分

当某个业务导致某个表的数据量超过单张表的瓶颈,比如按照阿里巴巴RDS建议一张表不要超过500w数据,可以将这张表在同一个库中拆成两个或多个表,其实就是希望底层能存在两个文件上。如果单表超过单个数据库瓶颈的话,就需要把这个表拆到两个或多个数据库中。比如当订单达到亿级别的时候,如图:

image.png 带来的问题:

  • sql路由的处理,因为同一张表会存放在不同的地方:数据中间件重写sql,像mycat,sharding-jdbc。
  • 主键的问题: 主键需要分布式环境唯一、有序,高性能产生,雪花算法搞定。
  • 分页的问题: 归并排序。

应用拆分微服务

随着版本的不断迭代,无穷无尽的业务使得原有的单体架构越来越复杂,越来越难以支撑业务体系的发展。提交代码总是会有冲突,模块直接耦合严重,一个小需求发布要牵扯到多个模块负责团队,主要业务和次要业务在一起,单个业务横向扩容复杂。在组员频繁的抱怨中,robben决定将单体的应用按模块拆成多个垂直应用。这样就解决了单一架构应用面临的部分业务扩容问题,流量能够分散到各个子系统里面,并且每个子系统有单独的软件开发周期,不同模块开发成员之间的协作和维护成本也降低了。Robben心想:这下代码不会被覆盖了。 架构如下:

image.png 带来的问题:

  • 不同模块之前的服务调用不再是内部方法调用,而是需要远程服务调用(RPC)
  • 服务的治理变成了一个难题:服务治理框架,配置中心,网关。

三、小结

看到这里,很容易明白,当架构演进到需要拆分微服务的时候,自然而然需要相应的框架来满足服务层和数据层的需求。
SpringCloud/Dubbo这些框架就是为了服务层应运而生。
MyCat/Sharding-Jdbc这些框架就是为了数据层而产生的。
还有像Mq、缓存都是一个大型分布式后端必不可少的中间件。

当然关系数据库搞不定的时候,数仓的概念就来了,像Hadoop全家桶/Es等大数据技术来满足海量数据的业务需求。这个系列就先不说了。 接下来主要是写一下服务层和数据层中间件的一些技术原理和使用要点。