微服务的自述(我是谁?我从哪里来?我能干啥?)

我是微服务,当下一个比较热的技术架构体系,接下来我要讲的故事是我的个人传记。要想了解我请允许我从我的前辈们说起,这样各位看客将会对我有个全方位的了解和认识。

一、单机时代

说起单机时代,那还是上个世纪八十年代的时候。哪个时代个人电脑还没有普及,所有的电脑都是奢侈品,如果你有一台个人电脑?哇塞!豪横!!还记得那个时候每个单位的电脑、学校的微机室都是干净整洁,必须换鞋才能进,那就是一个高级实验室,会用电脑电子那叫“香饽饽”、“关系户”。

那时几乎所有的应用程序都是单机运行,比如WPS、Auto CAD、3DS等等。一个很有名的公式:程序=数据结构+算法 不知各位是否还记得?如果你这都知道说明你已人近中年。这时的程序很少会涉及到高并发的情况,所以只要算法优秀你的程序一定快如闪电。各种数据的存储都放在本机的自定义格式或者DBF格式,需要考虑的是如何高效的存储和读取数据。

此时的应用程序多数都是为工具类、科学计算类、工程类,很少涉及到企业的业务管理,一个Foxbase(后来的Fox Pro)可以将企业大部分的业务功能都管理起来。

二、C/S时代

随着计算机硬件的大步发展,以及以Sysbase、IBM db2、Oracle、MS SQL Server为首数据库技术突飞猛进,开启了C/S时代。

这个时代将数据库放在远端,当然不是互联网,可以是局域网或者通过VPN访问远端数据库。这时的业务逻辑要么使用SQL写在数据库端,要么写在各个客户端,这里不进行展开叙述。总之你的数据库结构设计合理、SQL语句优化,你的程序也一定是飞一样的感觉。

此时的优化多数从数据库表结构、SQL语句优化考虑,应为这个时候的瓶颈不是在客户端而是在数据库端。

三、B/S王朝

随着HTTP、浏览器的出世,应用程序也跟着J2EE、JSP、ASP等等搭上了Http这辆快车,开启了B/S王朝。

这时我们将大部分的业务逻辑都统统的放在应用服务端,应用服务器如Tomcat、Web Sphere、Web Logic、IIS等等。

而这个时候随着应用逻辑日益复杂,各技术大牛们开始在应用服务器中各种代码优化。以及各种后端相继出现MVC、Hibernate、iBatis、Spring(刚刚出世时还不能称之为神)等等。我们把应用服务器放大看看里面大体的分层。

这样的分层体系能够让我们代码清晰,维护方便。但是随着我们的用户不断增长,请求不断增加的时候占用网络带宽的常常是一些图片、视频等静态文件,这些静态文件占用了大量的网络带宽。而且会发现用户处理业务逻辑的部分是高CPU、高内存型,静态文件是高带宽型,所以我们可以把架构调整成如下:

这样一来对于占用带宽较高的静态文件部分被分配到了文件服务器上(关于文件服务器的扩展后面会提到,这里暂时先放下),但是这样并没有解决由于用户增加带来的应用服务的压力,而且还容易出现一旦应用服务器宕机整个系统将会彻底不可用的情况发生。于是我们进一步优化系统结构

这里我们加入了一个负载均衡,经常使用的负载均衡有F5(硬件)、Nginx(软件)。根据不同的负载均衡策略可以将浏览器发来的请求分发给不同的应用服务节点,从而降低单个节点压了和不稳定性。

增加负载均衡后好像解决了单应用服务问题,但是随之而来的就是Session共享问题。当然我们可以通过在负载均衡将同一个Session转发到同一个应用服务节点,也可以在不同服务节点上共享Session,共享Session的缺点是需要各应用服务节点之间需要进行高速通讯,三个以上的应用服务节点就会大大降低效率。所以实际上使用时共享Session的方案都不会超过三个服务节点。

随着访问量的再次增加,数据的读写会成为下一个瓶颈,为了解决这个瓶颈继续优化系统架构。

把数据进行读写分离,应为对于数据库的访问80%~90%都是读取而不是写入,所以采用读写分离后会大大提高系统的响应速度,但同样会引入数据同步以及数据同步延迟的问题,这个问题会在另外一篇文章内详细介绍如何优化,这里不再讨论。

