微服务系统:解惑、技术选型

作者: judasn 分类: Java Web 开发 发布时间: 2018-04-03 15:25

在商言商

  • 一家公司在发现新的市场需求的时候,先发制人所产生的优势是非常重要的。所以美国利宝相互保险公司执行副总裁兼首席信息官 James McGlennon 说过这样的话:

“我们了解到的其中一件事是:如果你不能提高上市速度,毫无疑问,市场将发生变化,无论你对产品的设计、构建、部署或对员工的培训有多好,都不会完全适合市场需求,只因为晚了一点点。” 来源

  • 能减少生产的投入,自然推广的资源也就变多了,在保证良好服务的情况下,市场占有率就会越高。中小公司刚起步的时,系统压力小,采购服务器资源少。随着公司发展,部分功能模块流量越来越大,而部分功能流量依旧稀少,有的功能是 CPU 型应用,有的是内存型应用,有的是存储、宽带等,如果公司能只针对压力大的功能进行服务资源扩展那就好了。
  • 因为这个需求,我们也发现 IT 世界这几年发生新的变化:
    • 云服务
    • 容器
    • 微服务、前后端分离
    • DevOps
    • 服务网格(ServiceMesh)
    • 无服务器架构(Serverless)
  • 我们今天主要聊的是:微服务。至于其他概念在后续文章会进行补充。

微服务的根:敏捷开发

瀑布式开发

  • 在讲敏捷开发之前需要说下它的对立面:不敏捷,也就是敏捷之前大家常用的开发模式:瀑布式开发。
  • 瀑布式开发是一套经典的软件工程方法论,其定义了一套完备的过程规范,使得软件开发的运作就像是机器设备一样正常的运转而总结出来的项目管理方法论。
  • 这套方法论分为5个阶段:需求分析、设计、编码、测试和维护。
    • 需求分析阶段通常定义系统的需求,明确系统的目标;
    • 设计阶段通常确定系统使用什么数据库,系统模块的划分,各个模块的功能;
    • 编码阶段用编程语言实现设计阶段的任务;测试阶段主要测试功能是否实现,以及是否正确没用Bug;
    • 维护阶段是根据用户新的需求重新修改系统,使系统运行正常,更加稳定。
  • 现如今瀑布式开发一般在传统行业使用,互联网的公司如今一般用的是敏捷开发,那它为什么会互联网公司这么流行?主要还是传统软件开发模式过程太繁琐,且还有严格的文档的要求,了解过日本外包可能可以理解这个文档的概念,所以对于互联网行业这种传统模式开发效率太低低。

敏捷开发

  • 今天的主角是:微服务(Microservice Architecture,简称 MSA),这个概念其实很早就有了,只是没人像 Martin Fowler 那样进行系统整理、归纳。
  • 说到 Martin Fowler 那就得说道敏捷。Martin Fowler,这个老头子在面向对象分析设计、UML、模式、软件开发方法学、XP(敏捷极限编程)、重构等方面,都是世界顶级的专家,抽象能力不是一般的好。
  • 因为 Martin 是敏捷先驱,早期敏捷宣言的起草人之一,所以在他所理解的开发世界中,敏捷开发是最为关键的一个点。而敏捷开发有四个核心价值观被我们熟知:
    • 我们一直在实践中探寻更好的软件开发方法,身体力行的同时也帮助他人。由此我们建立了如下价值观:
    • 个体和互动 高于 流程和工具(我的理解:以人为本,有效沟通)
    • 工作的软件 高于 详尽的文档(我的理解:以实际产出的有效软件为目的,文档为辅助)
    • 客户合作 高于 合同谈判(我的理解:产出的软件最终是要服务客户)
    • 响应变化 高于 遵循计划(我的理解:世界上唯一不变的就是变化,我们经常在变化过程中发现我们真正需要的)
    • 也就是说,尽管右项有其价值,我们更重视左项的价值。
  • 敏捷宣言还有一套原则,来辅助这四个核心价值:
我们遵循以下原则:
我们最重要的目标,是通过持续不断地
及早交付有价值的软件使客户满意。

欣然面对需求变化,即使在开发后期也一样。
为了客户的竞争优势,敏捷过程掌控变化。

