微服务架构之我们应该从Dubbo中学到什么

文章首发于公众号:松花皮蛋的黑板报

作者就职于京东,在稳定性保障、敏捷开发、高级JAVA、微服务架构有深入的理解

一、 模块分包

整体上按分层进行分包,然后每个包又分API包和具体的方案包,从中提炼出三个需要注意的点

  • 1.1复用度
    1) 包中的类应具有相同的重用可能性
    2) 紧密协作的类应放在同一包
    3) 对于变化因子,包中的类应全改或全不改
    4) 变化应在包内终止,不应传播到其他包
  • 1.2 稳定度
    1) 被依赖的包总是比依赖者更稳定
    2) 不要让一个稳定的包依赖于不稳定的包
    3) 单向依赖,无环依赖
  • 1.3 抽象度
    1) 越稳定的包应越抽象
    2) 抽象的包不稳定导致其所有依赖包处于经常的变化中

二、 框架扩展之微核和插件

大凡发展的比较好的框架,都遵守微核的理念, Eclipse的微核是OSGi(依赖META-INF/MANIFEST.MF配置), Spring的微核是BeanFactory,Maven的微核是Plexus,Dubbo的微核是SPI(依赖META-INF/services/com.xxx.xxx配置)。通常核心是不应该带有功能性的,而是一个生命周期和集成容器,负责加载、卸载、运行插件模块,这样各功能可以通过相同的方式交互及扩展,并且任何功能都可以被替换。如果做不到微核,至少要平等对待第三方,即原作者能实现的功能,扩展者应该可以通过扩展的方式全部做到,原作者要把自己也当作扩展者,这样才能保证框架的可持续性及由内向外的稳定性。

三、 框架扩展之平等对待第三方

  • 3.1 Dogfoodin-吃自己的狗粮
    1) 框架自己的功能具备扩展点实现
    2) 微核的加载方式也可以扩展
  • 3.2 Autowire-依赖注入
    1) 装配逻辑由扩展点之间互助完成
    2) 杜绝硬编码的桥接和中间代码
  • 3.3 Cascading-层叠
    1) 层叠扩展粒度,逐级细分
    2) 由大的扩展点加载小的扩展点
  • 3.4 Low of Demeter-最少知识原则
    1) 只与触手可及的扩展点交互,间接转发
    2) 保持行为单一,输入输出明确
    3) 一个对象应该对其他对象有最少的了解

四、 框架扩展之Filter-Chain模型

将一个事件处理流程分派到一组执行对象上,这一组执行对象形成一个链式结构,事件处理在这一组对象上进行传递

五、 框架扩展之外置生命周期

框架不应该控制实现类的生命周期,框架最多提供工具类辅助管理,而不是绝对控制,应满足下面的规范

  • 1. 尽量引用外部对象的实例,不是类元。正确示例:usrInstance.xxx(),Spring IoC,错误示例:Class.forName(userClass).newInstance().xxx
  • 2. 使用IoC注入,减少静态工厂方法。正确示例:setXxx(xxx),错误示例:XxxFactory.getXxx(),applicationContext.getBean(“xxx”)

六、 框架扩展之一致性数据模型

URL作为Dubbo一个公共契约,所有的扩展点都包含URL参数,URL作为上下文信息贯穿整个扩展点设计体系。所有的配置信息都转换成URL的参数,所有的元信息传输都采用URL,所有的接口都可以获取到URL

七、 领域模型划分

  • 1. 服务域:也称为行为域,作为组件的功能集,同时负责实体域和会话域的生命周期管理,如Velocity的Engine\Spring的BeanFactory
  • 2. 实体域:表示操作的对象模型,任何产品都有核心概念,围绕它转,如Velocity的Templcat\Spring的Bean
  • 3. 会话域: 表示每次操作或运行的瞬时状态,操作前创建,操作后销毁,如Spring中的Invocation

领域模型划分好处:结构清晰,可直接套用;充血模型,实体域带行为;可变和不可变状态分离,可变状态集中;所有领域线程安全,不需要加锁

八、 Dubbo核心领域模型

  • 1. 服务域Protocol: Invoker暴露和引用的主功能入口,负责Invoker的生命周期管理
  • 2. 实例域Invoker: 它是Dubbo的核心模型,任何模型都向它靠拢或者转换成它,它代表一个可执行体,可它向发起Invoke调用,可能是一个本地实现,也可能是远程调用,也有可能是集群实现
  • 3. 会话域Invocation: 持有调用过程的变量,比如方法名和参数等

九、 领域模型线程安全性

  • 1. 服务域:通常无状态,是线程安全的
  • 2. 实体域:通过设计为不变类,所有属性只读,或整个类引用替换,是线程安全的
  • 3. 会话域:保持所有可变状态,且会话域只在线程栈内使用,每次调用都在线程栈内创建实例,调用完即销毁,是线程安全的

十、 API和SPI分离

Dubbo中的API如ServiceConfig\ReferenceConfig\RpcContext是给使用者使用的,Dubbo中的SPI如Protocol\Transporter\LoadBalance,是给扩展者使用的,API应该是声明式的,描述需要什么,SPI应该是过程式的,描述怎么实现。它们不应该混在一起,使用者不应该看到扩展者写的实现

十一、 API可配置一定可编程

  • 1. 配置用于简化常规使用
  • 2. 编程接口用于框架集成

十二、管道和派发

管道一般适用于组合行为,主功能以截面AOP实现,比如Servlet。派发一般适用于策略行为,主功能以事件Event实现,比如Flux

十三、主过程拦截

没有哪个公用的框架可以Cover住所有的需求,不管是Web框架的请求响应流、ORM框架的SQL-Mapping过程,还是Service框架的调用过程,允许外置行为是框架的基本扩展方式,不然如果需要添加安全、日记或者修改分页SQL等不得不hack源代码了

十四、Dubbo调用过程拦截

Dubbo中使用全管道设计,框架自身逻辑,均使用截面拦截实现,比如常见于消费端的context\collect\generic\activelimit\monitor\future等链式过滤器,常见于生产端的token\exception\echo\accesslog\trace\executelimit等链式过滤器

十五、事件派发

拦截器是在切点执行前后生效的,它是干预过程的,会触发非关键行为,而事件是基于状态数据的,会触发状态观察者行为

十六、Reactor和Proactor事件驱动模型

Reactor模型关注就绪状态,比如可读了就通知我们主动去读,类似Linux epoll,而proactor关心的是完成状态,比如我们指定存放数据的内存地址(Buffer)和读事件,当它读完了就会通知我们,类似Windows IO completion port

十七、Dubbo 暴露/引用/调用事件

Dubbo在关键路径上采用拦截链分离职责,保持界面功能单一,不易出问题。在非关键路径上,采用后置派发,即使派发失败也不会影响主流程运行

十八、协作防御

  • 1. 可靠性分离。不可靠操作尽量缩小
  • 2. 状态分离。有状态尽量缩小可变域,不可变类尽量声明为final
  • 3. 状态验证。尽早失败,在有传入参数或者状态变化时,均在入口处全部断言
  • 4. 异常防御。不要生吃异常,应该尽量保证异常信息给出解决方案,日记信息包含上下文
  • 5. 降低修改时的无界性,不埋雷。避免基于异常类型的分支流程,同时保持NULL和Empty语义一致

十九、开闭原则

开闭原则,对扩展开放,对修改关闭,因为风险往往来自于修改。拥抱变化时应该继承原有类然后重写方法扩展逻辑,而不是修改原来的类

二十、增量式和扩充式

如果现有一个无状态消息发送的场景,后来新增一个会话消息发送需求,如果采用增量式扩展,无状态消息发送原封不动,同步消息发送,在无状态消息基础上加一个 Request/Response 处理,会话消息发送,再加一个 SessionRequest/SessionResponse 处理

二十一、Dubbo增量式扩展

传统的C\S模型是一问一答模式,而Dubbo的RPC模型中包括了Proxy\Custer\Protocol, Protocol只负责协议实现,它是不透明的、点对点的,Cluster只负责将集群中多个提供者伪装成一个,Proxy只负责透明化接口,桥接动态代理,整体的架构非常容易扩展

