【转载】设计 RPC 接口时,你有考虑过这些吗?

按:系统架构经过多年演进,现在越来越多的系统采用微服务架构,而微服务架构最重要的就是面向接口编程,所以接口的设计就尤为重要了,我一直认为一个好的接口自己会说话,也就是看到接口,我就知道这个接口是干啥的、参数是啥、返回值是啥以及可能会遇到哪些问题,但目前对 RPC 接口设计可以说有两派,前一段时间看了一篇文章是我的想法完全一样,特转载到本人博客,希望更多的能够看到、有更多的人参与讨论两种的优劣。 在开始之前呢,先吐槽一个本文没有提到的问题,我不知道有些人是怎么想的,对外暴露的接口,也就是最终被打成 jar 包供外部服务依赖模块,有些人喜欢在里面引入各种无关的第三方依赖,我遇到过把 spring mvc、spring、mybatis、dubbo 等等还有其他的像 POI 什么乱七八糟的第三方 jar 都依赖进来的,说实话,我只想问:可以说脏话吗?不可以啊,那好吧,我无话可说了,我们开始看原文吧。 RPC 框架的讨论一直是各个技术交流群中的热点话题,阿里的 dubbo,新浪微博的 motan,谷歌的 grpc,以及不久前蚂蚁金服开源的 sofa,都是比较出名的 RPC 框架。RPC 框架,或者一部分人习惯称之为服务治理框架,更多的讨论是存在于其技术架构,比如 RPC 的实现原理,RPC 各个分层的意义,具体 RPC 框架的源码分析…但却并没有太多话题和“如何设计 RPC 接口”这样的业务架构相关。 可能很多小公司程序员还是比较关心这个问题的,这篇文章主要分享下一些个人眼中 RPC 接口设计的最佳实践。 初识 RPC 接口设计 由于 RPC 中的术语每个程序员的理解可能不同,所以文章开始,先统一下 RPC 术语,方便后续阐述。 大家都知道共享接口是 RPC 最典型的一个特点,每个服务对外暴露自己的接口,该模块一般称之为 api;外部模块想要实现对该模块的远程调用,则需要依赖其 api;每个服务都需要有一个应用来负责实现自己的 api,一般体现为一个独立的进程,该模块一般称之为 app。 api 和 app 是构建微服务项目的最简单组成部分,如果使用 maven 的多 module 组织代码,则体现为如下的形式。 serviceA 服务 serviceA/pom.xml 定义父 pom 文件 <modules> <module>serviceA-api</module> <module>serviceA-app</module> </modules> <packaging>pom</packaging> <groupId>moe.cnkirito</groupId> <artifactId>serviceA</artifactId> <version>1.0.0-SNAPSHOT</version> serviceA/serviceA-api/pom.xml 定义对外暴露的接口,最终会被打成 jar 包供外部服务依赖 ...

September 2, 2018 · 3 min · 635 words · Bridge Li

我看拉勾一拍之系统架构

