使用Python的gRPC的痛苦。 2019年11月。 (个人备忘录)


在gRPC世界中这可能是正常的,但是我会注意到,一个初学者出乎意料地沉迷于用Python编写gRPC客户端。

基于Python快速入门。首先,下载示例代码。现在使用稍旧的v1.19.0而不是最新的v1.25.0。原因将在后面描述。

1
git clone -b v1.19.0 https://github.com/grpc/grpc

让我们在与

文档不同的目录中创建一个Python项目。同样,我们将使用v1.19.0。

1
2
3
4
5
6
7
mkdir python-grpc
cd python-grpc
pipenv --python 3.7
pipenv install grpcio~=1.19.0
pipenv install --dev grpcio-tools
pipenv shell
mkdir pb

棘手的1:grpc_tools.protoc选项很困难。

使用

grpc_tools.protoc命令从proto文件创建py,并将其写入pb目录。

1
2
3
4
5
python -m grpc_tools.protoc \
    -I../grpc/examples/protos/ \
    --python_out=pb \
    --grpc_python_out=pb \
    ../grpc/examples/protos/helloworld.proto
  • -I:除了包含在proto中之外,此命令处理的proto文件的位置也必须使用-I指定。

  • --python_out:指定输出xxx_pb2.py文件的目录。

  • --grpc_python_out:指定用于输出xxx_pb2_grpc.py文件的目录。

首先,需要-I选项。没有它,您将得到一个File does not reside within any path specified using --proto_path (or -I).错误。为什么我找不到它是不合理的,因为我已经正确指定了原型的位置。

另外,-I选项有一个技巧:如果指定更高的目录,例如-I../grpc/examples/,则将在pb/protos而不是pb中生成文件。如果您不知道,那么文件将丢失。

此外,--help选项的描述没有提及--python_out--grpc_python_out之间的区别。尽管如上所述存在差异,但是使用其他选项是不合理的,因为如果将其放在另一个目录中仅导入失败是不够的。

麻辣2:生成的文件没有相对路径。

尝试从python读取创建的错误时出现错误。

1
2
3
4
5
6
7
$ python
>>> import pb.helloworld_pb2_grpc
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Users/tyamamiya/tmp/python-grpc/pb/helloworld_pb2_grpc.py", line 4, in <module>
    import helloworld_pb2 as helloworld__pb2
ModuleNotFoundError: No module named 'helloworld_pb2'

生成的代码的相对路径是错误的(它似乎是Python2样式)。它无济于事,因此请根据python添加pb/__init__.py:在生成的模块中使用相对导入。

1
2
3
4
import sys
from pathlib import Path

sys.path.append(str(Path(__file__).parent))

提示:如何调试

如果由于错误不明显而无法使用,则最好设置并执行环境变量。现在启动服务器和客户端并检查操作。

1
2
3
4
5
6
7
8
$ python ../grpc/examples/python/helloworld/greeter_server.py &
$ export GRPC_TRACE=all
$ export GRPC_VERBOSITY=DEBUG
$ python ../grpc/examples/python/helloworld/greeter_client.py
... 大量に色々出る。
Greeter client received: Hello, you!
$ unset GRPC_TRACE
$ unset GRPC_VERBOSITY

好。

香辣3:google.api

有时会有一个包含google.api的原始文件。原始文件本身位于https://github.com/googleapis/googleapis/tree/master/google/api,因此您可以下载该文件并使用-I指定它,但是转换后的代码包括原始内容。不包括在内。我觉得可以使用选项--include_imports导入它,但事实并非如此,我需要单独安装转换后的一个。

1
pipenv install googleapis-common-protos

好吧,如果您知道这一点,那就没关系了。

辣味4:missing selected ALPN property.

使用最新的Python grpcio库通过TLS连接到现有的gRPC服务器时,可能会出现missing selected ALPN property.

1
2
D1125 19:20:57.313482000 4619453888 security_handshaker.cc:186]        Security handshake failed: {"created":"@1574677257.313465000","description":"Cannot check peer: missing selected ALPN property.","file":"src/core/lib/security/security_connector/ssl_utils.cc","file_line":118}
I1125 19:20:57.313703000 4619453888 subchannel.cc:1000]                Connect failed: {"created":"@1574677257.313465000","description":"Cannot check peer: missing selected ALPN property.","file":"src/core/lib/security/security_connector/ssl_utils.cc","file_line":118}

使用该关键字进行搜索会发现很多有趣的事实,但是正如从https://github.com/grpc/grpc/issues/18710可以看到的那样,我无法访问不支持ALPN的服务器检查功能。

我别无选择,只能使用旧版本v1.19.0使茶变得浑浊。 https://stackoverflow.com/questions/57397723/grpc-client-failing-to-connect-to-server-with-tls-certificates

结论

我觉得Python和gRPC的结合还不够好。