微服务划分的原则

news/2024/5/17 18:09:41

微服务的划分

微服务的划分要保证的原则

单一职责原则

1、耦合性也称块间联系。指软件系统结构中各模块间相互联系紧密程度的一种度量。模块之间联系越紧密,其耦合性就越强,模块的独立性则越差。模块间耦合高低取决于模块间接口的复杂性、调用的方式及传递的信息

2、内聚性又称块内联系。指模块的功能强度的度量,即一个模块内部各个元素彼此结合的紧密程度的度量。若一个模块内各元素(语名之间、程序段之间)联系的越紧密,则它的内聚性就越高。

定义:单一职责原则(Single Responsibility Principle, SRP):一个类只负责一个功能领域中的相应职责,或者可以定义为:就一个类而言,应该只有一个引起它变化的原因。

理解:对于一个类而言,它所对外的作用域,应该是清晰明了,并且在限定范围内。简单来说,每一个类,都有自己的责任范围,该做什么不该做什么,这个类应该是界限清晰的。像现在的一个团队里面,各司其责,互相关联但是又职责明确。这样子的设计,有点类似于领域驱动设计。

单一职责原则是实现高内聚、低耦合的指导方针,它是最简单但又最难运用的原则

单一职责原则是最简单的面向对象设计原则,它用于控制类的粒度大小

设计原则很重要的一点就是简单,单一职责,也就是我们经常所说的专人干专事。一个单元(一个类、函数或者微服务)应该有且只有一个职责。无论如何,一个微服务不应该包含多于一个的职责。职责单一的后果之一就是职责单位(微服务,类,接口,函数)的数量剧增。据说Amazon,Netflix这些采用微服务架构的网站一个小功能就会调用几十上百个微服务。但是相较于每个函数都是多个业务逻辑或职责功能的混合体的情况,维护成本还是低很多的。 SRP中的“单一职责”是个比较模糊的概念。对于函数,它可能指单一的功能,不涉及复杂逻辑;但对于类或者接口,它可能是指对单一对象的操作,也可能是指对该对象单一属性的操作。总而言之,单一职责原则就是为了让代码逻辑更加清晰,可维护性更好,定位问题更快的一种设计原则。

高内聚原则

高内聚,从系统架构层次说的是系统的复用性,也就是java的封装、框架思想,从封装一个方法、一个工具类、一个jar包、一个微服务、到一个可以独立运行的框架,架构界里有句话,任何复用性的系统架构都有一个前置系统,前置层是用来处理非共用的逻辑,也就是适配层,有的使用业务前置,有的技术前置,微服务的网关服务可以理解为是技术前置,既然有前置处理层那就说明复用性是有边界的,那么这个边界怎么来区分呢,先卖个关子,下面介绍了低耦合之后在说。

内聚类型:
1.偶然内聚
模块的各成分之间没有关联,只是把分散的功能合并在一起。

例:A模块中有三条语句(一条赋值,一条求和,一条传参),表面上看不出任何联系,但是B、C模块中都用到了这三条语句,于是将这三条语句合并成了模块A。模块A中就是偶然内聚。

2.逻辑内聚
逻辑上相关的功能被放在同一模块中。

例:A模块实现的是将对应的人员信息发送给技术部,人事部和财政部,决定发送给哪个部门是输入的控制标志决定的。模块A中就是逻辑内聚。

3.时间内聚
模块完成的功能必须在同一时间内执行,但这些功能只是因为时间因素才有关联。

例:编程开始时,程序员把对所有全局变量的初始化操作放在模块A中。模块A中就是时间内聚。

4.过程内聚
模块内部的处理成分是相关的,而且这些处理必须以特定的次序进行执行。

例:用户登陆了某某网站,A模块负责依次读取用户的用户名、邮箱和联系方式,这个次序是事先规定的,不能改变。模块A中就是过程内聚。

5.通信内聚
模块的所有成分都操作同一数据集或生成同一数据集。

例:模块A实现将传入的Date类型数据转换成String类型,以及将Date类型数据插入数据库,这两个操作都是对“Date类型数据”而言的。模块A中就是通信内聚。

6.顺序内聚
模块的各个成分和同一个功能密切相关,而且一个成分的输出作为另一个成分的输入。

例:模块A实现将传入的Date类型数据转换成String类型,然后再将转换好的String类型数据插入数据库。模块A中就是顺序内聚。

7.功能内聚
模块的所有成分对于完成单一的功能都是必须的。

