Java Grpc实例创建负载均衡详解

网友投稿 542 2022-12-11


Java Grpc实例创建负载均衡详解

Grpc是googe开发的,是一款语言中立、平台中立、开源的远程过程调用(RPC)系统。新公司的项目服务之间的调用使用的Grpc来实现服务间的调用,这边一开始接到的工作内容是基于Nginx实现Grpc服务端的负载均衡。Nginx的1.13及以上版本是支持grpc的反向代理和负载均衡的。但是公司的nginx服务器的版本是1.10的,所以没办法直接使用grpc的代理。只能使用更底层的tcp层的负载均衡。最终服务跑起来是感觉挺简单的,但是nginx的基础太差,所以过程有点曲折。还是记录下吧。

文章分两部分,一个是创建简单的Grpc客户端和服务端的例子(其实也是用的网上的demo,这边就贴一下源码,讲下更细的实现步骤),然后对比下Nginx的Grpc负载均衡和Tcp的负载均衡。

1、在开发工具ide上创建一个maven project。打包方式选择jar。

2、在POM.xml上增加grpc相关的依赖及maven的打包插件

io.grpc

GzVYixKgrpc-netty

1.17.1

io.grpc

grpc-protobuf

1.17.1

io.grpc

grpc-stub

1.17.1

kr.motd.maven

os-maven-plugin

1.4.1.Final

org.xolstice.maven.plugins

protobuf-maven-plugin

0.5.0

com.google.protobuf:protoc:3.0.0:exe:${os.detected.classifier}

grpc-java

io.grpc:protoc-gen-grpc-java:1.0.0:exe:${os.detected.classifier}

compile

compile-custom

org.apache.maven.plugins

maven-compiler-plugin

2.3.2

1.8

1.8

3、在项目下的路径src/main下面创建proto文件夹,并在里面创建一个hello.proto文件。具体如下截图。

4、在hello.proto文件上输入,相应的配置信息,用来映射生成java代码。里面的内容就是生成一个MyRPC的服务提供一个sayHi的接口,接口需要传递一个request类的实例,该request实例只有一个name的字段。然后进行相应的业务代码处理之后,返回一个response类的实例,也是只有一个name的字段。

如果进行到这边,看到第2步添加依赖上面的标签可能报错,先暂时不要管他。直接进行第5步。

syntax = "proto3";

option java_package = "com.qidai.proto";

option java_outer_classname = "MyThing";

mesGzVYixKsage Request {

string name = 1;

}

message Response {

string name = 2;

}

service MyRPC {

rpc sayHi(Request) returns(Response);

}

5、运行项目,右击项目Run as -->maven build....->protobuf:compile以及protobuf:compile-custom,这样就编译生成了相应的代码了。不过存放的路径不对,需要自己拷贝到相应的项目目录下。

6、grpc的客户端和服务端代码需要自己编写。不过这一块的demo已经很全了。c+v然后改成自己的自己需要的就行了。

服务端demo:

package server;

import com.qidai.proto.MyRPCGrpc;

import com.qidai.proto.MyThing;

import io.grpc.ServerBuilder;

import io.grpc.stub.StreamObserver;

import service.RequestImpl;

import java.io.IOException;

public class Server {

private static final int PORT = 2222;

private final io.grpc.Server server;

public Server() throws IOException {

//这个部分启动server

this.server = ServerBuilder.forPort(PORT)

.addService(new RequestImpl())

.build()

.start();

System.out.println("Server1 Started ...");

}

private void stop() {

if (server != null) {

server.shutdown();

}

}

private void blockUntilShutdown() throws InterruptedException {

if (server != null) {

server.awaitTermination();

}

}

public static void main(String[] args) throws IOException, InterruptedException {

Server server = new Server();

//block Server防止关闭

server.blockUntilShutdown();

}

}

客户端demo

package client;

import com.qidai.proto.MyRPCGrpc;

import com.qidai.proto.MyRPCGrpc.MyRPCBlockingStub;

import com.qidai.proto.MyThing;

import io.grpc.ManagedChannel;

import io.grpc.ManagedChannelBuilder;

import java.util.concurrent.TimeUnit;

