YAZONG 我的开源

从代码层面对微服务改造的理解

 
0 评论0 浏览

一、微服务介绍
二、微服务查询端改造案例
三、微服务读写端改造案例
四、微服务总结(重点)
五、推荐书籍

一、微服务介绍

什么是微服务

微服务就是一些协同工作的小而自治的服务。

把因相同原因而变化的东西聚合到一起,而把因不同原因而变化的东西分离出来。

微服务把这个理念应用在独立的服务上。 微服务是在SOA(一种设计方法。网络调用而非进程内的调用。通信协议SOAP的选择、第三方中间件的选择、服务粒度的确定,在这三者中存在一定的问题。)的基础上,对其进行了扩展,是一种特定方法,也是一种思想。

微服务特性

多小才合适

足够小可以,不要过小。
该服务是否能够很好地与团队结构相匹配(调用方、被调用方:人员、时间安排等会引起一系列复杂度)。
服务越小,微服务架构的优点和缺点也就越明显。
使用的服务越小,独立性带来的好处就越多,但是管理大量服务也会越复杂。
在解决问题上也可以有更多的选择。

自治性

一个微服务就是一个独立的实体。它可以独立地部署在PAAS(Platform As A Service)上,也可以作为一个操作系统进程存在。尽量避免把多个服务部署到同一台机器上,尽管现如今机器的概念已经非常模糊了(可以思考一下容器化的概念)。
公司案例:SAAS的job和两个微服务部署在一起,服务资源不断被抢占。经常收到这些应用的UP和DOWN的邮件。当把job和微服务分别迁移后,邮件不再经常报警。

技术异构性

尝试使用一种适合所有场景的标准化技术,会使得所有的场景都无法得到很好的支持。
在微服务这种由多个服务相互协作的系统中,可以在不同的服务中使用最适合该服务的技术。
更快地使用新技术。当然会付出一些代价。寻找平衡点。跟服务拆成多小是一类意思。

弹性

服务边界。
单应用,运行在不同的机器降低功能不可用的概率。
微服务系统本身就能够很好地处理服务不可用和功能降级问题。
这种分布式系统引发的网络问题和机器问题。

扩展

针对某个模块来进行修改、提升性能。(监控)
可独立的进行修改。服务暴露的API,与具体技术不相关,避免与消费方耦合。要能实现,修改一个服务对其进行部署而不影响其他任务服务。
公司案例:借用第三方来解决复杂性问题。(比如配置中心Apollo、链路跟踪zipkin等。)

部署

快速回滚。两次发布之间的差异越大,出错的可能性就越大。

二、微服务查询端改造案例

APP改造结构

整体结构

Screenshot20200104从代码层面对微服务改造的理解亚龙的博客.png

结构细分

Screenshot20200104从代码层面对微服务改造的理解亚龙的博客1.png

APP改造项目模块

整体结构

Screenshot20200104从代码层面对微服务改造的理解亚龙的博客3.png

模块细分

Screenshot20200104从代码层面对微服务改造的理解亚龙的博客4.png

Screenshot20200104从代码层面对微服务改造的理解亚龙的博客5.png

Screenshot20200104从代码层面对微服务改造的理解亚龙的博客6.png

调用方式

整体结构

Screenshot20200104从代码层面对微服务改造的理解亚龙的博客7.png

微服务结构

Screenshot20200104从代码层面对微服务改造的理解亚龙的博客8.png

代码结构

调用流程

Screenshot20200104从代码层面对微服务改造的理解亚龙的博客9.png

参数化
反射(远程)调用(为以后的服务化做准备。控制层和服务层分离。)
Service模块化
其中加载的查询对象、响应对象、对象处理。
无状态。直接替换。
各个业务模块化,相对来说是模块独立的,除了一个调用链条外,其余模块与模块之间是无耦合的。

模块划分

Screenshot20200104从代码层面对微服务改造的理解亚龙的博客10.png

根据ES对象和业务来划分开发模块。而不是直接根据业务。这里要区分开发的维度与转换思考方式。

项目案例

案例1

Screenshot20200104从代码层面对微服务改造的理解亚龙的博客11.png

案例2

为什么没以实物商品或者虚拟商品作为维度拆分?
以二者只能拆分出两种维度的业务,但是不同模块都需要把实物、虚拟作为查询或校验条件。
这个粒度很粗,并不能根据业务复杂度的提升而降低各个模块间的耦合度。

