学习微服务首先要了解为何使用微服务

单体的优缺点前端

单体应用就是将应用程序的全部功能都打包成一个独立的单元,最终以一个WAR包或JAR包存在,没有外部的任何依赖,里面包含DAO,Service、UI等全部的逻辑。单体应用有如下优势:java

  • 便于开发:只需借助IDE的开发、调试功能便可完成
  • 易于测试:只须要经过单元测试或浏览器便可完成测试
  • 易于部署:打包成单一可执行jar包,执行jar包便可完成部署

不幸的是,这种简单的单元有很大的局限性。应用程序随着业务需求的迭代,功能的追加扩展,最终成为一个庞然大物。变得更加复杂,逻辑耦合严重,难以理解,团队开发 人员职责不清,部署困难,回归测试成本巨大,交付效率大大下降,总结下来,单体应用有一下缺点:redis

1. 复杂性高sql

  • 代码难以理解
    在业务规模和团队规模发展的必定阶段,这些不足表现的更加明显,单体架构的不足首先表如今复杂性上, maven模块增多,多个模块耦合在一块儿,代码结构混乱,使得团队成员没有一我的理解整个代码逻辑;数据库

  • 难以理解致使代码质量低,复杂性进一步增长
    难以理解致使代码复用度下降,由于你不知道哪些能够复用的;即使修改,影响范围也很差肯定,这致使这样开发宁愿新建一个新方法和新的类,进一步致使重复代码越积越多;后端

  • 代码难以被修改和重构
    不理解代码固然也就写不出高内聚低耦合的代码,和代码质量持续降低;复杂性进一步增长随着复杂度的增长,耦合度愈来愈高,代码牵一发而动全身,代码已经很难修改和重构了
  • 团队职责不清晰
    高度耦合的单体工程使得逻辑边界模糊不清,新的业务需求开发任务没法有效分配到人,团队人员职责不清晰,沟通成本增长。

2.交付效率低api

  • 构建和部署耗时长,难以定位问题,开发效率低
    代码量比较庞大,首先是编译耗时变长,开发调试将大部分时间花在从新编译上,代码量的增长又很难定位bug,致使开发效率进一步下降,在代码合并过程当中极易遇到代码冲突,又花上很多时间用在解决代码冲突上;这都是致使开发效率低下的因素;
  • 代码复杂和变动影响难以理解,须要数天完成全量测试
    当咱们开发完一个新的功能或者修复一个bug,代码的变动影响是很难预估的,因此每次发布以前都要进去全量功能的回归测试;
  • 全量部署耗时长、影响范围广、风险大,发布频次低
    正由于这种全量部署耗时长、影响范围广、风险大,致使咱们将不少功能和修复汇集在一块儿进行开发完成,这致使了产品发布频次下降,新的功和更换的体验能不能及时呈现给用户,甚至被竞争对手赶超。
    3.伸缩性(scalable)差浏览器

  • 单体只能按总体横向扩展,没法分模块垂直扩展安全

  • IO密集型模块和CPU密集型模块没法独立升级和扩容
    业务模块对资源的需求是不同的,因为全部模块部署到一块儿,单体架构IO密集型模块和CPU密集型模块没法独立升级和扩容的,好比图片压缩,加解密这些 都是cpu资源密集的应该升级CPU,而IO密集型的模块好比日志收集服务IO操做比较多须要更大的内存,使用好比SSD性能更好的磁盘。
    4. 可靠性差性能优化

  • 一个bug有可能引发整个应用的崩溃
    因为全部模块都是部署在一个实例中,一个bug会引发整个应用的崩溃,好比一个不重要的模块的内存泄露就将会致使全部应用实例一个个crash掉
    5.阻碍技术创新

  • 受技术栈限制,团队成员使用同一框架和语言
    受技术栈限制,团队成员必须使用同一框架和语言,模块得不到拆分,不能使用新的语言和框架;
  • 升级和变革技术框架变得困难
    当有符合业务场景的新技术产生或者新版本时,升级和变革技术框架所带来的重构成本和风险变革很高
  • 尝试新语言变得困难
    想尝试新的语言也变得很困难,由于开发成本的上升,重构和新需求迭代没法协调,因此最终只能是妥协继续使用原来的框架和语言
    那么如何解决单体的不足呢,经过迁移到微服务架构来解决,咱们看一下什么是微服务。

那么如何解决单体的不足呢,经过迁移到微服务架构来解决,咱们看一下什么是微服务。

微服务的定义

微服务架构:将单体应用拆分为多个高内聚低耦合的小型服务,每一个小服务运行在独立进程,由不一样的团队开发和维护,服务间采用轻量级通讯机制,独立自动部署,能够采用不一样的语言及存储。

