【微服务理论】微服务概览

530 阅读12分钟

为什么要学习架构?

因为架构思路是编码的基石,如果脑海中没有架构思路,编码就是一叶障目,看不到全局也就不可能写出好的代码。先别急着撸代码,先看看理论,有个大致的概念。原理可能看看就能懂,但是只有经历了实践,体会了痛点,才能理解和吸收。

当下互联网行业的火爆,用户量的激增,让各大公司开始考虑扩容和重构,微服务是首先映入眼帘的。然而据我所知,国内不少中小规模的技术团队对微服务的概念都不甚了解,对该不该引入微服务也不置可否。还有一些技术团队,没有考虑实际业务场景,只是为了追求技术热点,盲目引入微服务,但又缺乏相应的技术掌控能力,最后影响了业务的稳定性。

一、架构选型

组织沟通方式决定系统设计。

一定要根据自己的公司体量、业务形态来选择架构,好的架构都是一步步演进过来的。不要过于崇尚新技术、新架构。

架构的演进一定是源于痛点。

如果你不知道当前架构有什么问题,有什么痛点,那么一定无法演进。有很多公司或个人看到微服务很火爆,就开始盲目追求。这样只能是缘木求鱼。

对于微服务,我只能说,单挑死无全尸。

微服务的首要问题:

  • 该不该引入微服务
  • 微服务体系需要哪些技术
  • 团队怎么演进,怎么落地

该系列文章对于这些问题发表了一些个人的拙见,希望能抛砖引玉,欢迎大佬指点。

架构选型

组织沟通方式决定系统设计。

根据康威定律:康威定律

“设计系统的架构受制于产生这些设计的组织的沟通结构。”

每个公司的组织架构不同,则会演进出不同的架构。这个很关键,后面会反复提到。

比如你的公司是垂直架构,那就是递进关系,只有一条线:后端--前端--测试--运维,这样开发过来,最后找问题肯定是反向来的。

如果你的公司是水平架构,那就是分布式关系,比如:

游戏部+视频部+直播部----大后端(中台),那么你的架构一定是分布式的,并且做了服务拆分,将公共逻辑做成了服务。

那么,有银弹么?没有!

就像阿里为什么要建立中台又拆?只有不断的业务改进和架构演进,一切都是为了更好地服务业务,减少开发成本。

所以:

一定要根据自己的公司体量、业务形态来选择架构,好的架构都是一步步演进过来的。不要过于崇尚新技术、新架构。

架构的演进一定是源于痛点。

如果你不知道当前架构有什么问题,有什么痛点,那么一定无法演进。有很多公司或个人看到微服务很火爆,就开始盲目追求。这样只能是缘木求鱼。

对于微服务,我只能说,单挑死无全尸。

那么,我们来讲讲痛点。

二、单体架构,巨石架构

在开聊微服务之前,我先要你和介绍下单体应用。如果你不知道单体应用的痛,那也不会深刻理解微服务的价值。

当公司团队规模很小的时候,单体应用是最好的选择。主要模式有:LANMP(Linux + Apache或Nginx + MySQL + PHP)和MVC(Spring + iBatis/Hibernate + Tomcat)两种。其优点是学习成本低,开发上手快,测试、部署、运维也比较方便,甚至一个人就可以完成一个网站的开发与部署。

1-4人小团队首选,放开膀子就是撸。

别上来就微服务,几个开发人员的小公司,去追求微服务、去追求中台架构,这是追求完美吗?不是,是找死。

单体架构的优点

  • 应用开发简单;
  • 易对应用程序进行大规模修改;
  • 测试相对简单直观;
  • 部署简单明了;
  • 横向扩展不费吹灰之力;

