http 网关如何优雅的暴露内部 grpc 服务 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
ducuducu
V2EX    程序员

http 网关如何优雅的暴露内部 grpc 服务

  ducuducu 2024-04-15 18:20:06 +08:00 3663 次点击
这是一个创建于 621 天前的主题,其中的信息可能已经有所发展或是发生改变。

目前公司对外的 api 都要经过统一 http 网关,但一些内部的 rpc 服务想要对外服务的话,我们得专门写个 http 接口暴暴露给网关,但这样要维护两套代码有点麻烦,我想在网关这层做一道转换,把外部的 http 的 json 报文转换成内部的 rpc 调用。现在有两种方案:

  • 第一种方法:在 grpc 服务的容器内起个 http 服务,这个 http 服务跟容器内的 grpc 服务通信,然后把容器内的这个 http 服务暴露给网关。相似方案的实现者有 grpc-gateway
  • 第二种方式:grpc 服务在编译 proto 文件时生成 descriptorSet 描述文件,并上传的网关,网关解析这个文件能知道怎么组装 protobuf 消息,用 DynamicMessage 方式泛型调用内部 grpc 服务。相似方案的实现有 apisix 和 consul 的 grpc-transcoder

想知道下大厂是不是也有在网关层 json 转 rpc 的需求,你们是怎么做的呢?这两种方案你哪个好一些,有啥坑吗

28 条回复    2024-04-17 10:47:24 +08:00
DefoliationM
    1
DefoliationM  
   2024-04-15 18:34:03 +08:00 via Android
strings.Contains(r.Header.Get("Content-Type"), "application/grpc")

用 content-type 判断一下
DefoliationM
    2
DefoliationM  
   2024-04-15 18:34:46 +08:00 via Android
@DefoliationM 外面直接发 grpc 请求
ducuducu
    3
ducuducu  
OP
   2024-04-15 18:38:27 +08:00
@DefoliationM 也是个法子
GenericT
    4
GenericT  
   2024-04-15 18:38:59 +08:00
@DefoliationM grpc 是 http2 的,他这网关看起来就不支持的样子
tf2
    5
tf2  
   2024-04-15 18:39:43 +08:00
grpc 本来就是 h2 直接透传。谁不接住解析谁就是孙子就完事了。。。
luozic
    6
luozic  
   2024-04-15 18:49:42 +08:00
看你们的网关支持啥啊。已有网关是个不支持 h2 的,你这传了有啥用。 看别的网关有啥,是准备切换别的网关了?
coderxy
    7
coderxy  
   2024-04-15 18:50:52 +08:00
还可以用 json 作为 grpc 的传输协议,http 网关不需要了解 pb 的内容。 最好要在网关做一个映射配置列表,不然全自动映射把内部重要接口泄漏了就 G 了
ducuducu
    8
ducuducu  
OP
   2024-04-15 18:53:38 +08:00
@GenericT 想让外部调用者直接能用 http json 报文调用。或者我可以把 proto 文件他们,让外部调用方用 grpc 方式调网关,这样,,也行
luozic
    9
luozic  
   2024-04-15 18:54:47 +08:00
@coderxy 实际这种不是应该 两个么,一个外部的网关 流量出口,一个内部的网关 or 路由 作为 soa 的编排。
TheGonG
    10
TheGonG  
   2024-04-15 18:55:06 +08:00
像 k8s 的 ingress-nginx 代理 http 和 grpc 服务?如果是的话,用路径匹配,分别指向不同的服务
rrfeng
    11
rrfeng  
   2024-04-15 19:17:52 +08:00
grpc 用 http2 传输的,让我看看哪家网关还不支持 http2 ……
coderxy
    12
coderxy  
   2024-04-15 19:27:47 +08:00
@luozic 分开也可以,放在一起也可以。
pinne
    13
pinne  
   2024-04-15 19:39:04 +08:00
实现过第二种,不过只在内部做定时调用使用过。做法是将 proto 文件内容上传到一个地方,然后网关处解析。不过这样的问题是每次 proto 更新,都要重新上传。想法是可以直接暴露接口给网关,网关自动获取 pb 内容。
SethShi
    14
SethShi  
   2024-04-15 19:53:05 +08:00
第一个就错了吧, 不需要在 rpc 容器内启动 HTTP 服务,
你就另起服务作为 gateway, 然后穿透给 rpc 就好了. 就是你说的 grpc-gateway 不就挺好?
poltao
    15
poltao  
   2024-04-15 21:59:49 +08:00
结合注册中心,搞个统一网关管理平台,由网关负责转发 http 请求就可以了
macscsbf
    16
macscsbf  
   2024-04-15 22:07:39 +08:00
ducuducu
    17