图片描述

咱们经过上图来看下单体架构到微服务架构的对比。此图是一个简单电商单体到微服务架构的演进图,单体架构整个团队维护开发一个大工程及一个单库,到了微服务架构,用户请求通过API Gateway被路由到下游服务,服务之间以轻量级通讯协议进行通讯,服务经过注册中心发现彼此,每一个服务都有专门的开发维护团队,每一个服务对应独立的数据库,服务独立开发,独立部署和上线。 接下来咱们总结下微服务的优势。

微服务的优势

  • 易于开发与维护

    • 微服务相对小,易于理解
    • 启动时间短,开发效率高
  • 独立部署
    • 一个微服务的修改不须要协调其它服务
  • 伸缩性强
    • 每一个服务均可以在横向和纵向上扩展
    • 每一个服务均可按硬件资源的需求进行独立扩容
  • 与组织结构相匹配
    • 微服务架构能够更好将架构和组织相匹配
    • 每一个团队独立负责某些服务,得到更高的生产力
  • 技术异构性
    • 使用最适合该服务的技术
    • 下降尝试新技术的成本

微服务的挑战

没有任何技术是银弹,微服务也是如此 ,都或多或少有一些缺点和问题。那么咱们就必须针对这些问题一一解决,也是咱们接下来章节重点去作的. 我首先面对就是要将单体拆分红多个服务。
1.服务拆分

  • 微服务拆分原则:领域模型、限定上下文、组织架构、康威定律
    现实中没有一个具体明确的方法能够将拆分一步到位,而是遵照必定的原则,好比根据领域模型、组织架构、单一职责这些进行拆分在拆分的过程当中还要结合经验判断,而且随着需求迭代,架构持续优化演进,优化服务的拆分。

  • 每一个微服务拥有独立数据库
    服务拆分的同时还要考虑到存储数据库也要独立,当多个服务直接读写数据库中同一张表时,对这些表作任何改动都须要协调这些相关服务的部署。这一点违背了服务相互独立这一原则。共享的数据存储很容易不经意间形成耦合。每一个服务须要有本身的私有数据。好比订单表被订单服务和商品服务所共享,商品服务单独作统计并不知道本身一天多少商品被卖出,不知道哪些数据由本服务产生的,就没法进行技术产品规划,对表结构的修改也要通知多个服务,这是所不能容忍的。每一个服务须要本身的数据库,但这些数据库可共置在一台共享的数据服务器上,数据库私有的重点在于不该让服务知道其余服务底层数据库的存在。可用一台共享数据服务器先开始开发,之后若是数据量和并发量变大,服务器能够进行隔离。服务器隔离后,只要更改配置便可将不一样服务的数据库隔离起来。

  • 微服务之间肯定服务边界,经过共享模型创建联系
    每一个微服务都具有本身的业务能力,那么服务之间交互的部分便是服务边界; 肯定服务边界也是一个难题,须要对本身的产品和业务有足够的了解才能肯定最天然的服务边界肯定服务边界坚持的原则是要高内聚弱耦合,弱耦合就是一个服务与其余服务的任何通讯都应经过公开暴露的接口(API、事件等)实现,这些接口须要妥善设计以隐藏内部细节。这样咱们的服务之间保持独立,在将来咱们能够轻松重构,高内聚力就是密切相关的多个功能应尽可能包含在同一个服务中,这样可将服务之间的干扰降至最低。
    2.数据一致性

    在单体架构中,咱们经过数据库事务完成的操做 放在分布式微服务架构下没法完成了,由于实例被部署不一样服务器上,好比订单服务进行下单操做,下单操做和扣减库存应该放在同一个事务中,在微服务架构下,下单操做和扣库存操做被分布在不一样服务器上,就须要进行分布式事务操做,而分布式事务具备延迟较高、nosql数据库不支持等缺点。这些缺点致使分布式事务没法应用到微服务中在微服务场景下,咱们一般使用最终一致性来代替强一致性。

  • 可靠性事件模式
  • 补偿模式-sagas模式

