SSM(十一) 基于 dubbo 的分布式架構(gòu)

dubbo.jpg
dubbo.jpg

前言

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

淺談分布式架構(gòu)

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

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

單系統(tǒng)

E65B5547-AF84-4D31-836D-72892C7AC7EA.png
E65B5547-AF84-4D31-836D-72892C7AC7EA.png

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

這時(shí)候所有的業(yè)務(wù)邏輯都是在一個(gè)項(xiàng)目中就可以滿足。

垂直拆分-多應(yīng)用

QQ20170406-230056@2x.jpg
QQ20170406-230056@2x.jpg

當(dāng)業(yè)務(wù)量和用戶量發(fā)展到一定地步的時(shí)候,這時(shí)一般會(huì)將應(yīng)用同時(shí)部署到幾臺(tái)服務(wù)器上,在用戶訪問的時(shí)候使用Nginx進(jìn)行反向代理和簡單的負(fù)載均衡。

SOA服務(wù)化

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

  • 用戶系統(tǒng)
  • 訂單系統(tǒng)
  • 支付系統(tǒng)
  • 物流系統(tǒng)

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

所以需要將整個(gè)項(xiàng)目拆分成若干個(gè)獨(dú)立的應(yīng)用,可以進(jìn)行獨(dú)立的開發(fā)上線實(shí)現(xiàn)快速迭代。

dubbo.png
dubbo.png

如上圖所示每個(gè)應(yīng)用之間相互獨(dú)立,每個(gè)應(yīng)用可以消費(fèi)其他應(yīng)用暴露出來的服務(wù),同時(shí)也對(duì)外提供服務(wù)。

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

基于dubbo的實(shí)現(xiàn)

dubbo應(yīng)該算是國內(nèi)使用最多的分布式服務(wù)框架,基于此來實(shí)現(xiàn)對(duì)新入門的同學(xué)應(yīng)該很有幫助。

其中有涉及到安裝dubbo服務(wù)的注冊中心zookeeper等相關(guān)知識(shí)點(diǎn)可以自行查看官方文檔,這里就不單獨(dú)講了。

對(duì)外提供服務(wù)

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

