问题标题可能不那么有用,因为我正在尝试实现各种功能.我想根据他发送的标题授权调用者,并将此信息传播给gRPC方法处理程序.问题在于授权过程的异步性质.我最终得到了这个:
case class AsyncContextawareInterceptor[A](
f: Metadata ? Future[Either[Status, (Context.Key[A], A)]]
)(implicit val system: ActorSystem)
extends ServerInterceptor
with AnyLogging {
import system.dispatcher
sealed trait Msg
case object HalfClose extends Msg
case object Cancel extends Msg
case object Complete extends Msg
case object Ready extends Msg
case class Message[T](msg: T) extends Msg
override def interceptCall[ReqT, RespT](call: ServerCall[ReqT, RespT],
headers: Metadata,
next: ServerCallHandler[ReqT, RespT]): ServerCall.Listener[ReqT] =
new ServerCall.Listener[ReqT] {
private val stash = new java.util.concurrent.ConcurrentLinkedQueue[Msg]()
private var interceptor: Option[ServerCall.Listener[ReqT]] = None
private def …Run Code Online (Sandbox Code Playgroud) 使用 gRPC 时,我们需要通过协议缓冲区编译器 (protoc) 或使用 Gradle 或 Maven protoc 构建插件从 .proto 服务定义生成 gRPC 客户端和服务器接口。
Flow now: protobuf file -> java code -> gRPC client.
Run Code Online (Sandbox Code Playgroud)
那么,有没有办法可以跳过这一步呢?
如何创建一个通用的 gRPC 客户端,可以直接从 protobuf 文件调用服务器,而无需编译成 java 代码?或者,有没有办法在运行时生成代码?
Flow expect: protobuf file -> gRPC client.
Run Code Online (Sandbox Code Playgroud)
我想构建一个通用的 gRPC 客户端系统,输入是 protobuf 文件以及方法、包、消息请求的描述......而不必为每个 protobuf 再次编译。
非常感谢。
想知道是否有人尝试过使用 jmeter 来测试 gRPC 应用程序。
我本来希望
在投入时间尝试上述方法之前,我想看看是否有人尝试过类似的方法
我们已经尝试使用 python 客户端和 locust.io 进行负载测试,但是 python gRPC 与 gevent 不兼容,即使使用异步调用(例如 Stub.GetFeature.future),我们也会达到每个进程每秒请求的限制(异步调用不会似乎是异步的,GIL瓶颈,一旦TCP流)
解决方案:看看https://github.com/whatalokation/whatalokation-grpc-client Readme.md 应该是不言自明的
我必须在android grpc客户端中添加自定义标头.我无法成功发送.
public class HeaderClientInterceptor implements ClientInterceptor {
@Override
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method,
CallOptions callOptions, Channel next) {
return new SimpleForwardingClientCall<ReqT, RespT>(next.newCall(method, callOptions)) {
@Override
public void start(Listener<RespT> responseListener, Metadata headers) {
/* put custom header */
Timber.d("header sending to server:");
Metadata fixedHeaders=new Metadata();
Metadata.Key<String> key =
Metadata.Key.of("Grps-Matches-Key", Metadata.ASCII_STRING_MARSHALLER);
fixedHeaders.put(key, "primary.secondary");
headers.merge(fixedHeaders);
super.start(new SimpleForwardingClientCallListener<RespT>(responseListener) {
@Override
public void onHeaders(Metadata headers) {
/**
* if you don't need receive header from server,
* you can use {@link …Run Code Online (Sandbox Code Playgroud) 我已经在 tomcat 容器内部署了一个 Web 应用程序,并使用了 grpc-netty (1.2.0) 和 netty-tcnative-boringssl-static:jar:1.1.33.Fork26。
当我打开调试日志时,它告诉我“java.lang.IllegalArgumentException:无法加载任何给定的库:[netty-tcnative-linux-x86_64,netty-tcnative-linux-x86_64-fedora,netty-tcnative]”和然后出现错误消息“java.lang.IllegalArgumentException:Jetty ALPN/NPN 尚未正确配置。”。
我已经完成了https://github.com/grpc/grpc-java/blob/master/SECURITY.md的故障排除部分,并验证了我的 netty 版本,这看起来没问题。下面是我的 Maven 依赖项列表
[INFO] | +- io.grpc:grpc-core:jar:1.2.0:compile
[INFO] | | +- com.google.guava:guava:jar:19.0:compile
[INFO] | | +- com.google.errorprone:error_prone_annotations:jar:2.0.11:compile
[INFO] | | +- com.google.code.findbugs:jsr305:jar:3.0.0:compile
[INFO] | | +- io.grpc:grpc-context:jar:1.2.0:compile
[INFO] | | \- com.google.instrumentation:instrumentation-api:jar:0.3.0:compile
[INFO] | +- io.grpc:grpc-netty:jar:1.2.0:compile
[INFO] | | +- io.netty:netty-codec-http2:jar:4.1.8.Final:compile (version selected from constraint [4.1.8.Final,4.1.8.Final])
[INFO] | | | +- io.netty:netty-codec-http:jar:4.1.8.Final:compile
[INFO] | | | | \- io.netty:netty-codec:jar:4.1.8.Final:compile
[INFO] | | | \- …Run Code Online (Sandbox Code Playgroud) 该grpc-java库是使用通用构建器模式创建具有特定属性的对象的库的一个很好的示例:
val sslContext = ???
val nettyChannel : NettyChannel =
NettyChannelBuilder
.forAddress(hostIp, hostPort)
.useTransportSecurity()
.sslContext(sslContext)
.build
Run Code Online (Sandbox Code Playgroud)
给定一个使用此模式的库,它如何被包装,以便可以提供适当的功能API? 我认为monad是适合使用的工具.
基本的第一次尝试看起来像:
val updateBuilder : (NettyChannelBuilder => Unit) => NettyChannelBuilder => NettyChannelBuilder =
updateFunc => builder => {
updateFunc(builder)
builder
}
val addTransportSecurity : NettyChannelBuilder => Unit =
(_ : NettyChannelBuilder).useTransportSecurity()
val addSslContext : NettyChannelBuilder => Unit =
builder => {
val sslContext = ???
builder sslContext sslContext
}
Run Code Online (Sandbox Code Playgroud)
虽然这种方法很冗长,但它至少可以用于组合:
val builderPipeline : NettyChannelBuilder => NettyChannelBuilder =
updateBuilder(addTransportSecurity) andThen updateBuilder(addSslContext)
val …Run Code Online (Sandbox Code Playgroud) 通常,客户端可以通过以下方式取消 gRPC 调用:
(requestObserver as ClientCallStreamObserver<Request>)
.cancel("Cancelled", null)
Run Code Online (Sandbox Code Playgroud)
但是,它在Javadoc中显示:
CancellableContext withCancellation = Context.current().withCancellation();
// do stuff
withCancellation.cancel(t);
Run Code Online (Sandbox Code Playgroud)
哪一种是取消客户端调用并让服务器知道的“正确”方法?
编辑:
让事情变得更加混乱的是,还有ManagedChannel.shutdown*.
我有一个用 C++ 编写的 gRPC 服务器和一个用 Java 编写的客户端。使用阻塞存根一切工作正常。然后我决定将其中一个调用更改为异步,因此我在客户端中创建了一个额外的存根,该存根是使用 newStub(channel) 而不是 newBlockingStub(channel) 创建的。我没有在服务器端进行任何更改。这是一个简单的一元 RPC 调用。
所以我改变了
Empty response = blockingStub.callMethod(request);
Run Code Online (Sandbox Code Playgroud)
到
asyncStub.callMethod(request, new StreamObserver<Empty>() {
@Override
public void onNext(Empty response) {
logInfo("asyncStub.callMethod.onNext");
}
@Override
public void onError(Throwable throwable) {
logError("asyncStub.callMethod.onError " + throwable.getMessage());
}
@Override
public void onCompleted() {
logInfo("asyncStub.callMethod.onCompleted");
}
});
Run Code Online (Sandbox Code Playgroud)
从那时起,当我使用这个 RPC 时(大多数时候),onError 就会被调用,它给出的错误是“CANCELLED: io.grpc.Context was cancelled without error”。我读到过有关在 RPC 调用中进行 RPC 调用时分叉 Context 对象的内容,但这里的情况并非如此。另外,上下文似乎是一个服务器端对象,我不明白它与客户端有何关系。这是传播回客户端的服务器端错误吗?在服务器端,一切似乎都成功完成,所以我不知道为什么会发生这种情况。在调用 asyncStub.callMethod 之后插入 1ms 睡眠似乎可以使这个问题消失,但达不到目的。任何有助于理解这一点的帮助将不胜感激。
一些注意事项:
service EventHandler {
rpc callMethod(Msg) …Run Code Online (Sandbox Code Playgroud) 我添加了 maven 配置如下。
<plugin>
<groupId>com.github.os72</groupId>
<artifactId>protoc-jar-maven-plugin</artifactId>
<version>3.5.1</version>
<executions>
<execution>
<phase>generate-sources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<protocArtifact>com.google.protobuf:protoc:3.0.0</protocArtifact>
<inputDirectories>
<include>src/main/protobuf</include>
</inputDirectories>
<outputTargets>
<outputTarget>
<type>java</type>
<outputDirectory>src/main/java</outputDirectory>
</outputTarget>
<outputTarget>
<type>grpc-java</type>
<outputDirectory>src/main/java</outputDirectory>
<pluginArtifact>io.grpc:protoc-gen-grpc-java:1.0.1</pluginArtifact>
</outputTarget>
</outputTargets>
</configuration>
</execution>
</executions>
</plugin>
Run Code Online (Sandbox Code Playgroud)
我通过“mvn protoc-jar:run”执行它,但是它跳过了grpc服务存根,只将“消息”转换为java代码。
输出是
[INFO] Protoc version: 3.5.1
protoc-jar: protoc version: 3.5.1, detected platform: osx-x86_64 (mac os x/x86_64)
protoc-jar: embedded: bin/3.5.1/protoc-3.5.1-osx-x86_64.exe
protoc-jar: executing: [/var/folders/9y/w8qrc__9513dv57323sjdlmw0000gn/T/protocjar320569499467403052/bin/protoc.exe, --version]
libprotoc 3.5.1
[INFO] Protoc command: /var/folders/9y/w8qrc__9513dv57323sjdlmw0000gn/T/protocjar320569499467403052/bin/protoc.exe
[INFO] Input directories:
[INFO] /Users/dev/learn/proto-java/src/main/protobuf
[INFO] Output targets:
[INFO] java: /Users/dev/learn/proto-java/target/generated-sources (add: main, clean: false, plugin: null, …Run Code Online (Sandbox Code Playgroud) 如果我按照这两个测试运行,我会收到错误消息。
第一次测试
@Rule
public GrpcCleanupRule grpcCleanup = new GrpcCleanupRule();
@Test
public void findAll() throws Exception {
// Generate a unique in-process server name.
String serverName = InProcessServerBuilder.generateName();
// Create a server, add service, start, and register for automatic graceful shutdown.
grpcCleanup.register(InProcessServerBuilder
.forName(serverName)
.directExecutor()
.addService(new Data(mockMongoDatabase))
.build()
.start());
// Create a client channel and register for automatic graceful shutdown.
RoleServiceGrpc.RoleServiceBlockingStub stub = RoleServiceGrpc.newBlockingStub(
grpcCleanup.register(InProcessChannelBuilder
.forName(serverName)
.directExecutor()
.build()));
RoleOuter.Response response = stub.findAll(Empty.getDefaultInstance());
assertNotNull(response);
}
Run Code Online (Sandbox Code Playgroud)
第二次测试
@Test
public void testFindAll() {
ManagedChannel channel …Run Code Online (Sandbox Code Playgroud)