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
    权重可配置的负载均衡策略

猜你喜欢

转载自blog.csdn.net/qq_25627105/article/details/83894216