public class Client {

private final ManagedChannelBuilder> managedChannelBuilder;

private final MyRPCBlockingStub blockingStub;

private final ManagedChannel channel;

public Client(String name, int port) {

managedChannelBuilder = ManagedChannelBuilder.forAddress(name, port);

channel = managedChannelBuilder.usePlaintext().build();

blockingStub = MyRPCGrpc.newBlockingStub(channel);

}

public void shutdown() throws InterruptedException {

channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);

}

public void sayHi(String name){

MyThing.Request request = MyThing.Request.newBuilder().setName(name).build();

MyThing.Response response = blockingStub.sayHi(request);

System.out.println(response.getName());

}

public static void main(String[] args) throws Exception{

Client client = new Client("localhost", 5005);

for (int i = 0; i < 10; i++) {

Thread.sleep(1000);

//进行rpc调用的真正逻辑

client.sayHi("Hello Server1111 ->5005 " + i);

}

client.shutdown();

Client client2 = new Client("localhost", 5005);

for (int i = 0; i < 10; i++) {

Thread.sleep(1000);

//进行rpc调用的真正逻辑

client2.sayHi("Hello Server2222 ->5005 " + i);

}

client2.shutdown();

}

}

7、接下来就是才是比较关键的一步,实现自己的grpc服务端的业务代码。主要的关键步骤就是继承grpc自动映射出来的抽象类。是不是很熟悉,没错就是proto文件里面配置的服务。然后重写服务里面配置的方法即可。最后放心大胆的去根据传递的request参数去做相关的业务逻辑的处理。并用response封装需要返回的接口。(此处的request与response均是grcp根据proto配置文件映射出来的相关实体类。)

package service;

import com.qidai.proto.MyRPCGrpc.MyRPCImplBase;

import com.qidai.proto.MyThing.Response;

public class RequestImpl extends MyRPCImplBase {

@Override

public void sayHi(com.qidai.proto.MyThing.Request request,

io.grpc.stub.StreamObserver responseObserver) {

//proto文件上定义的response返回信息

Response response;

System.out.println("Request>>>say::" + request.getName());

//AccountQryResponse response = QryAccountProto.AccountQryResponse.newBuilder().setRc(1).setAmount(666).build();

response = Response.newBuilder().setName("Response11111>>>say:::hello_client"+request.getName()).build();

responseObserver.onNext(response);

responseObserver.onCompleted();

}

}

二、Grpc服务基于nginx(1.12.2)实现负载均衡。下面直接贴nginx相关的配置,服务端和客户端的代码改动都很小。只需调整ip和port的值即可。其他的不需要改动。

TCP层负载均衡配置

stream {

log_format proxy '$remote_addr [$time_local] '

'$protocol $status $bytes_sent $bytes_received '

'$session_time "$upstream_addr" '

'"$upstream_bytes_sent" "$upstream_bytes_received" "$upstream_connect_time"';

include ./conf.d/*.tcpstream;

upstream grpc {

server 127.0.0.1:2223;

server 127.0.0.1:2222;

}

server {

error_log logs/device5001_error.log;

access_log logs/device5001_access.log proxy;

listen 5005;

proxy_pass grpc;

}

}

grpc的负载均衡配置(grpc的支持在nginx1.13之后才有,所以这里是1.17.0)

http {

include mime.types;

default_type application/octet-stream;

log_format main '$remote_addr - $remote_user [$time_local] "$request" '

'$status $body_bytes_sent "$http_referer" '

'"$http_user_agent" "$http_x_forwarded_for"';

access_log logs/access.log main;

sendfile on;

keepalive_timeout 65;

gzip on;

upstream grpcservers {

server 127.0.0.1:2222;

server 127.0.0.1:2223;

}

server {

listen 8080 http2;

server_name localhost;

location / {

grpc_pass grpc://grpcservers;

}

}

}

最后分别启动nginx1.12.2和nginx1.17.0,并在ide上启动服务端和客户端,更改相应的客户端端口。就可以看到控制台打印不同的信息了。tcp和grcp的负载均衡的效果是不一样的。这也是我客户端new 了一个client,然后又new 了一个client2的原因。比较懒,效果图就不贴了。


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:Java后台判断ajax请求及处理过程详解
下一篇:Java Arrays.asList使用方法解析
相关文章

 发表评论

暂时没有评论,来抢沙发吧~