当前位置: 首页 > news >正文

微服务划分的原则

微服务的划分

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

单一职责原则

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

相关文章:

微服务划分的原则

微服务的划分 微服务的划分要保证的原则 单一职责原则 1、耦合性也称块间联系。指软件系统结构中各模块间相互联系紧密程度的一种度量。模块之间联系越紧密,其耦合性就越强,模块的独立性则越差。模块间耦合高低取决于模块间接口的复杂性、调用的方式及…...

作业 - 3

[ 作业 - 3 ] Industrial Melanism: The Case of the Peppered Moth melanism n. 黑化;黑变病;黑色素沉着症 peppered adj. 用胡椒调味的;加胡椒的,撒胡椒粉的 pepper的过去分词和过去式 moth n. 蛾;飞蛾 Paragraph 2 Over a …...

MTK联发科安卓核心板MT8385(Genio 500)规格参数资料_性能介绍

简介 MT8385安卓核心板 是一个高度集成且功能强大的物联网平台,具有以下主要特性: l 四核 Arm Cortex-A73 处理器 l 四核Arm Cortex-A53处理器 l Arm Mali™-G72 MP3 3D 图形加速器 (GPU),带有 Vulkan 1.0、OpenGL ES 3.2 和 OpenCL™ 2.x …...

ChatGPT付费创作系统小程序端开发工具提示打开显示无法打开页面解决办法

很多会员在上传小程序前端时经常出现首页无法打开的情况,错误提示无法打开该页面,不支持打开,这种问题其实就是权限问题,页面是通过调用web-view访问,说明业务域名有问题,很多都是合法域名加了,…...

CVPR2023新作:pix2pix3D

Title: 3D-Aware Conditional Image SynthesisAffiliation: Carnegie Mellon University (卡内基梅隆大学)Authors: Kangle Deng, Gengshan Yang, Deva Ramanan, Jun-Yan ZhuKeywords: Image Synthesis, 3D-aware, Neural Radiance Fields, Interactive Editing, Conditional G…...

Django自定义用户错误记录