经常地交付可工作的软件,
相隔几星期或一两个月,倾向于采取较短的周期。

业务人员和开发人员必须相互合作,
项目中的每一天都不例外。

激发个体的斗志,以他们为核心搭建项目。
提供所需的环境和支援,辅以信任,从而达成目标。

不论团队内外,传递信息效果最好效率也最高的方式是
面对面的交谈。

可工作的软件是进度的首要度量标准。

敏捷过程倡导可持续开发。
责任人、开发人员和用户要能够共同维持其步调稳定延续。

坚持不懈地追求技术卓越和良好设计,敏捷能力由此增强。

以简洁为本,它是极力减少不必要工作量的艺术。

最好的架构、需求和设计出自自组织团队。

团队定期地反思如何能提高成效,
并依此调整自身的举止表现。
  • 在 2001 年 2 月 Martin Fowler,Jim Highsmith 等 17 位著名的软件开发专家忍不了这些低效率,总结了他们过去的经验,提出了这个概念并发表宣言。
  • 敏捷开发的特点就是:拥抱市场变化,积极响应市场需求,利用变化为产品创造竞争优势。
  • 但是也因为这样的特点,敏捷开发在实际落地的时候很多团队又遇到了新的问题:走两个极端。
    • 一种极端:犹如敏捷宣言所说的:个体和互动高于流程和工具,工作的软件高于详尽的文档。有些团队理解成了,那就不需要详细的计划,不需要周全的架构。(比如我们有些人就不喜欢写 README.md)
    • 一种极端:既然需求都是在变的,那我们就不断根据变动需求开发、测试、测试、开发。(比如,我们有的开发从来不会思考需求是否真的符合人类的思维。我们开发者也是软件的使用者。)
  • 很明显这种极端可能在我们身边都有出现过,我们也感受到这两种极端所带来的危害。
  • 所以,在使用微服务的技术做项目之前,我们需要先搞懂敏捷开发在整个项目开发过程中关键点,这也是为什么介绍微服务开发之前觉得先应该说的。

模块拆分(组件化)、服务拆分、分布式、集群、负载均衡、微服务、DevOps、前后端分离

模块拆分

  • 只是为了让代码更加简洁和可以维护,根据技术带来拆分模块,模块之间互相依赖。

服务拆分

  • 是微服务的第一步,也是我认为最重要的一步,也是最初最难的一步,拆的不好后面的设计也会有问题。
  • 只有真正理解业务,摸清楚需求的核心,才能拆分出一个有良好边界的模型。并且还要尽可能考虑后续需求的变更。(当然,随着时间的发展,我们个人开发者阅历的发展,终归会有技术债务,但是只能努力去克服)。
  • 关于领域驱动设计(DDD)Martin Fowler 也在自己的博客也有文章。DDD 是著名建模专家 Eric Evans[‘erɪk ‘evənz] 提出来的,这两个人都是抽象的大神,同一个界面的。
  • 服务拆分,优先先找到核心领域,比如广告系统:
    – 核心领域:商户、渠道、推广用户、SKU、推广任务、广告、广告成效
    – 通用领域:系统用户、权限
    – 支撑领域:搜索、日志、图片、文件

分布式

  • 相对于单体系统,分布式是指将一个业务拆分不同的子业务,分布在不同的服务器上执行,不同服务器之间可以互相通信和协调。

分布式

集群

  • 是指多台服务器集中在一起,实现同一业务(同一个业务代码部署多套到不同机子上),集合起来提供服务的(一般会配上负载均衡)。理论上,分布式的系统一般都是带集群的。

集群

负载均衡

  • 高效分发请求

负载均衡

