作者:404,转载请注明出处。欢迎关注公众号:404P。

SOFA是蚂蚁自研的一套金融级分布式中间件,目前正在逐步向业界开源。SOFA的全称有两个,最早是Service Oriented Fabric Architecture,即面向服务的架构。随着2018年的开源,其全称改为Scalable Open Financial Architecture,即可扩展的开源金融架构。

SOFA技术栈包含了微服务架构体系的各类组件,主要包括RPC框架,服务注册中心,分布式链路追踪,Metrics监控度量等。

本文我们来聊聊SOFA的模块化。

一 什么是模块化

模块化在计算机领域是经常讨论的话题,在学校学编程语言的时候,教科书上说程序设计要遵循模块化原则。

模块化程序设计是指在进行程序设计时将一个大程序按照功能划分为若干小程序模块,每个小程序模块完成一个确定的功能,并在这些模块之间建立必要的联系,通过模块的互相协作完成整个功能的程序设计方法。

上面这段话引自百度百科,其实精炼下就是:高内聚和低耦合

二 模块化思想演变

1 代码设计模块化

最早学编程的时候,实现一个功能,所有逻辑放到一个main函数里去,后来发现理不清了,就把main里面的逻辑抽成几个函数。这是模块化吗?是。这个模块化是最基本的代码设计能力,增强代码的可读性、可维护性和可扩展性。如下图,计算成绩的时候,没有把所有逻辑放在A中,而是分在B1和B2中,单独计算,最后A调用B1、B2来实现。

在这种简单的程序设计中,往往更注重逻辑的内聚性,只要内聚做好了,往往就是低耦合的。

2 业务领域模块化

在真实做一些项目的时候,业务系统比较复杂,要实现的功能很多。这个时候出现了横向和纵向的模块化设计。横向的就是分层设计,纵向的就是按照不通的业务领域来设计。

一个业务系统,横向的模块化切分主要分为三大层:Web层,Service层,DAL层。

在业务初期,功能往往都是写在一个业务系统的,比如订单模块Order、库存模块Stock。在maven中这些模就是不同的module,但运行都是在同一个JVM,同一个web容器中的。

这在种情况下,订单服务依赖于库存服务怎么办?订单模块的pom中引入库存模块的依赖。然后注入bean。

public class OrderService {
@Autowired
private StockService stockService;
}

这种横纵模块化思想随着业务的复杂开始进化了。订单、库存模块虽然在一个Service层,但属于明显不同的领域,已经被分成不同的模块了,具有很好的内聚性,而且要引用其它模块,必须引入pom依赖之后才能访问,具有不错的隔离型。

3 业务系统模块化的弊端

但是,这样设计的耦合性还是不够低,隔离性不够强。

程序员小胖:还不够强吗?订单模块和库存模块都在不同的module了,不费任何力气,就可以直接把源代码分成两个项目,由不同的团队来写了。

404P: 不够,现在的隔离性最多在开发层,能够相互隔离开发。运行时呢?

所有module的bean都在同一个spring context中,A模块可以任意引用B模块的bean,开发同学引入另一个module之后,不太清楚该module中哪些是对外提供的的接口,哪些bean是可以直接注入调用的,哪些Bean是内部Bean,不适合直接去注入的。

长期如此,一个模块的bean被不断地注入到另外一个模块被调用,那么其运行时的隔离性就差了。运行时没有做好隔离,是服务拆分的一大痛点。大概就是下图这个样子。

程序员小胖:请继续你的表演。

404P:随着业务的增长,必然会把Order和Stock拆分,成为不同的子业务系统。代码在不同的module,拆分开来很简单,但是拆分后两个业务系统是运行在不同的SpringContext中的。而bean的注入只在一个SpringContext有效,所以之前通过bean注入来实模块交互的地方需要梳理出来,变成系统之间的接口交互才能实现服务拆分。

程序员小胖:听你这么一说,有道理。模块化思想都是跟着架构思想走的啊。如果要考虑未来模块拆分成服务,就需要考虑好运行时隔离,也就是运行时的低耦合交互。

404P: 是的。看看SOFA怎么做的。

三 SOFA模块化

为了防止这种模块之间滥用bean注入来交互。SOFA启动后,会为每个moudule创建一个SpringContext,每个module运行在各自的SpringContext中。不同模块之间的bean无法直接引用,具备了较好的运行时隔离能力。

