基于 dubbo 的分布式架構

前言

現(xiàn)在越來越多的互聯(lián)網公司還是將自己公司的項目進行服務化,這確實是今后項目開發(fā)的一個趨勢,就這個點再憑借之前的?SSM?項目來讓第一次接觸的同學能快速上手。

淺談分布式架構

分布式架構 單看這個名字給人的感覺就是高逼格,但其實從歷史的角度來分析一下就比較明了了。

我們拿一個電商系統(tǒng)來說:

單系統(tǒng)

對于一個剛起步的創(chuàng)業(yè)公司項目肯定是追求越快完成功能越好,并且用戶量也不大。

這時候所有的業(yè)務邏輯都是在一個項目中就可以滿足。

垂直拆分-多應用

當業(yè)務量和用戶量發(fā)展到一定地步的時候,這時一般會將應用同時部署到幾臺服務器上,在用戶訪問的時候使用 Nginx 進行反向代理和簡單的負載均衡。

SOA服務化

當整個系統(tǒng)以及發(fā)展的足夠大的時候,比如一個電商系統(tǒng)中存在有:

用戶系統(tǒng)

訂單系統(tǒng)

支付系統(tǒng)

物流系統(tǒng)

等系統(tǒng)。

如果每次修改了其中一個系統(tǒng)就要重新發(fā)布上線的話那么耦合就太嚴重了。

所以需要將整個項目拆分成若干個獨立的應用,可以進行獨立的開發(fā)上線實現(xiàn)快速迭代。

如上圖所示每個應用之間相互獨立,每個應用可以消費其他應用暴露出來的服務,同時也對外提供服務。

從架構的層面簡單的理解了,接下來看看如何編碼實現(xiàn)。

基于dubbo的實現(xiàn)

dubbo 應該算是國內使用最多的分布式服務框架,基于此來實現(xiàn)對新入門的同學應該很有幫助。

其中有涉及到安裝dubbo服務的注冊中心zookeeper等相關知識點可以自行查看?官方文檔,這里就不單獨講了。

對外提供服務

首先第一步需要在 SSM-API 模塊中定義一個接口,這里就搞了一個用戶查詢的接口

/**

* Function:用戶API

*?@author?chenjiec

* Date: 2017/4/4 下午9:46

*?@since?JDK 1.7

*/

public?interface?UserInfoApi?{

/**

* 獲取用戶信息

*?@param?userId

*?@return

*?@throws?Exception

*/

public?UserInfoRsp getUserInfo(int userId) throws?Exception;

}

接著在 SSM-SERVICE 模塊中進行實現(xiàn):

import?com.alibaba.dubbo.config.annotation.Service;

/**

* Function:

*?@author?chenjiec

* Date: 2017/4/4 下午9:51

*?@since?JDK 1.7

*/

@Service

public?class?UserInfoApiImpl?implements?UserInfoApi?{

private?static?Logger logger = LoggerFactory.getLogger(UserInfoApiImpl.class);

@Autowired

private?T_userService t_userService ;

/**

* 獲取用戶信息

*

*?@param?userId

*?@return

*?@throws?Exception

*/

@Override

public?UserInfoRsp?getUserInfo(int?userId)?throws?Exception {

logger.info("用戶查詢Id="+userId);

//返回對象

UserInfoRsp userInfoRsp =?new?UserInfoRsp() ;

T_user t_user = t_userService.selectByPrimaryKey(userId) ;

//構建

buildUserInfoRsp(userInfoRsp,t_user) ;

return?userInfoRsp;

}

/**

* 構建返回

*?@param?userInfoRsp

*?@param?t_user

*/

private?void?buildUserInfoRsp(UserInfoRsp userInfoRsp, T_user t_user) {

if?(t_user ==?null){

t_user =?new?T_user() ;

}

CommonUtil.setLogValueModelToModel(t_user,userInfoRsp);

}

}

這些都是通用的代碼,但值得注意的一點是這里使用的 dubbo 框架所提供的 @service 注解。作用是聲明需要暴露的服務接口。

再之后就是幾個dubbo相關的配置文件了。

spring-dubbo-config.xml

<dubbo:application?name="ssm-service" owner="crossoverJie"

organization="ssm-crossoverJie" logger="slf4j"/>

<dubbo:registry?id="dubbo-registry" address="zookeeper://192.168.0.188:2181"

file="/tmp/dubbo.cachr" />

<dubbo:monitor?protocol="registry" />

<dubbo:protocol?name="dubbo" port="20880" />

<dubbo:provider?timeout="15000" retries="0" delay="-1" />

<dubbo:consumer?check="false" timeout="15000" />

其實就是配置我們服務注冊的zk地址,以及服務名稱、超時時間等配置。

spring-dubbo-provider.xml

annotation?package="com.crossoverJie.api.impl" />

這個配置掃描注解包的位置,一般配置到接口實現(xiàn)包即可。

spring-dubbo-consumer.xml

這個是消費者配置項,表明我們需要依賴的其他應用。

這里我們在 SSM-BOOT 項目中進行配置:

interface="com.crossoverJie.api.UserInfoApi" />