/**
 * 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模塊中進(jìn)行實(shí)現(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);

        //返回對(duì)象
        UserInfoRsp userInfoRsp = new UserInfoRsp() ;
        T_user t_user = t_userService.selectByPrimaryKey(userId) ;

        //構(gòu)建
        buildUserInfoRsp(userInfoRsp,t_user) ;

        return userInfoRsp;
    }


    /**
     * 構(gòu)建返回
     * @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);
    }
}

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

再之后就是幾個(gè)dubbo相關(guān)的配置文件了。

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" />

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

spring-dubbo-provider.xml

<dubbo:annotation package="com.crossoverJie.api.impl" />

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

spring-dubbo-consumer.xml

這個(gè)是消費(fèi)者配置項(xiàng),表明我們需要依賴的其他應(yīng)用。
這里我們在SSM-BOOT項(xiàng)目中進(jìn)行配置:

<dubbo:reference id="userInfoApi"
        interface="com.crossoverJie.api.UserInfoApi" />

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

安裝管理控制臺(tái)

還有一個(gè)需要做的就是安裝管理控制臺(tái),這里可以看到我們有多少服務(wù)、調(diào)用情況是怎么樣等作用。

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

但是需要注意一點(diǎn)的是:
需要將其中的dubbo.properties的zk地址修改為自己的即可。

dubbo.registry.address=zookeeper://127.0.0.1:2181
dubbo.admin.root.password=root
dubbo.admin.guest.password=guest

到時(shí)候登陸的話使用root,密碼也是root。
使用guest,密碼也是guest。

登陸界面如下圖:


QQ20170407-001924@2x.jpg
QQ20170407-001924@2x.jpg

其中我們可以看到有兩個(gè)服務(wù)以及注冊上去了,但是沒有消費(fèi)者。

消費(fèi)服務(wù)

為了能夠更直觀的體驗(yàn)到消費(fèi)服務(wù),我新建了一個(gè)項(xiàng)目:
https://github.com/crossoverJie/SSM-CONSUMER

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

/**
 * 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;
}

因?yàn)樽鳛橄M(fèi)者的同時(shí)我們也對(duì)外提供了一個(gè)獲取薪資的一個(gè)服務(wù)。

SSM-CONSUMER-SERVICE模塊中進(jìn)行了實(shí)現(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);

        //返回對(duì)象
        SalaryInfoRsp salaryInfoRsp = new SalaryInfoRsp() ;
        
        //調(diào)用遠(yuǎn)程服務(wù)
        UserInfoRsp userInfo = userInfoApi.getUserInfo(userId);
        
        salaryInfoRsp.setUsername(userInfo.getUserName());

        return salaryInfoRsp;
    }


}

其中就可以直接使用userInfoApi調(diào)用之前的個(gè)人信息服務(wù)。

再調(diào)用之前需要注意的有點(diǎn)是,我們只需要依賴SSM-BOOT這個(gè)模塊即可進(jìn)行調(diào)用,因?yàn)?code>SSM-BOOT模塊已經(jīng)為我們配置了消費(fèi)者之類的操作了:

        <dependency>
            <groupId>com.crossoverJie</groupId>
            <artifactId>SSM-BOOT</artifactId>
        </dependency>

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

QQ20170407-005850@2x.jpg
QQ20170407-005850@2x.jpg

    <!-- Spring和mybatis的配置文件 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:spring/*.xml</param-value>
    </context-param>

接下來跑個(gè)單測試一下能否調(diào)通:

/**
 * 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));
    }

}
消費(fèi)者.jpg
消費(fèi)者.jpg

消費(fèi)者

提供者.jpg
提供者.jpg

提供者
可以看到確實(shí)是調(diào)用成功了的。

接下來將消費(fèi)者項(xiàng)目也同時(shí)啟動(dòng)在來觀察管理控制臺(tái)有什么不一樣:

QQ20170407-003413@2x.jpg
QQ20170407-003413@2x.jpg

會(huì)看到多了一個(gè)消費(fèi)者所提供的服務(wù)com.crossoverjie.consumer.api.SalaryInfoApi,同時(shí)
com.crossoverJie.api.UserInfoApi服務(wù)已經(jīng)正常,說明已經(jīng)有消費(fèi)者了。

QQ20170407-003456@2x.jpg
QQ20170407-003456@2x.jpg

點(diǎn)進(jìn)去便可查看具體的消費(fèi)者。

總結(jié)

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

再提一點(diǎn):
在實(shí)際的生產(chǎn)環(huán)境一般同一個(gè)服務(wù)我們都會(huì)有一個(gè)master,slave的主從服務(wù),這樣在上線的過程中不至于整個(gè)應(yīng)用出現(xiàn)無法使用的尷尬情況。

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

  • 拆分一個(gè)大的項(xiàng)目為成百上千的子應(yīng)用就不可能手動(dòng)上線了,即需要自動(dòng)化的部署上線,如Jenkins
  • 還有一個(gè)需要做到的就是監(jiān)控,需要一個(gè)單獨(dú)的監(jiān)控平臺(tái)來幫我們實(shí)時(shí)查看各個(gè)服務(wù)的運(yùn)行情況以便于及時(shí)定位和解決問題。
  • 日志查看分析,拆分之后不可能再去每臺(tái)服務(wù)器上查看日志,需要一個(gè)單獨(dú)的日志查看分析工具如elk

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

項(xiàng)目地址:https://github.com/crossoverJie/SSM.git

個(gè)人博客地址:http://crossoverjie.top

GitHub地址:https://github.com/crossoverJie

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

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 134,886評(píng)論 18 139
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,946評(píng)論 6 342
  • 文//夏玫小墨 夏天來了,夏天真的來了,時(shí)間總是過得這么讓人不由得感嘆時(shí)間都去了哪里,它卻偷偷地在我們指尖劃過,速...
    夏玫小墨閱讀 324評(píng)論 4 5
  • 隨著最近《小別離》的熱播,關(guān)于出國這個(gè)話題又被熱炒。關(guān)于是否有出國的必要暫時(shí)這里就先不討論,咱們討論的是出國是要花...
    時(shí)光星語閱讀 437評(píng)論 0 0
  • 每個(gè)胖子都有一顆奔跑的心。他們只是跑的慢,并沒有放棄。相信堅(jiān)持的力量,時(shí)間會(huì)給你一切你想要的。 2015年的我是9...
    有干貨也有故事的CCC閱讀 2,538評(píng)論 14 45