微服务

  • 作者有关 Microservice 的原文:https://martinfowler.com/articles/microservices.html
  • 中文翻译:http://insights.thoughtworks.cn/microservices-2/
  • 它不是框架,也不是系统,只是一种架构风格。所以我们用的 dubbo [‘dʌbəu]、Spring Cloud 等框架,都是分布式服务框架。只是这种分布式服务框架都是微服务架构必不可少的基础能力,微服务一定是分布式的。分布式服务的概念比较模糊,只是解决了网站的高并发问题,很多细节问题是微服务帮其明确的。微服务更加强调敏捷和健壮,强调服务的粒度,一个服务只需完成一个单一的、独立的功能,多个微服务组合完成相对复杂的业务系统,以满足需求。而且微服务注重借助于各种中间件进行业务解耦和提高性能,以及提高服务的容错性。
  • 所以,理论上:微服务的架构都是带:模块拆分、服务拆分、分布式、集群。
  • 微服务其实在很早以前就有人/公司在做,只是过去没人去给它做总结和思考它本身,然后 Martin Fowler 就帮我们帮我们做了。
  • 单体系统在早期也没啥不好,但是随着 AWS 这种可弹性扩展的云诞生之后,这种单体架构就显得不够时尚了,只有微服务的架构才能合理榨干这些各种类型的云服务。
    微服务的目的是有效的拆分应用,实现敏捷开发和部署 。

DevOps

  • DevOps

  • 我们知道微服务的服务一般要单一、独立,从技术上说,这是通过工具把应用程序的内部复杂度转化为外部复杂度,需要一系列工具支撑微服务本身以及服务之间的通信。从组织上说,微服务团队要满足“快速发布,独立部署”的能力,则必须具备 DevOps 的工作方式。

  • 当我们把服务拆分之后,团队组织结构还是保留单体系统的结构的时候会经常看到这类对话:

这个包在我本地运行没有问题,部署到服务器出问题了,那肯定是你那边环境有问题呀(开发者说)

你们到底是怎么开发的,一部署上去,CPU 和 内存的占用立马暴增(运维人员说)

  • 那简单地讲什么是 DevOps(Deveplopment 和 Operations 的简称)?DevOps 是一种研发模式,方法论,2009 年开始发展起来,它不是框架或是技术的东西,是更好的优化开发(DEV)、测试(QA)、运维(OPS)的流程,开发运维一体化,通过高度自动化工具与流程来使得软件构建、测试、发布更加快捷、频繁和可靠。主要目的在于提高用户和业务需求提高产品的交付能力与效率。所以要践行 DevOps 第一个要改变的就是管理理念。
  • 在这些 DevOps 工具中,现如今有一个东西是必不可少的的:Docker(容器化)。到了今年 2018 年,如果是微服务系统,没有用到容器化的技术的,一般也可以认为是微服务不够的表现。
  • 当然,更未来的技术也开始出现了:Serverless(无服务器风格的架构 AWS Lambda 免去了很多环境管理的工作,包括设备、网络、主机以及对应的软件和配置工作,使得软件运行时环境更加稳定)
  • DevOps 虽然不是技术,但是它有一堆的技术工具来践行它的理念。
  • 目前业界主流的 DevOps 工具箱有:
    • 版本控制&协作开发:GitHub、GitLab
    • 自动化构建和测试:Maven 、Gradle
    • 持续集成&交付:Jenkins、Travis CI
    • 容器平台:Docker、Rocket、第三方厂商如(AWS/阿里云)
    • 配置管理(或 Automated infrastructure ):Chef、Puppet、Ansible
    • 微服务平台:OpenShift、Cloud Foundry、Kubernetes、Mesosphere
    • 日志管理:Logstash、CollectD、StatsD
    • 监控,警告&分析:Nagios、zabbix、ELK
    • 编辑器:IntelliJ IDEA
    • IM: Slack、钉钉
  • 利用这些工具会产生什么样的效果:
    • 代码的提交直接触发测试、发布
    • 各服务功能单一:使问题定位和调试变得简单
    • 全开发流程高效自动化:稳定,快速,交付结果可预测
    • 持续进行自动化回归测试:提升交付质量
    • 设施共享并按需提供:资源利用最大化
  • 由上可以看出来:DevOps 和敏捷目的一样,都是为了更快、更好的交付。所以也有人认为 DevOps 是敏捷的子集,也有一种说法是:新的敏捷概念:大规模敏捷(Scaling Agile),团结更多人的敏捷。
  • 以前我们认为的敏捷基本都是认为一个项目开发过程的敏捷,但是 DevOps 方法下,运维也是敏捷。
  • 所以 Amazon CTO 2014 年有这样一句话: “You Build It, You Run It”(谁开发,谁运行)
  • 目前的趋势来看,随着未来运维智能化,可能就是 NoOps 了。