例:模块A实现将新注册的用户信息(用户名,密码,个性签名)全部转换成String类型并插入数据库。模块A中就是功能内聚。

低耦合原则

低耦合,从系统架构层次说的是系统的扩展性 ,怎么保证系统的扩展性呢,常用的设计原则就是单一职责、开闭原则,开闭原则常用的设计模式 模板方法、适配器、装饰器、职责链等。

1.内容耦合
一个模块直接修改或操作另一个模块的数据,或者直接转入另一个模块。

例:模块A中定义了变量a,在模块B中直接使用了。这种情况下模块A和模块B就是内容耦合。

2.公共耦合
两个以上的模块共同引用一个全局数据项。

例:定义了一个全局变量a,在A、B、C模块中均调用了a,这种情况下模块A、模块B、模块C就是公共耦合。

3.外部耦合
模块与软件的外部设备相连,共享外部资源

4.控制耦合
一个模块在界面上传递一个信号控制另一个模块,接收信号的模块的动作根据信号值进行调整。

例:模块A获取用户类型(普通用户、高级用户)传递给模块B,模块B根据不同类型的用户提供不同的服务。这种情况下模块A和模块B就是控制耦合。

5.标记耦合
模块间通过参数传递复杂的内部数据结构。

例:模块A向模块B传递Object类型的数据。这种情况下模块A和模块B就是标记耦合。

6.数据耦合
模块间通过参数传递基本类型的数据。

例:模块A实现两个数的加法操作,模块B实现两个加数的初始化,模块B将两个加数传给模块A,模块A进行相加。这种情况下模块A和模块B就是数据耦合。

7.非直接耦合
模块间没有信息传递。

例:模块A实现输出字符串,模块B实现接收int数据,两者之间没有信息传递。这种情况下模块A和模块B就是非直接耦合。

三、低内聚高耦合的坏处
低内聚的坏处
一个模块内聚很低的情况下,模块的功能很可能不单一,模块的职责也不明确,比较松散,更有甚者是完成不相关的功能,可读性也很差,在一个模块中看到不相关的内容,扩展性也会受到许多影响。

高耦合的坏处
耦合度很高的情况下,维护代码时修改一个地方会牵连到很多地方,如果修改时没有理清这些耦合关系,那么带来的后果可能会是灾难性的,特别是对于需求变化较多以及多人协作开发维护的项目,修改一个地方会引起本来已经运行稳定的模块错误,严重时会导致恶性循环,问题永远改不完,开发和测试都在各种问题之间奔波劳累,最后导致项目延期,用户满意度降低,成本也增加了,这对用户和开发商影响都是很恶劣的,各种风险也就不言而喻了。

四、如何提高内聚、降低耦合?
提高内聚
1、确定模块需要的功能点

2、不提供除本职工作外的功能

3、满足可读性、可扩展性、可复用、可维护性要求

4、单独方法不要太长

降低耦合
1、少使用类的继承,多用接口隐藏实现的细节。 java面向对象编程引入接口除了支持多态外, 隐藏实现细节也是其中一个目的。

2、模块的功能化分尽可能的单一,道理也很简单,功能单一的模块供其它模块调用的机会就少。

3、遵循一个定义只在一个地方出现。

4、少使用全局变量。

5、类属性和方法的声明少用public,多用private关键字,

6、多用设计模式,比如采用MVC的设计模式就可以降低界面与业务逻辑的耦合度。

7、尽量不用“硬编码”的方式写程序,同时也尽量避免直接用SQL语句操作数据库。

8、最后当然就是避免直接操作或调用其它模块或类(内容耦合);如果模块间必须存在耦合,原则上尽量使用数据耦合,少用控制耦合,限制公共耦合的范围避免使用内容耦合。

五、高内聚低耦合是否意味着内聚越高越好,耦合越低越好?
并不是内聚越高越好,耦合越低越好,真正好的设计
是在高内聚和低耦合间进行平衡,也就是说高内聚和低耦合是冲突的。

最强的内聚莫过于一个类只写一个函数,这样内聚性绝对是最高的。但这会带来一个明显
的问题:类的数量急剧增多,这样就导致了其它类的耦合特别多,于是整个设计就变成了“高内聚高耦合”了。由于高耦合,整个系统变动同样非常频繁。

对于耦合来说,最弱的耦合是一个类将所有的函数都包含了,这样类完全不依赖其它类,耦合性是最低的。但这样会带来一个明显的问题:内聚性很低,于是整个设计就变成了“低耦合低内聚”了。由于低内聚,整个类的变动同样非常频繁。