单体架构的缺点

  • 应用复杂,都耦合在一起。
    • 重构困难、难以敏捷性开发,一崩则全崩。牵一发而动全身。
    • 难以扩展,可能久了就谁都不敢动了。新同事一来需要阅读大量代码,学习成本极高。如果相关负责人离职,那将是雪崩效应。
    • 而且这种是恶性循环:难理解--容易出错--更不敢重构--更不好理解
  • IDE卡,代码都在一起,当然卡。
  • 编译慢、启动慢。当单体应用的代码越来越多,依赖的资源越来越多时,应用编译打包、部署测试一次,甚至需要10分钟以上。
  • 框架升级困难。升级就只能全升,不能有针对性地利用语言优势。
  • 团队协作开发成本高。以我的经验,早期在团队开发人员只有两三个人的时候,协作修改代码,最后合并到同一个master分支,然后打包部署,尚且可控。但是一旦团队人员扩张,超过5人修改代码,然后一起打包部署,测试阶段只要有一块功能有问题,就得重新编译打包部署,然后重新预览测试,所有相关的开发人员又都得参与其中,效率低下,开发成本极高。
    • 如果分了部门,时间是几乎不可能统一的,这就导致代码无法统一编译发布。

三、什么是服务化

将单体应用中的逻辑分离,单独成立一个项目,独立开发、测试、上线、运维,然后将进程间调用变成远程RPC调用,各个模块之间不耦合,可以交给不同的团队管理,还可以根据各个模块的特点选择不同的语言。这样就可以解决单体应用膨胀、团队开发耦合度高、协作效率低下的问题。

微服务1.0

什么东西过大,解决的最好办法就是把它变小。

分而治之,化繁为简。

在我看来,微服务也是分级别的。也就是微的程度。

比如可以先按大的逻辑拆分,用电商举例,商品展示、购买、物流这样分。 也可以商品服务、订单服务、支付服务等这样分。

纵向拆分:从业务维度进行拆分。比如可以先按大的逻辑拆分,用电商举例,商品展示、购买、物流信息。

横向拆分:从公共且独立功能维度拆分。标准是按照是否有公共的被多个其他服务调用,且依赖的资源独立不与其他业务耦合。比如商品服务、订单服务、支付服务、评价服务等。

差别是什么? 前一种只是按接口分,我把展示的接口都放到一个单体写,那样这个单体挂了,购买的人不受影响。 问题就是公共模块(鉴权、底层方法)我要写多套。 适用于中型团队,因为公共模块也不是天天改。

好处

最大程度将业务耦合性降低,A模块挂了不影响B模块,而且模块可以分配给不同的人,单独治理。

线下麻烦点,但是线上稳定点。

举例:账号模块,此时可能是每个单体里面都有一套账号数据生成代码,然后用同一个git维护,一旦更新了就所有单体都要更新。

尽管也是模块化逻辑,但是最终它还是会打包并部署为单体式应用。

问题

  • 代码冗余严重。
  • 单机扛不住只能上负载均衡,查日志可能要查多台机器。更新也是,要批量上代码。
  • 数据库难以隔离,尤其是用户这种量最多的数据,可能一个bug导致全盘慢。
  • 故障无法转移,A机器挂了, B机器的代码是一样的,基本也会挂。
  • 影响的是一个整体业务,无法降级,无法熔断。挂就是一个业务挂。

微服务2.0

另一种就是按模块分,或者叫按数据分,这才是真的微服务。SOA(面向服务的架构模式)

适用于大型公司,业务量很大,每个模块都是一个小团队负责。

最大程度减少沟通成本。

当人员数量上来后,最大的消耗并不是编码时间,而是沟通时间。

举例:我将账号集中到一个服务,所有人需要账号信息都找我来拿,然后我这边用负载均衡、集群保证我的高可用,如果有人要更新用户数据,要我走我的接口,要么走我的消息队列,我来维护账号数据的一致性。