前后端分离

  • 这几年前端发展太快,前端已经可以很好滴做很多事情,所以术业有专攻,很多时候,如果项目大、公司开发人员足够的话,最好都进行前后端分离。
  • 分离之后我们常会遇到下面几个问题:
    • Mock。推荐用 YApi 工具,具体看 YApi 官网,本质还是要了解 mockjs。
    • 开发阶段的调试:Swagger
    • 跨域问题:后端 Spring MVC 需要配置 CORS 相关(CORS = Cross-Origin Resource Sharing,在服务器端设置响应头,把发起跨域的原始域名添加到Access-Control-Allow-Origin 即可)。
    • 接口版本:在请求头有版本标识,后台接口 mapping 地址不变,扩展多个私有方法,根据请求版本来区分调用哪个。
    • 数据传输格式统一:JSON(不管是接受还是发送。除了批量初始化数据这类操作,建议 CSV 文件上传,后端用流方式)
    • 认证。这里主推 JWT,具体可以看我这篇 优化单点登录流程的好东西:JWT 介绍
    • 权限控制。如果有网关的话,后端的用户的认证和鉴权都是在网关进行处理。前端在用户登录后拿到用户权限列表标识,页面根据这些标识判断是否有对应的按钮、菜单权限。
    • SEO 问题。内部系统不需要,面向广大用户的外部系统可以 Google 下。
  • 根据实践,一般建议前端开发者给后端做一些目前大前端的基础培训,让他们可以简单看懂代码,会修改简单组件即可。

微服务团队

  • 根据康威定律:设计一个系统的任何组织(广义上)都会产生这样一种设计,其结构是组织交流结构的复制。
  • 意思就是:设计一个系统的团队结构将决定了一个软件系统的结构,将人员划分为 UI 团队,中间件团队,DBA 团队,那么相应地,软件系统也就会自然地被划分为 UI 界面,中间件系统,数据库。而一个高效的微服务团队会针对这种情况进行改善,微服务团队需要是一个全栈的团队,跨职能的团队,应该包含整个项目周期的所有技能,前后端开发、UI设计、测试、构建部署、上线与运维都是必须技能。
  • 这种组织结构的好处是:在业务服务的内部实现需要升级或者变更时,团队内的各角色成员进行沟通即可,而不需要进行跨团队沟通,这大大提高了沟通效率。只有服务之间的接口需要变更时才需要跨部门沟通,如果前期在服务之间的交互上定义了良好的接口,则接口变更的概率并不大,即使接口模式有变更,也可以通过一定的设计模式和规范来解决。

引入微服务带来的技术问题

  • 既然微服务的目的是有效的拆分应用,实现敏捷开发和部署,那拆分后的新模式肯定会带来新的问题。
    • 客户端怎么访问 N 个服务?
    • N 个服务怎么管理?
    • N 个服务如何通信?
    • 服务挂了怎么处理?
    • 服务变成无状态?
    • 网络开销?

微服务是如何解决

客户端如何访问这些服务?

  • 引入 API Gateway(网关),提供统一服务入口,让微服务对前台透明,方便客户端调用
  • 引入网关最大的问题是:单点故障,性能瓶颈。

服务是如何通信?

  • 最通用的有两种方式:
  • 同步调用:
    • REST
    • RPC(Thrift, Dubbo)
  • 异步调用:
    • MQ、Kafka
    • 异步主要是可以降低调用服务之间的耦合,又能成为调用之间的缓冲,确保消息积压不会冲垮被调用方,同时能 保证调用方的服务体验,继续干自己该干的活,不至于被后台性能拖慢。

这么多服务,怎么找?

  • 在微服务架构中,一般每一个服务都是有多个拷贝,来做负载均衡。一个服务随时可能下线,也可能应对临时访问压力增加新的服务节点。服务之间如何相互感知?服务如何管理?Dubbo 是用 zookeeper 来管理。

