SocketIO 与客户端和服务之间的网关通信?

Posted

技术标签:

【中文标题】SocketIO 与客户端和服务之间的网关通信?【英文标题】:SocketIO Communication with a Gateway Between the Client and a Service? 【发布时间】:2020-08-06 11:54:07 【问题描述】:

要点

我有一个在基于微服务的架构(在 Kubernetes 上)上运行的应用程序。与应用程序外部的所有通信都通过 API 网关进行。

这只是意味着来自我的前端的请求不会直接发送到服务,而是必须通过网关。

动机

现在我需要实现一个需要在前端和内部服务之间进行实时通信的功能。但由于内部服务不对外暴露,我需要一种通过网关“路由”实时数据的方法。

我所有的服务都在 Node.js 上运行,这就是我想使用Socket.IO 来实现实时通信的原因。

问题

但是如何实现草图中的紫色双箭头呢?

所以通常前端客户端会连接到运行 Socket.IO 的服务器。但是在我的例子中,这个服务器(实时功能服务器)不能从客户端访问(而且永远不应该),这意味着客户端必须连接到网关。因此网关需要实现一些机制来将所有传入的消息路由到实时服务,反之亦然。

想法

(1) 让第二个 HTTP 服务器监听网关上的事件并将这些事件发送到实时服务器。在另一个方向上,实时服务器将向网关发送事件,然后网关将它们发送到前端。我认为这种方法肯定会奏效,但是将所有内容都发出两次似乎是多余的。而且肯定会影响性能?

(2) 使用 Socket.IO 适配器到“pass event between nodes”,这似乎是正确的方法,因为它用于“在进程或计算机之间传递消息”。但是由于缺乏文档/示例,我在入门时遇到了问题。我也没有使用Redis(是否需要使用适配器?)

(3) 使用 socket.io-emitter 包,这似乎不是一个好的选择,因为上次提交是在 3 年前。

(4) 别的?

【问题讨论】:

so 您必须使用 API 网关来重定向流量吗?我们在浇注应用程序中实现了 socket.io,但该服务已部署在单独的服务(pod)中。使用ingress-controller k8s 将socket 流量发送到足球服务。 @GiorgioCerruti 不,我没有使用网关,但这是我计划我的应用程序工作的方式。所以你会建议通过 Ingress 暴露我的“内部服务”? 我使用nginx 作为入口控制器。如果您愿意,也可以使用 haproxy。您将拥有 2 个服务(部署),1 个用于管理 HTTP(s) 请求,1 个用于管理套接字请求。使用入口,您可以公开路径并将流量重定向到正确的服务,例如每个命中/socket 的请求都将被重定向到socket-service 应用程序。 好吧,这听起来像是在尝试,因为我已经使用了 nginx Ingress。如果您可以发布一个展示如何实现它的答案,那就太棒了(这是我目前使用的入口配置:github.com/flolu/centsideas/blob/…) 【参考方案1】:

好吧,基本上我是这样设计应用的

入口

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: centsideas-ingress
  annotations:
    kubernetes.io/tls-acme: 'true'
    kubernetes.io/ingress.class: 'nginx'
    cert-manager.io/cluster-issuer: letsencrypt
spec:
  tls:
    - hosts:
        - centsideas.com
        - api.centsideas.com
      secretName: centsideas-tls
  rules:
    - host: api.centsideas.com
      http:
        paths:
          - path: /socker.io
            backend: 
             serviceName: socket-service
             servicePort: 8000
          -  path: /
             backend:
              serviceName: centsideas-gateway
              servicePort: 3000
    - host: centsideas.com
      http:
        paths:
          - backend:
              serviceName: centsideas-client
              servicePort: 8080

服务

apiVersion: v1
kind: Service
metadata:
 name: socket-service
 annotations:
  service.beta.kubernetes.io/external-traffic: "OnlyLocal" 
 namespace: namespace
spec:
 sessionAffinity: ClientIP
 ports:
  - name: ws-port
    protocol: TCP
    port: 8000
 type: ClusterIP
 selector:
  service: ws-api

然后您创建部署以部署 ws-service。像这样,你也可以激活 k8s HPA(horizo​​ntal pod autoscaling)来扩展 socket.io 服务。 您必须根据您的 k8s 版本更改注解和其他选项(我认为注解 service.beta.kubernetes.io/external-traffic: "OnlyLocal" 已被弃用)。

【讨论】:

不错不错!澄清一下:对于每个需要 Web 套接字的内部服务,我会添加另一个 socket-service 并将其添加到 Ingress? 视情况而定。如果您需要公开新服务(新代码库),是的,您必须为每个微服务创建新的 k8s 服务。相反,如果您需要扩展您的 socket.io 应用程序(创建相同代码库的更多实例),不,您不需要。服务基本上是由 k8s 使用 iptables 制作的 LoadBalancer,它会在实例之间平衡您的请求,由它自己决定哪个 pod 不忙于请求/资源。 有道理,这取决于用例:) 所以我会等几天,以防万一我能得到其他答案。如果没有,您将获得赏金,谢谢!【参考方案2】:

由于内部服务不对外暴露,我建议使用隧道。 ngrok 是一个命令,用于通过任何 NAT 或防火墙为您的 localhost 服务器提供即时且安全的 URL。 如果您的服务器通过某个端口公开套接字服务,则使用 ngrok 创建一个反向代理来公开您可以连接到前端应用程序的世界。 使用这个命令很简单,下面是一个使用示例:

    在以下地址Official site注册并下载ngrok文件

    只需运行以下指令即可使其工作

    ./ngrok http 3000

    要使其永久化,您必须创建一个服务并使用文件 ngrok.yml 以获得最佳配置。

这里是官方文档Here

【讨论】:

我的回答可能不够精确。您的方法可能有效,但内部服务必须保持在内部。外部的任何人都不应该能够通过直接连接与它交谈

以上是关于SocketIO 与客户端和服务之间的网关通信?的主要内容,如果未能解决你的问题,请参考以下文章

SocketIO の 聊天练习

SocketIO の 聊天练习

个人技术总结——flask-socketio框架

java是如何实现客服在线聊天功能的?

autojs双向通信

Geode 通信机制