生产环境中,往往生产者和消费者都是多个,消费者需要从服务列表中挑选一个生产者进行消费,进而有了微服务环境中的一个特性负载均衡。RPC框架基本都支持负载均衡,duboo这方面做的很优秀,框架内部就支持了多种负载均衡策略。接下来,我们来介绍下负载均衡在grpc里的设计和思考。相信大家肯定在其中有所收获。
syntax = "proto3";//标识 proto版本 建议使用proto3
package casservice;//proto包名 避免命名冲突,也可以作为引入其他proto文件时使用
option java_package = "com.example.casservice" ;//生成的类将带有此包名,不指定则使用package
option cc_generic_services = true;
option go_package = "./pb";
option java_outer_classname = "CasServicePbEntity";
message CasLoginReq{
string userName = 1;
string password = 2;
}
message CasLoginRes{
string uid = 1;
string sex = 2;
}
service CasService {
rpc casLogin(CasLoginReq) returns (CasLoginRes);
}
package com.example.casservice.impl;
import com.example.casservice.CasServiceGrpc;
import com.example.casservice.CasServicePbEntity;
import io.grpc.stub.StreamObserver;
import java.util.UUID;
public class CasServiceImpl extends CasServiceGrpc.CasServiceImplBase {
public CasServiceImpl(Integer port) {
this.port = port;
}
private Integer port = 0 ;
@Override
public void casLogin(CasServicePbEntity.CasLoginReq request, StreamObserver<CasServicePbEntity.CasLoginRes> responseObserver) {
System.out.println("port:"+port+"登录请求,用户名:"+request.getUserName()+"\\t密码:"+request.getPassword());
responseObserver.onNext(CasServicePbEntity.CasLoginRes.newBuilder()
.setUid("port:"+port+"\\t"+UUID.randomUUID().toString().replaceAll("-",""))
.setSex("男").build());
responseObserver.onCompleted();
}
}
package com.example.casservice;
import com.example.casservice.impl.CasServiceImpl;
import com.google.common.collect.Lists;
import io.grpc.Server;
import io.grpc.ServerBuilder;
import java.io.IOException;
import java.util.List;
public class App {
public static void main(String[] args) throws IOException, InterruptedException {
List<Integer> ports = Lists.newArrayList();
List<Server> servers = Lists.newArrayList();
ports.add(10084);
ports.add(10085);
for (Integer port : ports) {
System.out.println(port + "启动成功...");
CasServiceImpl casService = new CasServiceImpl(port);
Server server = ServerBuilder.forPort(port).addService(casService)
.build();
server.start();
servers.add(server);
}
for (Server server : servers) {
server.awaitTermination();
}
}
}
package com.example.casservice.resolve;
import com.google.common.collect.Lists;
import io.grpc.EquivalentAddressGroup;
import io.grpc.NameResolver;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import io.grpc.Attributes;
public class CustomNameResolver extends NameResolver {
private final String path;
private Listener2 listener;
public CustomNameResolver(String path) {
this.path = path;
}
@Override
public String getServiceAuthority() {
return this.path;
}
@Override
public void shutdown() {
}
@Override
public void start(Listener2 listener) {
this.listener = listener;
this.resolve();
}
private void resolve() {
List<SocketAddress> socketAddressList = getAddressList(path).stream()
.map(this::toSocketAddress)
.collect(Collectors.toList());
List<EquivalentAddressGroup> equivalentAddressGroups = Lists.newArrayList();
for (SocketAddress socketAddress : socketAddressList) {
EquivalentAddressGroup equivalentAddressGroup = new EquivalentAddressGroup(socketAddress);
equivalentAddressGroups.add(equivalentAddressGroup);
}
ResolutionResult resolutionResult = ResolutionResult.newBuilder()
.setAddresses(equivalentAddressGroups)
.setAttributes(Attributes.EMPTY)
.build();
this.listener.onResult(resolutionResult);
}
private SocketAddress toSocketAddress(InetSocketAddress address) {
return new InetSocketAddress(address.getHostName(), address.getPort());
}
private List<InetSocketAddress> getAddressList(String path) {
System.out.println("path:"+path);
InetSocketAddress inetSocketAddress = new InetSocketAddress("localhost", 10084);
InetSocketAddress inetSocketAddress2 = new InetSocketAddress("localhost", 10085);
return Arrays.asList(inetSocketAddress, inetSocketAddress2);
}
}
package com.example.casservice.resolve;
import io.grpc.NameResolver;
import io.grpc.NameResolverProvider;
import java.net.URI;
public class CustomNameResolverProvider extends NameResolverProvider {
public CustomNameResolverProvider() {
}
@Override
public NameResolver newNameResolver(URI targetUri, NameResolver.Args args) {
return new CustomNameResolver(targetUri.getPath());
}
@Override
protected boolean isAvailable() {
return true;
}
@Override
protected int priority() {
return 10;
}
@Override
public String getDefaultScheme() {
return "example";
}
}
使用 **round_robin、**
pick_first
轮询的方式请求 发起二十次请求package com.example.casservice;
import com.example.casservice.resolve.CustomNameResolverProvider;
import io.grpc.*;
public class App {
public static void main(String[] args) {
NameResolverRegistry.getDefaultRegistry().register(new CustomNameResolverProvider());
ManagedChannel channel = ManagedChannelBuilder.forTarget("example:///lb.example.grpc.io")
.defaultLoadBalancingPolicy("pick_first")
.usePlaintext()
.build();
CasServiceGrpc.CasServiceBlockingStub casServiceBlockingStub = CasServiceGrpc.newBlockingStub(channel);
System.out.println("==== Calling with pick_first ====");
for (int i = 0; i < 20; i++) {
CasServicePbEntity.CasLoginRes casLoginRes =casServiceBlockingStub.casLogin(CasServicePbEntity.CasLoginReq.newBuilder()
.setUserName("java_test")
.setPassword("test_password").build());
System.out.println("casLoginRes,uid:"+casLoginRes.getUid()+"性别:\\t"+casLoginRes.getSex());
}
System.out.println("==== Calling with round_robin ====");
ManagedChannel channel2 = ManagedChannelBuilder.forTarget("example:///lb.example.grpc.io")
.defaultLoadBalancingPolicy("round_robin")
.usePlaintext()
.build();
CasServiceGrpc.CasServiceBlockingStub casServiceBlockingStub2 = CasServiceGrpc.newBlockingStub(channel2);
for (int i = 0; i < 20; i++) {
CasServicePbEntity.CasLoginRes casLoginRes =casServiceBlockingStub2.casLogin(CasServicePbEntity.CasLoginReq.newBuilder()
.setUserName("java_test2")
.setPassword("test_password2").build());
System.out.println("casLoginRes,uid:"+casLoginRes.getUid()+"性别:\\t"+casLoginRes.getSex());
}
}
}
==== Calling with pick_first ====
path:/lb.example.grpc.io
casLoginRes,uid:port:10084 441f1ce54214475cb366982e3e0fd726性别: 男
casLoginRes,uid:port:10084 a4cfed898db64706a18507983d8589d6性别: 男
casLoginRes,uid:port:10084 a04fb2b71944440b8ed00f02bdc3b15f性别: 男
casLoginRes,uid:port:10084 2b2668b2f1ad472ab35729708f0959d3性别: 男
casLoginRes,uid:port:10084 1fa78e4526c24daf9c6d9779d1626ca9性别: 男
casLoginRes,uid:port:10084 826faf498afc4e1ba65db18a1eb0ccf4性别: 男
casLoginRes,uid:port:10084 c9c992e0b4954b9a9f1e94022c8a65ca性别: 男
casLoginRes,uid:port:10084 08b52ac7e444450c9aaad323d255b168性别: 男
casLoginRes,uid:port:10084 9cde040761cb4de993f3fbc95e9299e3性别: 男
casLoginRes,uid:port:10084 d8aa79dbcd094c0f918b219ba3cbb7a2性别: 男
casLoginRes,uid:port:10084 78575fcb8e2f40cab1a3085e7d609c1f性别: 男
casLoginRes,uid:port:10084 c1863d7b914045d6b339a5be8770b215性别: 男
casLoginRes,uid:port:10084 80bd8a2a1a444ade901c849a7e338e63性别: 男
casLoginRes,uid:port:10084 5e37a848792a41dab612b13089677771性别: 男
casLoginRes,uid:port:10084 1674a08cdcc64b4882805038485742d5性别: 男
casLoginRes,uid:port:10084 192055f9ebfd4a1db03679cc875560c6性别: 男
casLoginRes,uid:port:10084 63d611cab7884ff7b3e5e21073fc6164性别: 男
casLoginRes,uid:port:10084 d2d7ca2e4122428a8d134160e47938e9性别: 男
casLoginRes,uid:port:10084 6e924aae0c3e44348dce641c06652440性别: 男
casLoginRes,uid:port:10084 91a9dd7f159e49a0948ce30c4fb1ecf2性别: 男
==== Calling with round_robin ====
path:/lb.example.grpc.io
casLoginRes,uid:port:10085 f3d4133b24ac4ab1ae2afac4078e46e7性别: 男
casLoginRes,uid:port:10084 075838a14fdc4626a07892d3701c30ce性别: 男
casLoginRes,uid:port:10085 a627d8c99a2b4b1185e5414565142611性别: 男
casLoginRes,uid:port:10084 58cca91d354b4688807674278cda539e性别: 男
casLoginRes,uid:port:10085 3be7bcd4a43247b4b889feb4daf8724f性别: 男
casLoginRes,uid:port:10084 b7ff85a74db44736804234bc20e1feb8性别: 男
casLoginRes,uid:port:10085 ba0028287c0c4a62b2854c25c1344120性别: 男
casLoginRes,uid:port:10084 f6a045814e2149e9833ae644d563c87b性别: 男
casLoginRes,uid:port:10085 0596a4fc0b644d5a9e734ec9262abf7f性别: 男
casLoginRes,uid:port:10084 574ff946c98547e7a23d30dd9905d9fa性别: 男
casLoginRes,uid:port:10085 b7d6a68b5e344310ae133b11a2b6635e性别: 男
casLoginRes,uid:port:10084 9ab058a644fd45eb9ea90fbb7df0b575性别: 男
casLoginRes,uid:port:10085 1153074d7626465d96ef041dafa55bb3性别: 男
casLoginRes,uid:port:10084 b00ddaec91cd40a1abe9cd83a39bd5ef性别: 男
casLoginRes,uid:port:10085 840417637b264cefb34b284ce55daa65性别: 男
casLoginRes,uid:port:10084 d033dba7c8fb49cdacbe4ae7bd91c714性别: 男
casLoginRes,uid:port:10085 7ccdd8f59a4f448a91df00dff15ac258性别: 男
casLoginRes,uid:port:10084 e6042be3517e47f9a95257507d1aa66c性别: 男
casLoginRes,uid:port:10085 8bf6183990c2449cb7e58f11534e4211性别: 男
casLoginRes,uid:port:10084 54788c7324ce45eb88339c14f03c9be2性别: 男