设计模式的使用

简单工厂(公共参数校验、业务参数校验)
桥接模式(不同类型的查询对象)
代理(远程)模式(调用service层的反射处理)
策略模式(各个查询、响应对象的接口及实现)

三、微服务读写端改造案例

模块

用户注册

业务流程

Screenshot20200104从代码层面对微服务改造的理解亚龙的博客12.png

技术栈

同步响应

Screenshot20200104从代码层面对微服务改造的理解亚龙的博客13.png

异步响应

Screenshot20200104从代码层面对微服务改造的理解亚龙的博客15.png

定时任务

业务流程

技术栈

单一应用

Screenshot20200104从代码层面对微服务改造的理解亚龙的博客16.png

拆分应用

Screenshot20200104从代码层面对微服务改造的理解亚龙的博客17.png

四、微服务总结

如何建模服务

图形结构

Screenshot20200104从代码层面对微服务改造的理解亚龙的博客18.png

案例分析

Screenshot20200104从代码层面对微服务改造的理解亚龙的博客19.png

这个案例的业务领域涉及了运营的多方面。它涵盖了从仓储到前台、从财务到订单的所有元素。这些元素就是领域,尽管不一定对所有的元素进行建模。

限界上下文

《领域驱动设计》中引入的一个很重要的概念”限界上下文”,一个由显示边界限定的特定职责。
任何一个给定的领域都包含多个限界上下文,每个限界上下文中的模型分成两部分,一部分不需要与外部通信,另一部分则需要。
每个上下文中都有明确的接口,该接口决定了它会暴露哪些模型给其他的上下文。

共享隐藏模型

模型一:
财务部门和仓库是两个独立的上下文。这里的库存项就变成了两个上下文之间的共享模型。
然而,尽管在仓库内部有相应的模型来表示库存项,但并不会把库存项在仓库上下文中的所有内容都暴露出去。也就是对该模型来说,有内部和外部两种方式。

模型二:
有时候,同一个名字在不同的上下文中有着完全不同的含义。
比如,退货是表示客户退回的一些东西,与将要执行的任务有关。
在客户的上下文中,表示寄回包裹,然后等待退款。
在仓库的上下文中,表示即将到来的一个包裹。
这个退货的共享模型会在多个不同的进程中使用,并且在不同的上下文中都会存在相应的实体,不过,这些实体仅仅是在每个上下文的内部表示而已。

所以应该是共享特定模型,而不是共享内部表示。这样就可以避免潜在的紧耦合风险。
在做适当的隔离时,要发现复杂度是否远远大于它带来的好处。
尽管在一个单块进程中创建隔离性很好的模块是可能的,但事实上很少有人能做到。而进程边界的存在则能够有效地避免这种情况发生。

模块与服务

领域内的一些边界,边界内部是相关性比较高的业务功能,从而得到高内聚。这些限界上线文可以很好地形成组合边界。
一旦发现了领域内部的限界上下文,一定要使用模块对其建模,同时使用共享和隐藏模型。这些模型边界就可以成为绝佳的微服务候选。
一般来说,微服务应该清晰地和限界上下文保持一致(服务边界和领域的界限上下文保持一致)。
对于一个新系统而言,可以先使用一段时间的单块系统,等系统稳定之后,再直接使用单独的服务(服务边界问题)。

过早划分

代价十分昂贵。不仅是模块的边界,还有事物的边界等。
公司案例:未使用反射调用service层;未按照模块化开发,而仅仅是按照功能。

业务功能

当在思考组织内的限界上下文时,不应该从共享数据的角度来考虑,而应该从这些上下文能够提供的功能来考虑。
首先考虑,这个上下文是做什么用的,再考虑,它需要什么样的数据和模型。
提供服务时,应该将这些功能的关键操作提供给其他服务或协作者。
公司案例:太多的CRUD操作只考虑模型从而会导致贫血。

逐步划分上下文

当考虑微服务边界时,首先考虑比较大的、粗粒度的上下文,然后当发现合适的缝隙后,再进一步划分出那些嵌套的上下文。

关于业务概念的沟通