3.服务通讯

  • 通讯技术方案: RPC vs REST vs 异步消息
    • RPC、REST API、异步消息,异步消息咱们能够借助一些消息队列框架来实现好比kafka、rrabbitMQ,那如今咱们说下rpc和使用http协议的相似REST API之间 如何选择,TTP的好处是方便调试、跨语言、门槛低、普遍接受,一样缺点是协议文档很差维护,协议较为繁琐,性能较TCP要差是http协议的不足。
      Rpc通讯一般基于Tcp,经常使用的技术选型是thrift、grpc、dubbo,像thrift、grpc须要定义idl文件,经过idl文件来生成java代码,经过rpc的好处是IDE友好,有代码提示,协议维护在代码中,传参和响应结果都经过代码能够知道。但同时也有缺点好比不少rpc方案不知道跨语言,所支持的语言有限,须要定义和维护idl文件,且有必定的学习成本,另外rpc不容易方便的调试和测试
  • 服务注册和发现
    • 在服务实例变化不定的环境中,用硬编码指定IP地址的方式是行不通的,须要经过某种发现机制让服务能相互查找。这就须要咱们将咱们的服务信息注册到一个分布式存储中,这些服务信息就叫作服务注册表服务注册表能够做为信息的权威来源。其中包含有关可用服务的信息,以及服务网络位置好比ip、端口号这些信息。那借助什么组件进行实现呢,通常有Eureka和zookeeper,除此以外咱们还能够借助etcd,consul,redis这些。
  • 负载均衡
    • 有了注册发现功能,客户端经过服务注册表发现实例清单并决定要链接哪一个实例,在客户端作负载均衡,基于客户端作负载均衡相比服务端负载均衡有诸多好处:首先节省了硬件均衡设备,减小了运维成本,其次能够实现多种负载均衡策略好比响应感知的负载均衡策略。

4.服务网关

  • API Gateway
    咱们的微服务若是和终端用户交互,势必要考虑身份认证、安全防护等这些方面,若是每一个微服务都与终端用户打交道,那么这些方面代码须要拷贝多份植入到每一个微服务业务代码中。这形成了业务代码和身份认证代码的耦合,下降了代码的复用性。这就须要在网络边界实现一个服务网关(这里的网络边界能够认为是内网和外网之间的边界),将身份认证,安全防护,流量控制这些功能放到服务网关中,向业务服务屏蔽网络边界服务的细节,使得业务服务专一于业务逻辑的开发维护和测试。
  • 为前端服务的后端(Backends For Forntends)
    服务网关能够根据终端产品形态来划分,好比公共API,桌面客户端,移动客户端分别对应一个服务网关,而服务网关能够是API Gateway只输出api,或者是为前端服务的后端,这里的为前端服务的后端,好比未来自多个服务的数据聚合到一块儿返回给前端。
  • 身份认证、路由服务、限流防刷、日志统计

5.高可观察

  • 健康检测、集中监控
    • 每一个服务和使用的组件都有提供健康检测机制,使得咱们能够及时发现异常的节点,而后作出判断和调整,将全部的监控指标进行聚合输出可视化图表和界面帮助咱们快速直观发现问题。
  • 日志聚合及检索
    • 好比在电商app咱们发现没法进行下单操做,在分布式架构下,日志散落在多个服务多个服务器中,咱们不知道错误日志打在哪台服务器上,若是每台服务器去登录去看是极其低效的。这要求咱们作到日志格式标准化,并经过一些手段聚合到一块儿进行检索查询。同时可跨越全部服务、特定的某个服务,或服务的某个实例搜索日志;将日志发送至集中化日志系统所用的代码可包含在共享库中或经过代码脚手架提供。
  • 分布式追踪
    • 在微服务架构场景中,一个客户端发起的请求要通过多个服务的调用最终聚合数据结构返回给客户端,但咱们不知道这个请求不知道通过哪些服务,调用哪一个服务出现了问题,每一个服务的输入输出是什么,这给咱们定位问题带来了困扰,除此之外,若是一个请求耗时较长,咱们不知道到底哪一个服务耗时最长,好有针对性的性能优化。随着架构的演进,咱们在架构设计规划时须要知道 服务之间的依赖关系,这有须要什么技术来实现呢,这就是咱们要介绍的分布式追踪,分布式追踪借助关联id,在请求源头建立这个关联id,而且在服务间进行透传,最终将关联id等信息聚合到一块儿进行查询分析。

6.可靠性

在讲单体的过程当中,咱们讲到,一个业务模块的内存泄露会致使整个进程退出。 在微服务场景下,若是一个服务出现内存泄露是不会影响 没有依赖关系的服务的。 可是却能够由于该异常服务的僵死或不可用形成上游服务线程hang住,进而产生级联效应,故障进一步向上游传播。

  • 流量控制,超时控制
    • 可靠性技术经过流量的控制和超时控制,保证服务消费者不被下游服务拖慢,及时对业务线程循环复用。
  • 舱壁隔离,熔断机制
    • 熔断是指服务调用出错次数在必定时间达到必定数量,自动关闭对该服务的调用开关,改成返回错误或者将请求转交给降级方法,下降资源耗尽的风险,当服务不可用时,做为服务消费者应该对接口方法编写一个降级方法。
  • 服务降级, 幂等重试
    • 因为服务间通讯是经过网络传输的,网络异常和网络分区故障 就会常常出现,咱们遇到这种状况能够进行调用重试,重试时要注意两点,一个是接口必须是幂等的,不管运行一次或屡次,最终结果必须相同。幂等性保证了重试不会产生负面影响。在重试过程时休眠时间应该是指数增加的,不然会产生惊群效应,好比:故障后的服务恢复上线后,若是有大量其余服务正在同一个重试窗口内重试,此时很容易给系统形成巨大压力。

