Dezenas de milhões de design de estrutura [Gateway] de serviços de entrada (3: modo em camadas)

Este artigo será escrito em modo de pesquisa técnica, e alunos não técnicos podem ignorá-lo.

fundo

Na implementação do serviço de entrada baseado no design e construção do modelo de componente (plug-in), ao usar o plug-in do pacote nativo Go, haverá defeitos funcionais, que não são suficientes para suportar os recursos esperados; ao usar o pacote de código aberto go-plugin, embora os defeitos funcionais tenham sido corrigidos, mas perdeu parte do desempenho (custos de comunicação entre os componentes e o programa principal).

Para obter detalhes, consulte o design da estrutura das dezenas de milhões de serviços de entrada [Gateway] (1)

Para obter detalhes, consulte o design da estrutura de dezenas de milhões de serviços de entrada [Gateway] acima (1)

Este artigo apresentará outro padrão de arquitetura baseado em "camadas" e "pipeline".

em camadas

A ideia de camadas foi vista desde que você começou a aprender computadores. Arquitetura de computador modelo "von Neumann", arquitetura de banco de dados/kernel Linux, etc. Pode-se dizer que "camadas" é a maneira principal e eficaz de desmontar problemas complexos e simplificá-los.

insira a descrição da imagem aqui

A lógica de negócios é abstraída no nível superior e dividida em várias camadas, e os níveis superior e inferior dependem um do outro. No entanto, deve-se notar que quanto mais fina a granularidade do controle de abstração de negócios, maior o custo de implementação; e se o relacionamento de chamada do negócio for dinâmico, mais camadas de abstração levarão a um aumento na complexidade geral e maior magnitude; negócios subsequentes comunicação Na ausência de um entendimento completo da estrutura abstrata em camadas, a qualidade da implementação da função é cara, adicionando uma camada de neblina à manutenção e expansão dos serviços subseqüentes.

Relacionamento de chamada dinâmico: Aparece em cenários de negócios complexos, ou seja, existem vários serviços de downstream, o serviço de chamada real é determinado pelo campo de resposta do serviço de upstream e toda a rota apresenta uma topologia de relacionamento dinâmico.

A névoa da manutenção e expansão: Refere-se ao desenvolvimento iterativo sem entender completamente o design do framework, o que não pode garantir que as funções entregues farão uso total dos recursos do framework, tornando a qualidade de saída um tanto especulativa.

O seguinte é dividido em três maneiras de diferentes granularidades de divisão.

Distribuição + Handle

Na base atual, o tamanho da partícula é aumentado, então

  • A realização do negócio é mais gratuita.
  • A estrutura é retirada do negócio e o custo de manutenção é menor.

insira a descrição da imagem aquiNo modo Web, o processo existente é dividido em duas partes: roteador + executar.

  • roteador
    • Distribua o tráfego para o identificador correspondente.
  • executar
    • O processamento de negócios específico não é dividido em camadas de estrutura, e o design e a implementação específicos são realizados por estudantes de desenvolvimento de negócios.

distribuição+gancho

Com base no identificador, adicione restrições de gancho, então

  • A granularidade da restrição é muito pequena e a complexidade é muito alta para cenários sem requisitos de gancho.

insira a descrição da imagem aqui

No modo Web, divida o processo existente em roteador + afterhook\execute\beforehook\assert logic.

  • roteador

    • Distribua o tráfego para o identificador correspondente.
  • afterhook\execute\beforehook\assert

    • Entre processos de negócios específicos, controle o tamanho da granularidade, pré-execução, execução e pós-execução.

Distribuição + camadas simultâneas

É necessário organizar o negócio atual, redividir a ordem de chamada dos subserviços e chamar simultaneamente em camadas, de modo

  • Existem cenários em que o roteamento de subserviços downstream é alterado dinamicamente, o que não pode ser previsto e colocado em camadas com antecedência, e roteamento adicional precisa ser projetado.
  • A maioria das chamadas de serviço pode ser alterada de serial para paralelo e o desempenho será melhorado.
  • Se houver um problema de roteamento dinâmico, processamento adicional precisa ser feito para esse problema e a complexidade do projeto e da implementação é alta.

A premissa de uso é que existe um mapa estático de topologia de subserviços, e o relacionamento da chamada de serviço é colorido dinamicamente e dividido em diferentes níveis, e as chamadas concorrentes são feitas de acordo com o nível de serviços.

  • Duas partes são abstraídas: construção de parâmetros + emenda de resposta e invocação simultânea de serviço.

gasoduto

A ideia de pipelines pode ser raramente vista em linguagens tradicionais. É mais comum em novos estilos como Goland e Ruby, especialmente em designs que suportam simultaneidade no nível da linguagem e são nativos da nuvem. O foco está na busca final de desempenho e processamento de stream de alto desempenho de dados, como big data e modelos grandes.

