1. 程式人生 > >motan+zookeeper搭建rpc服務

motan+zookeeper搭建rpc服務

服務提供者

服務端的配置

<?xml version="1.0" encoding="UTF-8"?>
<!--suppress SpringFacetInspection -->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:motan="http://api.weibo.com/schema/motan"
       xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://api.weibo.com/schema/motan http://api.weibo.com/schema/motan.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"
>
<!-- enable autowire --> <context:annotation-config/> <!--motan服務配置--> <bean id="empService" class="com.per.service.impl.EmpServiceImpl"/> <motan:service interface="com.per.service.EmpService" ref="empService" export="demoMotan:8520" basicService="serviceBasicConfig"
/>
<!-- 註冊中心配置 使用不同註冊中心需要依賴對應的jar包。如果不使用註冊中心,可以把check屬性改為false,忽略註冊失敗。--> <motan:registry regProtocol="zookeeper" name="zkRegistry" address="127.0.0.1:2181"/> <!-- 協議配置。為防止多個業務配置衝突,推薦使用id表示具體協議。--> <motan:protocol id="demoMotan" default="true" name="motan" maxServerConnection="80000" maxContentLength="10485760" maxWorkerThread="800" minWorkerThread="20"/> <!-- 通用配置,多個rpc服務使用相同的基礎配置. group和module定義具體的服務池。export格式為“protocol id:提供服務的埠”--> <motan:basicService export="demoMotan:8520" group="demo-emp-rpc" accessLog="false" shareChannel="true" module="emp-rpc" application="myMotanDemo" registry="zkRegistry" id="serviceBasicConfig"/> </beans>

定義服務介面

package com.per.service;

import com.per.domain.Emp;

import java.util.List;

public interface EmpService {

    public List<Emp> getAllEmp();

    public Emp getEmpById(Integer id);

    public Integer addEmp(Emp emp);

    public Integer deleteEmp(Emp emp);

    public Integer updateEmp(Emp emp);
}

定義domain,要實現Serializable介面

package com.per.domain;

import com.alibaba.fastjson.annotation.JSONField;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.beetl.sql.core.annotatoin.AutoID;
import org.beetl.sql.core.annotatoin.Table;

import java.io.Serializable;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "emp")
public class Emp implements Serializable {

    @AutoID
    private Integer id;

    private String name;

    @JSONField(name = "dept_id")
    private Integer deptId;
}

服務提供者實現service介面

package com.per.service.impl;

import com.per.dao.EmpDao;
import com.per.domain.Emp;
import com.per.service.EmpService;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;

public class EmpServiceImpl implements EmpService {

    @Autowired
    private EmpDao empDao;

    @Override
    public List<Emp> getAllEmp() {
        System.out.println("getAllEmp");
        List<Emp> list = empDao.all();
        System.out.println(list);
        return list;
    }

    @Override
    public Emp getEmpById(Integer id) {
        System.out.println("server1 id = " + id);
        return empDao.createLambdaQuery().andEq(Emp::getId, id).single();
    }

    ......

實現兩個服務提供者,另一個的配置的埠改為8521

<?xml version="1.0" encoding="UTF-8"?>
<!--suppress SpringFacetInspection -->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:motan="http://api.weibo.com/schema/motan"
       xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://api.weibo.com/schema/motan http://api.weibo.com/schema/motan.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">

    <!-- enable autowire -->
    <context:annotation-config/>

    <!--motan服務配置-->
    <bean id="empService" class="com.per.service.impl.EmpServiceImpl"/>
    <motan:service interface="com.per.service.EmpService" ref="empService" export="demoMotan:8521" basicService="serviceBasicConfig"/>
    <!-- 註冊中心配置 使用不同註冊中心需要依賴對應的jar包。如果不使用註冊中心,可以把check屬性改為false,忽略註冊失敗。-->
    <motan:registry regProtocol="zookeeper" name="zkRegistry" address="127.0.0.1:2181"/>

    <!-- 協議配置。為防止多個業務配置衝突,推薦使用id表示具體協議。-->
    <motan:protocol id="demoMotan" default="true" name="motan"
                    maxServerConnection="80000" maxContentLength="10485760"
                    maxWorkerThread="800" minWorkerThread="20"/>