四、移动互联网、物联网的革命

智能移动终端的普及使得系统访问的形式发生了重大变化,智能终端可能在3G/4G/5G网络、Wifi网络之间随意切换,使得服务器不能再用Session保持用户的访问信息。而且由于智能终端能够充分利用人的碎片时间使得系统的访问量骤然增加。

为了保证浏览器和移动APP在应用服务端的处理逻辑一致我们将抛弃在Session中保存用户的任何信息。而采用在用户的每次请求时都带上用户本次登录的唯一标识——Token,该Token是由用户本次登录时随机生成的一个长字符串,应用服务器接收到请求后根据Token重新查找本次登录的基本信息——你会发问: “什么?每个请求都需要重新查询数据库?这不增加了数据库的负担吗?”——是的,如果不优化系统架构就会出现这个问题,所以需要继续优化。

这时引入了远程缓存服务,常用的有Redis和Memchached。通过远程缓存服务的集群保证的了远程缓存服务的高可用性。这时将所有选用在各个应用服务之间共享的信息都放入到远程缓存服务中,保证应用服务逻辑一致性。

我们还会发现一个问题就是所有HTML都是在应用服务端实时渲染好后给到浏览器的,这样会增加应用服务CPU负担,造成不必要的浪费。浏览器是否也可以像移动APP那样一次性把HTML下载后,以后所有的请求只返回数据,而页面有浏览器端动态渲染生成呢?当然可以了,这里就用到了Ajax和前(浏览器)后台(应用服务)分离。继续优化系统架构。

注:

  1. 如果你的系统需要SEO,那最好还是使用应用服务端渲染后发给浏览器,这个技术名称叫SSR(Server Side Render 服务端渲染)。
  2. 如果你的页面内容基本不会变化,也可以将该页面进行静态化(保存成HTML格式文件)放入文件服务器。再次请求这个页面时请求的是该静态HTML文件。这样可以降低应用服务器压力,提高系统响应速度。如何生成、保存、访问、刷新静态文件这个技术和策略您可以自行学习。

这里将HTML、JavaScript和CSS进行重新打包,浏览器只需第一次下载所有的HTML、JavaScript和CSS,以后请求应用服务只交换数据,减轻了应用服务的CPU负担。常用到的前端技术有Angular和VUE。

当然这里同样会引入另外一个问题,如果你的应用特别大(HTML、JavaScript和CSS体积大)就会导致浏览器第一次载入时特别慢而且是白屏,降低用户体验。为了解决这一问题可以使用前端延迟加载技术,也就是将一次性加载变成多次按需加载,这里的技术您可以自行问Google或度娘。

五、开启微服务

重新回到应用服务节点上,现在有n个服务节点,每个服务节点都可以独立完成所有的请求,看似完美但还有改进空间。

能够想象按照业务逻辑访问量来统计会得到如下结论:

业务逻辑访问量占比
用户业务10%
订单业务40%
支付业务40%
其他n%
这里只是举一个例子,具体数值您可以根据您系统的业务场景进行估算

所有的业务逻辑都捆绑在一起也会浪费服务器资源,如果我们的业务逻辑也可以单独按需部署是否会更合理呢?如:用户逻辑服务部署2个节点、订单业务服务部署10个节点等等。

这样按照业务逻辑将每个业务都分别部署成单独节点或者服务集群的架构既可以称之为微服务架构。

现在比较热门的微服务架构有Apache Dubbo (由阿里发起后交由Apache管理)和Spring Cloud,以下内容将会穿插介绍Dubbo和Spring Cloud的一些概念,具体关于这两个技术会在后续文章进行详细介绍。

继续优化我们的架构:

系统架构一:多域名部署
系统架构二:单域名部署

个人偏好除非特殊情况大多数喜欢使用第二种系统架构:单域名部署。