提炼代码脚手架

除了开发业务逻辑,咱们还须要搭建一套微服务工程可用框架,这样是是为了加快团队工做效率,微服务解决方案保持统一,加强代码复用性,统一进行优化,微服务要解决的问题很是多,因此抽取服务代码模板是有必要的,它包括服务注册发现、服务通讯、监控、日志、异常处理等等。

从单体迁移到微服务

  • 什么时候迁移到微服务上来
    讲了这么多微服务的好处,咱们是否是能够今后抛弃单体架构,一切项目直接投向微服务的怀抱了呢? Martin Fowler在MicroservicePremium一文说 "don't even consider microservices unless you have a system that's too complex to manage as a monolith",翻译过来就是若是你的系统不到足够复杂的程度不要考虑使用微服务。

图片描述
咱们先看这张图,这张图是从一篇外文中摘出来的,连接已经编辑在图片中; 绿线表明单体架构,蓝线表明微服务架构,X轴表明复杂度,Y轴表明生产效率。

当业务不复杂,团队规模不大的时候,单块架构比微服务架构具备更高的生产率(productivity),由于创建微服务架构须要额外的开销来支持和管理微服务, 从而下降生产率;可是随着业务复杂性的增长和团队规模的扩大,单块架构比微服务架构的生产率降低更趋明显, 当复杂性达到一个临界点,微服务架构的生产率会优于单块架构, 由于微服务的松散耦合自治特性减缓了生产率的降低趋势。

因此咱们在作项目时,必定要根据本身的团队和业务复杂性来判断,什么时候应用微服务。 以个人经验给你们的建议时,一个全新项目在1-3团队时,能够先拆分红一个API 网关和一个集合全部业务的后端服务,API网关关注鉴权和路由、处理部分失败;后端服务要划分好业务模块;项目初期,因为流量很少,能够没必要添加流量控制和断路器等组件。

同时即便向微服务架构迁移以后,拆分的粒度也要由粗到细演进式发展,必定要根据本身的业务规模复杂性和团队规模来定。

  • 如何迁移到微服务架构上来

一个策略是:不要大规模(big bang)重写代码(只有当你承担重建一套全新基于微服务的应用时候能够采用重写这种方法)。重写代码听起来很不错,但实际上充满了风险最终可能会失败,就如Martin Fowler所说:“the only thing a Big Bang rewrite guarantees is a Big Bang!”

相反,应该采起逐步迁移单体式应用的策略,经过逐步生成微服务新应用,与旧的单体式应用集成,随着时间推移,单体式应用在整个架构中比例逐渐降低直到消失或者成为微服务架构一部分。这个策略有点像在高速路上限速到70迈对车作维护,尽管有挑战,可是比起重写的风险小不少。

Martin Fowler将这种现代化策略成为绞杀应用,名字来源于雨林中的绞杀藤(strangler vine),也叫绞杀榕(strangler fig)。绞杀藤为了爬到森林顶端都要缠绕着大叔生长,一段时间后,树死了,留下树形藤。这种应用也使用同一种模式,围绕着传统应用开发了新型微服务应用,传统应用会渐渐退出舞台。

SOA VS 微服务

SOA和微服务的对比是一个老生常谈的话题,我认为二者最大的不一样是提出时所处的技术背景和环境。

SOA的出现实际上是为了解决历史问题:企业在信息化的过程当中会有各类各样互相隔离的系统,须要有一种机制将他们整合起来,因此才会有ESB的出现。一样的,也成了SOA初期的服务是很大的概念,一般指定的一个能够独立运做的系统。

微服务没有历史包袱,服务的尺寸一般不会太大,从服务粒度来说,SOA更像是单体的简单组合,而微服务是粒度更细小的服务,其次数据拆分SOA倾向于共享数据库,微服务一个服务对应一个数据库。

微服务知识全景图

微服务知识全景图会在课程《Java深刻微服务原理改造房产销售平台》中介绍和实践。
图片描述

相关文章
相关标签/搜索