3.1 最期的单体架构带来的问题
单体架构在规模比较小的情况下工作情况良好,但是随着系统规模的扩大,它暴露出来的问题也越来越多,主要有以下几点:
1.复杂性逐渐变高
-
比如有的项目有几十万行代码,各个模块之间区别比较模糊,逻辑比较混乱,代码越多复杂性越高,越难解决遇到的问题。
2.技术债务逐渐上升
-
公司的人员流动是再正常不过的事情,有的员工在离职之前,疏于代码质量的自我管束,导致留下来很多坑,由于单体项目代码量庞大的惊人,留下的坑很难被发觉,这就给新来的员工带来很大的烦恼,人员流动越大所留下的坑越多,也就是所谓的技术债务越来越多。
3.部署速度逐渐变慢
-
这个就很好理解了,单体架构模块非常多,代码量非常庞大,导致部署项目所花费的时间越来越多,曾经有的项目启动就要一二十分钟,这是多么恐怖的事情啊,启动几次项目一天的时间就过去了,留给开发者开发的时间就非常少了。
4.阻碍技术创新
-
比如以前的某个项目使用struts2写的,由于各个模块之间有着千丝万缕的联系,代码量大,逻辑不够清楚,如果现在想用spring mvc来重构这个项目将是非常困难的,付出的成本将非常大,所以更多的时候公司不得不硬着头皮继续使用老的struts架构,这就阻碍了技术的创新。
5.无法按需伸缩
-
比如说电影模块是CPU密集型的模块,而订单模块是IO密集型的模块,假如我们要提升订单模块的性能,比如加大内存、增加硬盘,但是由于所有的模块都在一个架构下,因此我们在扩展订单模块的性能时不得不考虑其它模块的因素,因为我们不能因为扩展某个模块的性能而损害其它模块的性能,从而无法按需进行伸缩。
3.2 微服务与单体架构区别
-
单体架构所有的模块全都耦合在一块,代码量大,维护困难,微服务每个模块就相当于一个单独的项目,代码量明显减少,遇到问题也相对来说比较好解决。
-
单体架构所有的模块都共用一个数据库,存储方式比较单一,微服务每个模块都可以使用不同的存储方式(比如有的用redis,有的用mysql等),数据库也是单个模块对应自己的数据库。
-
单体架构所有的模块开发所使用的技术一样,微服务每个模块都可以使用不同的开发技术,开发模式更灵活。
3.3 微服务与SOA区别
微服务,从本质意义上看,还是 SOA 架构。但内涵有所不同,微服务并不绑定某种特殊的技术,在一个微服务的系统中,可以有 Java 编写的服务,也可以有 Python编写的服务,他们是靠Restful架构风格统一成一个系统的。所以微服务本身与具体技术实现无关,扩展性强。
4. 微服务本质
-
微服务,关键其实不仅仅是微服务本身,而是系统要提供一套基础的架构,这种架构使得微服务可以独立的部署、运行、升级,不仅如此,这个系统架构还让微服务与微服务之间在结构上“松耦合”,而在功能上则表现为一个统一的整体。这种所谓的“统一的整体”表现出来的是统一风格的界面,统一的权限管理,统一的安全策略,统一的上线过程,统一的日志和审计方法,统一的调度方式,统一的访问入口等等。
-
微服务的目的是有效的拆分应用,实现敏捷开发和部署 。
-
微服务提倡的理念团队间应该是 inter-operate, not integrate 。inter-operate是定义好系统的边界和接口,在一个团队内全栈,让团队自治,原因就是因为如果团队按照这样的方式组建,将沟通的成本维持在系统内部,每个子系统就会更加内聚,彼此的依赖耦合能变弱,跨系统的沟通成本也就能降低。
5. 什么样的项目适合微服务
微服务可以按照业务功能本身的独立性来划分,如果系统提供的业务是非常底层的,如:操作系统内核、存储系统、网络系统、数据库系统等等,这类系统都偏底层,功能和功能之间有着紧密的配合关系,如果强制拆分为较小的服务单元,会让集成工作量急剧上升,并且这种人为的切割无法带来业务上的真正的隔离,所以无法做到独立部署和运行,也就不适合做成微服务了。
能不能做成微服务,取决于四个要素:
-
小:微服务体积小,2 pizza 团队。
-
独:能够独立的部署和运行。
-
轻:使用轻量级的通信机制和架构。
-
松:为服务之间是松耦合的。
6. 微服务折分与设计
-
从单体式结构转向微服务架构中会持续碰到服务边界划分的问题:比如,我们有user 服务来提供用户的基础信息,那么用户的头像和图片等是应该单独划分为一个新的service更好还是应该合并到user服务里呢?如果服务的粒度划分的过粗,那就回到了单体式的老路;如果过细,那服务间调用的开销就变得不可忽视了,管理难度也会指数级增加。目前为止还没有一个可以称之为服务边界划分的标准,只能根据不同的业务系统加以调节
-
拆分的大原则是当一块业务不依赖或极少依赖其它服务,有独立的业务语义,为超过2个的其他服务或客户端提供数据,那么它就应该被拆分成一个独立的服务模块。
6.1 微服务设计原则
单一职责原则
-
意思是每个微服务只需要实现自己的业务逻辑就可以了,比如订单管理模块,它只需要处理订单的业务逻辑就可以了,其它的不必考虑。
服务自治原则
-
意思是每个微服务从开发、测试、运维等都是独立的,包括存储的数据库也都是独立的,自己就有一套完整的流程,我们完全可以把它当成一个项目来对待。不必依赖于其它模块。
轻量级通信原则
-
首先是通信的语言非常的轻量,第二,该通信方式需要是跨语言、跨平台的,之所以要跨平台、跨语言就是为了让每个微服务都有足够的独立性,可以不受技术的钳制。
接口明确原则
-
由于微服务之间可能存在着调用关系,为了尽量避免以后由于某个微服务的接口变化而导致其它微服务都做调整,在设计之初就要考虑到所有情况,让接口尽量做的更通用,更灵活,从而尽量避免其它模块也做调整。
7. 微服务优势与缺点
7.1 特性
-
每个微服务可独立运行在自己的进程里;
-
一系列独立运行的微服务共同构建起了整个系统;
-
每个服务为独立的业务开发,一个微服务一般完成某个特定的功能,比如:订单管理,用户管理等;
-
微服务之间通过一些轻量级的通信机制进行通信,例如通过REST API或者RPC的方式进行调用。
7.2 特点
易于开发和维护
-
由于微服务单个模块就相当于一个项目,开发这个模块我们就只需关心这个模块的逻辑即可,代码量和逻辑复杂度都会降低,从而易于开发和维护。
启动较快
-
这是相对单个微服务来讲的,相比于启动单体架构的整个项目,启动某个模块的服务速度明显是要快很多的。
局部修改容易部署
-
在开发中发现了一个问题,如果是单体架构的话,我们就需要重新发布并启动整个项目,非常耗时间,但是微服务则不同,哪个模块出现了bug我们只需要解决那个模块的bug就可以了,解决完bug之后,我们只需要重启这个模块的服务即可,部署相对简单,不必重启整个项目从而大大节约时间。
技术栈不受限
-
比如订单微服务和电影微服务原来都是用java写的,现在我们想把电影微服务改成nodeJs技术,这是完全可以的,而且由于所关注的只是电影的逻辑而已,因此技术更换的成本也就会少很多。
按需伸缩
-
我们上面说了单体架构在想扩展某个模块的性能时不得不考虑到其它模块的性能会不会受影响,对于我们微服务来讲,完全不是问题,电影模块通过什么方式来提升性能不必考虑其它模块的情况。
7.3 缺点
运维要求较高
-
对于单体架构来讲,我们只需要维护好这一个项目就可以了,但是对于微服务架构来讲,由于项目是由多个微服务构成的,每个模块出现问题都会造成整个项目运行出现异常,想要知道是哪个模块造成的问题往往是不容易的,因为我们无法一步一步通过debug的方式来跟踪,这就对运维人员提出了很高的要求。
分布式的复杂性
-
对于单体架构来讲,我们可以不使用分布式,但是对于微服务架构来说,分布式几乎是必会用的技术,由于分布式本身的复杂性,导致微服务架构也变得复杂起来。
接口调整成本高
-
比如,用户微服务是要被订单微服务和电影微服务所调用的,一旦用户微服务的接口发生大的变动,那么所有依赖它的微服务都要做相应的调整,由于微服务可能非常多,那么调整接口所造成的成本将会明显提高。
重复劳动
-
对于单体架构来讲,如果某段业务被多个模块所共同使用,我们便可以抽象成一个工具类,被所有模块直接调用,但是微服务却无法这样做,因为这个微服务的工具类是不能被其它微服务所直接调用的,从而我们便不得不在每个微服务上都建这么一个工具类,从而导致代码的重复。
8. 微服务开发框架
目前微服务的开发框架,最常用的有以下四个:
-
Spring Cloud:http://projects.spring.io/spring-cloud(现在非常流行的微服务架构)
-
Dubbo:http://dubbo.io
-
Dropwizard:http://www.dropwizard.io (关注单个微服务的开发)
-
Consul、etcd&etc.(微服务的模块)
9. Sprint cloud 和 Sprint boot区别
Spring Boot:
旨在简化创建产品级的Spring应用和服务,简化了配置文件,使用嵌入式web服务器,含有诸多开箱即用微服务功能,可以和spring cloud联合部署。
Spring Cloud:
微服务工具包,为开发者提供了在分布式系统的配置管理、服务发现、断路器、智能路由、微代理、控制总线等开发工具包。
二、微服务实践先知
1. 客户端如何访问这些服务?(API Gateway)
传统的开发方式,所有的服务都是本地的,UI可以直接调用,现在按功能拆分成独立的服务,跑在独立的一般都在独立的虚拟机上的 Java进程了。客户端UI如何访问他的?后台有N个服务,前台就需要记住管理N个服务,一个服务下线/更新/升级,前台就要重新部署,这明显不服务我们 拆分的理念,特别当前台是移动应用的时候,通常业务变化的节奏更快。另外,N个小服务的调用也是一个不小的网络开销。还有一般微服务在系统内部,通常是无状态的,用户登录信息和权限管理最好有一个统一的地方维护管理(OAuth)。
所以,一般在后台N个服务和UI之间一般会一个代理或者叫API Gateway,他的作用包括
-
提供统一服务入口,让微服务对前台透明
-
聚合后台的服务,节省流量,提升性能
-
提供安全,过滤,流控等API管理功能
-
我的理解其实这个API Gateway可以有很多广义的实现办法,可以是一个软硬一体的盒子,也可以是一个简单的MVC框架,甚至是一个Node.js的服务端。他们最重要的作用是为前台(通常是移动应用)提供后台服务的聚合,提供一个统一的服务出口,解除他们之间的耦合,不过API Gateway也有可能成为单点故障点或者性能的瓶颈。
2. 服务之间如何通信?(服务调用)
因为所有的微服务都是独立的Java进程跑在独立的虚拟机上,所以服务间的通行就是IPC(inter process communication),已经有很多成熟的方案。现在基本最通用的有两种方式。这几种方式,展开来讲都可以写本书,而且大家一般都比较熟悉细节了, 就不展开讲了。
-
REST(JAX-RS,Spring Boot)
-
RPC(Thrift, Dubbo)
-
异步消息调用(Kafka, Notify)
一般同步调用比较简单,一致性强,但是容易出调用问题,性能体验上也会差些,特别是调用层次多的时候。RESTful和RPC的比较也是一个很有意 思的话题。一般REST基于HTTP,更容易实现,更容易被接受,服务端实现技术也更灵活些,各个语言都能支持,同时能跨客户端,对客户端没有特殊的要 求,只要封装了HTTP的SDK就能调用,所以相对使用的广一些。RPC也有自己的优点,传输协议更高效,安全更可控,特别在一个公司内部,如果有统一个的开发规范和统一的服务框架时,他的开发效率优势更明显些。就看各自的技术积累实际条件,自己的选择了。
而异步消息的方式在分布式系统中有特别广泛的应用,他既能减低调用服务之间的耦合,又能成为调用之间的缓冲,确保消息积压不会冲垮被调用方,同时能 保证调用方的服务体验,继续干自己该干的活,不至于被后台性能拖慢。不过需要付出的代价是一致性的减弱,需要接受数据最终一致性;还有就是后台服务一般要 实现幂等性,因为消息发送出于性能的考虑一般会有重复(保证消息的被收到且仅收到一次对性能是很大的考验);最后就是必须引入一个独立的broker,如 果公司内部没有技术积累,对broker分布式管理也是一个很大的挑战。
3. 这么多服务怎么查找?(服务发现)
在微服务架构中,一般每一个服务都是有多个拷贝,来做负载均衡。一个服务随时可能下线,也可能应对临时访问压力增加新的服务节点。服务之间如何相互 感知?服务如何管理?这就是服务发现的问题了。一般有两类做法,也各有优缺点。基本都是通过zookeeper等类似技术做服务注册信息的分布式管理。当 服务上线时,服务提供者将自己的服务信息注册到ZK(或类似框架),并通过心跳维持长链接,实时更新链接信息。服务调用者通过ZK寻址,根据可定制算法,找到一个服务,还可以将服务信息缓存在本地以提高性能。当服务下线时,ZK会发通知给服务客户端。
客户端做:优点是架构简单,扩展灵活,只对服务注册器依赖。缺点是客户端要维护所有调用服务的地址,有技术难度,一般大公司都有成熟的内部框架支持,比如Dubbo。
服务端做:优点是简单,所有服务对于前台调用方透明,一般在小公司在云服务上部署的应用采用的比较多。
4. 服务挂了怎么办?
分布式最大的特性就是网络是不可靠 的。通过微服务拆分能降低这个风险,不过如果没有特别的保障,结局肯定是噩梦。我们刚遇到一个线上故障就是一个很不起眼的SQL计数功能,在访问量上升 时,导致数据库load彪高,影响了所在应用的性能,从而影响所有调用这个应用服务的前台应用。所以当我们的系统是由一系列的服务调用链组成的时候,我们必须确保任一环节出问题都不至于影响整体链路。相应的手段有很多:
-
重试机制
-
限流
-
熔断机制
-
负载均衡
-
降级(本地缓存) 这些方法基本上都很明确通用,就不详细说明了。比如Netflix的Hystrix:https://github.com/Netflix/Hystrix
5. 微服务需要考虑的问题
这里有一个图非常好的总结微服务架构需要考虑的问题,包括
-
API Gateway
-
服务间调用
-
服务发现
-
服务容错
-
服务部署
-
数据调用
微服务等于Spring Cloud?一文告诉你微服务到底是什么。
19天前2928
微服务初探
什么是微服务
首先微服务并没有一个官方的定义,想要直接描述微服务比较困难,我们可以通过对比传统WEB应用,来理解什么是微服务。
传统的WEB应用核心分为业务逻辑、适配器以及API或通过UI访问的WEB界面。业务逻辑定义业务流程、业务规则以及领域实体。适配器包括数据库访问组件、消息组件以及访问接口等。一个打车软件的架构图如下:
尽管也是遵循模块化开发,但最终它们会打包并部署为单体式应用。例如Java应用程序会被打包成WAR,部署在Tomcat或者Jetty上。
这种单体应用比较适合于小项目,优点是:
1.开发简单直接,集中式管理
2.基本不会重复开发
3.功能都在本地,没有分布式的管理开销和调用开销
当然它的缺点也十分明显,特别对于互联网公司来说:
1.开发效率低:所有的开发在一个项目改代码,递交代码相互等待,代码冲突不断
2.代码维护难:代码功能耦合在一起,新人不知道何从下手
3.部署不灵活:构建时间长,任何小修改必须重新构建整个项目,这个过程往往很长
4.稳定性不高:一个微不足道的小问题,可以导致整个应用挂掉
5.扩展性不够:无法满足高并发情况下的业务需求
所以,现在主流的设计一般会采用微服务架构。其思路不是开发一个巨大的单体式应用,而是将应用分解为小的、互相连接的微服务。一个微服务完成某个特定功能,比如乘客管理和下单管理等。每个微服务都有自己的业务逻辑和适配器。一些微服务还会提供API接口给其他微服务和应用客户端使用。
比如,前面描述的系统可被分解为:
每个业务逻辑都被分解为一个微服务,微服务之间通过REST API通信。一些微服务也会向终端用户或客户端开发API接口。但通常情况下,这些客户端并不能直接访问后台微服务,而是通过API Gateway来传递请求。API Gateway一般负责服务路由、负载均衡、缓存、访问控制和鉴权等任务。
微服务架构的优点
微服务架构有很多重要的优点。首先,它解决了复杂性问题。它将单体应用分解为一组服务。虽然功能总量不变,但应用程序已被分解为可管理的模块或服务。这些服务定义了明确的RPC或消息驱动的API边界。微服务架构强化了应用模块化的水平,而这通过单体代码库很难实现。因此,微服务开发的速度要快很多,更容易理解和维护。
其次,这种体系结构使得每个服务都可以由专注于此服务的团队独立开发。只要符合服务API契约,开发人员可以*选择开发技术。这就意味着开发人员可以采用新技术编写或重构服务,由于服务相对较小,所以这并不会对整体应用造成太大影响。
第三,微服务架构可以使每个微服务独立部署。开发人员无需协调对服务升级或更改的部署。这些更改可以在测试通过后立即部署。所以微服务架构也使得CI/CD成为可能。
最后,微服务架构使得每个服务都可独立扩展。我们只需定义满足服务部署要求的配置、容量、实例数量等约束条件即可。比如我们可以在EC2计算优化实例上部署CPU密集型服务,在EC2内存优化实例上部署内存数据库服务。
微服务架构的缺点和挑战
实际上并不存在silver bullets,微服务架构也会给我们带来新的问题和挑战。其中一个就和它的名字类似,微服务强调了服务大小,但实际上这并没有一个统一的标准。业务逻辑应该按照什么规则划分为微服务,这本身就是一个经验工程。有些开发者主张10-100行代码就应该建立一个微服务。虽然建立小型服务是微服务架构崇尚的,但要记住,微服务是达到目的的手段,而不是目标。微服务的目标是充分分解应用程序,以促进敏捷开发和持续集成部署。
微服务的另一个主要缺点是微服务的分布式特点带来的复杂性。开发人员需要基于RPC或者消息实现微服务之间的调用和通信,而这就使得服务之间的发现、服务调用链的跟踪和质量问题变得的相当棘手。
微服务的另一个挑战是分区的数据库体系和分布式事务。更新多个业务实体的业务交易相当普遍。这些类型的事务在单体应用中实现非常简单,因为单体应用往往只存在一个数据库。但在微服务架构下,不同服务可能拥有不同的数据库。CAP原理的约束,使得我们不得不放弃传统的强一致性,而转而追求最终一致性,这个对开发人员来说是一个挑战。
微服务架构对测试也带来了很大的挑战。传统的单体WEB应用只需测试单一的REST API即可,而对微服务进行测试,需要启动它依赖的所有其他服务。这种复杂性不可低估。
微服务的另一大挑战是跨多个服务的更改。比如在传统单体应用中,若有A、B、C三个服务需要更改,A依赖B,B依赖C。我们只需更改相应的模块,然后一次性部署即可。但是在微服务架构中,我们需要仔细规划和协调每个服务的变更部署。我们需要先更新C,然后更新B,最后更新A。
部署基于微服务的应用也要复杂得多。单体应用可以简单的部署在一组相同的服务器上,然后前端使用负载均衡即可。每个应用都有相同的基础服务地址,例如数据库和消息队列。而微服务由不同的大量服务构成。每种服务可能拥有自己的配置、应用实例数量以及基础服务地址。这里就需要不同的配置、部署、扩展和监控组件。此外,我们还需要服务发现机制,以便服务可以发现与其通信的其他服务的地址。因此,成功部署微服务应用需要开发人员有更好地部署策略和高度自动化的水平。
以上问题和挑战可大体概括为:
- API Gateway
- 服务间调用
- 服务发现
- 服务容错
- 服务部署
- 数据调用
幸运的是,出现了很多微服务框架,可以解决以上问题。
第一代微服务框架
Spring Cloud
Spring Cloud为开发者提供了快速构建分布式系统的通用模型的工具(包括配置管理,服务发现,熔断器,智能路由,微代理,控制总线,一次性令牌,全局锁,领导选举,分布式会话,集群状态等)。 主要项目包括:
- spring cloud config:由git存储库支持的集中式外部配置管理。配置资源直接映射到Spring Environment,但是如果需要可以被非Spring应用程序使用。
- spring cloud netflix:与各种Netflix OSS组件(Eureka,Hystrix,Zuul,Archaius等)集成。
- spring cloud bus:用于将服务和服务实例与分布式消息传递联系起来的事件总线。用于在集群中传播状态更改(例如配置更改事件)
- spring cloud for cloud foundry:将您的应用程序与Pivotal Cloudfoundry集成。提供服务发现实现,还可以轻松实现通过SSO和OAuth2保护资源,还可以创建Cloudfoundry服务代理。
- spring cloud cloud foundry service broker:提供构建管理一个Cloud Foundry中服务的服务代理的起点。
- spring cloud cluster:领导选举和通用状态模型(基于zookeeper,redis,hazelcast,Consul的抽象和实现)
- spring cloud consul:结合Hashicorp Consul的服务发现和配置管理
- spring cloud security:在Zuul代理中为负载平衡的OAuth2休眠客户端和认证头中继提供支持。
- spring cloud sleuth:适用于Spring Cloud应用程序的分布式跟踪,与Zipkin,HTrace和基于日志(例如ELK)跟踪兼容。
- spring cloud data flow:针对现代运行时的可组合微服务应用程序的云本地编排服务。易于使用的DSL,拖放式GUI和REST-API一起简化了基于微服务的数据管道的整体编排。
- spring cloud stream:轻量级事件驱动的微服务框架,可快速构建可连接到外部系统的应用程序。使用Apache Kafka或RabbitMQ在Spring Boot应用程序之间发送和接收消息的简单声明式模型。
- spring cloud stream app starters:Spring Cloud任务应用程序启动器是Spring Boot应用程序,可能是任何进程,包括不会永远运行的Spring Batch作业,并且它们在有限时间的数据处理之后结束/停止。
- spring cloud zookeeper:Zookeeper的服务发现和配置管理
- spring cloud for amazon web services:轻松集成托管的Amazon的Web Services服务。它通过使用spring的idioms和APIs便捷集成AWS服务,例如缓存或消息API。开发人员可以围绕托管服务,不必关心基础架构来构建应用。
- spring cloud connectors:使PaaS应用程序在各种平台上轻松连接到后端服务,如数据库和消息代理(以前称为“Spring Cloud”的项目)
- spring cloud starters:作为基于spring boot的启动项目,降低依赖管理(在Angel.SR2后,不在作为独立项目)
- spring cloud cli:插件支持基于Groovy预言快速创建spring cloud的组件应用
Dubbo
Dubbo是一个阿里巴巴开源出来的一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。其核心部分包含:
- 远程通讯: 提供对多种基于长连接的NIO框架抽象封装,包括多种线程模型,序列化,以及“请求-响应”模式的信息交换方式。
- 集群容错: 提供基于接口方法的透明远程过程调用,包括多协议支持,以及软负载均衡,失败容错,地址路由,动态配置等集群支持。
- 自动发现: 基于注册中心目录服务,使服务消费方能动态的查找服务提供方,使地址透明,使服务提供方可以平滑增加或减少机器。
但是显而易见,无论是Dubbo还是Spring Cloud都只适用于特定的应用场景和开发环境,它们的设计目的并不是为了支持通用性和多语言性。并且它们只是Dev层的框架,缺少DevOps的整体解决方案(这正是微服务架构需要关注的)。而随之而来的便是Service Mesh的兴起。
下一代微服务:Service Mesh?
Service Mesh
Service Mesh又译作“服务网格”,作为服务间通信的基础设施层。如果用一句话来解释什么是Service Mesh,可以将它比作是应用程序或者说微服务间的TCP/IP,负责服务之间的网络调用、限流、熔断和监控。对于编写应用程序来说一般无须关心TCP/IP这一层(比如通过 HTTP 协议的 RESTful 应用),同样使用Service Mesh也就无须关系服务之间的那些原来是通过应用程序或者其他框架实现的事情,比如Spring Cloud、OSS,现在只要交给Service Mesh就可以了。
Service Mesh有如下几个特点:
- 应用程序间通讯的中间层
- 轻量级网络代理
- 应用程序无感知
- 解耦应用程序的重试/超时、监控、追踪和服务发现
Service Mesh的架构如下图所示:
Service Mesh作为Sidebar运行,对应用程序来说是透明,所有应用程序间的流量都会通过它,所以对应用程序流量的控制都可以在Service Mesh中实现。
目前流行的Service Mesh开源软件有Linkerd、Envoy和Istio,而最近Buoyant(开源Linkerd的公司)又发布了基于Kubernetes的Service Mesh开源项目Conduit。
Linkerd
Linkerd是开源网络代理,设计为以服务网格部署:用于管理,控制和监控应用程序内的服务与服务间通讯的专用层。
Linkerd旨在解决Twitter,Yahoo,Google和Microsoft等公司运营大型生产系统时发现的问题。根据经验,最复杂,令人惊奇和紧急行为的来源通常不是服务本身,而是服务之间的通讯。Linkerd解决了这些问题,不仅仅是控制通讯机制,而是在其上提供一个抽象层。
它的主要特性有:
- 负载平衡:linkerd提供了多种负载均衡算法,它们使用实时性能指标来分配负载并减少整个应用程序的尾部延迟。
- 熔断:linkerd包含自动熔断,将停止将流量发送到被认为不健康的实例,从而使他们有机会恢复并避免连锁反应故障。
- 服务发现:linkerd 与各种服务发现后端集成,通过删除特定的(ad-hoc)服务发现实现来帮助您降低代码的复杂性。
- 动态请求路由:linkerd 启用动态请求路由和重新路由,允许您使用最少量的配置来设置分段服务(staging service),金丝雀(canaries),蓝绿部署(blue-green deploy),跨DC故障切换和黑暗流量(dark traffic)。
- 重试次数和截止日期:linkerd可以在某些故障时自动重试请求,并且可以在指定的时间段之后让请求超时。
- TLS:linkerd 可以配置为使用 TLS 发送和接收请求,您可以使用它来加密跨主机边界的通信,而不用修改现有的应用程序代码。
- HTTP代理集成:linkerd 可以作为 HTTP 代理,几乎所有现代 HTTP 客户端都广泛支持,使其易于集成到现有应用程序中。
- 透明代理:您可以在主机上使用 iptables 规则,设置通过 linkerd 的透明代理
- gRPC:linkerd 支持 HTTP/2 和 TLS,允许它路由 gRPC 请求,支持高级 RPC 机制,如双向流,流程控制和结构化数据负载。
- 分布式跟踪:linkerd 支持分布式跟踪和度量仪器,可以提供跨越所有服务的统一的可观察性。
- 仪器仪表: linkerd 支持分布式跟踪和度量仪器,可以提供跨越所有服务的统一的可观察性。
Envoy
Envoy 是一个面向服务架构的L7代理和通信总线而设计的,这个项目诞生是出于以下目标:
对于应用程序而言,网络应该是透明的,当发生网络和应用程序故障时,能够很容易定位出问题的根源。
Envoy可提供以下特性:
- 外置进程架构:可与任何语言开发的应用一起工作;可快速升级
- 基于新C++11编码:能够提供高效的性能
- L3/L4过滤器:核心是一个L3/L4网络代理,能够作为一个可编程过滤器实现不同TCP代理任务,插入到主服务当中。通过编写过滤器来支持各种任务,如原始TCP代理、HTTP代理、TLS客户端证书身份验证等。
- HTTP L7过滤器:支持一个额外的HTTP L7过滤层。HTTP过滤器作为一个插件,插入到HTTP链接管理子系统中,从而执行不同的任务,如缓冲,速率限制,路由/转发,嗅探Amazon的DynamoDB等等。
- 支持HTTP/2:在HTTP模式下,支持HTTP/1.1、HTTP/2,并且支持HTTP/1.1、HTTP/2双向代理。这意味着HTTP/1.1和HTTP/2,在客户机和目标服务器的任何组合都可以桥接
- HTTP L7路由:在HTTP模式下运行时,支持根据content type、runtime values等,基于path的路由和重定向。可用于服务的前端/边缘代理
- 支持gRPC:gRPC是一个来自谷歌的RPC框架,使用HTTP/2作为底层的多路传输。HTTP/2承载的gRPC请求和应答,都可以使用Envoy的路由和LB能力
- 支持MongoDB L7:支持获取统计和连接记录等信息
- 支持DynamoDB L7:支持获取统计和连接等信息
- 服务发现:支持多种服务发现方法,包括异步DNS解析和通过REST请求服务发现服务
- 健康检查:含有一个健康检查子系统,可以对上游服务集群进行主动的健康检查。也支持被动健康检查。
- 高级LB:包括自动重试、断路器,全局限速,阻隔请求,异常检测。未来还计划支持请求速率控制
- 前端代理:可作为前端代理,包括TLS、HTTP/1.1、HTTP/2,以及HTTP L7路由
- 极好的可观察性:对所有子系统,提供了可靠的统计能力。目前支持statsd以及兼容的统计库。还可以通过管理端口查看统计信息,还支持第三方的分布式跟踪机制
- 动态配置:提供分层的动态配置API,用户可以使用这些API构建复杂的集中管理部署
Istio
Istio是一个用来连接、管理和保护微服务的开放平台。Istio提供一种简单的方式来建立已部署服务网络,具备负载均衡、服务间认证、监控等功能,而不需要改动任何服务代码。想要为服务增加对Istio的支持,您只需要在环境中部署一个特殊的边车(sidecar),使用Istio控制面板功能配置和管理代理,拦截微服务之间的所有网络通信。
Istio目前仅支持在Kubernetes上的服务部署,但未来版本中将支持其他环境。
Istio提供了一个完整的解决方案,通过为整个服务网格提供行为洞察和操作控制来满足微服务应用程序的多样化需求。它在服务网络中统一提供了许多关键功能:
- 流量管理:控制服务之间的流量和API调用的流向,使得调用更可靠,并使网络在恶劣情况下更加健壮
- 可观察性:了解服务之间的依赖关系,以及它们之间流量的本质和流向,从而提供快速识别问题的能力
- 策略执行:将组织策略应用于服务之间的互动,确保访问策略得以执行,资源在消费者之间良好分配。策略的更改是通过配置网格而不是修改应用程序代码
- 服务身份和安全:为网格中的服务提供可验证身份,并提供保护服务流量的能力,使其可以在不同可信度的网络上流转
Istio服务网格逻辑上分为数据面板和控制面板:
- 数据面板由一组智能代理(Envoy)组成,代理部署为边车,调解和控制微服务之间所有的网络通信
- 控制面板负责管理和配置代理来路由流量,以及在运行时执行策略
下图显示了构成每个面板的不同组件:
Conduit
Conduit是为Kubernetes设计的一个超轻型服务网格服务,它可透明地管理在Kubernetes上运行的服务的运行时通信,使得它们更安全可靠。Conduit提供了可见性、可靠性和安全性的功能,而无需更改代码。
Conduit service mesh也是由数据面板和控制面板组成。数据面板承载应用实际的网络流量。控制面板驱动数据面板,并对外提供北向接口。
对比
Linkerd和Envoy比较相似,都是一种面向服务通信的网络代理,均可实现诸如服务发现、请求路由、负载均衡等功能。它们的设计目标就是为了解决服务之间的通信问题,使得应用对服务通信无感知,这也是Service Mesh的核心理念。Linkerd和Envoy像是分布式的Sidebar,多个类似Linkerd和Envoy的proxy互相连接,就组成了service mesh。
而Istio则是站在了一个更高的角度,它将Service Mesh分为了Data Plane和Control Plane。Data Plane负责微服务间的所有网络通信,而Control Plane负责管理Data Plane Proxy:
并且Istio天生的支持Kubernetes,这也弥合了应用调度框架与Service Mesh之间的空隙。
关于Conduit的资料较少,从官方介绍看它的定位和功能与Istio类似。
Kubernetes + Service Mesh
Kubernets已经成为了容器调度编排的事实标准,而容器正好可以作为微服务的最小工作单元,从而发挥微服务架构的最大优势。所以我认为未来微服务架构会围绕Kubernetes展开。而Istio和Conduit这类Service Mesh天生就是为了Kubernetes设计,它们的出现补足了Kubernetes在微服务间服务通讯上的短板。虽然Dubbo、Spring Cloud等都是成熟的微服务框架,但是它们或多或少都会和具体语言或应用场景绑定,并只解决了微服务Dev层面的问题。若想解决Ops问题,它们还需和诸如Cloud Foundry、Mesos、Docker Swarm或Kubernetes这类资源调度框架做结合:
但是这种结合又由于初始设计和生态,有很多适用性问题需要解决。
Kubernetes则不同,它本身就是一个和开发语言无关的、通用的容器管理平台,它可以支持运行云原生和传统的容器化应用。并且它覆盖了微服务的Dev和Ops阶段,结合Service Mesh,它可以为用户提供完整端到端的微服务体验。
所以我认为,未来的微服务架构和技术栈可能是如下形式:
多云平台为微服务提供了资源能力(计算、存储和网络等),容器作为最小工作单元被Kubernetes调度和编排,Service Mesh管理微服务的服务通信,最后通过API Gateway向外暴露微服务的业务接口。
我相信未来随着以Kubernetes和Service Mesh为标准的微服务框架的盛行,将大大降低微服务实施的成本,最终为微服务落地以及大规模使用提供坚实的基础和保障。
微服务框架
目前国内企业使用的微服务框架主要是Spring Cloud和Dubbo(或者DubboX),但是Dubbo那两年的停更严重打击了开发人员对它的信心,Spring Cloud已经逐渐成为主流,比较两个框架的优劣势的文章在网上有很多,这里就不重复了,选择什么框架还是按业务需求来吧,业务框架决定技术框架。
Spring Cloud全家桶提供了各种各样的组件,基本可以覆盖微服务的服务治理的方方面面,以下列出了Spring Cloud一些常用组件:
搭建典型微服务架构
本章节主要介绍如何基于Spring Cloud相关组件搭建一个典型的微服务架构。
首先,创建一个Maven父项目spring-cloud-examples
,用于管理项目依赖包版本。由于Spring Cloud组件很多,为保证不同组件之间的兼容性,一般通过spring-cloud-dependencies
统一管理Spring Cloud组件版本,而非每个组件单独引入。
pom.xml配置如下:
<!-- 继承SpringBoot父项目,注意与SpringCloud版本的匹配 -->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.4.RELEASE</version>
</parent>
<properties>
<spring.boot.version>2.1.4.RELEASE</spring.boot.version>
<spring.cloud.version>Greenwich.SR1</spring.cloud.version>
<lombok.version>1.18.8</lombok.version>
<maven.compiler.plugin.version>3.8.1</maven.compiler.plugin.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring.cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
搭建服务配置中心
- 在
spring-cloud-examples
项目下创建一个子项目spring-cloud-example-config
,添加Spring Cloud Config Server端的相关依赖包:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
</dependencies>
- 添加Spring Boot配置文件
application.yml
,配置如下:
spring:
application:
name: spring-cloud-example-config
profiles:
active: native #启用本地配置文件
cloud:
config:
server:
native:
search-locations: classpath:/configs/ #配置文件扫描目录
server:
port: 8000 #服务端口
- 启动类添加注解
@EnableConfigServer
通过启用Config Server服务。
@SpringBootApplication
@EnableConfigServer
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
搭建服务注册中心
- 在
spring-cloud-examples
项目下创建一个子项目spring-cloud-example-registry
,在pom.xml
中添加Eureka Server相关依赖包:
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-netflix-eureka-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
</dependencies>
- 在
spring-cloud-example-config
配置中心项目的src/main/resource/configs
目录下添加一个服务配置文件spring-cloud-example-registry.yml
,配置如下:
spring:
application:
name: spring-cloud-example-registry
# Eureka相关配置
eureka:
client:
register-with-eureka: false #不注册服务
fetch-registry: false #不拉去服务清单
serviceUrl:
defaultZone: http://localhost:${server.port}/eureka/ #多个通过英文逗号分隔
server:
port: 8001
- 在
spring-cloud-example-registry
项目的src/main/resource/
目录添加bootstrap.yml
配置文件,配置如下:
spring:
cloud:
config:
name: spring-cloud-example-registry #配置文件名称,多个通过逗号分隔
uri: http://localhost:8000 #Config Server服务地址
- 启动类添加注解
@EnableEurekaServer
通过启用Eureka Server服务。
@SpringBootApplication
@EnableEurekaServer
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
搭建业务服务A
- 在
spring-cloud-examples
项目下创建一个业务服务A的子项目spring-cloud-example-biz-a
,在pom.xml
中添加以下依赖包:
<dependencies>
<!-- Spring Boot Web Starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- feign -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
<!-- Eureka Client Starter -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- Config Client Starter -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
</dependencies>
- 在
spring-cloud-example-config
配置中心项目的src/main/resource/configs
目录下添加一个服务配置文件spring-cloud-example-biz-a.yml
,配置如下:
spring:
application:
name: spring-cloud-example-biz-a
server:
port: 8010
# Eureka相关配置
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8001/eureka/
instance:
lease-renewal-interval-in-seconds: 10 # 心跳时间,即服务续约间隔时间(缺省为30s)
lease-expiration-duration-in-seconds: 60 # 发呆时间,即服务续约到期时间(缺省为90s)
prefer-ip-address: true
instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}}
- 在
spring-cloud-example-biz-a
项目的src/main/resource/
目录添加bootstrap.yml
配置文件,配置如下:
spring:
cloud:
config:
name: spring-cloud-example-biz-a #配置文件名称,多个通过逗号分隔
uri: http://localhost:8000 #Config Server服务地址
- 添加一个示例接口,代码参考:
@RestController
@RequestMapping("/hello")
public class HelloController {
/**
* 示例方法
*
* @return
*/
@GetMapping
public String sayHello() {
return "Hello,This is Biz-A Service.";
}
}
搭建业务服务B
参考上面业务服务A搭建另外一个业务服务B。
搭建服务网关
- 在
spring-cloud-examples
项目下创建一个业务服务A的子项目spring-cloud-example-gateway
,在pom.xml
中添加以下依赖包:
<dependencies>
<!-- zuul -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-zuul</artifactId>
</dependency>
<!-- Eureka Client Starter -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- Config Client Starter -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
</dependencies>
- 在
spring-cloud-example-config
配置中心项目的src/main/resource/configs
目录下添加一个服务配置文件spring-cloud-example-gateway.yml
,配置如下:
spring:
application:
name: spring-cloud-example-gateway
server:
port: 8002
# Eureka相关配置
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8001/eureka/
instance:
lease-renewal-interval-in-seconds: 10 # 心跳时间,即服务续约间隔时间(缺省为30s)
lease-expiration-duration-in-seconds: 60 # 发呆时间,即服务续约到期时间(缺省为90s)
prefer-ip-address: true
instance-id: ${spring.application.name}:${spring.application.instance_id:${server.port}}
- 在
spring-cloud-example-gateway
项目的src/main/resource/
目录添加bootstrap.yml
配置文件,配置如下:
spring:
cloud:
config:
name: spring-cloud-example-gateway #配置文件名称,多个通过逗号分隔
uri: http://localhost:8000 #Config Server服务地址
- 启动类添加注解
@EnableZuulProxy
通过启用网关代理服务。
@SpringBootApplication
@EnableZuulProxy
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
启动示例
-
启动顺序
spring-cloud-example-config
>>spring-cloud-example-eureka
>>spring-cloud-example-biz-a
/spring-cloud-example-biz-b
/spring-cloud-example-gateway
-
通过网关访问服务A接口
-
通过网关访问服务B接口
三、微服务技术选型和微服务的问题
3.1 技术选型
3.1.1 技术矩阵结论
-
Netflix提供了比较全面的解决方案
-
Spring Cloud对于Netflix的封装比较全面
-
Spring Cloud基于Spring Boot,团队有基础
-
Spring Cloud提供了Control Bus能够帮助实现监控埋点
-
业务应用部署在阿里云,Spring Cloud对12 Factors以及Cloud-Native的支持,有利于在云环境下使用
3.1.2 团队期望
-
首先支持Rest
-
团队技术栈和实例比较单薄,希望对新的技术平滑的学习曲线和能够Hold住
-
小团队,希望能够有一个比较全面的解决方案
-
目前团队主要采用Spring Cloud + Spring Boot的方式实现服务化
有关技术选型详细分析,请查看我的上一篇文章《我的技术选型》。
3.2 微服务带来的问题
-
依赖服务变更很难跟踪,其他团队的服务接口文档过期怎么办?依赖的服务没有准备好,如何验证我开发的功能。
-
部分模块重复构建,跨团队、跨系统、跨语言会有很多的重复建设。
-
微服务放大了分布式架构的系列问题,如分布式事务怎么处理?依赖服务不稳定怎么办?
-
运维复杂度陡增,如:部署物数量多、监控进程多导致整体运维复杂度提升。
上面这些问题我们应该都遇到过,并且总结形成了自己的一些解决方案,比如提供文档管理、服务治理、服务模拟的工具和框架; 实现统一认证、统一配置、统一日志框架、分布式汇总分析; 采用全局事务方案、采用异步模拟同步;搭建持续集成平台、统一监控平台等等。
微服务架构是一把双刃剑,虽然解决了集中式架构和分布式架构的问题,却带来了如上种种问题。因此我们是需要一个微服务应用平台才能整体性的解决这些问题。
四、微服务架构设计
4.1 微服务应用架构设计原则
4.2 微服务应用架构设计目标
微服务架构设计的目标,满足快速开发、灵活升级、高性能、高可用、高稳定、简化运维等更高的需求。
4.3 微服务应用总体架构
微服务应用平台的总体架构,主要是从开发集成、微服务运行容器与平台、运行时监控治理和外部渠道接入等维度来划分和考虑的。
-
开发集成:主要是搭建一个微服务平台需要具备的一些工具和仓库
-
运行时:要有微服务平台来提供一些基础能力和分布式的支撑能力,我们的微服务运行容器则会运行在这个平台之上。
-
监控治理:则是致力于在运行时能够对受管的微服务进行统一的监控、配置等能力。
-
服务网关: 则是负责与前端的WEB应用 移动APP 等渠道集成,对前端请求进行认证鉴权,然后路由转发。
4.4 微服务框架概览
这里不详细讲解服务框架中每一个组件,另开一篇文章来讲解。
五、微服务架构设计落地
5.1 基础环境
一个企业的IT建设非常重要的三大基础环境:团队协作环境、服务基础环境、IT基础设施。
-
团队协作环境:主要是DevOps领域的范畴,负责从需求到计划任务,团队协作,再到质量管理、持续集成和发布。
-
服务基础环境:指的是微服务应用平台,其目标主要就是要支撑微服务应用的设计开发测试,运行期的业务数据处理和应用的管理监控。
-
IT基础设施:主要是各种运行环境支撑如IaaS (VM虚拟化)和CaaS (容器虚拟化)等实现方式。
5.2 服务通信
服务间的通信,往往采用HTTP+REST 和 RPC通信协议。
HTTP+REST,对服务约束完全靠提供者的自觉。
-
特点是简单,对开发使用友好。
-
缺点治理起来困难,连接的无状态,缺失多路复用、服务端推送等。
RPC对通信双方定义了数据约束。
-
连接大多基于长连接以获得性能的提升及附带的服务端推、调用链路监控埋点等,增强了系统的附加能力。
-
缺点是对调用端提出了新的要求。
综合来看,RPC从性能、契约优先来说具有优势,如何做到扬长避短呢?
引入GateWay层,让REST与RPC的优点进行融合,在GateWay层提供REST的接入能力。
5.3 服务注册/发现
以前的单体应用之间互相调用时配置个IP或域名就行了,但在微服务架构下,服务提供者会有很多,手工配置IP地址或域名又变成了一个耦合和繁琐的事情。那么服务自动注册发现的方案就解决了这个问题。
我们的服务注册发现能力是依赖SpringCloud Eureka组件实现的。服务在启动的时候,会将自己要发布的服务注册到服务注册中心;运行时,如果需要调用其他微服务的接口,那么就要先到注册中心获取服务提供者的地址,拿到地址后,通过微服务容器内部的简单负载均衡期进行路由用。
Eureka Server特点:
-
Eureka Client会缓存服务注册信息
-
Eureka Server的注册信息只存储在内存中
-
Eureka的注册只针对application级别,不支持更细粒度的服务注册,如单个服务Rest
-
服务每隔30秒向Eureka Server发送心跳,不建议修改心跳时间。Eureka用这个时间来判断集群内是否存在大范围的服务通信异常
-
如果在15分钟内有85%的服务没有被续约,则Eureka Server停止移除已注册的服务,以保障已注册的服务信息不丢失
-
Eureka Server之间的数据同步,采用全量拉取,增量同步的方式
-
Eureka 满足分布式事务中的CAP理论中的AP
5.4 集中式配置管理
微服务分布式环境下,一个系统拆分为很多个微服务,一定要告别运维手工修改配置配置的方式。需要采用集中配置管理的方式来提升运维的效率。配置文件主要有运行前的静态配置和运行期的动态配置两种。
-
静态配置通常是在编译部署包之前设置好。
-
动态配置则是系统运行过程中需要调整的系统变量或者业务参数。
要想做到集中的配置管理,那么需要注意以下几点。
-
配置与介质分离,这个就需要通过制定规范的方式来控制。
-
配置的方式要统一,格式、读写方式、变更热更新的模式尽量统一,要采用统一的配置框架。
-
需要运行时需要有个配置中心来统一管理业务系统中的配置信息。
概念抽象:
介质,是源码编译后的产物与环境无关,多环境下应该是可以共用的如:jar
5.5 统一认证鉴权
安全认证方面,我们基于Spring Security OAuth2 + JWT做安全令牌,实现统一的安全认证与鉴权,使得微服务之间能够按需隔离和安全互通。
认证鉴权一定是个公共的服务,而不是多个系统各自建设。
5.6 分布式调用
微服务架构下,相对于传统部署方式,存在更多的分布式调用,那么“如何在不确定的环境中交付确定的服务”,这句话可以简单理解为,我所依赖的服务的可靠性是无法保证的情况下,我如何保证自己能够正常的提供服务,不被我依赖的其他服务拖垮?
我们采用的方案:
-
合理的超时时间
-
合理的重试机制
-
合理的异步机制
-
合理的限流机制(调用次数和频率)
-
合理的降级机制
-
合理的熔断机制
推荐SEDA架构来解决这个问题。
SEDA : staged event-driven architecture本质上就是采用分布式事件驱动的模式,用异步模拟来同步,无阻塞等待,再加上资源分配隔离结起来的一个解决方案。
5.7 分布式事务
分布式事务-CAP
-
C 分布式环境下多个节点的数据是否强一致
-
A 分布式服务能一直保证可用状态
-
P 网络分区的容错性
分布式事务-策略
-
避免跨库事务,尽可能相关表在同一个DB
-
2PC 3PC TCC 补偿模式等, 耗时且复杂
-
基于MQ的最终一致性 简单、高效、易于理解
-
将远程分布式事务拆解成一系列本地的事务
分布式事务-基于MQ
5.8 服务拆分
服务拆分方式
AKF扩展立方体,是抽象总结的应用扩展的三个维度。
-
X轴 扩展部署实例,就是讲单体系统多运行几个实例,做个集群加负载均衡的模式。
-
Y轴 业务领域分离,就是基于不同的业务拆分。
-
Z轴 数据隔离分区,比如共享单车在用户量激增时,集群模式撑不住了,那就按照用户请求的地区进行数据分区,北京、上海、深圳等多建几个集群。
服务拆分要点
-
低耦合、高内聚:一个服务完成一个独立的功能
-
按照团队结构:小规模团队维护,快速迭代
5.9 数据库拆分
单库单表难以支撑日益增长的业务量和数据量,服务拆分了数据库也跟着拆分。
5.9.1 模式
-
垂直拆分
-
水平拆分
5.9.2 原则
-
尽可能不拆分
-
避免跨库事务
-
单表量级1000w
-
避免垮裤join(冗余、全局表)
5.10 日志管理
日志主要有三种,系统日志,业务日志,跟踪日志。有了这些日志,在出问题的时候能够帮助我们获取一些关键信息进行问题定位。
要想做到,出了问题能够追根溯源,那么我们需要一个可以将整个完整的请求调用链串联起来的标识,这个标识能够让我们快速定位问题发生的具体时间地点以及相关信息,能够快速还原业务交易全链路。对这些日志与流水的细节处理,对于系统运维问题定位有非常大的帮助。通常开源框架只是提供基础的框架,而设计一个平台则一定要考虑直接提供统一规范的基础能力。
分布式跟踪
5.11 服务契约与API管理
对于前面提到的微服务带来的依赖管理问题,我们需要提供API管理能力。说到API管理,那首先就用提到服务契约。
服务契约,主要描述服务接口的输入输出规格标准和其他一些服务调用集成相关的规格内容。
5.12 服务契约与服务模拟
有了服务契约,研发人员就可以方便的获取到依赖服务变更的情况,能够及时的根据依赖服务的变化调整自己的程序,并且能够方便的进行模拟测试验证。
根据契约生成模拟服务也就是我们常说的服务挡板,这样即使依赖的其他服务还无法提供功能,我们也可以通过挡板来进行联调测试。
5.13 微服务容器
我们要做稳定、高效、易扩展的微服务应用,实际上我们需要做的事情还是非常多的。如果没有一个统一的微服务容器,这些能力在每个微服务组件中都需要建设一遍,也很难集成到一起。有了统一的微服务运行容器和一些公共的基础服务,前面所提到的微服务架构下部分组件重复建设的问题也迎刃而解。
5.14 持续集成与持续部署
在运维方面,首先我们要解决的就是持续集成和持续交付,能够方便的用持续集成环境把程序编译成介质包和部署包并持续稳定的部署到每个环境。
概念抽象:
介质:是源码编译后的产物与环境无关,多环境下应该是可以共用的。如:jar
配置:则是环境相关的信息。
部署包=配置+介质。
5.15 微服务平台与容器云、DevOps的关系
就微服务应用平台本身来说,并不依赖DevOps和容器云,开发好的部署包可以运行在物理机、虚拟机或者是容器中。然而当微服务应用平台结合了DevOps和容器云之后,我们就会发现,持续集成和交付变成了一个非常简单便捷并且又可靠的过程。简单几步操作,整套开发、测试、预发或者生产环境就能够搭建完成。
整个过程的复杂度都由平台给屏蔽掉了,通过三大基础环境的整合,我们能够使分散的微服务组件更简单方便的进行统一管理和运维交付。
5.16 技术团队的组织
技术团队组织 – 小团队
根据“康威定律”,软件架构是由组织的架构决定的,因此按照贝索斯“two-pizza”团队的理论和敏捷方法,构建小的团队,可以有效减少沟通成本,有利于团队的自治。
我们通过让一个小的团队有比较全面的建制,Leader(熟悉业务和技术)+ 前端工程师 + 后端工程师,往往可以能够比较独立地承接一个或者几个业务的工作。这样团队成员整体负责一个或者几个业务模块,可以极大地提高团队成员的参与感、使命感和责任感,团队成员相互帮助,高度自治,大家要么一起成功,要么一起失败。
技术团队组织 – 团队划分
团队的划分,是按照业务线划分的。随着业务的复杂度的增加,可以按照业务/子业务线的方式来划分团队,但并不是绝对的扁平化,而是严格遵循two-pizza原则。
业务线的划分常常按业务细分,技术团队要负责支持全部业务线,因此技术团队的划分通常按系统或者是业务,Two pizza团队的原则在组织层级的任何部分都适用,当人数过多时,必须继续拆分。
技术团队组织 – 团队合作
技术团队组织 – 结果导向
-
主人翁意识(Ownership)
-
行动力(Bias for Action)
-
吃自己的狗粮(Eat your dog food)
• 工程师负责从需求调研、设计、开发、测试、部署、维护、监控、功能升级等一系列的工作,也就是说软件工程师负责应用或者服务的全生命周期的所有工作
• 运维是团队成员的第一要务,在强大的自动化运维工具的支撑下,软件工程师必须负责服务或者应用的SLA -
开发人员参与架构设计,而不是架构师参与开发
• 研发人员是Owner,对业务和团队负责
• 强调抽象和简化,将复杂的问题分解成简单的问题,并有效解决,避免过度设计
• 鼓励用新技术解决问题,但强调掌控力
六、微服务架构设计过程中积累的心得
-
深入理解业务
-
设计阶段要追求完美,实践阶段要考虑实际情况作出平衡
-
容错能力
-
监控先行
-
任何上线可回滚
七、总结
微服务架构是技术升级,但更多的是管理模式的升级、思维方式的转变。