那么当Order模块想引用Stock模块的Bean,怎么办呢?

首先,需要Stock模块有发布对外的公共bean,通过如下声明式发布(也可以通过注解方式):

<sofa:service ref="stockBeanA" interface="com.alipay.sofa.StockBeanA"/>

那Order模块怎么引用Stock模块中的公开bean呢?通过如下声明方式引用:

<sofa:reference id="stockBeanA" interface="com.alipay.sofa.StockBeanA"/>

Stock模块的stockBeanA已经公开发布,并且Order模块已经引用,那么Order模块在编码的时候,就可以直接注入bean stockBeanA了。

这种方式,我们可以很清晰地看到一个模块公开了哪些服务,引用了哪些服务。模块之间的交互变得非常清晰。

四 SOFA模块拆分成微服务

当一个SOFA应用开始变得复杂,开发团队成员开始增多时,就需要进行服务化了。比如,Order模块和Stock模块,不再是运行在一个系统了,而是要变成Order系统和Stock系统了。这意味着这两个领域之间的交互从模块级别的交互上升到应用系统级别的交互了。

这种服务化拆分需要考虑两点:

(1)模块化的交互是在同一JVM内存中不同SpringContext之间的交互,拆分成两个应用系统后,应用系统之间交互必然是通过网络请求来交互,必然要考虑远程通信的问题。

(2)模块之间的服务发布和引用与应用系统之间的服务发布和引用是否有差异,需要改造?

SOFA考虑了以上两点,要将一个SOFA模块拆成微服务是非常便捷的。

Stock应用发布的时候,如下:

<sofa:service ref="stockBeanA" interface="com.alipay.sofa.StockBeanA">
<sofa:binding.bolt/>
</sofa:service>

Order应用引用Stock的服务时,如下

<sofa:reference id="stockBeanA" interface="com.alipay.sofa.StockBeanA">
<sofa:binding.bolt/>
</sofa:reference>

可以看出,就是添加了个属性 ,

<sofa:binding.bolt/>

表示服务之间的交互是通过sofa bolt远程调用框架来完成,发布和引用方式几乎没有变化。这种简易的服务化拆分,为蚂蚁架构在服务化演进的过程中带来了很大的便利。

五 结语

随着问题域的复杂性越来越高,模块之间的隔离边界也有更高的要求,本文从简单的例子,逐渐演变到服务拆分,从而引出SOFA的模块化。SOFA基于SpringContext作为模块隔离边界,充分降低了模块交互的耦合性,同时也为后续服务拆分提供了便利。

关于SOFA模块化的实现原理,将另起一文,欢迎关注下方公众号,更多思考,与你分享。


近期文章:

分布式幂等问题解决方案三部曲

Java跨平台?慎用这些有平台差异性的方法!

蚂蚁SOFA系列(1) - 聊聊SOFA的模块化的更多相关文章

  1. 蚂蚁SOFA系列(2) - SOFABoot的Readiness健康检查机制

    作者:404,公众号404P,转载请注明出处. 前言 SOFABoot是蚂蚁金服的开源框架,在原有Spring Boot的基础上增强了不少能力,例如Readiness Check,类隔离,日志空间隔离 ...

  2. Java9系列第8篇-Module模块化编程

    我计划在后续的一段时间内,写一系列关于java 9的文章,虽然java 9 不像Java 8或者Java 11那样的核心java版本,但是还是有很多的特性值得关注.期待您能关注我,我将把java 9 ...

  3. 深入浅出百度地图API开发系列(3):模块化设计

    在前面两张简单介绍了百度地图API的基础知识和使用之后,我们来分析一下百度地图API的基本架构,了解一下基本架构可以帮助我们更清晰的了解API的功能和调用过程,也就可以帮助我们在实际开发中可以更方便的 ...

  4. Python 单元测试框架系列:聊聊 Python 的单元测试框架(一):unittest

    作者:HelloGitHub-Prodesire HelloGitHub 的<讲解开源项目>系列,项目地址:https://github.com/HelloGitHub-Team/Arti ...

  5. 聊聊MVC和模块化以及MVVM和组件化

    原文链接 小寒的博客,带你理解更深的世界 面向对象,模块化和MVC 面向对象是指把写程序映射到现实生活,从而一来逻辑性更强,更容易写好代码,二来代码很贴切,通俗易懂,更被人理解,三来更加容易拓展和管理 ...

  6. 模块化系列教程 | 阿里JarsLink1.0模块化场景实战Demo

    场景实战Demo使用指引 Quickstart 快速开始 Demo说明 模块说明 使用说明 情景一环境部署 工作原理 情景二环境部署 工作原理 场景实战Demo使用指引 个人之前学习过程中对JarsL ...

  7. C#系列之聊聊.Net Core的InMemoryCache

    作者:暴王 个人博客:http://www.boydwang.com/2017/12/net-core-in-memory-cache/ 这两天在看.net core的in memory cache, ...

  8. 蚂蚁金服研发的金融级分布式中间件SOFA背后的故事

    导读:GIAC大会期间,蚂蚁金服杨冰,黄挺等讲师面向华南技术社区做了<数字金融时代的云原生架构转型路径>和<从传统服务化走向Service Mesh>等演讲,就此机会,高可用架 ...

  9. Train-Alypay-Cloud:分布式微服务中间件sofa 开发培训(第二次)

    ylbtech-Train-Alypay-Cloud:分布式微服务中间件sofa 开发培训(第二次) 1.返回顶部 1. 这是本次培训的内容,望各位提前配好环境.工具.2.6-2.7 我们在环球金融8 ...

