首页 > 代码库 > 微服务架构与实践及云原生等相关概念

微服务架构与实践及云原生等相关概念

微服务架构与实践

笔记:《微服务架构与实践》 王磊 著

一 单块架构

  1 定义:对于这种功能集中、代码和数据中心化、一个发布包、部署后运行在同一进程的应用程序,我们通常称之为单块架构应用,并非物理上的分层。

  2 单层架构:数据 逻辑 页面 混合

  3 三层架构:

    1)表示层:数据显示和用户交互

    2)业务逻辑层:业务逻辑处理

    3)数据访问层:数据存储访问

  4 优势: 比较适合小项目

    易于开发:开发简单直接,集中式管理,基本不会重复开发,集成工具适合

    易于测试:单进程

    易于部署:单项目包,功能都在本地,没有分布式的管理开销和调用开销

    易于水平伸缩:发布相同的项目包,部署多个运行环境,使用负载均衡器分发,克隆

  5 挑战:

    开发效率低:所有的开发在一个项目改代码,递交代码相互等待,代码冲突不断

    代码维护难:代码功能耦合在一起,新人不知道何从下手

    部署不灵活:构建时间长,任何小修改必须重新构建整个项目,这个过程往往很长

    稳定性不高:一个微不足道的小问题,可以导致整个应用挂掉

    维护成本增加:功能多,团队大,管理复杂,缺陷修复容易导致新的缺陷问题

    持续交付周期长:

    技术选型成本高:采用统一的技术平台或方案开发,当尝试引入新的框架、技术或对技术站升级会面临不小的风险。技术变化快,平滑完成替代较难。

    可扩展性差:无法满足高并发情况下的业务需求

    构建全功能团队难:单块架构往往以技能为单位进行分组,如前端、业务层、数据库团队等。

二 微服务架构

  微服务架构是一种架构模式,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。每个服务运行在其独立的进程中,服务与服务间采用轻量级的通信机制互相沟通(通常是基于HTTP的RESTful API)。每个服务都围绕着具体业务进行构建,并且能够被独立地部署到生产环境、类生产环境等。另外,应尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建。

                                                        ——摘自马丁· 福勒先生的博客

  1 特点:

    1)微

    微服务架构通过对特定业务领域的分析与建模,将复杂的应用分解成小而专、低耦合并且高度自治的一组服务。微的定义最好符合项目的敏捷开发周期。

    2)单一职责

    业务逻辑单一,高内聚低耦合,不同服务通过管道等方式灵活组合。

      注:面向对象设计之SOLID原则

SRP

The Single Responsibility Principle 

单一责任原则

一个对象/类应该只有一个发生变化的原因,如果一个对象/类被多个原因改变,则说明该对象/类承担了多个职责

OCP

The Open Closed Principle

开放封闭原则

软件实体应该是可扩展,而不可修改的。也就是说,对扩展是开放的,而对修改是封闭的。

LSP

The Liskov Substitution Principle

里氏替换原则

当一个子类的实例应该能够替换任何其超类的实例时,它们之间才具有is-A关系(is-a 指的是类的父子继承关系)

DIP

The Dependency Inversion Principle

依赖倒置原则

1. 高层模块不应该依赖于低层模块,二者都应该依赖于抽象

2. 抽象不应该依赖于细节,细节应该依赖于抽象

ISP

The Interface Segregation Principle

接口分离原则

