基於 dubbo 的分布式架構


dubbo.jpg

前言

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

淺談分布式架構

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

我們拿一個電商系統來說:

單系統

E65B5547-AF84-4D31-836D-72892C7AC7EA.png
對於一個剛起步的創業公司項目肯定是追求越快完成功能越好,並且用戶量也不大。

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

垂直拆分-多應用

QQ20170406-230056@2x.jpg
當業務量和用戶量發展到一定地步的時候,這時一般會將應用同時部署到幾台服務器上,在用戶訪問的時候使用Nginx進行反向代理和簡單的負載均衡。

SOA服務化

當整個系統以及發展的足夠大的時候,比如一個電商系統中存在有:

  • 用戶系統
  • 訂單系統
  • 支付系統
  • 物流系統

等系統。
如果每次修改了其中一個系統就要重新發布上線的話那么耦合就太嚴重了。

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

dubbo.png

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

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

基於dubbo的實現

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

其中有涉及到安裝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模塊中進行實現:

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

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

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

spring-dubbo-consumer.xml

這個是消費者配置項,表明我們需要依賴的其他應用。
這里我們在SSM-BOOT項目中進行配置:

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

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

登陸界面如下圖:
QQ20170407-001924@2x.jpg

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

消費服務

為了能夠更直觀的體驗到消費服務,我新建了一個項目:
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模塊中進行了實現:

/**
 * 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.crossoverJie</groupId>
            <artifactId>SSM-BOOT</artifactId>
        </dependency>

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

    <!-- Spring和mybatis的配置文件 -->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath*:spring/*.xml</param-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));
    }

}

消費者.jpg
消費者

提供者.jpg
提供者
可以看到確實是調用成功了的。

接下來將消費者項目也同時啟動在來觀察管理控制台有什么不一樣:
QQ20170407-003413@2x.jpg
會看到多了一個消費者所提供的服務com.crossoverjie.consumer.api.SalaryInfoApi,同時
com.crossoverJie.api.UserInfoApi服務已經正常,說明已經有消費者了。

QQ20170407-003456@2x.jpg
點進去便可查看具體的消費者。

總結

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

再提一點:
在實際的生產環境一般同一個服務我們都會有一個master,slave的主從服務,這樣在上線的過程中不至於整個應用出現無法使用的尷尬情況。

談到了SOA的好處,那么自然也有相對於傳統模式的不方便之處:

  • 拆分一個大的項目為成百上千的子應用就不可能手動上線了,即需要自動化的部署上線,如Jenkins
  • 還有一個需要做到的就是監控,需要一個單獨的監控平台來幫我們實時查看各個服務的運行情況以便於及時定位和解決問題。
  • 日志查看分析,拆分之后不可能再去每台服務器上查看日志,需要一個單獨的日志查看分析工具如elk

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

項目地址:https://github.com/crossoverJie/SSM.git

個人博客地址:http://crossoverjie.top

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM