首先,ER图设计时假定了使用的是关系型的数据库。微服务的一个特点在于它支持异构架构,系统的不同部分,依据实际需要可选择不同的编程语言、框架以及数据库的类型。关系型数据库采用平面表的结构,atv直播,如果有两类嵌套关系的对象,只能使用关联表来表达两个实体之间的关系,然后通过复杂的SQL语句在查询时将多个表拼成更大的平面表,最后在业务代码里再分解到各个独立的对象里去。这些单独的表又可能在其他地方与另一个表存在关联查询。这样设计出来的表结构的冗余很低,且使用非常灵活,但正是这种灵活性往导致系统中多个业务逻辑表出现错中缠绕的关系,从而使剥离单独服务进行异构设计变得困难。 其次,ER图还会导致实体相似的不同业务逻辑在设计时被耦合在一起。举一个具体的例子,在汽车代理销售系统中,不同品牌汽车的购买流程后端实际上分别对接的是完全不同的分销渠道系统和逻辑流程,但它们在用户视图上所需要的信息比较一致,因此存储的数据结构也比较相似。这个系统在最初设计时采用了ER图的方式建模,由于ER图模型不关心业务层面上的东西,不同品牌汽车的实体数据看上去都是一种类型的数据,仅仅是一个品牌字段的差异而已,因此被理所当然的设计成了同一张表。上层逻辑实现的时候使用了大量的if-else语句来区分各种品牌的购买流程,结果使得多条完全不同的业务线糅合在同一个上下文里,后来的开发非常容易在这里错改、漏改代码。若当初使用的是领域建模,则不同的购车流程会自然的被划分到各种不同的用户场景,即使它们在数据结构上看起来基本相同,也会被识别为两个独立的上下文,这就会使得未来划分服务时能够更加容易。 最后,ER图设计的架构会使得系统的模块之间倾向于使用数据库集成,而非API集成。在ER图中没有明确划分模块和表的所有权关系,所有的数据表对所有的模块都是可见的,倘若不加额外约束,各个模块便都会轻易的读写其中的内容。数据集成并不会直接导致服务无法拆分,但由于数据的所有权不清晰,十分容易引发的意想不到的状况。还是举销售平台的例子,在ER图建模得到的模型中,有一张与购买记录相关的表。在一次销售业务的代码更新中,对购买结果的增加了字段,在测试过程中没有发现问题,结果上线几天以后,由于售后服务也在修改这个表而导致出现了脏数据,造成难以排查的故障。 当然,我们并非要完全否认ER图建模的价值,只不过通过数据库角度建立模型的过程容易倾向于设计出庞大的单体应用,因而不太适应于服务划分的目的。 端到端的划分服务 在拆服务时要端到端的划分,这是我们在设计微服务时经常听到的一句话。端到端的划分,指的是一个服务负责一个业务领域,这个功能领域的所有逻辑、数据都归它管,这有利于微服务的数据治理。与之相对的是MVC那样的横向服务划分,将所有数据归一块,所有逻辑归另一块,特别是在跨团队管理的情况,横向划分服务会带来十分高昂的协调和联调成本。 道理不必多说,还是讲个例子吧。在汽车销售平台的最初架构中,使用了典型的MVC三层结构,由于人比较多,分成了前台组、后台组,就时不时要出现新开发一个功能,一动底层数据结构,结果上层的另一个不相干页面挂了,一查发现原来那这个页面间接的用了同一个数据模型。比较典型的例子是,有一回负责后台的小组调整了汽车销售服务里面的汽车参数信息相关的对象结构,结果一上线,销售功能正常,试驾服务的页面挂了。原来是试驾功能的前端开发人员在处理汽车信息时候,看到销售模块有现成功能,就直接拿来复用了。这便是服务上下层分团队开发导致的问题。 此外,横向划分服务也不利于系统的开发效率的提升。不同业务服务对功能发布频率的的需求是不一样的,比如试驾平台经常推出新的优惠促销活动,需要尽快进行一次版本更新,于此同时售后服务有一个需要和第三方联调的功能也已经差不多完成并提交到代码仓库了,但由于需要协调第三方系统的时间,最近还不能够上线,此时两边的业务主管就要开掐了。类似这样的情况其实经常发生,通常使用特性分支、特性开关等流程或者技术手段能够规避一部分业务开发进度不一致的风险,但若要从根本上解决这种问题,还是需要端到端的按业务来划分服务。 (责任编辑:本港台直播) |