拆分:分解单块系统——《微服务设计》读书笔记

通常,我们可能已有有一个巨大的单块系统,如何实现微服务,我们需要把它分解。

从哪里开始拆分:接缝

      接缝:从接缝处可以抽取相对独立的一部分代码,对这部分代码的修改不会影响系统的其他部分。这些接缝就可以作为服务的边界。

      那如何识别出接缝呢?我们可以使用前面所提到的限界上下文,也可通过程序中的命名空间来帮助我们,也可以通过工具来帮助我们,如structure101这样的工具来可视化包之间的依赖。

杂乱依赖的根源:数据库

      为什么这么说?因为,通常情况下,我们在业务层的代码已经通过分层组织到相应的包中了,但是只有数据库是共用的,数据库对所有的代码都允许访问,是一个巨大的API。我们举例说明:有一张仓储表,它被“产品目录”、“仓库”、“财务”等服务所共用,那么在单块应用程序中,通常会是下面的结构:

     

      对于同一张表被多个限界上下文使用的场景,我们应该如何处理?以下是一些处理的步骤和原则 :

      一.分清代码中对数据库进行读写的部分

      我们需要厘清代码是如何访问数据库的,在什么地方读,在什么地方写?他们分别位于什么样的上下文中。

      二.打破外键关系

      对于表与表之间的外键关系,如果这两张表需要被拆分至两个微服务中,我们可能需要放弃外键关系,同时把这个约束关系放到代码中实现,我们可能还需要实现跨服务的一致性检查,或者周期性触发清理数据的任务。

      我们可以通过类似于SchemeSpy这样的工具来分析数据库表之间的依赖关系。

      三.共享静态数据

      比如,国家、部门之类的数据都是各个微服务之间经常使用的,这些数据的特征是不会经常变,而且是通用性高。这些数据在微服务划分之后该如何处理呢?

      方法一:我们可以为每个微服务复制一份这样的数据,但是这个会导致数据的一致性问题;

      方法二:把共享的数据放入代码之中,比如放在属性文件 中,或者简单地放在一个枚举中,但数据一致性仍然存在。

      方法三:把这些静态数据放在一个单独的服务中。

      四.共享数据

      如果不同的微服务都使用了同一张表,比如仓库和财务都用到了客户信息表,这种情况下该如何分享?其实这种情况很常见:领域概念不是在代码中建模,相反是在数据库中隐式地进行建模。这里缺失的领域概念是客户,因而我们需要提供一个新的服务:客户服务。

      五.共享表

      与共享数据不同的是:不同的微服务也会使用同一张表,但两者修改的部分不一样,这样的情况下,我们可以把这张表拆分出两张表,分别供两个微服务使用。

      六.实施拆分

      通常,我们推荐先分离数据库结构然后对代码进行拆分。表结构分离之后,对于原先的某个动作而言,对数据库的访问次数可能会变多。这也是我们需要考虑的问题,这里涉及到分布式事务的相关问题。

另外,先拆分数据库但不分离代码的好处在于,可以随时选择回退这些修改或是继续,而不影响服务的任何消费者。

分布式事务

      一个事务可以帮助系统从一个一致性的状态迁移到另一个一致的状态,要么全部都做,要么什么都不做。

       在单块结构中,所有的创建或者更新都可以在一个事务边界内完成,分离数据库之后,这种好处就没有了。在分布式事务中,我们有可能面临一个操作成功,而另一个操作失败的局而,我们该如何处理这些问题?

       方法1:补偿机制——最终一致性

       对于失败的动作,我们进行重复触发,只要在系统可接受的时间范围内,最终一致性是可以接受的。

       方法2:回滚机制

       对于失败的动作,我们可以选择回滚。但是回滚也失败的呢?这个时间,要么我们在某个时间重试回滚操作,或者提供一些自动化的操作或界面操作来清除这些不一致的状态。

      方法3:分布式事务

      我们可以使用事务管理器来统一编排横跨多个服务的事务,分布式的事务会保证整个系统处于一致的状态,唯一不同的是,这里的事务会运行在不同系统的不同进程中,通常它们之间使用网络进行通信。

      分布式事务的常见算法是两段提交,在这种方式中,首先是投票阶段,在这个阶段,每个参与者都会告诉事务管理器是否应该继续,如果事务管理器收到所有的投票都是成功,则事务管理器会告知各个参与者执行提交操作,只要收到一个否定的投标,事务管理器就会让所有的参与者回退。

      但两段提交也有缺点,首先所有的参与者都等待中央协调进程的指令,从而很容易导致系统的中断,如果事务管理器宕机了,处于等待状态的事务就永远无法完成;如果有一个参与者在投票阶段发送消息失败,则所有的其他参与者都会被阻,投票之后的提交也可能会失败;另外中央协调进程也可能使用锁,这样会对系统的扩展带来影响。因而这种算法并不是万无一失的。

      如果确实存在保持一致怀的场合,应该尽量避免把它们放在不同的地方。

 