修改系统的目的是为了满足业务需求。
微服务之间如同一个业务概念进行通信。
基于业务领域的软件建模不应该止于限界上下文的概念。
在组织内部共享的那些相同的术语和想法,也应该被反应到服务的接口中(比如字段等其他方式)。
以跟组织内通信相同的方式,来思考微服务之间的通信形式是非常有用的。
事实上,通信形式在整个组织范围内都非常重要。

康威定律

第一定律:企业沟通方式会通过系统设计表达出来
第二定律:再多的时间也没办法让任务完美至极,但总有时间能将它完成
第三定律:线型系统和线型组织架构间有潜在的异质同态特性
第四定律:大系统比小系统更适用于任务分解
https://zhuanlan.zhihu.com/p/29248567

领域驱动设计

Screenshot20200104从代码层面对微服务改造的理解亚龙的博客20.png

业务驱动技术发展(什么样的技术推动了什么样的技术发展,从而某几项技术才能融入到相关业务中)。最终会发现,在推动过程中,”人”这一主要要素的影响是最大的。

注意内容

约束、原则、实践

约束的是行为,原则是边界。
通过规则来指导自己去做事,而不是一味的遵从。
约束是很难(或者说不可能)改变的,但原则也是自己决定的。应该显示地指出哪些是约束,哪些是原则,这样无论是用户还是开发人员就会很清楚哪些是不能改变的(对用户的体验、文档、代码处理、与其他人沟通)。

思考1:
从个人角度来说,是可以把约束和原则放一起的,这种也可以时不时地确定这些约束和原则到底能不能改变。

思考2:
在现有开发项目中,比如必须按照模块化流程开发/某些设计原则,这是约束性(针对行为)的,其他的开发可以根据这种约束规范来进行快速迭代(在这四个多月来,与我们交互的项目组和产品相关人员应该能切实感受到这种快速迭代的情况)。而期间不同模块间的调用方式、参数化处理、实体的封装的处理就是原则性(针对的边界)的内容。

思考3:
在实践/开发的过程中,应当遵守约束,并且应该来巩固原则性的内容。

思考4:
高内聚低耦合:边界性问题
而怎么去处理边界性的问题。那么就需要通过不同的行为来处理。
边界是谁定的,是行为定的。
在不断的迭代过程中,关键是要有一些重要的原则来指导系统的演化,同时也要有一些细节来指导如何实现这些原则。实践的方式有很多种,只要能够映射到相同的原则即可(一定的取舍),比如不同的团队有不同的实践/技术实现方法,只要最终的/背后的原则是相同的即可。

约束>原则<>实践

架构安全性

必须保证每个服务都可以应对下游服务的错误请求。没有很好的处理下游错误请求的服务越多,系统就会越脆弱。我们至少可以让每个下游服务使用它们自己的连接池,进一步让每个服务使用一个断路器。
系统及时失败追溯问题:
1)正常并且被正确处理的请求。
2)错误请求,并且服务识别出了它是错误的,但什么也没做。
3)被访问的服务宕机了,所以无法判断请求是否正常。
如果这些服务没有很好地遵守这些规则,那么整个系统就会更加脆弱。

依赖整理

数据库(存储相关)是所有杂乱的源头。杂乱的依赖整理。区分复杂度与关系。看看这些接缝之间的关系,是否可以形成有向无环图,如果是,那么就能看出来哪些难处理。

Screenshot20200104从代码层面对微服务改造的理解亚龙的博客21.png

可用性与监控

超时!处理系统缓慢要比处理系统快速失败困难得多。在分布式系统中,延迟是致命的!一个缓慢的服务就可能耗尽所有可用的worker工作进程。
正确地设置超时,实现合适的上下文并隔离不同的线程池,并实现一个断路器,可以在第一时间避免给一个不健康的系统发送调用。

安全措施

反脆弱:通过印发故障来确保其系统的容错性。不同的演练。

个人错误与认识

一直想着全部都设计好再推进:在微服务选型和迁移时。
在微服务改造时,有同事间交流的方式,以及其他项目组对改造微服务的质疑。
在改造服务的过程中,”人”的问题在大多数。

五、推荐书籍

Screenshot20200104从代码层面对微服务改造的理解亚龙的博客22.png

Screenshot20200104从代码层面对微服务改造的理解亚龙的博客23.png

Screenshot20200104从代码层面对微服务改造的理解亚龙的博客24.png


标题:从代码层面对微服务改造的理解
作者:yazong
地址:https://blog.llyweb.com/articles/2019/10/21/1578150298817.html