这么多服务,服务挂了怎么办?

  • 随机中一个,多个服务器挂了是正常,但是服务还是得照样提供,所以我们需要解决:
    • 重试机制
    • 限流
    • 熔断机制
    • 负载均衡
    • 降级

难点

多套系统的数据

  • 每个微服务都有自己独立的数据库,那么后台管理的联合查询怎么处理?这应该是大家会普遍遇到的一个问题,目前常见有三种处理方案。
    • 严格按照微服务的划分来做,微服务相互独立,各微服务数据库也独立,后台需要展示数据时,调用各微服务的接口来获取对应的数据,再进行数据处理后展示出来,这是标准的用法,也是最麻烦的用法。
    • 将业务高度相关的表放到一个库中,将业务关系不是很紧密的表严格按照微服务模式来拆分,这样既可以使用微服务,也避免了数据库分散导致后台系统统计功能难以实现,是一个折中的方案。
    • 数据库严格按照微服务的要求来切分,以满足业务高并发,实时或者准实时将各微服务数据库数据同步到 NoSQL 数据库中,在同步的过程中进行数据清洗,用来满足后台业务系统的使用,推荐使用 MongoDB、Elasticsearch、HBase 等。
  • 未来 TiDB 这类 NewSQL 成熟了,我们就会好过点。

微服务架构的数据一致性问题

  • 以电商平台为例,当用户下单并支付后,系统需要修改订单的状态并且增加用户积分。由于系统采用的是微服务架构,分离出了支付服务、订单服务和积分服务,每个服务都有独立数据库做数据存储。当用户支付成功后,无论是修改订单状态失败还是增加积分失败,都会造成数据的不一致。目前常见的三种方式解决最终一致性:
    • 可靠消息最终一致性
    • TCC(Try-Confirm-Cancel)
    • 最大努力通知
  • 三者比较:

最终一致性

微服务的主要组件

  • 常见的微服务组件及概念
    • 服务注册,服务提供方将自己调用地址注册到服务注册中心,让服务调用方能够方便地找到自己。
    • 服务发现,服务调用方从服务注册中心找到自己需要调用的服务的地址。
    • 负载均衡,服务提供方一般以多实例的形式提供服务,负载均衡功能能够让服务调用方连接到合适的服务节点。并且,节点选择的工作对服务调用方来说是透明的。
    • 服务网关,服务网关是服务调用的唯一入口,可以在这个组件是实现用户鉴权、动态路由、灰度发布、A/B测试、负载限流等功能。
    • 配置中心,将本地化的配置信息(properties, xml, yaml等)注册到配置中心,实现程序包在开发、测试、生产环境的无差别性,方便程序包的迁移。
    • API管理,以方便的形式编写及更新API文档,并以方便的形式供调用者查看和测试。
    • 集成框架,微服务组件都以职责单一的程序包对外提供服务,集成框架以配置的形式将所有微服务组件(特别是管理端组件)集成到统一的界面框架下,让用户能够在统一的界面中使用系统。
    • 分布式事务,对于重要的业务,需要通过分布式事务技术(TCC、高可用消息服务、最大努力通知)保证数据的一致性。
    • 调用链,记录完成一个业务逻辑时调用到的微服务,并将这种串行或并行的调用关系展示出来。在系统出错时,可以方便地找到出错点。
    • 支撑平台,系统微服务化后,系统变得更加碎片化,系统的部署、运维、监控等都比单体架构更加复杂,那么,就需要将大部分的工作自动化。

