Comunicação SocketIO com um gateway entre o cliente e um serviço?

8

Essência

Eu tenho um aplicativo que é executado em uma arquitetura baseada em microsserviço (no Kubernetes). Toda a comunicação de / para fora do aplicativo ocorre através de um API Gateway .

O que significa apenas que solicitações do meu front-end não vão diretamente para os serviços, mas precisam passar pelo Gateway.

Motivo

Agora preciso implementar um recurso que exija comunicação em tempo real entre o frontend e um serviço interno. Mas como o serviço interno não é exposto ao exterior, preciso de uma maneira de "rotear" os dados em tempo real através do Gateway.

Todos os meus serviços estão em execução no Node.js, motivo pelo qual desejo usar o Socket.IO para implementar a comunicação em tempo real.

arquitetura

Questão

Mas como implementar a seta dupla roxa do esboço?

Geralmente, o cliente front-end se conecta ao servidor em que o Socket.IO está sendo executado. Mas, no meu caso, esse servidor (o servidor de recursos em tempo real) não pode ser acessado pelo cliente (e nunca deveria estar), o que significa que o cliente precisa se conectar ao Gateway. Portanto, o Gateway precisa implementar algum mecanismo para rotear todas as mensagens recebidas para o serviço em tempo real e vice-versa.

Ideias

(1) Tenha um segundo servidor HTTP escutando eventos no Gateway e emita esses eventos para o servidor em tempo real. Na outra direção, o servidor em tempo real emitirá eventos para o Gateway, que os emitirão para o frontend. Eu acho que essa abordagem definitivamente funcionará, mas parece redundante emitir tudo duas vezes. E isso definitivamente prejudicaria o desempenho?

(2) Use um adaptador Socket.IO para " passar evento entre nós ", o que parece ser o caminho certo, pois é usado para "transmitir mensagens entre processos ou computadores". Mas tenho problemas para começar devido à falta de documentação / exemplos. Também não estou usando Redis (é necessário usar o adaptador?)

(3) Use o pacote socket.io-emitter , que não parece ser uma boa opção, já que o último commit foi de 3 anos atrás.

(4) Algo mais?

Florian Ludewig
fonte
então Você deve usar o API Gateway para redirecionar o tráfego? Temos o socket.io implementado no aplicativo pour, mas o serviço foi implantado em um serviço separado (pod). O uso do ingress-controllerk8s envia o sockettráfego para o serviço de futebol.
Giorgio Cerruti
@GiorgioCerruti Não, não preciso usar o Gateway, mas foi assim que planejei que meu aplicativo funcionasse. Então, você recomendaria apenas expor meu "serviço interno" via Ingress?
Florian Ludewig 27/04
Eu fiz isso usando nginxcomo um controlador de entrada. Você também pode usar haproxy, se preferir. Você terá 2 serviços (implantação) 1 para gerenciar solicitações HTTP (s) e 1 para gerenciar solicitações de soquete. Usando o ingresso, você pode expor o caminho e redirecionar o tráfego para o serviço certo, por exemplo, toda solicitação atingida /socketserá redirecionada para o socket-serviceaplicativo.
Giorgio Cerruti
ok, isso soa como algo que está tentando, porque eu já uso o nginx Ingress. Seria incrível se você pudesse postar uma resposta mostrando como implementá-la (aqui está a configuração de entrada que eu uso atualmente: github.com/flolu/centsideas/blob/… )
Florian Ludewig

Respostas:

3

Tudo bem, basicamente eu projetei o aplicativo assim

Entrada

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

Serviço

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

Em seguida, você cria sua implementação para implantar o serviço ws. Assim, você também pode ativar o k8s HPA (escalonamento automático do pod horizontal) para ampliar o serviço socket.io. Você deve alterar as anotações e outras opções com base na sua versão do k8s (acho que a anotação service.beta.kubernetes.io/external-traffic: "OnlyLocal"foi descontinuada).

Giorgio Cerruti
fonte
OK, fixe! Apenas para esclarecer: para cada serviço interno que requer soquetes da web, eu adicionaria outro socket-servicee o acrescentaria ao Ingress?
Florian Ludewig 27/04
Depende. Se você precisar expor novos serviços (nova base de código), sim, precisará criar novos serviços k8s a cada microsserviço. Em vez disso, se você precisar ampliar seu aplicativo socket.io (crie mais instâncias da mesma base de código), não precisa. Um serviço é basicamente um LoadBalancer feito pelo k8s usando o iptables; ele equilibrará sua solicitação entre instâncias que decidem por si próprias qual pod não está ocupado com solicitações / recursos.
Giorgio Cerruti
Faz sentido, depende do caso de uso :) Portanto, esperarei alguns dias para obter outras respostas. Caso contrário, você receberá a recompensa, obrigado!
Florian Ludewig
0

Como o serviço interno não é exposto ao exterior, recomendo usar um túnel. ngrok é um comando para uma URL instantânea e segura para o servidor localhost através de qualquer NAT ou firewall. Se o seu servidor expuser o serviço de soquete através de uma determinada porta, use o ngrok para criar um proxy reverso para expor o mundo com o qual você pode se conectar ao seu aplicativo de front-end. Usando este comando é muito simples, aqui está um exemplo de como usá-lo:

  1. Registre-se e faça o download do arquivo ngrok no seguinte endereço Site oficial
  2. Basta executar as seguintes instruções para fazê-lo funcionar

    ./ngrok http 3000

  3. Para torná-lo permanente, você deve criar um serviço e usar um arquivo ngrok.yml para obter a melhor configuração.

Aqui está a documentação oficial Aqui

Godie007
fonte
Provavelmente não fui suficientemente preciso na minha resposta. Sua abordagem pode funcionar, mas o serviço interno precisa permanecer interno. Ninguém de fora deve poder falar com ele com uma conexão direta
Florian Ludewig