
gRPC作为当前最热门的RPC框架之一,以其独特的跨语言、跨平台特性,赢得许多公司的青睐。
老实说,之前我只是道听途说并没有认真去研究,今天我会根据官网的demo展开介绍整个gRPC的功能,
后面一篇会介绍gRPC如何整合到SpringCloud。
我这里只提供了搭建demo工程的资料,建议自己动手来操作。没有截图项目也是因为官方的资料相当齐全,没必要重复造轮子。
gRPC总览在直接使用gRPC之前,我们先了解下它的所有特性。官方描述 我就不展开讲了,gRPC有以下几点主要功能:
自己创建一个maven项目就好,没有别的要求(All in one,暂时不需要分模块)。想要偷懒的同学也可以借鉴我的项目,这里已经给你准备好了。但是我建议自己动手尝试搭建比较好,不然印象不太深刻,等于没学(有个词儿叫行动废人,虽然不好听但目的是希望能让你动手实践)。
说明: 这里之所以没用官方的demo是因为我本地实在编译不出来,而且官方给的项目太大,对于学习来说没必要全部下载。(我只想要examples模块,但是必须强制全部下载,就很烦)
当然,要下载的朋友看这里 。
官方的中文文档地址是这个 ,可以按照官方提供的文档做。但如果只是玩具,那我这种All on one的方式我觉得更简单。
我们直接拿官方的例子来讲解,官方代码地址 。里面有很多例子,我这里只讲部分。
proto文件我们到官方地址 抄作业时要注意,整个目录的结构。
proto文件只能放在模块的src/main下面,注意位置还有名字是否弄错,不然生成不了代码。
服务端:代码地址
客户端:代码地址
特性讲解我们知道gRPC不仅仅是一个helloworld就能描述清楚的,我下面将官方的代码例子做个分类,顺便总结下。
Stream 例子上述代码想表达的意思是,服务端在收到全部的客户端数据之后再响应回客户端处理结果。实际情况可以是服务端先处理一部分,然后返回部分。
也可以是任意顺序, 重要的是了解如何使用Stream的相关API来做交互。
(还是helloworld的例子)
总结这个就没啥好说的,用了Http2.0的TLS特性,默认就是开启的。如果客户端要传明文则必须在channel中配置,如下所示。
官方并没提供,下面都是自己的尝试
Client端在创建ManagedChannel时指定SLB策略。默认实现只有 pick_first 和 round_robin,这里以round_robin为例子讲解。
target字符串做调整
public class MyNameResolverProvider extends NameResolverProvider {
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;
}
private NameResolver of(final String targetAuthority, int defaultPort) {
requireNonNull(targetAuthority, "targetAuthority");
// Determine target ips
final String[] hosts = PATTERN_COMMA.split(targetAuthority);
final List 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;
public MyStaticNameResolver(final String authority, final EquivalentAddressGroup target) {
this(authority, ImmutableList.of(requireNonNull(target, "target")));
}
public MyStaticNameResolver(final String authority, final Collection 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();
}
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 + "]";
}
}
说明:上面的代码是从grpc-spring-boot-start中抄过来的,后面会细讲。原生的grpc只能用dns,本地没法做,所以采用这种方式验证SLB。
其实在这个过程中我们也能看到,如果要基于grpc功能组件做扩展也是极方便的。
负载均衡的实现是基于静态地址的,也就是说没有动态的服务发现。当然也可以自己扩展,这个会在后面集成grpc-spring-boot-start时会讲。
扩展时只需要实现io.grpc.LoadBalancerProvider然后再配置注册文件就好
这里主要是一些重试(容错)策略的配置,例子中通过人为的注入延迟来测试。了解下参数含义就好
写在最后其实我们会发现,原生的grpc整个治理能力偏弱。熔断、降级等功能基本没有,也无法做动态的服务发现,只支持dns来做负载均衡(别看文档里写的有zookeeper协议,但实际不支持)流量的调度能力也比较弱,并没有类似分组、版本的概念,无法做到灰度发布。
不过,有很多人在grpc的基础上已经添加了服务治理的解决方案,在后面的grpc-spring-boot-start会讲到,大家不用担心。
为什么市面上其他的RPC框架功能都比这齐全,但是越来越多的公司开始转向gRPC了呢?
踩坑笔记我个人认为主要是gRPC的传输协议以及服务定义方式都是天然的支持跨语言的,而服务端编程语言越来越多样化,因此越来越多的公司转向gRPC,即使他们要为此写很多的gRPC插件。
不过工作量并没有想想的那么多,比如Dubbo3.0目前就将他的传输层使用gRPC,而服务治理能力则是使用它自身的,只需要将服务治理能力适配到gRPC插件中就好。
grpc官方文档