Java 的微服务方案:Spring Boot、Spring Cloud

  • 先推荐业界的 Spring Cloud 最佳实战:https://github.com/sqshq/PiggyMetrics
  • Spring Cloud 起源于 Netflix (网飞)的 NetflixOSS(因为是基于 Spring Boot,所以是和 Spring 深度合作的产物),并且在他们的产品上得到成功验证,也是目前业界最认可并推崇微服务框架。
  • 关于 Spring Boot 和 Spring Cloud 两者之间的关系可以这样简单粗暴地理解:
    • 因为:
      • Spring Core == Spring Boot
      • Spring MVC == Spring Cloud
    • 所有:
      • Spring MVC 依赖 Spring Core
      • Spring Cloud 依赖 Spring Boot
  • 但是,Spring Boot 严格一样上不算是一个框架(也算是框架),应该是说 Spring 框架的一个组合表达方式。这种表达方式主要是为了解决过往 Spring 项目中各种 xml 文件配置、各种依赖包带来复杂度。
  • Spring Cloud 是微服务的各个服务的管家。这些集合主要解决:服务发现注册、配置中心、网关路由、消息总线、负载均衡、断路器、数据监控等,实现这些功能组件有:
    • Spring Cloud Config:配置管理工具包,让你可以把配置放到远程服务器,集中化管理集群配置,目前支持本地存储、Git以及Subversion。
    • Spring Cloud Bus:事件、消息总线,用于在集群(例如,配置变化事件)中传播状态变化,可与 Spring Cloud Config 联合实现热部署。
    • Eureka [jʊ’rikə]:云端服务发现,一个基于 REST 的服务,用于定位服务,以实现云端中间层服务发现和故障转移。
    • Hystrix [hɪst’rɪks] :熔断器,容错管理工具,旨在通过熔断机制控制服务和第三方库的节点,从而对延迟和故障提供更强大的容错能力。
    • Ribbon [‘rɪbən]:提供云端负载均衡,有多种负载均衡策略可供选择,可配合服务发现和断路器使用。
    • Feign [fen]:Feign是一种声明式、模板化的HTTP客户端。
    • Zuul:Zuul 是在云平台上提供动态路由,监控,弹性,安全等边缘服务的框架。Zuul 相当于是设备和 Netflix 流应用的 Web 网站后端所有请求的前门。
    • Turbine [‘tɝbaɪn]:是聚合服务器发送事件流数据的一个工具,用来监控集群下 hystrix 的 metrics 情况。
    • Spring Cloud OAuth2 – 基于 Spring Security 和 OAuth2 的安全工具包,为你的应用程序添加安全控制。
    • Spring Cloud Sleuth [sluθ]:日志收集工具包,封装了Dapper和log-based追踪以及Zipkin和HTrace操作,为SpringCloud应用实现了一种分布式追踪解决方案。
    • Spring Cloud Stream:基于Redis,Rabbit,Kafka实现的消息微服务,简单声明模型用以在Spring Cloud应用中收发消息。
  • 实际常见的流程:
    • 请求统一通过API网关(Zuul)来访问内部服务,在网关这一步做认证和鉴权
    • 认证和鉴权后,网关从注册中心(Eureka)获取可用服务
    • 由Ribbon进行均衡负载后,分发到后端具体实例
    • 微服务之间通过Feign进行通信处理业务
    • Hystrix 负责处理服务超时熔断
    • Turbine 监控服务间的调用和熔断相关指标
    • Sleuth + Zipkin 将所有的请求数据记录下来,方便我们进行后续分析(分布式链路跟踪)

最终个人在技术选型上的选择

  • 优先级高
    • 统一环境:NTP、时区、hosts
    • 服务注册:Eureka
    • 熔断器:Hystrix + Turbine
    • 网关:zuul
    • 客户端负载均衡:Ribbon
    • 内部服务调用:Feign
    • 认证鉴权:Spring Cloud OAuth2 + JWT
    • 分布式调用链监控:Spring Cloud Sleuth + Zipkin
    • 状态机:Spring StateMachine
    • 数据库:MyCAT + MySQL 5.7
    • 部署:Docker
    • 持续集成:Jenkins
    • 构建工具:Maven
    • 版本控制:Gogs
    • 项目管理:TAPD
    • 后台 API 文档:Swagger
  • 优先级中
    • 消息队列:Kafka
    • 日志收集:ELK + Kafka
    • 图片系统:FastDFS
    • 分布式调度:xxl-job
    • 缓存:Redis
    • API Mock:YApi
    • 前端:Angular
    • 程序监控:Spring Boot Admin / Spring Boot Actuator
  • 优先级低
    • 分布式配置中心:Spring Cloud Config Monitor / Apollo(携程)
    • Docker 监控:CAdvisor + InfuxDB + Grafana

资料

希望对你有帮助!