服务提供者
服务端的配置
<?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>
server程序启动后,需要显式调用心跳开关,注册到zookeeper。
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的运行结果为空
剩下的负载均衡策略请自行测试。
负载均衡策略有
- ActiveWeight(缺省)
低并发度优先: referer 的某时刻的 call 数越小优先级越高
由于 Referer List 可能很多,比如上百台,如果每次都要从这上百个 Referer 或者最低并发的几个,性能有些损耗,因此 random.nextInt(list.size()) 获取一个起始的 index,然后获取最多不超过 MAX_REFERER_COUNT 的状态是 isAvailable 的 referer 进行判断 activeCount. - Random:
随机选择。在一个截面上碰撞的概率高,但调用量越大分布越均匀,而且按概率使用权重后也比较均匀,有利于动态调整提供者权重。 - RoundRobin
轮循选择,调用比较均匀 - LocalFirst
本地服务优先获取策略,对referers根据ip顺序查找本地服务,多存在多个本地服务,获取Active最小的本地服务进行服务。
当不存在本地服务,但是存在远程RPC服务,则根据ActivWeight获取远程RPC服务
当两者都存在,所有本地服务都应优先于远程服务,本地RPC服务与远程RPC服务内部则根据ActiveWeight进行 - Consistent
一致性 Hash,相同参数的请求总是发到同一提供者 - ConfigurableWeight
权重可配置的负载均衡策略