V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
ducuducu
V2EX  ›  程序员

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

  •  
  •   ducuducu · 14 天前 · 2033 次点击

    目前公司对外的 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  
       14 天前 via Android
    strings.Contains(r.Header.Get("Content-Type"), "application/grpc")

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

    根据这边的落地经验,出于性能考虑,推荐以下两种:
    - 基于 grpc-gateway 另起一个 http server 用于转发 grpc 请求,每次调整需要重新发布代码,性能可用,无需引入新的中间件
    - 基于 envoy 配置 protoset 和 filter ,每次调整只需要更改配置,性能相对较高,需要引入新的中间件
    SmiteChow
        24
    SmiteChow  
       13 天前
    搞复杂了,网关直接根据 http 请求组装一个 general 的 grpc 消息,grpc 有一个统一入口二次分发,并不是说网关直接就 touch 到业务层级去根据 proto 组装业务 grpc 数据
    MelodYi
        25
    MelodYi  
       13 天前
    先报下网关选型吧,不然也不好说你能有哪些方案。
    常见的方式有
    grpc2grpc ,直接过网关透传,网关正常解 ssl 之类的。envoy 之类的技术选型天然支持。
    http2grpc ,网关做协议转换,kong 之类的网关有插件做。这类一般比较耗 cpu ,机器开大点。如果 protobuf 和 json 的银蛇关系非常基础、标准,可以用。这类插件遇到复杂一些的报文拼装逻辑基本歇菜。
    服务自己开个 http 口子。咋说呢,用 grpc 的服务不多的话,这个方案其实最省事,啥也不用折腾,毕竟网关改个配置搞错了还影响别的业务。
    nevermoreluo
        26
    nevermoreluo  
       13 天前
    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  
       13 天前
    在 grpc 服务中增加一个 http 服务对现有系统影响是最小的,也就是一个微服务中同时提供了 http 和 grpc 两种调用(不是 grpc-gateway 方式),共用一套业务逻辑,B 站开源的微服务框架 kratos 是支持 http 和 grpc 的,我猜 B 站应该是这样的方案。
    lemon1997
        28
    lemon1997  
       12 天前
    可以参考下这个 https://github.com/lemon-1997/dynamic-grpc
    会监听 grpc 服务,服务更新会利用反射读取最新的协议,无需手动去生成代码或者上传 proto ,采用跟 grpc-gateway 同样的 proto http 注解
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   975 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 103ms · UTC 19:48 · PVG 03:48 · LAX 12:48 · JFK 15:48
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.