围绕业务或者数据构建,服务关注单一业务。服务间采用轻量级的通信机制,可以全自动独立部署,可以使用不同的编程语言和数据存储技术。微服务架构通过业务拆分实现服务组件化,通过组件组合快速开发系统,业务单一的服务组件又可以独立部署,使得整个系统变得清晰灵活。

  • 小即是美:小的服务代码少,bug 也少,易测试,易维护,也更容易不断迭代完善的精致进而美妙。
  • 单一职责:一个服务也只需要做好一件事,专注才能做好。
    • 一个服务只做一件事
    • 一个包只做一件事
    • 一个函数只做一件事
  • 尽可能早地创建原型:尽可能早的提供服务 API,建立服务契约,达成服务间沟通的一致性约定,至于实现和完善可以慢慢再做。
  • 可移植性比效率更重要:服务间的轻量级交互协议在效率和可移植性二者间,首要依然考虑兼容性和移植性。

image.png

问题是什么?

Fred Brooks 在30年前写道,

“there are no silver bullets”。

但凡事有利就有弊,微服务也不是万能的。

  • 天然的复杂性
    • 每个模块之间的调用会不会有bug?
    • A模块调B、C、D,一个环节出了问题,是不是每个模块报错日志都要看一下?
    • 数据一致性怎么保证?
  • 沟通成本短期内甚至会上升。
    • 原本是我本地的一个方法,现在要转成远程调用,接口或RPC,我是不是还要判断一下ping得通不。
    • 原本我可以直接看到代码里面的逻辑的,现在调用有问题是不是要去问,然后提供者还要加文档。
  • 测试困难
    • 原来单体应用一更新,测就完事了。现在模块B的代码更新了,不兼容或者有bug,是不是依赖他的模块全挂?
  • 避免连锁反应。上游(调用者)写了个for循环,给下游(提供者),然后下游再给他的下游,可能就指数级放大了。
  • 兼容问题。一旦大家都不一样了,必然会有很多兼容问题。
  • 依赖关系复杂。可能到了最后,服务之间的相互依赖会成一团乱麻。
  • 分布式事务问题

怎么解决?

  • 基建搭建好:消息队列、日志采集、容器编排等。
  • 文档写好,gRPC代码即文档。
  • 自动部署,CICD:Gitlab + Gitlab Hooks + k8s
  • 染色发布,方便开发和压测。
  • 监控体系:k8s,以及一系列 Prometheus、ELK、Conrtol Panle
  • Testing:测试环境、单元测试、API自动化测试

image.png

好处

既然这么多人选择微服务,肯定是利大于弊的。

  • 耦合性极低。(去中心化)
    • 数据去中心化: 独占DB,减少数据干扰。以前一个慢SQL打挂全服的情况不会有了。
    • 技术去中心化:想用什么语言都可以,只要实现协议即可。便于重构和迭代。
    • 治理去中心化
      • 独立进程,隔离部署。有针对性的上集群,热点服务就加机器。
      • 监控、日志都在一起,可以很快发现问题。
  • 可以用并行思路去调用数据,比串行更快。
  • 减少了沟通成本,每个人维护好自己的服务即可。
  • 拆分后,代码量少了, bug也更好发现。

四、怎么实现微服务

  • kit:一个微服务的基础库(框架)。
  • service:业务代码 + kit 依赖 + 第三方依赖组成的业务微服务
  • rpc + message queue:轻量级通讯

本质上等同于,多个微服务组合(compose)完成了一个完整的用户场景(usecase)。

可用性

这是一个大话题,后面慢慢讲到。

  • 隔离
  • 超时控制
  • 负载保护
  • 限流
  • 降级
  • 重试
  • 负载均衡

兼容性

Be conservative in what you send, be liberal in what you accept.

发送时要保守,接收时要开放。 按照伯斯塔尔法则的思想来设计和实现服务时,发送的数据要更保守,意味着最小化的传送必要的信息,接收时更开放意味着要最大限度的容忍冗余数据,保证兼容性。

所有依赖的东西都会崩。 所有依赖的东西都会崩。 所有依赖的东西都会崩。

总结

没有最好的架构,只有最适合自己的架构。根据自己的业务、团队来定制架构,能快速交付、快速迭代、持续重构的架构,就是好架构。

相关阅读: