自从2015年毕业开始从事 Java 开发工作,已经过去3年多了, 在各种不知名的小公司待过,经历过生产力从低到高,技术从落后到先进的过程, Dubbo 和 Spring Cloud 就是我曾经所经历过的两次技术变革。微服务这个概念已经出现好多年了,但是最近几年微服务异常火爆,很多以前使用 Dubbo 的公司也在纷纷尝试转型。Dubbo 好还是 Spring Cloud 好,有啥差异,有啥优缺点是人们常常讨论的话题,很多知名大V也纷纷写一些科普文章,我也拜读过很多,读完感受良多,也激起了我写这篇文章的动力。这篇文章更多的不是解释概念,而是讲述我曾经使用到的两种技术的方式,希望大家可以从文章中获得启发。

原生状态

如果以前关注过 Dubbo ,对 Dubbo 印象最深的一个定位就是 ”服务治理“的概念。为什么要服务治理?服务治理到底治理了什么方面?这是我们遇到的最直观的问题。

下面就展示下我们曾经没有使用 Dubbo 的业务模型:
【图解】我使用过的 Dubbo 和 Spring Cloud-LMLPHP

大体的业务如下:

1、我们有项目A,和项目B,项目A由项目管理部负责使用,项目B由物流部负责使用;

2、每当项目管理部在项目A中完成一个项目,那么就必须发请求给项目B,通知项目B进行物流发货;

3、项目B物流完成之后给项目A发送一个请求,完成物流操作,告知项目A进入结算。

根据图看的话,无非就是两个项目互相调用,在没用采用 Dubbo 之前,我们的项目结构就像图中那样混乱,很多问题都是不可避免的。下面我就把所有遇到的问题一一进行列举,以项目A为例,:

1、开发者由于自身综合素质不高,没有良好编码习惯和架构能力,对 webservice 的调用和服务暴露散落在各个层面如图所示;

2、项目A中所有的请求的ip,写在配置文件,如果项目B修改了部署ip或者端口,项目A需要手动修改配置文件然后重启;

3、项目B如果修改了方法的参数和返回值,项目A无法得知;

4、项目A调用项目B使用的方式由于开发者的能力和经验不同,采用的实现方式千奇百怪,有的使用 okhttp ,有的使用 Apache 的 HttpClient,有的使用原生的使用 Java 提供的原生操作。同样,项目B中提供服务的方式也千奇百怪,有的是 Spring MVC 提供的 http 接口,有的使用的是 webservice,整个项目混乱不堪;

5、每个人写的请求参数五花八门,比如超时时间设置,比如MediaType的设置等,没有统一的规范;

6、当时接口是暴露在内网的,所以接口没有做安全性校验,但是这也是一大遗留问题。

Dubbo

当原生的架构出现了这些问题之后,我们需要对架构进行更新升级,综合以前遇到的问题,我们提出了一些关于框架的需求:

1、调用其他服务的时候,不用手动的维护ip和端口;

2、暴露给其他服务的接口,接口形式要一致;调用其他服务的接口,方式要统一,参数统一设置,支持个别方法单独设置参数;

3、采用RPC的形式,本地项目依赖远程项目提供的sdk,调用sdk中的方法就可以实现远程方法的调用。

在这样的趋势下,就很正常的选择了 Dubbo 作为项目的框架,当时的想法也特别单纯,和 Dubbo 当时的定位一样,主要就是”服务治理“,让混乱不堪的项目结构清晰起来。当时还没有想到什么分布式事务、服务熔断、服务鉴权这些概念。我们使用 Dubbo 的时候, Dubbo 依然是停止更新状态,还没有捐献给 Apache 。才采用 Dubbo 架构之后,我们对项目进行了整体的重构,同时引入了 SSO 的单点登录,最后的架构大致如下:

【图解】我使用过的 Dubbo 和 Spring Cloud-LMLPHP

修改之后的架构大概如下:

1、新增了 CAS 服务器作为统一认证,实现多项目的 SSO,保证登录了一个系统之后,其他的系统也处于登录状态;

2、项目A和项目B,每个项目给对方提供一个 rpc-client 的包,里面包含所提供的接口,公用的实体类等;

3、项目A和项目B,配置上增加 Dubbo 配置,比如注册地址,序列化协议扥等 。一般都是采用 Dubbo 协议,认证到zookeeper中;

4、调用对方项目的接口时候,只需要注入 rpc-client 包中的类,调用其中的方法即可,dubbo会自动在zookeeper中查找服务注册信息,发送请求,返回结构。