又一个难点:报表数据库

      报表通常需要来自组织内各个部分的数据,在以往的单块结构来说,这是很方便的。但也存在一些缺点:首先是修改表结构的风险增大;再者则是报表系统的优先手段有限,比如关系型数据库对于海量的数据不能呈现很好的支持,而MongoDB则地文档存储有其独特的优越性。

      一.通过服务调用来获取数据

      报表数据通常需要大量的数据,通过服务提供接口来一条条调用很显示是不太合适的,这样非常低效而且对服务来说负载过重。

      我们可以一次性返回分页的多条记录,或者在本地将数据导出到文件文件的地址返回给调用方以供使用。

      二.数据导出

      我们也可以把报表数据周期性的导出,推送到报表数据库,但这样不同微服务的数据又集成到一起的,这时我们可以使用一些技术来屏蔽这些耦合,比如视图

      三.事件数据导出

      在每次数据发生变化时,数据提供方也会提供一些事件,数据订阅方可以将这些数据导出到报表数据库中,这样源数据与数据之间的耦合就消除掉了,我们只需要绑定到服务所发送的事件即可。

      不同前面的周期性导出数据,这里的事件数据是实时,所以能让数据更快地流入报表系统。

      另外,我们只需要对新事件产生的新数据进行处理,即处理增量数据,这样的操作会更加高效。

      而缺点在于事件数据必须以事件的形式广播出去,同时在数据量时,不容易进行扩展,而前面的数据导出的方式,可以在数据库级别进行扩展。

      四.数据导出的备份

      这里是整库备份,因而也会造成不同微服务之间数据的耦合。

 

参考

      《微服务设计》(Sam Newman 著 / 崔力强 张骏 译)

相关文章: 

  • 微服务的概念——《微服务设计》读书笔记

  • 微服务架构师的职责——《微服务设计读书笔记》

  • 建模:确定服务的边界——《微服务设计》读书笔记

  • 微服务集成——《微服务设计》读书笔记

  • 服务的协作:服务间的消息传递——《微服务设计》读书笔记

原文地址:http://www.cnblogs.com/gudi/p/6667107.html


.NET社区新闻,深度好文,微信中搜索dotNET跨平台或扫描二维码关注

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/325844.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

winfrom实现简单计算器V2版本

前面,使用winform实现了个简单的计算器,今天,再来给大家看一个稍微复杂点的计算器,效果图如下: 包括归零,退格,加减乘除都已经实现,如果想要继续扩展的可以在稍微改改即可。 现在看…

ACID中C与CAP定理中C的区别

转载自 ACID中C与CAP定理中C的区别 ACID和CAP定理中都有C,代表Consistent一致性,很多人容易将这两个C混为一谈,其实这两个一致性是有区别的。 事务的定义是一系列操作要么全部成功,要么全部不成功,数据库的事务机制是…

单例模式——Java

单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建…

winform通过ListView绑定数据库数据源

来,我们开始拉窗体,和我一样的这个就可以: 很简单,在窗体里面只放一个ListView控件即可,然后点击ListView的属性Columns 分别在Text里面写用户名和密码,点击确定。 然后设置显示视图View为Details&…

理解C# 4 dynamic(4) – 让人惊艳的Clay

一,多种方式初始化对象 1, 最简单的对象构建和初始化 dynamic New new ClayFactory();var person New.Person(); person.FirstName "Louis"; person.LastName "Dejardin"; 注意这里的Person并不是一个具体的,实际存在的类或者…