二十二、在高阶附加功能

尽可能少的依赖低阶契约,用最少的抽象概念实现功能。当低阶切换实现时,高阶功能可以继续复用

二十三、Dubbo高阶泛化调用

以PHP到Router的request body中的方法名和方法参数作为Router远程调用后端Java服务的入参,最后将远程调用的result返回给PHP端就是兼容Restful服务的高阶泛化调用

二十四、总结

文章来源:www.liangsonghua.me
作者介绍:京东资深工程师-梁松华,长期关注稳定性保障、敏捷开发、JAVA高级、微服务架构



全部评论

相关推荐

避坑恶心到我了大家好,今天我想跟大家聊聊我在成都千子成智能科技有限公司(以下简称千子成)的求职经历,希望能给大家一些参考。千子成的母公司是“同创主悦”,主要经营各种产品,比如菜刀、POS机、电话卡等等。听起来是不是有点像地推销售公司?没错,就是那种类型的公司。我当时刚毕业,急需一份临时工作,所以在BOSS上看到了千子成的招聘信息。他们承诺无责底薪5000元,还包住宿,这吸引了我。面试的时候,HR也说了同样的话,感觉挺靠谱的。于是,我满怀期待地等待结果。结果出来后,我通过了面试,第二天就收到了试岗通知。试岗的内容就是地推销售,公司划定一个区域,然后你就得见人就问,问店铺、问路人,一直问到他们有意向为止。如果他们有兴趣,你就得摇同事帮忙推动,促进成交。说说一天的工作安排吧。工作时间是从早上8:30到晚上18:30。早上7点有人叫你起床,收拾后去公司,然后唱歌跳舞(销售公司都这样),7:55早课(类似宣誓),8:05同事间联系销售话术,8:15分享销售技巧,8:30经理训话。9:20左右从公司下市场,公交、地铁、自行车自费。到了市场大概10点左右,开始地推工作。中午吃饭时间大约是12:00,公司附近的路边盖饭面馆店自费AA,吃饭时间大约40分钟左右。吃完饭后继续地推工作,没有所谓的固定中午午休时间。下午6点下班后返回公司,不能直接下班,需要与同事交流话术,经理讲话洗脑。正常情况下9点下班。整个上班的一天中,早上到公司就是站着的,到晚上下班前都是站着。每天步数2万步以上。公司员工没有自己的工位,百来号人挤在一个20平方米的空间里听经理洗脑。白天就在市场上奔波,公司的投入成本几乎只有租金和工资,没有中央空调。早上2小时,晚上加班2小时,纯蒸桑拿。没有任何福利,节假日也没有3倍工资之类的。偶尔会有冲的酸梅汤和西瓜什么的。公司的晋升路径也很有意思:新人—组长—领队—主管—副经理—经理。要求是业绩和团队人数,类似传销模式,把人留下来。新人不能加微信、不能吐槽公司、不能有负面情绪、不能谈恋爱、不能说累。在公司没有任何坐的地方,不能依墙而坐。早上吃早饭在公司外面的安全通道,未到上班时间还会让你吃快些不能磨蹭。总之就是想榨干你。复试的时候,带你的师傅会给你营造一个钱多事少离家近的工作氛围,吹嘘工资有多高、还能吹自己毕业于好大学。然后让你早点来公司、无偿加班、抓住你可能不会走的心思进一步压榨你。总之,大家在找工作的时候一定要擦亮眼睛,避免踩坑!———来自网友
qq乃乃好喝到咩噗茶:不要做没有专业门槛的工作
点赞 评论 收藏
分享
真烦好烦真烦:牛友太有实力了
点赞 评论 收藏
分享
05-28 23:26
河南大学 Java
双非本,刚学完Redis,项目只有外卖和点评,八股没准备,算法只有lqb省一,感觉敲的项目也是一言难尽没怎么吸收。怎么你们都有实习了
大牛之途:27急个锤子,你投日常实习最好的时间就是9,10月份,那时候暑期实习都结束了,正是缺人的时候。这份日常又能给你的暑期实习增加竞争力,暑期找的好了秋招也不怕了,都是环环相扣的
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务