将系统按照业务逻辑(微服务)单独进行部署,会遇如下问题:

  1. 如何划分业务逻辑最合理?
  2. 如何保证各个微服务之间同一事务问题(分布式事务)?
  3. 各个微服务之间如何通讯?是普通的http?RPC?还是有更好的方案?
  4. 如果微服务数量太多,微服务如何统一管理?
  5. 各位服务节点是否可以根据业务访问量自行增加和减少(动态伸缩)?
  6. 微服务如何调试、编译、发布?
  7. 发布新版本时如何保证每个微服务能够及时更新。手工发布?太累容易出错!可否自动发布?
  8. 成百上千个微服务如何保证微服务的配置不出错?能否进行统一管理?
  9. 一旦某个微服务宕机谁来负责监控?谁能帮忙重新启动这个微服务?
  10. 数据库是否可以划分成不同的实例也按照业务逻辑分开?

带着这些问题继续我的自述。

业务逻辑如何划分这是一个只有更好没有最好的哲学问题,每个公司、每个系统、每个团队都会有自己想法和答案,这里只给出作者的个人建议:

  1. 各业务在各自业务内完成逻辑闭环
  2. 尽量避免分布式事务的发生
  3. 对外提供的接口尽量保持统一不变

一旦发送分布式事务各位可以自行学习分布式事务(三段式提交、事务补偿等等)相关知识,不在这里作为重点讨论内容。

如果您的系统只有2个微服务一起都还美好,但是随着业务复杂、访问量不断增大,可能微服务的数量也会不断增加。各个微服务之间的调用也会随之复杂,有可能A调用B,B调用C,C调用A或者其他,总之非常多非常繁琐。所以为了简化这一操作,这里我们就要引入新模块:注册中心(Register Center),监控中心。

A. 注册中心

如果A调用B,A称之为Consumer(消费者)、B称之为Producer(生产者)也可以称为Provider(提供者)。

首先Producer向注册中心报告:我是谁(Service name),怎么找到我(地址URI),我能干什么(Interface)、我有多大能力(权重weight)等信息。

提供一样功能的Producer可以在注册中心注册同一个Service name,但是URI不同,Weight有可能不同。

Consumer向注册中心点声明我需要一个Service name,注册中心即可返回一个可用的Producer节点(根据规则返回)。

Consumer根据注册中心返回的节点地址进行调用。

  • Dubbo常用zoomkeeper等作为注册中心
  • Spring Cloud注册中心为 Spring Cloud Eureka

当然注册中心为了避免单机故障,也可以部署多台注册中心。

B. 监控中心

监控中心可以监控各个微服务的Consumer和Provider之间的调用信息,设置负载均衡的规则等等。

Dubbo 的原理图

C. Spring Cloud Config(配置中心)

D. Spring Cloud Gateway(Spring网关)

六、一切虚拟化

七、写在最后

这篇文章是从一个系统在访问量不断增大、数据不断增加是如何一步一步优化系统架构角度介绍出了微服务架构。里面涉及的概念和技术细节没有一一展开,希望能够为大家换一个角度审视系统架构。

个人对于系统架构的几点心得:

  1. 微服务不是一门技术,而是一个架构的理念和体系。这个理念能够帮助我们在系统架构时知道用什么技术实现什么功能,如何在成本最低的情况下使系统具有更好的可扩展性、更高可用性。如果脱离业务和成本只考虑IT技术我觉得不是一个好的架构师。
  2. 不要为了微服务而微服务。例如你遇到一个非常小的系统,用户数在千人以下,可预计的将来用户数量也不会太多增长,我想这个系统只需考虑逻辑分层合理、数据结构设计合理即可,考虑后期维护成本不高足以。我相信一个最基本的Web服务就可以搞定一切。
  3. 微服务的颗粒度划分一致是一个好问题,这个问题需要我们不断的总结经验,记住千万不要抛开业务逻辑讨论颗粒度。
  4. 所有的技术架构都是先有需求,才有解决方案,任何的方案都不会100%满足要求,任何技术都会有利的一面、也有弊的一面——哲学思想就是这样——。如何取舍?只要利益最大化即可。利益是什么?每个人的答案都不一样。哈哈有点形而上学的味道了。
  5. 架构师更应该从上帝的视角看待整个系统,而不纠结于某个技术。系统是服务于人,而不是人服务于系统。

发表评论

电子邮件地址不会被公开。 必填项已用*标注