不能强迫用户去依赖那些他们不使用的接口。换句话说,使用多个专门的接口比使用单一的总接口总要好。

     3)轻量级通信

    轻量级通信机制通常指语言无关、平台无关的交互方式。通信消息格式,如xml、json等,他们的解析和使用基本与语言、平台无关。通信协议,通常基于HTTP,能让服务间的通信标准化、无状态化。REST是实现服务之间互相协作的轻量级通信机制之一。

    4)独立性

    开发测试部署的独立。每个服务都是一个独立单元,有独立的代码库。服务与服务隔离。

    5)进程隔离

    每个服务都运行在不同的进程中,可以部署在不同节点。组件一般指独立升级 独立替换掉的部分。

  2 背景技术

    1)互联网时代的产品通常有两类特点:需求变化快和用户群体庞大。在这种情况下,如何从系统架构的角度出发,构建灵活、易扩展的系统,快速应对需求       的变化;同时,随着用户量的增加,如何保证系统的可伸缩性、高可用性,成为系统架构面临的挑战。

    2)敏捷、精益方法论、DevOps的深入人心

    精益创业(Lean Startup)帮助组织分析并建立最小可实行产品(Minimum Viable Product),通过迭代持续改进;敏捷方法帮助组织消除浪费,通过反       馈不断找到正确的方向;持续交付帮助组织构建更快、更可靠、可频繁发布的交付机制。DevOps文化的推行打破了传统开发与运维之间的壁垒,帮助组织形成         更高效的、开发与运维高度协作的交付团队。

    3)虚拟化技术和容器化技术

    虚拟化技术和基础设施自动化(Infrastructure As Code)的快速发展极大的简化了基础设施的创建、配置以及系统的安装和部署。譬如云平台的成熟以及像         Chef、Puppet、Ansible等工具的使用,让更多的基础设施能够通过自动化的方式动态创建。

      容器化技术的发展以及Docker的出现,更是将虚拟化技术推向了一个史无前例的高潮。 

  3 SOA面向服务架构

  SOA阐述了“对于复杂的企业IT系统,应按照不同的、可重用的粒度划分,将功能相关的一组功能提供者组织在一起为消费者提供服务”,其目的是为了解决企业内部不同IT资源之间无法互联而导致的信息孤岛问题。直到2000年左右,ESB(Enterprise Service Bus)、WebService、SOAP等这类技术的出现,才使得SOA渐渐落地。

  实际上, SOA的概念和微服务思想几乎一致。主要区别如下表所示:

                 SOA实现

微服务架构实现

企业级,自顶向下开展实施

团队级,自底向上开展实施

服务由多个子系统组成,粒度大

一个系统被拆分成多个服务,粒度细

企业服务总线,集中式的服务架构

无集中式总线,松散的服务架构

集成方式复杂(ESB/WS/SOAP)

集成方式简单(HTTP/REST/JSON)

单块架构系统,相互依赖,部署复杂

服务都能独立部署

  相比传统SOA的服务实现方式,微服务更具有灵活性、可实施性以及可扩展性,其强调的是一种独立测试、独立部署、独立运行的软件架构模式。

  4 微服务本质

    服务作为组件

      传统实现组件方式是隔离独立的部分或抽出公用的部分,构建共享库,从而达到解耦和复用的效果。服务之间定义清晰、语言无关、平台无关的接口。

    围绕业务组织团队

    关注产品而非项目

    技术多样性

    业务数据独立

      提供业务数据接口,而非公用数据库

    基础设施自动化

      每个服务需分别部署,则部署 运维的成本增加,对持续交付和部署流水线要求高。实现基础设施的自动化促进微服务构建。

    演进式架构

      敏捷开发 版本更新

  5 微服务实施因素

    分布式系统的复杂度

      微服务架构师一种基于分布式的系统。

      性能:多服务之间响应延迟及协作

      可靠性:单点故障率增大

      异步:

      数据一致性:分布式事务管理 或保证数据的瞬时一致性

      工具:IDE对微服务的支持不太好

    运维成本

      配置信息:

      部署

      监控与告警

      日志收集

    部署自动化

      构建有效的自动化部署流水线

    DevOps与组织架构

      微服务不仅是一种架构模型,也表现出一种组织模型(开发者将承担部署运维监控)

    服务间依赖测试

    服务间依赖管理 