Observação: para saber mais sobre o nativo da nuvem, acesse: Migração da arquitetura de aplicativo nativo da nuvem 1: Paradigma de migração incremental

insira a descrição da imagem aqui

Mas não importa, você pode simplesmente transplantar o conceito de middleware para o pipeline primeiro e depois aprender mais. O design aqui é baseado no Canal em Goland.

Nota: Se você quiser saber mais sobre a Goland, acesse: Design Reflection of Go Language

Canal

Nos vários esquemas e implementações mencionados acima, todos eles são alterações de string e fusões dentro da solicitação e até mesmo deixam o nível da linguagem "operando com base no PHP existente".

Aqui falamos sobre um design de padrão baseado em pipeline que realiza o paralelismo no nível de serviço, que é especialmente adequado para cenários de simultaneidade extremamente grandes e está em conformidade com as características da linguagem Go.

insira a descrição da imagem aqui

A co-rotina principal será responsável pelo monitoramento e chamadas concorrentes de cada autoatendimento, sendo que a cor-rotina de negócios é utilizada apenas para iniciação do serviço e recebimento de resposta. Agregue diferentes solicitações na dimensão de subserviço e chame-as em paralelo.

Aqui está uma breve visão geral do programa:

  • Montando "apenas orquestrar parâmetros de serviço"
    • Do projeto de processo linear ao simplificado e altamente montado.
  • acelerar
    • Converta vários serviços em um único pv de serial para paralelo.
    • Converta chamadas pv únicas em simultâneas.
  • expandir
    • Modularização do serviço, chamadas multi-rotas são 100% reutilizáveis.
    • A estrutura é forte, protege o uso do negócio e possui altos requisitos para a realização da função de chamada básica "funções completas, suporte à configuração personalizada".

Mas deve-se notar que,

  • Envolve o modelo Go Channel, e o custo de implementação é relativamente alto.
    • É necessária a consideração de problemas/esquemas, como cobertura rigorosa e científica e impasses simultâneos.
implementação de demonstração
package main

import (
	"fmt"
	"sync"
)


type FInput struct{
    
    
	callback chan FInput
	param string
	res string
}


func main () {
    
    
	fmt.Println("hello https://tool.lu/")
	c := make(chan FInput,3)
	defer close(c)
	var wg sync.WaitGroup
	wg.Add(3)  
	go F(c,wg) //服务开启监听
	go A(c,wg) //发起服务请求
	go B(c,wg) //发起服务请求
	wg.Wait()
	fmt.Println("X https://tool.lu/ is finish")
}

func F (c chan FInput,wg sync.WaitGroup){
    
    
	fmt.Println("F https://tool.lu/ len:",len(c))
	for{
    
    
		i, ok := <-c
		fmt.Println("F https://tool.lu/ ok:",ok)
		fmt.Println("F https://tool.lu/ param:",i.param)
		if ok{
    
    
			i.res = i.param + " is executed "
			i.callback <- i
		}
	}
	fmt.Println("F https://tool.lu/ is finish")
	wg.Done()
}

func A (c chan FInput,wg sync.WaitGroup){
    
    
	cb:=make(chan FInput)
	defer close(cb)
	var p FInput
	p.callback = cb
	p.param = "A"
	c<-p
	i, ok := <-cb
	if ok{
    
    
		fmt.Println("A https://tool.lu/ res ok:",ok)
		fmt.Println("A https://tool.lu/ res param:",i.param)
		fmt.Println("A https://tool.lu/ res value:",i.res)
	}
	fmt.Println("A https://tool.lu/ is finish")
	wg.Done()
}

func B (c chan FInput,wg sync.WaitGroup){
    
    
	cb:=make(chan FInput)
	defer close(cb)
	var p FInput
	p.callback = cb
	p.param = "B"
	c<-p
	i, ok := <-cb
	if ok{
    
    
		fmt.Println("B https://tool.lu/ res ok:",ok)
		fmt.Println("B https://tool.lu/ res param:",i.param)
		fmt.Println("B https://tool.lu/ res value:",i.res)
	}
	fmt.Println("B https://tool.lu/ is finish")
	wg.Done()
}

resumo

Na verdade, comparando os vários projetos de padrões arquitetônicos mencionados acima, cada um tem suas próprias características e suas vantagens e desvantagens são combinadas. Na hora de escolher uma arquitetura, pensar em diferentes modelos é apenas o primeiro passo. Somente sob esta premissa pode ser feita uma seleção adicional.

À medida que o chatGPT entra no campo de visão do público, o "canal modelo grande" se populariza, e seu processo de evolução singular é ainda mais marcante. Para ser franco, vários aplicativos no futuro serão modelos mais inteligentes e maiores...

O próximo capítulo apresentará como o "serviço de entrada" é combinado com o "grande modelo" para projetar um modelo de arquitetura orientado para o futuro, portanto, fique atento!

apêndice

Acho que você gosta

Origin blog.csdn.net/qq_34417408/article/details/131473186
Recomendado
Clasificación