django.db.migrations.exceptions.InconsistentMigrationHistory: Migration admin.0001_initial is applied before its dependency mysit.0001_initial on database default.执行: 1 setttings.py: 先注释掉 django.contrib.admin 2 注释掉urls.py path(“admin/…...

Abaqus 导出单元刚度矩阵和全局刚度矩阵

Abaqus 导出单元刚度矩阵和全局刚度矩阵 首次创建:2023.7.29 最后更新:2023.7.29 如有什么改进的地方,欢迎大家讨论! 详细情况请查阅:Abaqus Analysis User’s Guide 一、Abaqus 导出单元刚度矩阵 1.生成单元刚度矩阵…...

Pytorch(一)

目录 一、基本操作 二、自动求导机制 三、线性回归DEMO 3.1模型的读取与保存 3.2利用GPU训练时 四、常见的Tensor形式 五、Hub模块 一、基本操作 操作代码如下: import torch import numpy as np#创建一个矩阵 x1 torch.empty(5,3)# 随机值 x2 torch.rand(5,3)# 初始化…...

图数据库Neo4j学习三——cypher语法总结

1MATCH 1.1作用 MATCH是Cypher查询语言中用于从图数据库中检索数据的关键字。它的作用是在图中查找满足指定条件的节点和边,并返回这些节点和边的属性信息。 在MATCH语句中,通过节点标签和边类型来限定查找范围,然后通过WHERE语句来筛选符合…...

2023杭电多校第一场部分题解

还有些没补的题以后回来补。 索引 1001100210031005100910101012 1001 感觉是大暴力题,数据范围给的很小所以每次可以暴力求出两人的路径。枚举路径的交集里的点然后看看两个人在这个点相遇需要的最短时间就可以了。确定了具体的点之后求 4 4 4 次exgcd即可知道答…...

算法38:反转链表【O(n)方案】

一、需求 给你单链表的头节点 head ,请你反转链表,并返回反转后的链表。 示例 1: 输入:head [1,2,3,4,5] 输出:[5,4,3,2,1] 示例 2: 输入:head [1,2] 输出:[2,1] 示例3&#xff…...

redis基本架构:一个键值数据库包含什么?(这篇文章主要是一个引导的作用)

我们设计一个简单的smpliekv数据库,来体验简直数据库包含什么 体来说,一个键值数据库包括了访问框架、索引模块、操作模块和存储模块四部分(见 下图)。接下来,我们就从这四个部分入手,继续构建我们的 Simpl…...

HIS信息管理系统 HIS源码

HIS(Hospital Information System)是覆盖医院所有业务和业务全过程的信息管理系统。 HIS系统以财务信息、病人信息和物资信息为主线,通过对信息的收集、存储、传递、统计、分析、综合查询、报表输出和信息共享,及时为医院领导及各…...

微信小程序之富文本那些事

文章目录 前言一、video的处理二、img的处理总结 前言 小程序中使用富文本编辑器,由于rich-text受限 部分富文本内容无法渲染或排版错乱。以img和video为例,处理起来让人头疼。网上各种长篇大论,实际上没有任何帮助。接下来我们就一起聊聊im…...

kaggle新赛:RSNA 2023 腹部创伤检测大赛赛题解析(CV)

赛题名称:RSNA 2023 Abdominal Trauma Detection 赛题链接: https://www.kaggle.com/competitions/rsna-2023-abdominal-trauma-detection 赛题背景 腹部钝力创伤是最常见的创伤性损伤类型之一,最常见的原因是机动车事故。腹部创伤可能导致…...

【JavaEE初阶】Servlet (二) Servlet中常用的API

文章目录 HttpServlet核心方法 HttpServletRequest核心方法 HttpServletResponse核心方法 Servlet中常用的API有以下三个: HttpServletHttpServletRequestHttpServletResponse HttpServlet 我们写 Servlet 代码的时候, 首先第一步就是先创建类, 继承自 HttpServlet, 并重写其…...

redis 存储原理与数据模型

文章目录 一、redis的存储结构1.1 存储结构1.2 存储转换 二、字典(dict)实现2.1 数据结构2.2 哈希冲突2.3 扩容2.4 缩容2.5 渐进式rehash2.6 scan 命令2.7 expire机制 三、跳表(skiplist)实现3.1 理想跳表3.2 redis跳表 一、redis的存储结构 1.1 存储结构 1.2 存储转换 二、字…...

初识mysql数据库之事务的隔离性

目录 一、理解隔离性 二、隔离级别 1. 不同的隔离级别的简单概述 2. 查看隔离级别 2.1 查看全局隔离级别 2.2 查看会话隔离级别 3. 设置隔离界别 4. 读未提交(Read Uncommitted) 4.1 读未提交测试 5. 读提交(Read Committed&#x…...

今天学学消息队列RocketMQ:消息类型

RocketMQ支持的消息类型有三种:普通消息、顺序消息、延时消息、事务消息。以下内容的代码部分都是基于rocketmq-spring-boot-starter做的。 普通消息 普通消息是一种无序消息,消息分布在各个MessageQueue当中,以保证效率为第一使命。这种消息…...

小程序附件下载并预览功能

一、实现的功能: 1、word、excel、图片等实现下载并预览 2、打开文件后显示文件名称 二、代码: // 判断文件类型whatFileType(url) {let sr url.lastIndexOf("."); // 最后一次出现的位置let fileType url.substr(sr 1); // 截取url的…...

数据库缓存服务——NoSQL之Redis配置与优化

目录 一、缓存概念 1.1 系统缓存 1.2 缓存保存位置及分层结构 1.2.1 DNS缓存 1.2.2 应用层缓存 1.2.3 数据层缓存 1.2.4 硬件缓存 二、关系型数据库与非关系型数据库 2.1 关系型数据库 2.2 非关系型数据库 2.3 关系型数据库和非关系型数据库区别: 2.4 非…...

【雕爷学编程】MicroPython动手做(13)——掌控板之RGB三色灯

知识点:什么是掌控板? 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片,支持WiFi和蓝牙双模通信,可作为物联网节点,实现物联网应用。同时掌控板上集成了OLED…...

.Net Core上传组件_.Net Core图片上传组件_Uploader7.0

一、.Net Core上传组件Uploader7.0简介 1.当前版本v7.0,前端框架丰富升级 2.前端jquery框架封装,cover.js, 腾讯云cos-js-sdk-v5.min.js 3.后端,支持Asp.Net 和 Asp.Net Core 矿建 4.数据传输模式支持:WebScoket 、Ajax、Form 模式上传到…...

Exadata磁盘损坏导致磁盘组无法mount恢复(oracle一体机磁盘组异常恢复)---惜分飞

Oracle Exadata客户,在换盘过程中,cell节点又一块磁盘损坏,导致datac1磁盘组(该磁盘组是normal方式冗余)无法mount Thu Jul 20 22:01:21 2023 SQL> alter diskgroup datac1 mount force NOTE: cache registered group DATAC1 number1 incarn0x0728ad12 NOTE: ca…...

左值引用与右值引用的区别?右值引用的意义?

左值引用与右值引用的区别?右值引用的意义? 1 区别1.1 功能差异1.2 左值引用1.3 右值引用1.3.1 实现移动语义1.3.2 实现完美转发 2 引用的作用3 区分左值和右值3.1 左值3.2 右值 1 区别 左值引用是对左值的引用;右值引用是对右值的引用。 &…...

2023年深圳杯数学建模D题基于机理的致伤工具推断

2023年深圳杯数学建模 D题 基于机理的致伤工具推断 原题再现: 致伤工具的推断一直是法医工作中的热点和难点。由于作用位置、作用方式的不同,相同的致伤工具在人体组织上会形成不同的损伤形态,不同的致伤工具也可能形成相同的损伤形态。致伤…...

Vue的router学习

,前端路由的核心是什么呢?改变URL,但是页面不进行整体的刷新。 vue-router是基于路由和组件的  路由用于设定访问路径, 将路径和组件映射起来;  在vue-router的单页面应用中, 页面的路径的改变就是组件的切换; 使用router需要…...

Inpaint Anything: 自动化抹除视频元素

自动化抹除视频元素 不用逐帧抠图,直接SAM Tracking Video Inpainting就能实现自动化抹除奔跑吧idol。 https://github.com/geekyutao/Inpaint-Anything 目录 网站演示参考文献 网站 https://huggingface.co/spaces/InpaintAI/Inpaint-Anything 演示 原理就是&a…...

Flutter 开发者工具 Android Studio 开发Flutter应用

Flutter 开发者工具 在 Android Studio 开发Flutter应用 🔥 Android Studio 版本更新 🔥 Android Studio Check for Update Connection failed ​ 解决方案 如果是运行的是32位的android studio需要在andriod studio的启动目录下找到studio.exe.vmoptio…...

后端byte[]传给前端接收默认变成string字符串

创建时间:2023.7.28 建议:最好直接用字符串,我是没办法要求保密,存取都是字符串,程序里面是byte数组 既然他到前端会转换成字符串那么就是被转码了 那我们反向转码就好了 这是在后端处理,反正前端也是乱…...