三 微服务实践/项目开发流程

  敏捷开发 自动化工具

  1 API实现(REST)

    选择合适的开发语言及开发框架

    选择合适的代码仓库,svn、git

  2 代码检查

    1)代码自动化测试工具

    2)单元测试覆盖率统计

    3)代码静态检查,如代码的可读性、命名风格及统一的格式等

    4)代码复杂度检查

    可集成,如自动化测试的同时进行代码的静态检查

  3 代码构建

    代码构建工具及构建所生成文件类型,如war、jar、镜像等

  4 项目部署

    基础设施自动化(Puppet Ambari等)

    自动化部署,如部署脚本deploy.sh,可包括基础设施环境准备 

  5 持续交付流水线

    持续集成环境,如jenkins

    持续交付:小批量价值流动  频繁可发布  快速反馈

    1 提交阶段

      代码编译 静态检查 单元测试等等

      持续集成工具可通过WebHook的方式检测到代码仓库的提交并触发相应的处理机制,可以轮询的方式定期检测代码库(提交版本时间)的变化。

    2 构建阶段

      构建部署包,提交阶段完成后触发构建,注意部署包的版本定义    

    3 部署阶段

      测试环境

      生产环境

      基础环境搭建,如tomcat等,执行部署脚本deploy.sh等

  6 日志聚合

    日志聚合工具 splunk kafka flume

    数据采集  数据存储 高效索引 数据搜索 数据分析

  7 监控与告警 

    主机监控 基础设施 Nagios zabbix

    应用监控 项目相关的状态

    告警 服务出现异常通知相关人员修复

  8 功能迭代

    服务描述文件:服务介绍 (名称 功能) 服务维护者 服务级信息 运行环境(地址) 开发(搭建 运行) 测试 构建 部署 运维(日志URL 监控URL)

四 微服务进阶

  1 轻量级通信机制

    定义:平台无关、语言无关的消息通信协议

    同步通信:请求->等待->响应->处理

      1)远程过程调用RPC:

        典型的分布式节点间同步通信

        语言依赖

        传输格式为二进制  一端变化另一端也许对应修改

      2)表述性状态传递REST

        以资源为核心、以HTTP为操作方式 HTTP通信是同步的

        核心:资源:信息实体的抽象

           表述:对资源某一特定时刻的状态描述,如json格式等,URI仅代表资源的实体,HTTP请求头Accept、Content-Type字段才是表述

           状态转移:客户端同服务器端交互的过程中,客户端能通过资源的表述来实现操作资源的目的。

           统一接口:GET获取资源 POST新建资源 PUT更新资源 DELETE销毁资源

      3)超文本应用语言HAL

        轻量级超文本应用描述协议,基于REST,并解决REST中资源结构标准化和定义资源链接的问题。可使用HAL浏览器可视化资源信息。

        HAL又将资源分为:状态 链接 子资源

          状态:资源本身固有的属性

          链接Links:与当前资源相关的一组资源的链接的集合

          子资源:描述 在当前资源内部 其嵌套资源的定义

    异步通信:

      1)消息队列

        核心:持久性(消息保持在内存、磁盘、或数据库中)  排队标准(消息队列的标准及算法)安全策略 清理策略 处理通知

        访问方式:

          拉模式pull:消费者定期检查队列上的消息,一般存在一个发布者和一个消费者

          推模式push:每当发布者将消息添加到队列中时,会通过某种机制通知消费者,一般存在多个消费者,也叫订阅者。

      2)后台任务处理系统

        相对简单的异步场景中使用消息队列略微复杂。常见的后台任务处理系统有Resque、Sidekiq、Delayed_job等

        核心:任务 队列 执行器 定时器

        服务回调:保持任务的轻量级 不在任务中定义过多逻辑 尽量做到由任务回调具体的服务来完成交互。

          技术分享

   2 微服务与测试

            微服务的组成部分及测试内容

      技术分享

 

     在微服务场景下,这个层次可以被扩展为5层(如果将UI测试单独抽取出来,可以分为六层):

      单元测试:

        针对程序单元的正确性进行的检验。被测单元依赖于模拟部分和被测单元依赖于真实部分。工具如java中的JUnit

      接口/契约 测试

        针对服务接口进行的测试,验证提供者提供的契约/接口是否满足消费者的期望。对于微服务,建议使用基于消费者驱动的契约测试。

        工具如Pact、Pacto、Janus

      集成测试

        将不同的单元按照期望组合起来,对其接口进行正确性检验的测试工作,如数据库访问模块与数据库的集成、对外部service依赖的测试。

        自顶向下集成(从应用的入口开始,把不同部分组合起来,进行验证,并向底层移动)自底向上集成(传统瀑布模型常用)。

        工具如WireMock、mountebank

      组件测试

        对组件提供的功能进行正确性检验。进程内测试和进程外测试。

        工具如WireMock、mountebank、moco

      端到端测试

        从用户使用系统的角度出发,对系统的行为进行正确性检验。在端到端测试中,最重要的反而不是测试本身,而是环境的自动化能力。

        采用BDD方式描述测试用例,工具如Jbehave,Cucumber

    参考:微服务场景下的自动化测试