今年年中的时候由公司平台部转组到Alpha项目中心负责公司一拍项目组的技术研发工作,到现在已经快有将近半年的时间了,随着对系统的越来越熟悉,对原有系统的架构也越来越感到有些不合理的地方,随着自己水平的提升感觉对架构也有了一点自己的理解,所以今天就借这个机会说说自己的不成熟的建议。 一. 原有的架构 俗话说,一图胜千言,直接上图: 解释一下这几个系统分别的作用: 后台管理系统不用说了,管理C和B可见的内容; C端用户系统,是对C可见的一个系统,一拍是一个招聘系统,所以就是对候选人操作的后台; B端用户系统,是对B可见的一个系统,通俗点讲就是HR操作的后台; Dubbo系统,是对兄弟部门和B提供服务的一个系统; Recommend系统,其实也是一个Dubbo系统,区别在于Dubbo系统是对外提供各种服务的,而Recommend系统是发现全站系统用户的行为,然后对用户的行为进行分析,甄选出一部分C端用户作为一拍的现在用户; msgpush系统,是用netty做的一个实时消息推送的IM服务,目前主要是给后台管理用户和C端候选人聊天的一个系统; 其中:1. 在我们接手之前B和C是同一个系统,也就是说B是我们这半年新加的一个系统;2. Recommend和msgpush系统也同样是我们这半年新增的一个系统 二. 系统架构存在的问题 目前后台管理系统、C端用户系统、Dubbo系统各自独立,这样存在的问题: 最主要的是各自分别操作数据库,这样只要底层数据库发送变动,那么三个系统操作数据库的地方都要同步修改三次; 操作数据库的地方代码冗余,很多地方都一样,这样一个地方出bug,三个地方要同步修改,然后都要上线; 后台管理系统采用分层的模式分模块而不是根据业务分模块,这样每次上线service和dao都要先deploy jar到maven私服; 当时为了快速迭代,Recommend系统也是单独操作操作数据库,不过还好用了后台管理系统的dao这个jar包,但是首先根本不需要这么重的一个jar包,其次jar出bug了,有时候他也需要重新上线啊,不然这个jar包就会一直很旧,当然只要不涉及到他操作数据库的地方出bug,你不改也是可以的; 目前C和B虽然已经分开,但如果用户激增,横向扩展依然不合理,只能整体加机器,而不能针对性对某些模块单独加机器; 代码中存在的问题:不知道什么原因大量的逻辑被写在了controller层,导致代码可复用性差; 由于之前后台管理系统和其他系统不是同一个团队开发的,命名各有各的风格,代码不仅冗余还同样一个类名字不一样; 很多系统日志配置的也有问题,错误日志和最基本的业务日志没有区分开,目前在将就用; 系统中的jar依赖不仅存在循环依赖,而且加入了大量的自己不需要的依赖,导致各种jar冲突出问题; 综合以上问题,我个人认为这是一个:可维护性、可扩展性不高的系统。 三. 我的个人思考 同样先来一张图,来总体说明一下我的想法: 整体来说只有相对独立的实时消息推送系统不懂,然后把其余的各个业务层抽象成微服务,采用公司目前使用比较成熟的dubbo作为rpc框架,controller层只负责业务转发不负责逻辑的一个简单系统,这样带来的好处: Dubbo系统作为核心的业务系统,分别对兄弟部门、后台管理系统、C端用户系统、B端用户系统、Recommend系统提供服务,如果用户量增加,不仅可以整体增加Dubbo系统的机器,也可以把调用量大的接口单独拆出来,部署到另外的机器上,实现隔离,不会因某个接口调用量大,导致整个系统不可用,而且把数据库的底层操作也放到了这个Dubbo系统中,这样就可以避免数据库修改,要修改多处的问题; 抽象出来的这个dubbo系统,不仅可以解决后台系统和其他系统命名不一样的问题,而且和可以解决不同团队造成的coding style不一的问题,一举多得; 由于后台管理系统、C端用户系统、B端用户系统、Recommend系统都调用Dubbo系统,所以他们的controller层讲极其简单,很多业务逻辑类似的东西全部放到了Dubbo系统里面,代码的可复用性提高了不少; 抽象出来的逻辑都统一放到了dubbo中,这样系统如果有bug,这样就做到了一个地方修改,这样多个地方就可以同时生效; 由于业务都在Dubbo系统里面这样同时也避免了曾经出现了,后台管理系统和BC系统使用的缓存不一致,导致缓存出问题的这种低级bug; 由于controller层简单没有逻辑,这样就可以避免目前由于后台管理系统单机,修改一个业务逻辑bug重启系统,导致后台不可用的问题,因为只需要重启dubbo就行了; 这样controller层变得很轻,只需要一个简单的servlet容器,对机器的要求会降低不少; 四. 备注 由于我工作时间不长,见过的系统更有限,所以对系统架构几乎没有什么经验,这些只是我个人的一点很粗浅的理解,例如把dubbo做的那么重,虽然可扩展性提高了不少,但其实也不知道算不算合理,因为调用rpc服务,肯定会增加网络IO延时,所以这些算是我个人的抛砖引玉吧,一方面希望对同样和我一样没有经验的小伙伴能有所帮助,另一方面希望有经验的小伙伴能留言交流 五. 总结 以上便是我个人对拉勾一拍所有的核心系统进行了审视后的一番分析,如果这些核心系统架构的重构真的达到自己的理想状况这将是一番浩大的工程,对于高速发展的互联网公司来说,这就是一边驾驶者一辆高速前进的汽车,一边对这辆汽车进行换轮胎换发动机,先不说工作量的问题,难度程度也可见一斑。

