前言gRPC作为以后最热门的RPC框架之一,以其独特的跨语言、跨平台个性,博得许多公司的青眼。诚实说,之前我只是一人传虚;万人传实并没有认真去钻研,明天我会依据官网的demo开展介绍整个gRPC的性能,前面一篇会介绍gRPC如何整合到SpringCloud。
我这里只提供了搭建demo工程的材料,倡议本人入手来操作。没有截图我的项目也是因为官网的材料相当齐全,没必要反复造轮子。
gRPC总览在间接应用gRPC之前,咱们先理解下它的所有个性。官网形容 我就不开展讲了,gRPC有以下几点次要性能:
应用Protocol Buffer 定义服务。语言和平台的中立性双向流式通信基于HTTP2.0身份认证、SLB、tracing、health check组件可扩大。疾速搭建环境筹备操作系统:WindownsJDK版本:1.8编辑工具:IntelliJ IDEA Community Edition 2021.1.2 x64
创立我的项目本人创立一个maven我的项目就好,没有别的要求(All in one,临时不须要分模块)。想要偷懒的同学也能够借鉴我的我的项目,这里曾经给你筹备好了。然而我倡议本人入手尝试搭建比拟好,不然印象不太粗浅,等于没学(有个词儿叫口头废人,尽管不好听但目标是心愿能让你入手实际)。
阐明: 这里之所以没用官网的demo是因为我本地切实编译不进去,而且官网给的我的项目太大,对于学习来说没必要全副下载。(我只想要examples模块,然而必须强制全副下载,就很烦)当然,要下载的敌人看这里 。官网的中文文档地址是这个 ,能够依照官网提供的文档做。但如果只是玩具,那我这种All on one的形式我感觉更简略。
Helloworld咱们间接拿官网的例子来解说,官网代码地址 。外面有很多例子,我这里只讲局部。
proto文件咱们到官网地址 抄作业时要留神,整个目录的构造。proto文件只能放在模块的src/main上面,留神地位还有名字是否弄错,不然生成不了代码。
代码服务端:代码地址
客户端:代码地址
个性解说咱们晓得gRPC不仅仅是一个helloworld就能形容分明的,我上面将官网的代码例子做个分类,顺便总结下。
Stream例子proto: 代码地址代码目录: 代码地址总结上述代码想表白的意思是,服务端在收到全副的客户端数据之后再响应回客户端处理结果。理论状况能够是服务端先解决一部分,而后返回局部。也能够是任意程序, 重要的是理解如何应用Stream的相干API来做交互。
TLS例子proto: 代码地址代码目录: 代码地址(还是helloworld的例子)
总结这个就没啥好说的,用了Http2.0的TLS个性,默认就是开启的。如果客户端要传明文则必须在channel中配置,如下所示。
SLB 和 Health Check例子proto: 代码地址代码目录: 代码地址官网并没提供,上面都是本人的尝试
Client端在创立ManagedChannel时指定SLB策略。默认实现只有 pick_first 和 round_robin,这里以round_robin为例子解说。target字符串做调整新增两个类,代码如下。
public class MyNameResolverProvider extends NameResolverProvider { /** * The constant containing the scheme that will be used by this factory. */ public static final String STATIC_SCHEME = "static"; private static final Pattern PATTERN_COMMA = Pattern.compile(","); @Nullable @Override public NameResolver newNameResolver(final URI targetUri, final NameResolver.Args args) { if (STATIC_SCHEME.equals(targetUri.getScheme())) { return of(targetUri.getAuthority(), args.getDefaultPort()); } return null; } /** * Creates a new {@link NameResolver} for the given authority and attributes. * * @param targetAuthority The authority to connect to. * @param defaultPort The default port to use, if none is specified. * @return The newly created name resolver for the given target. */ private NameResolver of(final String targetAuthority, int defaultPort) { requireNonNull(targetAuthority, "targetAuthority"); // Determine target ips final String[] hosts = PATTERN_COMMA.split(targetAuthority); final List<EquivalentAddressGroup> targets = new ArrayList<>(hosts.length); for (final String host : hosts) { final URI uri = URI.create("//" + host); int port = uri.getPort(); if (port == -1) { port = defaultPort; } targets.add(new EquivalentAddressGroup(new InetSocketAddress(uri.getHost(), port))); } if (targets.isEmpty()) { throw new IllegalArgumentException("Must have at least one target, but was: " + targetAuthority); } return new MyStaticNameResolver(targetAuthority, targets); } @Override public String getDefaultScheme() { return STATIC_SCHEME; } @Override protected boolean isAvailable() { return true; } @Override protected int priority() { return 4; // Less important than DNS } @Override public String toString() { return "StaticNameResolverProvider [scheme=" + getDefaultScheme() + "]"; }}public class MyStaticNameResolver extends NameResolver { private final String authority; private final ResolutionResult result; /** * Creates a static name resolver with only a single target server. * * @param authority The authority this name resolver was created for. * @param target The target address of the server to use. */ public MyStaticNameResolver(final String authority, final EquivalentAddressGroup target) { this(authority, ImmutableList.of(requireNonNull(target, "target"))); } /** * Creates a static name resolver with multiple target servers. * * @param authority The authority this name resolver was created for. * @param targets The target addresses of the servers to use. */ public MyStaticNameResolver(final String authority, final Collection<EquivalentAddressGroup> targets) { this.authority = requireNonNull(authority, "authority"); if (requireNonNull(targets, "targets").isEmpty()) { throw new IllegalArgumentException("Must have at least one target"); } this.result = ResolutionResult.newBuilder() .setAddresses(ImmutableList.copyOf(targets)) .build(); } /** * Creates a static name resolver with multiple target servers. * * @param authority The authority this name resolver was created for. * @param result The resolution result to use.. */ public MyStaticNameResolver(final String authority, final ResolutionResult result) { this.authority = requireNonNull(authority, "authority"); this.result = requireNonNull(result, "result"); } @Override public String getServiceAuthority() { return this.authority; } @Override public void start(final Listener2 listener) { listener.onResult(this.result); } @Override public void refresh() { // Does nothing } @Override public void shutdown() { // Does nothing } @Override public String toString() { return "StaticNameResolver [authority=" + this.authority + ", result=" + this.result + "]"; }}新增文件io.grpc.NameResolverProviderServer端启动多个实现,记得要改端口(能够在server端加些日志来验证)阐明:下面的代码是从grpc-spring-boot-start中抄过来的,前面会细讲。原生的grpc只能用dns,本地没法做,所以采纳这种形式验证SLB。其实在这个过程中咱们也能看到,如果要基于grpc性能组件做扩大也是极不便的。
...