java实现多文件上传至本地服务器

转载自 java实现多文件上传至本地服务器 博主最近在做一个内网项目,内部可以访问外部数据,但是外部访问不了内部数据,这也就造成了可能文件无法上传,所以博主另辟蹊径,在本地服务器上建立一个文件夹专门用来存储上传…

配置struts.xml时extends=struts-default会报错,原因和解决

提示:此种解决方法只适用于Intellij IDEA,MyEclipse或者Eclipse还得另寻它法,但估计原因应该是类似的。 在Intellij IDEA 2017使用Struts2框架时,若新建项目时并未导入Struts2框架而是在后期手动新建lib目录导入Struts2框架后&…

React生命周期(新)

三个标红的需要前面加上UNSAFE_ 三个常用的组件

《坚毅》的读后感

1.你的梦想是什么?有了梦想,那么接下来呢? 2.有什么问题? 3.你每天醒来后想阿着的是什么? 4.为什么现在是正确的时机? 5.你曾经做过的最艰难的事情是什么? 6.谁希望你成功? 7.你最重…

发力企业级市场,微软Hololens开辟了一条VR新道路

近日微软Hololens可谓是动作频频,2月份Hololens与BGC Engineering合作,从矿山规划到泥石流建模,该应用程序可帮助BGC Engineering及其客户可视化一个场景并解决工程问题。 3月份HoloLens与Cigna展开医疗合作,将Hololens用于健康检…

写给工程师的10条精进原则

转载自 写给工程师的10条精进原则 引言 时间回到8年前,我人生中的第一份实习工作,是在某互联网公司的无线搜索部做一个C工程师。当时的我可谓意气风发,想要大干一场,结果第一次上线就写了人生中第一个CaseStudy。由于对部署环境…

Struts2下创建自定义类型转换器(表单中日期的处理)

在表单提交中需要有日期的输入,默认的Struts2处理机制可能不能满足需求,需要自定义一下类型转换器。如: String----->java.util.Date:输入 java.util.Date------>String:输出:查询显示,输出错误回显 …

部署:持续集成(CI)与持续交付(CD)——《微服务设计》读书笔记

一.CI(Continuous Integration)简介 CI规则1:尽量频繁地把代码签入到分支中以进行集成 CI规则2:不光要对语法进行验,也要提供一系列的自动化来验证 CI规则3:CI失败后,要把修复CI当做第一优先级的…

使用ListView控件展示数据

一、使用ListView实现大图标小图标的功能: 1.拖一个ListView控件 2.拖两个imageList控件,并且重命名为imgBig和imgSmall,分别设置两个控件的图片和大小。 3.编辑ListView的Items,添加几项(C、D、E盘) 4.通过ListView绑…

React中的唯一标识key(用index VS id)和key的选择

1. 虚拟DOM中key的作用:1). 简单的说: key是虚拟DOM对象的标识, 在更新显示时key起着极其重要的作用。2). 详细的说: 当状态中的数据发生变化时,react会根据【新数据】生成【新的虚拟DOM】, 随后React进行【新虚拟DOM】与【旧虚拟DOM】的diff比较&#x…

Android中ImageView的scaleType 属性说明。

ImageView是Android中最常用的控件之一,在使用ImageView的时候,必不可少的会使用到scaleType属性,该属性指定了你的ImageView如何显示图片。包括是否进行缩放,等比缩放,缩放后显示的位置, Android中提供了八…

支付渠道参数如何设计成路由化配置

转载自 支付渠道参数如何设计成路由化配置 今天我们来探讨在搭建支付系统时一个比较关键的问题:渠道参数路由化配置如何设计? 在开发支付系统的时候,我们经常会涉及到对接多个支付渠道,除常见的支付宝、微信外可能还会根据不同的…

实现Windows程序的数据更新

一、枚举: 1.语法:public enum 名字{ 值1,值2} 2.eg:public enum Genders{Male,FeMale} 3.使用枚举:枚举名.值 4.枚举的好处: (1)使代码更易于维护 (2)更易于用户输入值,直接用.的方式就可以获取值 (3)使代码更清晰&a…