October 23, 2016 · 1 min · 46 words · Bridge Li

Dubbo和zookeeper入门实例

公司项目里用到了dubbo,感觉挺好玩,以前没有玩过,自己抽时间就小小研究了一下,今天记录一下自己的学习成果。 关于Dubbo和zookeeper是干嘛的,网上一搜一大堆所以就不多做介绍了,想了解的可以自己搜搜看,今天就只记录怎么跑一个最基本的Dubbo和zookeeper小示例程序是怎么跑起来的,当然虽然是一个demo,但和真实环境也是无差的哦。 一. 安装zookeeper 要想使用Dubbo,必须给Dubbo一个注册中心,当然这个注册中心不一定必须是zookeeper,也可以是redis等,但用zookeeper是一个相对比较好的方式,咱们暂且就这么办。 关于zookeeper的安装,老夫窃以为这篇文章写得非常棒,就不多赘述了,大家可以直接参考:http://blog.csdn.net/wxwzy738/article/details/16330253,看了这篇文章,大家立马就会就明白怎么一回事了,看过自知。 二. Dubbo实现 Dubbo的实现肯定是要靠自己写代码啦,我的代码使用maven编译的,引入的jar文件如下: 依赖的jar文件 <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>dubbo</artifactId> <version>2.5.3</version> <exclusions> <exclusion> <artifactId>spring</artifactId> <groupId>org.springframework</groupId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>1.7.7</version> </dependency> <dependency> <groupId>com.101tec</groupId> <artifactId>zkclient</artifactId> <version>0.5</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>4.1.7.RELEASE</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>4.1.7.RELEASE</version> </dependency> 其中junit和spring-test大家肯定看出来是干嘛的了,为了跑测试,Dubbo分为生产者和消费者,接下来我们先看看生产者是怎么实现的 生产者的实现 ①. 配置文件applicationProvider.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:dubbo="http://code.alibabatech.com/schema/dubbo" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://code.alibabatech.com/schema/dubbo http://code.alibabatech.com/schema/dubbo/dubbo.xsd"> <!&#8211; Auto Scan &#8211;> <context:component-scan base-package="cn.bridgeli.provider" /> <!&#8211; Application name &#8211;> <dubbo:application name="hello-world-app" /> <!&#8211; registry address, used for service to register itself &#8211;> <dubbo:registry address="zookeeper://127.0.0.1:2181" /> <!&#8211; expose this service through dubbo protocol, through port 20880 &#8211;> <!&#8211; <dubbo:protocol name="dubbo" port="20880" /> <dubbo:protocol name="dubbo" port="9090" server="netty" client="netty" codec="dubbo" serialization="hessian2" charset="UTF-8" threadpool="fixed" threads="100" queues="0" iothreads="9" buffer="8192" accepts="1000" payload="8388608" /> &#8211;> <!&#8211; Service interface Concurrent Control &#8211;> <!&#8211; <dubbo:service interface="cn.bridgeli.provider.service.ProviderService" ref="providerService"/> &#8211;> <!&#8211; 扫描注解包路径,多个包用逗号分隔,不填pacakge表示扫描当前ApplicationContext中所有的类 &#8211;> <dubbo:annotation package="cn.bridgeli.provider.service" /> <!&#8211; Default Protocol &#8211;> <!&#8211; <dubbo:protocol server="netty" /> &#8211;> </beans> 注释很详细,不解释,就是dubbo和spring的集成 ...

July 26, 2015 · 3 min · 497 words · Bridge Li