微服务实践 

摘自:微服务(Microservice)那点事

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

  后台有N个服务,前台就需要记住管理N个服务,一个服务下线/更新/升级,前台就要重新部署,这明显不服务我们 拆分的理念,特别当前台是移动应用的时候,通常业务变化的节奏更快。另外,N个小服务的调用也是一个不小的网络开销。还有一般微服务在系统内部,通常是无状态的,用户登录信息和权限管理最好有一个统一的地方维护管理(OAuth)。所以,一般在后台N个服务和UI之间一般会一个代理或者叫API Gateway: 

  1)提供统一服务入口,让微服务对前台透明

  2)聚合后台的服务,节省流量,提升性能

  3)提供安全,过滤,流控等API管理功能 

  API Gateway可以是一个软硬一体的盒子,也可以是一个简单的MVC框架,甚至是一个Node.js的服务端。他们最重要的作 用是为前台(通常是移动应用)提供后台服务的聚合,提供一个统一的服务出口,解除他们之间的耦合,不过API Gateway也有可能成为单点故障点或者性能的瓶颈。

 二 服务之间如何通信?

   因为所有的微服务都是独立的Java进程跑在独立的虚拟机上,所以服务间的通行就是IPC(inter process communication),现在基本最通用的有两种方式。

    1)同步调用:

      REST(JAX-RS,Spring Boot)

      RPC(Thrift, Dubbo)

    2)异步消息调用:(Kafka, Notify, MetaQ)

  一般同步调用比较简单,一致性强,但是容易出调用问题,性能体验上也会差些,特别是调用层次多的时候。RESTful和RPC的比较也是一个很有意思的话题。一般REST基于HTTP,更容易实现,更容易被接受,服务端实现技术也更灵活些,各个语言都能支持,同时能跨客户端,对客户端没有特殊的要 求,只要封装了HTTP的SDK就能调用,所以相对使用的广一些。RPC也有自己的优点,传输协议更高效,安全更可控,特别在一个公司内部,如果有统一个 的开发规范和统一的服务框架时,他的开发效率优势更明显些。

  异步消息的方式在分布式系统中有特别广泛的应用,他既能减低调用服务之间的耦合,又能成为调用之间的缓冲,确保消息积压不会冲垮被调用方,同时能保证调用方的服务体验,继续干自己该干的活,不至于被后台性能拖慢。不过需要付出的代价是一致性的减弱,需要接受数据最终一致性;还有就是后台服务一般要实现幂等性,因为消息发送出于性能的考虑一般会有重复(保证消息的被收到且仅收到一次对性能是很大的考验);最后就是必须引入一个独立的broker,如果公司内部没有技术积累,对分布式管理之broker模式也是一个很大的挑战。broker模式:引入一个Broker组件,解耦客户端和服务端。服务端注册自己到Broker,通过暴露接口的方式允许客户端接入服务。客户端是通过Broker发送请求的,Broker转发请求道服务端,并将请求的结果或异常回发给客户端。通过使用Broker模式,应用可以通过发送消息访问远程的服务。

三 这么多服务,怎么找? 

  在微服务架构中,一般每一个服务都是有多个拷贝,来做负载均衡。一个服务随时可能下线,也可能应对临时访问压力增加新的服务节点。服务之间如何相互感知?服务如何管理?这就是服务发现的问题了。一般有两类做法,也各有优缺点。基本都是通过zookeeper等类似技术做服务注册信息的分布式管理。

    客户端做:优点是架构简单,扩展灵活,只对服务注册器依赖。缺点是客户端要维护所有调用服务的地址,有技术难度,一般大公司都有成熟的内部框架支         持,比如Dubbo。

    服务端做:优点是简单,所有服务对于前台调用方透明,一般在小公司在云服务上部署的应用采用的比较多。