随机推荐

  1. X-Admin&ABP框架开发-系统日志

    网站正常运行中有时出现异常在所难免,查看系统运行日志分析问题并能够根据错误信息快速解决问题尤为重要,ABP对于系统运行日志这块已经做了很好的处理,默认采用的Log4Net已经足够满足开发过程中的需要了 ...

  2. 读JDK源码集合部分

    以前读过一遍JDK源码的集合部分,读完了一段时间后忘了,直到有一次面试简历上还写着读过JDK集合部分的源码,但面试官让我说说,感觉记得不是很清楚了,回答的也模模糊糊的,哎,老了记性越来越差了,所以再回 ...

  3. 【Java笔记】【Java核心技术卷1】chapter3 D2注释

    package chapter3; /** * 文档注释 *@author lp *@version 1 **/ public class D2注释 { //单行注释 /* 长注释 */ }

  4. 【原创】POI操作Excel导入导出工具类ExcelUtil

    关于本类线程安全性的解释: 多数工具方法不涉及共享变量问题,至于添加合并单元格方法addMergeArea,使用ThreadLocal变量存储合并数据,ThreadLocal内部借用Thread.Th ...

  5. 为什么unsigned (-1)表示无符号整数的最大值

    整数在计算机中的表示 在计算机中,整数采用补码表示.当前主流编译器中整型在内存中占用四个字节,共32位. 机器数:一个数在计算机中的二进制表示形式, 叫做这个数的机器数.机器数是带符号的,在计算机用一 ...

  6. 消息中间件-activemq入门(二)

    上一节我们了解了JMS规范并且知道了JMS规范的良好实现者-activemq.今天我们就去了解一下activemq的使用.另外我们应该抱着目的去学习,别忘了我们为什么要使用消息中间件:解耦系统之间的联 ...

  7. JavaWeb——Servlet开发2

    1.HttpServletRequest的使用 获取Request的参数的方法. 方法getParameter将返回参数的单个值 方法getParameterValues将返回参数的值的数组 方法ge ...

  8. 【Aizu - 2249】Road Construction(最短路 Dijkstra算法)

    Road Construction Descriptions Mercer国王是ACM王国的王者.他的王国里有一个首都和一些城市.令人惊讶的是,现在王国没有道路.最近,他计划在首都和城市之间修建道路, ...

  9. Source Maps简介

    提高网站性能最简单的方式之一是合并压缩JavaScript和CSS文件.但是当你需要调试这些压缩文件中的代码时,那将会是一场噩梦.不过也不用担心,souce maps将会帮你解决这一问题. Sourc ...

  10. 深入分析Java的编译期与运行期

    不知大家有没有思考过,当我们使用IDE写了一个Demo类,并执行main函数打印 hello world时都经历了哪些流程么? 想通过这篇文章来分析分析Java的执行流程,或者换句话说想聊聊Java的 ...