直接就是配置的剛才我們提供的那個用戶查詢的接口,這樣當我們自己的內部項目需要使用到這個服務只需要依賴 SSM-BOOT 即可,不需要單獨的再去配置 consumer 。這個我有在上一篇?SSM(十) 項目重構-互聯(lián)網項目的Maven結構?中也有提到。

安裝管理控制臺

還有一個需要做的就是安裝管理控制臺,這里可以看到我們有多少服務、調用情況是怎么樣等作用。

這里我們可以將dubbo的官方源碼下載下來,對其中的 dubbo-admin 模塊進行打包,將生成的 WAR包 放到 Tomcat 中運行起來即可。

但是需要注意一點的是:

需要將其中的 dubbo.properties 的zk地址修改為自己的即可。

dubbo.registry.address=zookeeper://127.0.0.1:2181

dubbo.admin.root.password=root

dubbo.admin.guest.password=guest

到時候登陸的話使用root,密碼也是root。

使用guest,密碼也是guest。

登陸界面如下圖:

其中我們可以看到有兩個服務以及注冊上去了,但是沒有消費者。

消費服務

為了能夠更直觀的體驗到消費服務,我新建了一個項目:

https://github.com/crossoverJie/SSM-CONSUMER?。

其中在 SSM-CONSUMER-API 中我也定義了一個接口:

/**

* Function:薪資API

*?@author?chenjiec

* Date: 2017/4/4 下午9:46

*?@since?JDK 1.7

*/

public?interface?SalaryInfoApi?{

/**

* 獲取薪資

*?@param?userId

*?@return

*?@throws?Exception

*/

public?SalaryInfoRsp getSalaryInfo(int userId) throws?Exception;

}

因為作為消費者的同時我們也對外提供了一個獲取薪資的一個服務。

在 SSM-CONSUMER-SERVICE 模塊中進行了實現(xiàn):

/**

* Function:

*?@author?chenjiec

* Date: 2017/4/4 下午9:51

*?@since?JDK 1.7

*/

@Service

public?class?SalaryInfoApiImpl?implements?SalaryInfoApi?{

private?static?Logger logger = LoggerFactory.getLogger(SalaryInfoApiImpl.class);

@Autowired

UserInfoApi userInfoApi ;

/**

* 獲取用戶信息

*

*?@param?userId

*?@return

*?@throws?Exception

*/

@Override

public?SalaryInfoRsp?getSalaryInfo(int?userId)?throws?Exception {

logger.info("薪資查詢Id="+userId);

//返回對象

SalaryInfoRsp salaryInfoRsp =?new?SalaryInfoRsp() ;

//調用遠程服務

UserInfoRsp userInfo = userInfoApi.getUserInfo(userId);

salaryInfoRsp.setUsername(userInfo.getUserName());

return?salaryInfoRsp;

}

}

其中就可以直接使用 userInfoApi 調用之前的個人信息服務。

再調用之前需要注意的有點是,我們只需要依賴 SSM-BOOT 這個模塊即可進行調用,因為 SSM-BOOT 模塊已經為我們配置了消費者之類的操作了:

<dependency>

<groupId>com.crossoverJiegroupId>

<artifactId>SSM-BOOTartifactId>

dependency>

還有一點是在配置 SSM-BOOT 中的 spring-dubbo-cosumer.xml 配置文件的時候,路徑要和我們初始化spring配置文件時的路徑一致:


<context-param>

<param-name>contextConfigLocationparam-name>

<param-value>classpath*:spring/*.xmlparam-value>

context-param>

接下來跑個單測試一下能否調通:

/**

* Function:

*

*?@author?chenjiec

* Date: 2017/4/5 下午10:41

*?@since?JDK 1.7

*/

@RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration(locations = { "classpath*:/spring/*.xml" })

public?class?SalaryInfoApiImplTest?{

@Autowired

private?SalaryInfoApi salaryInfoApi ;

@Test

public?void getSalaryInfo() throws Exception {

SalaryInfoRsp salaryInfo = salaryInfoApi.getSalaryInfo(1);

System.out.println(JSON.toJSONString(salaryInfo));

}

}

消費者

提供者

可以看到確實是調用成功了的。

接下來將消費者項目也同時啟動在來觀察管理控制臺有什么不一樣:

會看到多了一個消費者所提供的服務 com.crossoverjie.consumer.api.SalaryInfoApi ,同時

com.crossoverJie.api.UserInfoApi 服務已經正常,說明已經有消費者了。

點進去便可查看具體的消費者。

總結

這樣一個基于dubbo的分布式服務已經講的差不多了,在實際的開發(fā)中我們便會開發(fā)一個大系統(tǒng)中的某一個子應用,這樣就算一個子應用出問題了也不會影響到整個大的項目。

再提一點:

在實際的生產環(huán)境一般同一個服務我們都會有一個 master , slave 的主從服務,這樣在上線的過程中不至于整個應用出現(xiàn)無法使用的尷尬情況。

談到了 SOA 的好處,那么自然也有相對于傳統(tǒng)模式的不方便之處:

Jenkins

elk

以上就是我理解的,如有差錯歡迎指正。

如果想學習Java工程化、高性能及分布式、深入淺出。微服務、Spring,MyBatis,Netty源碼分析的朋友可以加我的Java進階群:617434785,群里有阿里大牛直播講解技術,以及Java大型互聯(lián)網技術的視頻免費分享給大家。

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容