四 服务挂了怎么办?

        当我们的系统是由一系列的服务调用链组成的时候,我们 必须确保任一环节出问题都不至于影响整体链路。相应的手段有很多:

    重试机制

    限流

    熔断机制

    负载均衡

    降级(本地缓存)

云原生

参考:云原生应用程序架构的五大特性(上)- 12要素应用

参考: 云原生机制的三个核心思想及其未来之路

  在云的时代,应用会更多的迁移到云端,基于云的架构设计和开发模式需要一套全新的理念去承载,于是云原生思想应运而生,而针对云原生应用开发的最佳实践原则,12-Factor脱颖而出。

  云计算平台的三个层次:

    IaaS 基础云设施:提供各种基础资源(Infrastructure)

    PaaS 开发平台:提供各种平台服务(Platform)

    SaaS 交付应用或服务:直面用户,提供应用价值(Application)

12要素

1、基准代码

  一份基准代码,多份部署。每个可部署的应用程序均被视为在版本控制中的代码库来进行追踪,相同的基准代码可能在多个环境下部署有许多的应用程序实例。

2、依赖

  显式声明依赖关系。应用程序通过适当的工具(如:Maven、Bundler、NPM)隔离依赖性,目的就是不依赖于部署环境。

3、配置

  在环境中存储配置。通过操作系统级的环境变量将配置信息或其他可能存在的不同信息(如:开发环境、预生产环境、生产环境)应用到各个部署环境中。

4、 后端服务

  把后端服务当作附加资源。数据库、消息队列、邮件发送服务或缓存系统等均被作为是附加资源在不同环境中被同等地调用,每个不同的后端服务都是一份资源 。举个例子,一个MySQL 数据库是一个资源,两个MySQL 数据库(用来给数据分区)就是两个不同的资源。12要素应用将这些数据库都视作附加资源 ,将它们和部署环境保持松耦合。

5、构建、发布、运行

  严格分离构建和运行。基准代码转化为部署(非开发环境)需要以下三个阶段:

    构建阶段,是指将代码仓库转化为可执行包的过程。构建时会使用指定版本的代码,获取和打包依赖项,编译成二进制文件和资源文件。

    发布阶段,会将构建的结果和当前部署所需的配置相结合,并能够立刻在运行环境中投入使用。

    运行阶段,是指针对选定的发布版本在执行环境中启动一系列应用程序的进程。

  以上所有阶段都是严格分离的。

6、进程

  以一个或多个无状态进程运行应用。在运行环境中,应用程序作为一个或多个无共享的无状态进程(如:master/workers)来执行,任何需要持久化的数据都要存储在后端服务内(例如:缓存、对象存储等)。

7、端口绑定

  通过端口绑定(Port Binding)来提供服务。具有12要素的应用能够实现完全自我加载,不依赖于任何网络服务器就可以创建基于网络的服务。互联网应用可以通过端口绑定来提供服务并随时监听所有发送至该端口的请求。

8、并发

  通过进程模型进行扩展。一般而言,并行由水平向外扩展应用程序进程(尽管必要时进程也可通过内部管理线程多路传输工作)来实现。

9、易处理

  通过快速启动和终止来实现应用程序韧性的最大化。这包括了快速而有弹性的扩展、对变更的部署以及宕机恢复能力。      

10、开发环境与生产环境等价

  通过尽可能地保持开发环境、预生产环境和生产环境三者的相似性来实现持续交付与部署。

11、日志

  将日志作为事件流,允许执行环境通过集中式服务来收集、聚合、检索和分析日志,而非仅仅管理日志文件。

12、管理进程

  将后台管理任务当作一次性进程运行。当环境就等同于应用程序长时间运行的进程时,管理任务(如:数据库迁移)会被作为一次性进程而执行。

 

 

微服务架构与实践及云原生等相关概念