    <!-- 通用配置,多個rpc服務使用相同的基礎配置. group和module定義具體的服務池。export格式為“protocol id:提供服務的埠”-->
    <motan:basicService export="demoMotan:8521"
                        group="demo-emp-rpc" accessLog="false" shareChannel="true" module="emp-rpc"
                        application="myMotanDemo" registry="zkRegistry" id="serviceBasicConfig"/>

</beans>

用springboot啟動,motan可能有bug,要加上MotanSwitcherUtil.setSwitcherValue(MotanConstants.REGISTRY_HEARTBEAT_SWITCHER, true);後才能正常提供服務。

public static void main(String[] args) {
        new ClassPathXmlApplicationContext("application.xml");
        MotanSwitcherUtil.setSwitcherValue(MotanConstants.REGISTRY_HEARTBEAT_SWITCHER, true);
        System.out.println("server1 start!!!!");
    }

客戶端

客戶端的配置,負載均衡配置為activeWeight

<?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:motan="http://api.weibo.com/schema/motan"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://api.weibo.com/schema/motan http://api.weibo.com/schema/motan.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

    <!--enabled autowired-->
    <context:annotation-config/>

    <!-- 註冊中心配置 -->
    <!--<motan:registry regProtocol="zookeeper" name="registry" address="192.168.2.239:2181"/>-->
    <motan:registry regProtocol="zookeeper" name="zkRegistry" address="127.0.0.1:2181"/>

    <!-- motan協議配置 -->
    <motan:protocol default="true" name="motan" haStrategy="failover"
                    loadbalance="activeWeight" maxClientConnection="10" minClientConnection="1"/>

    <!-- 通用referer基礎配置 -->
    <motan:basicReferer requestTimeout="200" accessLog="false"
                        retries="2" group="demo-emp-rpc" module="emp-rpc"
                        application="myMotanDemo" protocol="motan" registry="zkRegistry"
                        id="basicReferer" throwException="false" check="true"/>

    <motan:referer id="empService" interface="com.per.service.EmpService"
                   connectTimeout="20000" requestTimeout="20000" basicReferer="basicReferer"/>
</beans>

客戶端同樣匯入service介面,路徑要與服務提供者一致

package com.per.service;

import com.per.domain.Emp;

import java.util.List;

public interface EmpService {

    public List<Emp> getAllEmp();

    public Emp getEmpById(Integer id);

    public Integer addEmp(Emp emp);

    public Integer deleteEmp(Emp emp);

    public Integer updateEmp(Emp emp);
}

啟動客戶端

public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:motan-client.xml");
        EmpService empService = (EmpService) applicationContext.getBean("empService");
        System.out.println("client start...");
        for (int i = 0; i < 10; i++) {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(empService.getEmpById(1));
        }

        System.out.println("end...");
    }

執行結果

客戶端執行結果
在這裡插入圖片描述
服務提供者1的執行結果
在這裡插入圖片描述
服務提供者2的執行結果
在這裡插入圖片描述
修改負載均衡策略為consistent

<motan:protocol default="true" name="motan" haStrategy="failover"
                    loadbalance="consistent" maxClientConnection="10" minClientConnection="1"/>

服務提供者1的執行結果為
在這裡插入圖片描述
服務提供者2的執行結果為空
在這裡插入圖片描述
剩下的負載均衡策略請自行測試。

負載均衡策略有

  1. ActiveWeight(預設)
    低併發度優先: referer 的某時刻的 call 數越小優先順序越高
    由於 Referer List 可能很多,比如上百臺,如果每次都要從這上百個 Referer 或者最低併發的幾個,效能有些損耗,因此 random.nextInt(list.size()) 獲取一個起始的 index,然後獲取最多不超過 MAX_REFERER_COUNT 的狀態是 isAvailable 的 referer 進行判斷 activeCount.
  2. Random:
    隨機選擇。在一個截面上碰撞的概率高,但呼叫量越大分佈越均勻,而且按概率使用權重後也比較均勻,有利於動態調整提供者權重。
  3. RoundRobin
    輪循選擇,呼叫比較均勻
  4. LocalFirst
    本地服務優先獲取策略,對referers根據ip順序查詢本地服務,多存在多個本地服務,獲取Active最小的本地服務進行服務。
    當不存在本地服務,但是存在遠端RPC服務,則根據ActivWeight獲取遠端RPC服務
    當兩者都存在,所有本地服務都應優先於遠端服務,本地RPC服務與遠端RPC服務內部則根據ActiveWeight進行
  5. Consistent
    一致性 Hash,相同引數的請求總是發到同一提供者
  6. ConfigurableWeight
    權重可配置的負載均衡策略