前言
一直对微服务非常感兴趣,因为公司的架构改造正好有机会能够接触微服务,买来一些书,请教了很多微服务大牛同时自己也做了很多总结,写成了80页ppt,算是我对微服务的一个认识吧,微服务本身不同的人有不同的理解,而我就从我自己的角度来谈谈微服务是什么。
目前市面上的不少书或者不少相关文章写的都是框架的使用,或者架构的介绍,其实对于刚入门不久的同学来说很容易造成微服务就是一堆框架和组件的堆砌,于是今天我将从理论和实践的角度来说说微服务。
现代互联网的方向是当企业发展到一定规模后,一定是大规模、云计算和大数据的三者的结合,从而形成平台,那么微服务就是基于此而提出的。
一、什么是微服务
1、常见的系统架构
目前我们经常接触的网络架构主要有三种,如下图:
从图中可以看到,共有三种模式,第一种是集中式架构也是单块应用最常使用的架构模式。第二种是分布式架构,最常见的应用是将一个大的任务拆分到不同的机器中进行计算,最终有一台服务器合并计算结果就是分布式架构的一个好的体现。第三种就是微服务架构。
2、现实遇到的挑战
- 扩容困难
我们之前开发项目用的是虚拟机,每次上线项目需要加机器总会遇到资源不足的情况,还要走非常复杂工单审批流程,还要与运维人员不断PK,才能申请下来资源,整个流程冗长,机器受限于资源申请困难。
- 部署困难
每次上线采用专门的人进行布署,上线之前需要与上线人员沟通上线的环境,防止上线出错。
- 发布回滚困难
每次上线发现问题后,需要重新从svn主干上面进行代码编译,但是有时候会因为各种问题回滚失败,而且重新编译很耗时导致回滚缓慢。
- 适配新技术困难
如果打算在不同的模块采用不同的语言开发,或者想在架构中做技术升级都很困难或者不支持。
- 快速开发困难
项目中采用单体应用,里面集成了太多功能模块,无法快速进行功能开发并且很容易牵一发动全身。
- 测试困难
测试人员没有自动化测试框架,或者Mock系统,导致只能采用简单的人工测试流程,而且还经常发生功能覆盖不全面等问题。
- 学习困难
于是我们把项目中遇到上述问题的项目称为单体应用。
3、微服务的定义
The microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. There is a bare minimum of centralized management of these services , which may be written in different programming languages and use different data storage technologies.
– James Lewis and Martin Fowler
原文:http://martinfowler.com/articles/microservices.html
翻译文:http://blog.csdn.net/u013970991/article/details/53333921
总结了一下共有四点特性:
- 一些列的独立的服务共同组成系统
- 单独部署,跑在自己的进程里
- 每个服务为独立的业务开发
- 分布式的管理
4、微服务和SOA的区别
- 微服务只是一种为经过良好架构设计的SOA解决方案,是面向服务的交付方案。
- 微服务更趋向于以自治的方式产生价值。
- 微服务与敏捷开发的思想高度结合在一起,服务的定义更加清晰,同时减少了企业ESB开发的复杂性。
- 微服务是soa思想的一种提炼!
- SOA是重ESB,微服务是轻网关。
5、微服务定义小结
二、关于微服务的建模
我们在谈建模,首先想到的是领域驱动设计的内容,没错,微服务的建模思想也是基于建模的思想,下面我将给简单给与介绍什么样的服务才算是好服务。
1、松耦合和高内聚
松耦合:修改一个服务不需要同时修改另一个,每个微服务都可以单独修改和布署。
高内聚:把相关的事务放在一起,把不相关的排除出去,聚集在一起的事务只能干同一件事。
用如下图可以清晰的表示:
2、限界上下文
限界:就是划分、规定,界限、边界。
上下文:是业务的整个流程。
当我们检查已有的系统时,经常会发现系统中存在混杂在一起的模型,他们之间的边界是非常模糊的。此时你应该为整个系统绘制一个边界,然后将其归纳在大泥球范围之内。往往在我们所在的项目中,经常是项目版本的迭代的时候出现这样的情况,导致后期维护代码越来越困难。
3、逐步上下文
- 划分方法:一开始识别粗粒度的限界上下文、这些粗粒度的上下文可能包括一些套嵌的限界上下文,这些套嵌的上下文不直接对外可见。
- 暴露原则:使用粗粒度上下文还是套嵌上下文暴露服务,哪个更合理,应该有组织结构来决定的。
正如上面二个图的示例所示,左边的订单处理,货物接收和库存管理三个模块在项目研发初期被归集到了仓库服务中,财务服务获取库存管理的数据,直接访问仓库服务的库存管理接口就可以了。随着这三个模块的不断演进和壮大,单个服务已经不能满足业务和团队发展的需求,这时候将这三个模块分别拆分演变成右边的结构图,这时候订单管理,货物接收和库存管理分别以服务的形式对应不同的团队,财务服务只需请求库存管理服务就可以得到相应的数据。
三、关于微服务的集成
1、集成原则
微服务的集成做到好,可以保持自治性、可以独立发布修改和发布。
- 避免破坏性修改
服务的一些修改不能导致该服务的消费方发生改变。
- 保证API与技术的无关性
- 保证API的易用性
- 隐藏内部实现细节
2、编排与协同
编排:同步调用一组服务,等待各个服务的返回结果。优点知道业务流程中每一步跨服务调用结果,缺点容易承担太多的调用,太耗时,导致调用方的不稳定性。
协同:异步调用一组服务或服务调用加入队列中,降低服务之间的耦合度,带来的额外工作业务流程跨服务的监控,不过可通过消费方处理完成后,回调服务方告知处理结果。
(编排)
(协同)
3、版本管理
- 尽可能推迟破坏性修改
宽进严出的原则
- 尽早发现破坏性的修改
按照契约,通过测试及早发现是服务方还是消费方破坏性的修改
- 不同的接口版本共存
最好共存两个版本
4、案例分析
案例一:如何拆分单块系统结构
当我们看到一个单块系统时,往往首先要从数据库入手进行拆分,规划好哪些是财务代码的表,哪些是客户代码的表,将二者进行分离,这时候单块系统的应用结构并没有拆分,这还需要我们在进行设计单块系统的时候,客户代表和财务代码的表字段不能混在一起,还是要设计成不同的表才能方便我们将来拆分,虽然系统是在一起的,但是却为未来做了拆分准备,最后将应用系统拆分独立布署,这个过程就结束了。
案例二:如何跨系统访问数据表
有二个服务,分别是产品目录和财务,左图的场景是财务服务直接调用产品目录的数据表进行数据获取,这种跨服务的数据获取方式是有问题的,首先我们无法把控财务服务是如何获取数据的,是否对我们的数据表造成影响,其次从设计的角度来说无疑又增长了系统之间调用的耦合度,系统之间的依赖又增强了。于是演变成右图这样,左图只需提供服务接口给右图调用即可。
案例三:服务设计中的坏味道
在这样的系统中,ABCD四个系统进行了串联,这样也就要求这四个系统分别都是高可用,如果其中任何一个系统挂了或者发生问题,都会直接影响其他所有系统,所以我们设计微服务架构的时候要尽量避免这种集中式的架构。
四、如何大规模的使用微服务
我们真正使用微服务的时候,有很多需要注意和关注的点:
1、故障无所不在
网络是不可靠,只能尽力限制引起故障的因数,达到一定规模后,故障不可避免。
2、跨功能需求
服务吞吐量、可用性和数据持久性等这些需求需要持续测量,并保证服务满足可接受的目标。
3、功能降级
构建弹性系统,因微服务功能分散,在有可能down机的微服务上,能够安全的降级以保证弹性
4、反服务脆弱
为了不会引起严重级联影响,需要正确的设置超时、实现舱壁隔离或断路层等以避免在第一时间调用一个不健康的服务。
- 超时
设置超时时间对于调用下游服务十分重要,超时时间设置太长有可能把下游系统拖慢,设置太短可能下游服务未处理完成。最好设置一个默认的超时时间,当超时发生时后,记录到日志里看看发生了什么,并且做响应的调整。
- 断路器
使用断路器,当请求下游服务发生一定数量的失败后,短路器打开,接下来的请求快速失败。一断时间后,查看下游服务是否已服务,重置断路器。
- 舱壁
为每个下游服务建立单独的连接池。超时和断路器资源受限时释放资源,舱壁第一时间确保它不成为限制。还有一个拒绝请求的舱壁,用以避免资源饱和,称之为减载。
- 隔离
当下游服务离线,上游服务不受影响。设置成为服务间隔离。
5、幂等
幂等操作,多次执行所产生的影响,均与一次执行影响相同。可以把某些特定业务操作设计成幂等的,比如客户下单送积分。
6、扩展
增加负载、减少延迟。
- 更强大的主机:垂直扩展,更好的机器。
- 拆分负载:按业务拆分成不同的微服务
- 分散风险:数据跨机房,异地备份等
- 负载均衡:避免服务单点故障
- 作业分离:Job独立服务执行
- 重新设计:一般设计系统需要考虑10倍容量增长。重新设计系统应对规模化,是成功的标志。
7、扩展数据库
- 服务的可用性
- 服务的持久性:多副本
- 读取数据扩展:读写分离
- 写操作扩展:分表分库
- 共享数据库设施:容易形成单点故障
- CQRS:命令查询职责分离
8、缓存的使用
通过存储之前的操作结果,以便后续请求使用这个结果,而无需花重新计算或查询。
- 客户端缓存
客户端缓存获取的结果,客户端决定何时获取新副本。一般是有下游服务提供缓冲的过期时间。客户端缓存可以减少网络调用次数,并且减少下游服务负载的最快方法之一,客户端缓存数据,让数据失效需要做额外的工作。
- 服务端缓存
服务端来负责处理缓存,容易跟踪和优化缓存的命中率。
- 代理服务器缓存
缓存在服务的和客户端之间,比如方向代理或CDN等。对一切客户端和服务端不透明
- HTTP缓存
- 为写使用缓存
先写入本地缓存,之后某个时刻将数据写入下游的,可能更规范化的数据源中。
- 为弹性使用缓存
下游服务不可用,客户端可以缓存可能失效的数据。
- 隐藏源服务
保护源服务,不直接暴露源服务。如果缓存不命中,立即失败,异步重建缓存。
- 保持简单
避免太多地方使用缓存,缓存越多,数据越可能失效,就越难保证数据的新鲜程度。
9、自动伸缩
响应型伸缩、预测型伸缩
10、CAP定理
在分布式系统中有三方面需要彼此权衡:一致性、可用性和分区容忍性。这个定理告之我们最多只能能保证三个中的两个。CA系统在分布式系统中根本不存在。
六、阶段总结:
在第一部分我们重点介绍了涉及微服务的一些思想,总结了如何设计一个相对好的服务,并且也介绍了一些微服务和领域驱动的相关概念帮助大家学习掌握。
那么在第二部分介绍中,我将在如何在微服务中使用事务,自动化测试怎么做,Devops是什么,如何利用康威定律管理团队,以及重点介绍实战项目,如何基于Spring boot/netflix来构建微服务项目。