对于“低耦合低内聚”来说,还有另外一个明显的问题:几乎无法被其它类重用。原因很简单,类本身太庞大了,要么实现很复杂,要么数据很大,其它类无法明确该如何重用这个类。

粒度把控原则

目前很多传统的单体应用再向微服务架构进行升级改造,如果拆分粒度太细会增加运维复杂度,粒度过大又起不到效果,那么改造过程中如何平衡拆分粒度呢?

弓箭原理

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xwYzXCQh-1690357557279)(//upload-images.jianshu.io/upload_images/23166491-eb38d1e3b248f111.png?imageMogr2/auto-orient/strip|imageView2/2/w/344/format/webp)]image.png

弓箭原理

平衡拆分粒度可以从两方面进行权衡,一是业务发展的复杂度,二是团队规模的人数。如上图,它就像弓箭一样,只有当业务复杂度和团队人数足够大的时候,射出的服务拆分粒度这把剑才会飞的更远,发挥出最大的威力。比如说电商的商品服务,当我们把商品从大的单体里拆分出来的时候,就商品服务本身来讲,逻辑并没有足够复杂到 2~3 个人没法维护的地步,这时我们没有必要继续将商品服务拆的更细,但是随着业务的发展,商品的业务逻辑变的越来越复杂,可能同时服务公司的多个平台,此时你会发现商品服务本身面临的问题跟单体架构阶段面临的问题基本一样,这个阶段就需要我们将商品拆成更细粒度的服务,比如:库存服务、价格服务、类目服务、商品基础信息服务等等。虽然业务复杂度已经满足了,如果公司此时没有足够的人力(招聘不及时或员工异动比较多),服务最好也不要拆分,拆分会因为人力的不足导致更多的问题,如研发效率大幅下降(一个开发负责与其不匹配数量的服务)。这里引申另外一个问题,一个微服务究竟需要几个开发维护是比较理性的?

三个火枪手原则

为什么说是三个人分配一个服务是比较理性的?而不是 4 个,也不是 2 个呢?首先,从系统规模来讲,3 个人负责开发一个系统,系统的复杂度刚好达到每个人都能全面理解整个系统,又能够进行分工的粒度;如果是 2 个人开发一个系统,系统的复杂度不够,开发人员可能觉得无法体现自己的技术实力;如果是 4 个甚至更多人开发一个系统,系统复杂度又会无法让开发人员对系统的细节都了解很深。其次,从团队管理来说,3 个人可以形成一个稳定的备份,即使 1 个人休假或者调配到其他系统,剩余 2 个人还可以支撑;如果是 2 个人,抽调 1 个后剩余的 1 个人压力很大;如果是 1 个人,这就是单点了,团队没有备份,某些情况下是很危险的,假如这个人休假了,系统出问题了怎么办?最后,从技术提升的角度来讲,3 个人的技术小组既能够形成有效的讨论,又能够快速达成一致意见;如果是 2 个人,可能会出现互相坚持自己的意见,或者 2 个人经验都不足导致设计缺陷;如果是 1 个人,由于没有人跟他进行技术讨论,很可能陷入思维盲区导致重大问题;如果是 4 个人或者更多,可能有的参与的人员并没有认真参与,只是完成任务而已。“三个火枪手”的原则主要应用于微服务设计和开发阶段,如果微服务经过一段时间发展后已经比较稳定,处于维护期了,无须太多的开发,那么平均 1 个人维护 1 个微服务甚至几个微服务都可以。当然考虑到人员备份问题,每个微服务最好都安排 2 个人维护,每个人都可以维护多个微服务。

**综上所诉,拆分粒度不是越细越好,粒度需要符合弓箭原理及三个火枪手原则。**

前后端分离原则

前后端分离原则,简单来讲就是前端和后端的代码分离也就是技术上做分离,我们推荐的模式是最好直接采用物理分离的方式部署,进一步促使进行更彻底的分离。不要继续以前的服务端模板技术,比如JSP ,把Java JS HTML CSS 都堆到一个页面里,稍复杂的页面就无法维护。这种分离模式的方式有几个好处:

前后端技术分离,可以由各自的专家来对各自的领域进行优化,这样前端的用户体验优化效果会更好。
分离模式下,前后端交互界面更加清晰,就剩下了接口和模型,后端的接口简洁明了,更容易维护。
前端多渠道集成场景更容易实现,后端服务无需变更,采用统一的数据和模型,可以支撑前端的web UI\ 移动App等访问。

无状态服务

阻碍单体架构变为分布式架构的关键点就在于状态的处理。如果状态全部保存在本地,无论是本地的内存,还是本地的硬盘,都会给架构的横向扩展带来瓶颈。

状态分为分发、处理、存储几个过程,如果对于一个用户的所有的信息都保存在一个进程中,则从分发阶段,就必须将这个用户分发到这个进程,否则无法对这个用户进行处理,然而当一个进程压力很大的时候,根本无法扩容,新启动的进程根本无法处理那些保存在原来进程的用户的数据,不能分担压力。所以要讲整个架构分成两个部分,无状态部分和有状态部分,而业务逻辑的部分往往作为无状态的部分,而将状态保存在有状态的中间件中,如缓存、数据库、对象存储、大数据平台、消息队列等。

这样无状态的部分可以很容易的横向扩展,在用户分发的时候,可以很容易分发到新的进程进行处理,而状态保存到后端。而后端的中间件是有状态的,这些中间件设计之初,就考虑了扩容的时候,状态的迁移,复制,同步等机制,不用业务层关心

AKF原则

IDEALS原则

在IDEALS原则中,作者提出了6个原则,目前这些原则虽然笔者无法保证可以适用于所有的微服务体系的东西,但是却是关键点与成功点。

1、Interface Segregation(接口分离)

2、Deployability(可部署性)

3、EventDriven(事件驱动)

4、Availability Over Consistency(可用性高于一致性)

5、Loose Coupling(松耦合)

6、Single Responsibility(单一责任)

Interface Segregation(接口分离)

最初进行接口设计的时候想着复用,随着项目的推进,发现这个接口越来越臃肿,这里的臃肿不单单是代码量上的增加,更多的是一个接口出现了很多的调用方,后台、小程序、苹果端、安卓端、第三方等,这就导致了同一个服务逻辑里面需要对接很多客户端,后期在进行代码修改的时候经常是牵一发而动全身,所有的客户端不可用的情况会越来越常见,这z就是为什么我们要将接口进行隔离。

接口隔离有个最重要的目的,就是让不同类型的客户端只能看到自己所对应的接口(服务契约),在框架的设计上,按照不同类型的客户端设计不同的接口,可以参考《springboot2.2.X手册:构建多元化的API接口,我们这样子设计 》,在这里面分别用application,view,external分别对应小程序接口,后端管理接口,第三方管理接口,从而实现接口隔离。

Deployability(可部署性)

从软件发展至今,从来没有一个时期像微服务这样子它的部署会成为重中之重,笔者认为,这一切都是互联网快速发展的产物,快,轻,持续才能满足现在高速变化的C端需求,特别是像我们人口基数这么大的国家来说。

在微服务的应用中,强调的是每一个服务可独立部署,独立拓展,在应用上是隔离的,这里要区分上面的接口隔离,接口隔离更加注重某一个应用对外的服务提供策略,这里更趋向于业务边界、性能边界、技术边界三者。在设计里面,设计模式及其他设计策略,主要还是集中于每一个独立应用,应尽可能避免过度依赖的同时一些通用的“组织”应该形成连锁依赖,从而避免过渡设计与过渡开发,又可以实现独立服务运行,这个考验每一个架构师的技术功底及业务功底。

连锁依赖

微服务的可部署性不单单体现在能够独立部署,它更加趋向于部署运维体系的一体化,从而形成标准化,流程化的一套章程。一个软件如果采用微服务思想来进行设计,那它从一开始就注定要实现非常高效的可部署性,如何做到可以考虑以下策略

1、容器化

目前很多微服务的应用都离不开Docker+Kubernetes,Docker是DotCloud开发的一个基于LXC的高级容器引擎,基于Apache2.0协议开源,没有使用过的同学可以参考一下《收藏手册:Docker安装RabbitMQ,只需3步 》第二章 。Kubernetes我们一般叫做K8S,是用来部署,管理Docker的,可以实现Docker的WEB操作。微服务容器化指的是把我们的服务打包成docker文件后部署上去,从而实现跨平台及云服务提供商的复制跟部署,K8S同步提供了共享机制跟资源,目前来说,Docker跟Kubernetes是目前业界用的最普遍的一套组合。

2、网格化

这个名词相对于很多同学比较陌生跟抽象,可能听的最多的是服务网格,它处于基础设施层,使服务与服务之间的通信更加便捷,通过服务里复杂的技术组成的云基础设施层,来保证请求的可靠性。目前开源的软件包含Istio、Linkerd和Consul Connect,很遗憾,笔者目前只接触过Istio。

Istio 提供一种简单的方式来为已部署的服务建立网络,该网络具有负载均衡、服务间认证、监控等功能,而不需要对服务的代码做任何改动。想要让服务支持 Istio,只需要在您的环境中部署一个特殊的 sidecar 代理,使用 Istio 控制平面功能配置和管理代理,拦截微服务之间的所有网络通信:

1、HTTP、gRPC、WebSocket 和 TCP 流量的自动负载均衡。

2、通过丰富的路由规则、重试、故障转移和故障注入,可以对流量行为进行细粒度控制。

3、可插入的策略层和配置 API,支持访问控制、速率限制和配额。

4、对出入集群入口和出口中所有流量的自动度量指标、日志记录和跟踪。

5、通过强大的基于身份的验证和授权,在集群中实现安全的服务间通信。

6、Istio 旨在实现可扩展性,满足各种部署需求。

3、网关化

网关在微服务中起着一个非常重要的作用,包含但不限于以下内容:路由,安全稽查,请求限流,熔断,缓存,协议消息转换,请求流量分配等,目前国内用得最多的是zuul,kong,spring gateway等,目前在应用中,主要集中两点

企业级应用:面对一些企业级开发的时候,这时候的业务流程是非常复杂的,采用微服务如果划分的不好,很容易导致开发量剧增,目前笔者采用一种方式聚合网关的方式来丰富网关的应用,让网关可以满足企业级的应用《微服务网关实战01-网关介绍 》

互联网应用:互联网讲究快速反应,快速迭代,业务相对比较单一化,此时我们的目的是不能把网关做的太重,尽可能轻量级来满足拓展性强的特点,当出现数据聚合的时候,笔者采用ES来做数据聚合底层,这方面的方案比较开放,可以有不同的设计策略。

4、日志集中化

应用微服务化能非常轻松的扩容后,日志输出的分散程度会成线性增加从而增加运维的压力,我们需要一个工具来把日志整合起来,目前采用比较多的事ELK,Graylog,Fluentd等,笔者前段时间发现了一个私人开发的工具类EasyLog《springboot2.2.X手册:抛弃ELK,百亿日志+调用链的Easylog很放心 》,整合了调用链的轻量级应用,可以试试。

但是对于普通的只有2-3个服务的系统,是否考虑有必要性去加个日志服务器?

5、服务追踪化

这里的服务追踪指的是服务调用链的追踪,每一个服务从发起,流经哪些服务,最终结束于哪个服务,可以采用工具来进行检测、收集、跟踪这些数据并可视化出来,在spring cloud里面提供了Zipkin来做,但是这个界面并不是很友善,经常使用的工具可以有Cat,PingPoint等。

6、配置化

微服务的数量级别的增加导致配置也成了一个难题,目前笔者采用阿里的Nacos来做注册中心兼配置中心《springboot2.2.X手册:Eureka不更,Consul被禁,启用Nacos 》,已经集成了两种功能的东西就不再自己添加另外的组件。

7、持续交付部署化

从刚开始的手动发布部署到现在全自动化的操作,微服务在部署上是很需要自动化的,但是这种前提也是建立在当你的服务已经成为标准化之后,传统的发布工具Jenkins、Gitlab CI/CD等都很好用,如果采用阿里云的话可以直接使用云效来做,个人想玩的话玩一下瓦力《发现开源:替换Jenkins,支持多用户多语言部署平台Walle很震撼 》。

在发布中,经常会使用蓝绿部署和金丝雀发布来保证微服务在上线的时候几乎接近0的停机空档,实现问题服务的快速切换。

EventDriven(事件驱动)

提到微服务的事件驱动就不得不讲一下微服务的调用方式,通常我们采用以下三种调用方式

1、Rest风格的Http调用

2、RPC调用,做过dobbo的同学应该知道dubbo里面的RPC调用,开源的有gRPC可以使用

3、消息中间件方式进行调用

这三种方式没有绝对的好坏,需要根据实际场景来做决策,用得最多的还是采用http的方式进行调用,RPC最少。相对于消息中间件,其他两种方式都是同步阻塞式,当然现在很多应用都是这种方式,很多应用也需要这种方式,异步处理不好容易出现服务灾难。

在消息中间件的选择上,目前最多的有三个kafka,rabbitmq,rocketmq,笔者目前在处理大文件的导出方面采用mq跟批处理的方式来做,避免等待,避免服务器同时处理太多数据从而内存跟CPU撑不住。从事件角度说,事件驱动基本组织是由一个事件集合器、一个事件发送器、一个事件监听处理器,这里也要区分消息驱动。

事件驱动构建的微服务效果是非常明显的,在伸缩性与吞吐量上具有非常明显的性能优势,像我们在做接口服务的时候,面对一些外部接口的数据接入,这类做法是非常值得借鉴的。

Availability Over Consistency(可用性高于一致性)

CAP定理告诉我们,在一个分布式的系统中一致性、可用性、分区容错性这三者不能同时兼顾到,最多只能同时实现其中两者。一致性在微服务中一直是一个非常棘手的问题,目前业界采用最多的是可用性优先,最终实现一致性,这么做考虑的问题点是强一致性需要加入网络之间的性能及通信损耗,这点上在用户体验至上的社会里很可能让用户爆炸。

但是也并不是说任何场景都是可用性优先,这里应该是大部分场景是可用性优先,特别是面向C端用户的时候,但是像面对一个业务逻辑非常复杂的操作并且允许比较长的等待时长的时候,一致性是第一优先考虑的,目前我们在解决强一致性的时候可以用阿里的Seata《微服务难点:阿里的分布式事务中间件,seata能上生产吗 》。

Loose Coupling(松耦合)

一直在强调高内聚低耦合,但是怎样的程度才算高内聚低耦合?都没有一个很标准化或者可量化的东西来说明,也许很多人说的就真的就是随口一说的概念。在微服务中,服务与服务之间往往存在调用关系,采用约定的方式来对服务之间进行解耦,实现服务交互,这种我们称之为服务契约。

服务契约的形成往往通过约定的技术手段来实现,约定好输入输出的规范,约定好输入输出的方式(HTTP或者MQ),约定好数据聚合方式,这种约定俗成的规矩可以帮我们减少服务与服务之间调用错乱的问题,成功的对每个服务进行解耦,同时每个服务在自身应用中可以做到高内聚,不过这里面笔者认为最重要的一点就是服务的划分,下面会通过服务的职责问题来讲解。

具体落地到如果去实现高内聚低耦合,笔者目前通过以下4点来实现

1、契约精神优先,所有的服务的输入输出全部约定好,不允许更改。

2、限定数据聚合方法,搭建数据聚合服务,做单向聚合不做服务之间的互相调用

3、发布-订阅模式开启,针对一些特殊应用启用消息投递模式进行异步解耦

4、指定一个服务一个库,从数据进行隔离,实现服务的底层解耦,增加可移植化。

Single Responsibility(单一责任)

微服务的职责问题,笔者目前觉得是最难的,划分的颗粒度在哪?这是笔者从几年前接触微服务以来经常要思考的一个问题。服务的划分包含具备太多的内聚力的话会导致服务膨胀,在持续部署与持续交付上变得越来越慢;如果服务的划分颗粒度太细又很容易陷入开发人员疲于奔命的场景,服务越多一致性问题越严重,如何做一个颗粒度适中的微服务确实头疼,目前笔者发现最好用的方式还是基于领域驱动设计与建模

1、根据业务边界划分服务职责

2、根据性能问题划分服务

3、切记不要为了微服务而拼命划分

结论
在面对微服务设计的时候IDEALS原则可以应付大多数的场景,但是这个并不是银弹,好比经常说微服务并不是银弹一样的,架构设计是一个不断演化不断适配的过程,它并不是一种技术或解决方案,笔者相信IDEALS原则可以帮我们更好实现微服务的落地,微服务的工具,平台,框架不断的出现,但是设计原则或者思想还是不变,工具或者框架并不能成为设计思想的拦路虎,万变不离其宗,应用原文作者最后的一句话:

总结:实际的业务划分中如何进行微服务的划分??

实际的业务服务其实按照你的实际情况来进行划分的,不是说一定要按照上述的原则,一般来说,小型工程业务服务6-8个会比较合理,加上你的注册中心,网关,差不多整体的服务有11个左右,大的服务差不多12-15个,因为再继续加的话,业务的部署压力以及依赖关系的压力会非常大。

我们这里可以看一下我们的业务该如何进行划分。首先,我们看我们的整体的图,我们可以将整个业务划分成为医院域以及预约平台域

image.png

此时,医院域我们不用进行过度划分,因为这里是只需要对接院方的API,所以只需要对接就行。而预约平台域,我们可以稍微划分一下,我们根据业务分析一下我们的需求,第一个,我们有不同的医院需要进行预约,其次,我们会有很多的科室,所以,我们肯定需要做一个字典。

其次医疗系统,用户信息都是重中之重,所以,用户模块肯定需要单独进行划分。而我们可能会有文件的上传下载,所以文件上传下载需要单独的业务。

我们去进行登录这种预约平台的时候,我们思考一下,我们的挂号成功与失败是不是都会用到咱们的短信预约,所以,短信平台肯定是需要进行设计的。

并且,这里有个隐藏需求,什么隐藏需求呢?就是咱们的预约要是过期了,我们该如何进行处理的问题,比如我预约了,缴纳了挂号费,而医院今天由于疫情,不接待患者,那么这个时候我们是不是要做定时的批处理,取消预约,又或者我今天没有去,那么你的预约的钱是不是应该原路返回。

image.png


http://www.mrgr.cn/p/41888185

相关文章

重生之我要学C++第四天

这篇文章的主要内容是类的默认成员函数。如果对大家有用的话,希望大家三连支持,博主会继续努力! 目录 一.类的默认成员函数 二.构造函数 三.析构函数 四.拷贝构造函数 五.运算符重载 一.类的默认成员函数 如果一个类中什么成员都没有&…

揭秘!头条百科词条创建全过程及技巧解析

随着互联网时代的到来,人们获取信息的方式越来越便捷。作为国内领先的信息平台,头条百科成为了很多人查阅知识的首选。然而,如何在头条上创建百科词条,让更多人了解和熟知自己呢?本文伯乐网络传媒将为您揭开这个谜团&a…

C++模拟操作系统睡眠机制

在系统中定义一个变量bHiberable,如果是3分钟内休眠,那么每隔3分钟检测一次这个变量,如果为真,则进入睡眠,如果是假,就把这个标志设置为真。继续等待和检测。 程序阻止操作系统休眠的办法:操作…

基于多任务学习卷积神经网络的皮肤损伤联合分割与分类

文章目录 Joint segmentation and classification of skin lesions via a multi-task learning convolutional neural network摘要本文方法实验结果 Joint segmentation and classification of skin lesions via a multi-task learning convolutional neural network 摘要 在…

【运维】hive 终端突然不能使用:Hive Schema version does not match metastore‘s schema version

文章目录 一. 问题描述二. 常规排查1. 元数据库2. hive-site.xml相关meta连接信息检查 三. 正解 一. 问题描述 进入hive终端,执行如下命令报错: hive> show tables; FAILED: SemanticException org.apache.hadoop.hive.ql.metadata.HiveException: …

flutter 打包iOS安装包

flutter iOS Xcode打包并导出ipa文件安装包 1、 Xcode配置 1、 启动打包 1、 等待打包 1、 打包完成、准备导出ipa 1、 选择模式 1、 选择配置文件 1、 导出 1、 选择导出位置 1、 得到ipa

sql server导入.back文件

使用SQL server官方的连接工具 SQL server Management studio 有两种方式 第一种: 前提是,提前知道数据库名称,建好数据库 以数据库 TEST为例子 右键数据库选型,选择新建数据库 输入数据库名字,点击确定 创建完成之…

Mock-MOCO使用过程

一、jar包下载:https://github.com/dreamhead/moco 二、准备mock的json文件 data.json内容: ####GET请求 [{"description": "response使用Content-Type为charsetGBK编码格式来查看返回信息为中文的内容","request": {&q…

1230. K倍区间(超级详细,小白入!!!)

输入样例&#xff1a; 5 2 1 2 3 4 5输出样例&#xff1a; 6 这个题看到区间两个字&#xff0c;两眼一瞪可能就和前缀和差分有关 做题思路&#xff1a; 通过记录每个[1,r]区间值的和,看它前面是否出现过一个[1,l](l<r),使得[l,r]区间的值能除尽k 有同学就好奇&#xff0c;…

通过RPM方式安装,升级,卸载,以及配置使用MySQL

通过RPM方式安装&#xff0c;升级&#xff0c;卸载&#xff0c;以及配置使用MySQL 一、下载 MySQL是一种开源的关系数据库管理系统&#xff0c;被广泛应用于各种业务应用中。本文将讲解如何下载和安装MySQL的rpm安装包。 下载rmp安装包有多种方式&#xff1a; 1、官网下载 …

视频内存过大如何压缩变小?这个压缩方法了解一下

在日常生活中&#xff0c;不管是日常随手拍的视频还是在工作中遇到的视频文件&#xff0c;在编辑处理的时候&#xff0c;如果视频的内存过大&#xff0c;不仅会占用很大的内存&#xff0c;在传送的时候也会花费很长时间&#xff0c;这时候将视频给压缩一下就可以很好的解决这一…

STM32入门学习之外部中断

1.STM32的IO口可以作为外部中断输入口。本文通过按键按下作为外部中断的输入&#xff0c;点亮LED灯。在STM32的19个外部中断中&#xff0c;0-15为外部IO口的中断输入口。STM32的引脚分别对应着0-15的外部中断线。比如&#xff0c;外部中断线0对应着GPIOA.0-GPIOG.0&#xff0c;…

论文笔记:Fine-Grained Urban Flow Prediction

2021 WWW 1 intro 细粒度城市流量预测 两个挑战 细粒度数据中观察到的网格间的转移动态使得预测变得更加复杂 需要在全局范围内捕获网格单元之间的空间依赖性单独学习外部因素&#xff08;例如天气、POI、路段信息等&#xff09;对大量网格单元的影响非常具有挑战性——>论…

【客户案例】云联壹云助力某保险公司搭建公有云费用管理平台

客户介绍 客户成立于 1996 年 11 月&#xff0c;现已拥有逾 2000 名员工和 12000 名营销员&#xff0c;为 280 万客户提供专业的金融保险服务。在上海、北京、广东、浙江、江苏、四川、山东、福建、重庆、辽宁、天津、湖北、河北、湖南和陕西等地的 50 多个城市稳步发展&#…

数据结构之顺序表

一、概念及结构 顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构&#xff0c;一般情况下采用数组存 储。在数组上完成数据的增删查改。 顺序表一般可以分为&#xff1a; 1. 静态顺序表&#xff1a;使用定长数组存储元素。 2. 动态顺序表&#xff1a;使用动…

骨传导耳机它的工作原理是什么?骨传导耳机长期使用会有脑损伤吗?

骨传导耳机&#xff0c;就是利用头骨和额骨传导声音头骨和额骨传导声音的耳机&#xff0c;这并不是夸大其词&#xff0c;不用惊讶。 骨传导耳机的工作原理其实也很简单&#xff0c;声波通过颅骨、颌骨等头部骨头的振动&#xff0c;直接将声音传到内耳&#xff0c;直接避免接触到…

DataEase开源BI工具安装_数据全量_增量同步_大屏拖拽自动生成_多数据源支持_数据血缘分析---大数据工作笔记0183

我这里用的是Centos7.9安装的 可以通过uname -p来查看一下我们的电脑架构,可以看到是x86_64架构的 我们下第一个,这个是x86架构的,第二个arm架构的 然后解压到/opt/module中 然后再去重命名一下文件夹. 推荐200G 本地模式的功能比较多 推荐100G

立即报名 | AI +Serverless Meetup 上海站 8 月 5 日等你相约!

自 2021 年 5 月后&#xff0c;KubeSphere 社区与上海的各位小伙伴已阔别两年&#xff0c;许久不见&#xff0c;甚是想念&#xff01;2023 年 8 月 5 日&#xff0c;KubeSphere 社区将走进上海组织一场主题为 “AI Serverless” 的 Meetup。此外&#xff0c;云原生也依旧是本次…

windows中注册redis服务启动时报1067错误

注册完redis服务&#xff0c;打开计算机 服务时确实有redis服务存在&#xff0c;但是点击启动时却报1067错误&#xff0c;而命令行用redis-server.exe redis.windows.conf 命令却也可以启动 查看6379的端口也没有被占用&#xff08;netstat -ano | findstr :6379&#xff09; …

【二开】JeecgBoot-vue3二次开发 前端 扩展online表单js增强等-初始化列表之后执行

【二开】JeecgBoot-vue3二次开发 前端 扩展online表单js增强等-初始化列表之后执行 二开位置 OnlineAutoList.js.initAutoList 定义方法 /*** 初始化列表之后执行* js增强* param tableColumns* returns {Promise<void>|*}*/onlineTableContext["afterInitAutoList…