ducuducu  
OP
   2024-04-15 23:43:46 +08:00
@macscsbf 对的
mind3x
    18
mind3x  
   2024-04-16 00:15:40 +08:00
敝司是写了个简单的 HTTP bridge 给一些作 gRPC 调用比较麻烦的 client 用,大概就是 header 里传 service 和 method 名,payload 和 response 都转 JSON 。
layxy
    19
layxy  
   2024-04-16 09:12:12 +08:00   1
感觉你们网关还是不健全,网关一个很重要的基础能力就是协议转换,对外统一都是 http(s),但是内部服务有 springcloud,dubbo,grpc 等,不可能让内部服务再封装 http 再在网关注册,这样所有接入方的工作量会大上不少,而且也浪费资源
layxy
    20
layxy  
   2024-04-16 09:13:27 +08:00
@layxy 大点的公司会分流量网关和业务网关,但是一般公司不会拆分这么细
dhb233
    21
dhb233  
   2024-04-16 09:37:10 +08:00
GRPC 记得有一个功能是 Server Reflection ,是把自己支持的接口暴露出来,具体参考 https://ithub.com/fullstorydev/grpcurl 的文档
dhb233
    22
dhb233  
   2024-04-16 09:38:10 +08:00
但是感觉这个 Server Reflection 直接对外的话,有点不安全。。。如果 GRPC 只对 gateway 开放应该还好
sophos
    23
sophos  
   2024-04-16 09:48:03 +08:00
协议转换这块是 cpu 密集型场景,apisix 等 nginx+lua 的方案,目前的实现方案性能最差(基于 lua 做的协议转换)

根据这边的落地经验,出于性能考虑,推荐以下两种:
- 基于 grpc-gateway 另起一个 http server 用于转发 grpc 请求,每次调整需要重新发布代码,性能可用,无需引入新的中间件
- 基于 envoy 配置 protoset 和 filter ,每次调整只需要更改配置,性能相对较高,需要引入新的中间件
SmiteChow
    24
SmiteChow  
   2024-04-16 10:26:40 +08:00
搞复杂了,网关直接根据 http 请求组装一个 general 的 grpc 消息,grpc 有一个统一入口二次分发,并不是说网关直接就 touch 到业务层级去根据 proto 组装业务 grpc 数据
MelodYi
    25
MelodYi  
   2024-04-16 15:28:24 +08:00
先报下网关选型吧,不然也不好说你能有哪些方案。
常见的方式有
grpc2grpc ,直接过网关透传,网关正常解 ssl 之类的。envoy 之类的技术选型天然支持。
http2grpc ,网关做协议转换,kong 之类的网关有插件做。这类一般比较耗 cpu ,机器开大点。如果 protobuf 和 json 的银蛇关系非常基础、标准,可以用。这类插件遇到复杂一些的报文拼装逻辑基本歇菜。
服务自己开个 http 口子。咋说呢,用 grpc 的服务不多的话,这个方案其实最省事,啥也不用折腾,毕竟网关改个配置搞错了还影响别的业务。
nevermoreluo
    26
nevermoreluo  
   2024-04-16 16:05:03 +08:00
c#的话 我记得用过微软自己有一套 引入库直接在 grpc 文件里面定义 api 就好了
两个端口 一个 grpc 一个 http 调用
```
import "google/api/annotations.proto";

service Greeter {
rpc SayHello (HelloRequest) returns (HelloReply) {
option (google.api.http) = {
get: "/v1/greeter/{name}"
};
}
}
```
详细的看看微软的文档吧
https://learn.microsoft.com/en-us/aspnet/core/grpc/browser?view=aspnetcore-8.0

还有 go 的 grpc gateway
https://github.com/grpc-ecosystem/grpc-gateway
gvison
    27
gvison  
   2024-04-16 16:23:01 +08:00
在 grpc 服务中增加一个 http 服务对现有系统影响是最小的,也就是一个微服务中同时提供了 http 和 grpc 两种调用(不是 grpc-gateway 方式),共用一套业务逻辑,B 站开源的微服务框架 kratos 是支持 http 和 grpc 的,我猜 B 站应该是这样的方案。
lemon1997
    28
lemon1997  
   2024-04-17 10:47:24 +08:00
可以参考下这个 https://github.com/lemon-1997/dynamic-grpc
会监听 grpc 服务,服务更新会利用反射读取最新的协议,无需手动去生成代码或者上传 proto ,采用跟 grpc-gateway 同样的 proto http 注解
关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2598 人在线   最高记录 6679       Select Language
创意工作者们的社区
World is powered by solitude
VERSION: 3.9.8.5 30ms UTC 11:37 PVG 19:37 LAX 03:37 JFK 06:37
Do have faith in what you're doing.
ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86