Spring Cloud

现在的公司架构采用的 Spring Cloud 微服务架构,平时自己也有学习和研究 Spring Cloud 相关的知识,自己对 Spring Cloud 的架构认识大概如下图:

【图解】我使用过的 Dubbo 和 Spring Cloud-LMLPHP

大概的架构如下:

1、用户访问Nginx,跳转到前台页面;

2、当页面有ajax请求时候,通过访问nginx,nginx转发到 Spring Cloud Gateway,然后根据路由规则转发到具体的某个微服务中;

3、nacos作为服务注册发现 + 动态配置 + 服务监控使用,这里替代了 eureka + config + admin,其中config 项目,没有可视化页面,同时必须配合 Spring Cloud Bus + RabbitMQ通过订阅消息才可以实现配置的动态刷新。是nacos一个项目融合了多个功能,如果以集群方式部署,大大节省了项目的数量,比如 eureka + config + admin 都要实现高可用,那么需要至少 3*3个实例,而 nacos 只需要3个实例即可,同时降低项目复杂度。同时动态配置这块nacos提供了可视化界面,并且有配置信息回滚等操作,简单且功能强大 ;

4、每个微服务之间难免有服务的调用,比如支付服务在付款的时候,必须调用订单服务,把订单中商品的数量和价格等信息查询过来,这里使用的是 Feign ,每个微服务本身属于 server 服务,给调用方提供一个 client 的sdk,当调用方使用 client 中的方法时候,就是实现了微服务之间的 Fegin 调用,同时配有 Hystrix 熔断功能,防止接口长时间不返回,阻塞后续请求造成服务的连锁奔溃反应。同时还包括有 Rbbion 的负载均衡和自动重试功能,某个服务无法访问时候,自动进行切换并重试;

5、一次请求,可能涉及多个微服务,如果请求超时,那么必须要能定位到哪一步的请求耗时过多,方便后续的优化修改,这时候就必须使用微服务的全链路追踪,这里使用了 Skywalking ,是因为 Skywalking 是通过字节码增强技术实现,无须手动埋点,切性能较高。 Zipkin + Seluth 的组合,需要多个项目,同时 Zipkin 是通过 http 请求收集信息,性能较差;

6、其他的分布式事务、分布式主键发号器、分库分表、缓存等方案就暂时不写,主要就是为了表达下 Spring Cloud 架构下的 Java 项目结构。

总结

大部分情况下,说区别其实是个伪概念,因为 Dubbo 能实现的方式 Spring Cloud 也能实现, 反之亦然。下面所说的区别是针对我个人曾经经历过的项目,个人所得出的感觉,欢迎不同观点朋友的探讨:

  • Dubbo
    • 项目结构:一般为前后一体化的项目为主,多以 JSP 为页面技术;
    • 项目定位:每个项目一般称之为一个系统,如 OA管理系统,BOSS系统等;
    • 团队构成:Java Web 员工为主,前后台都写;
    • 使用群体:一般为公司内部员工及管理人员使用,受众在百人与千人左右;
    • 性能要求:性能要求不高,高可用要求也不高,偶尔停机更新影响个5分钟,半小时都不会有太大影响(额。。好像容易挨打);
    • 技术聚焦:采用 Dubbo 更多是出于服务治理的原因,就是为了解决原生架构中,服务调用的混乱和难以管理等问题。
  • Spring Cloud
    1. 项目结构: 微服务化,每个服务关于某个具体领域,每个项目拥有自己的数据库。采用前后分离技术,前台页面关注于效果展示,页面统一访问网关,由网关根据路由规则转发到具体的某个微服务中;
    2. 项目定位:每个项目称之为微服务,只提供 http ( restful ) 接口,不负责页面;
    3. 研发团队:以微服务领域划分,每个微服务应该有自己的团队,独立开发和维护,每个团队尽可能将自己所负责的项目做到做好;
    4. 使用群体:以广大用户为主,人数成千上万乃至亿;
    5. 性能要求:一般微服务项目要求全年3个9(99.999%)或者4个9(99.9999%)高可用,微服务需要具备自动降级、故障切换、熔断、在线扩容、重启等功能;
    6. 技术聚焦:采用 Spring Cloud 架构,整个系统复杂度大幅度提升了,更多的是为在高并发和大流量下系统可以正常运行。

后记

由于本人经验有限,经验不足,文笔笨拙,文章写的有点过于粗糙,以上分析和解释可能还有错误和有失偏驳,还望大家批评指正。

02-15 06:55