Componentes do K8s: instalação, uso e princípio do etcd (Linux)

Componentes do K8s: instalação, uso e princípio do etcd (Linux)

1 Introdução e instalação

1.1 Introdução

A arquitetura do sistema distribuído requer alta consistência e o etcd atende aos requisitos de consistência no sistema distribuído.

  • Middleware que implementa armazenamento distribuído de par chave-valor consistente, suporta plataforma cruzada e tem uma comunidade ativa.
  • O etcd é um armazenamento de chave-valor distribuído baseado em go (semelhante ao Redis), projetado para salvar dados de chave de forma confiável e rápida e fornecer acesso. A colaboração distribuída confiável é obtida por meio de bloqueios distribuídos, eleições de líder e barreiras de gravação. Os clusters do etcd são preparados para armazenamento e recuperação de dados altamente disponíveis e persistentes.
  • Um cluster etcd completo (cluster) precisa de pelo menos 3 unidades, para que um mestre e dois nós possam ser selecionados
  • etcd atualmente ocupa duas portas 2379 e 2380
  • 2379: Fornece serviço API HTTP e interage com etcdctl;
  • 2380: comunicação entre nós no cluster;
  • Tem forte consistência, 常用于注册中心(compartilhamento de configuração e descoberta de serviço)
  • Atualmente é o componente básico dos nativos distribuídos e em nuvem, como: k8s, etc.

Teoria CAP: consistência, disponibilidade, tolerância de partição [CP, AP]

  • estrutura do sistema:
    insira a descrição da imagem aqui

Cenário de aplicação:

  1. armazenamento de chave-valor
  2. Registro e descoberta de serviços
  3. Publicação e assinatura de mensagens
  4. bloqueio distribuído

1.2 Protocolo da Balsa

Referência: https://juejin.cn/post/7035179267918938119#heading-3

1.2.1 Conceitos básicos

① Explicação dos termos

O protocolo Raft consiste em 3 papéis:

  • Líder: O líder é eleito pelas massas, e apenas um líder pode ser eleito em cada eleição;
  • Candidate (candidato): Quando não há dirigente, algumas pessoas podem se candidatar e então concorrer ao cargo de dirigente;
  • Seguidor (massa): Isso é fácil de entender, então não vou explicar.

Então, durante o processo eleitoral, existem vários conceitos importantes:

  1. Eleição de Líder (Leader Election): Eleição para abreviar, é selecionar um líder entre os candidatos;
  2. Termo (termo): Na verdade é um número contínuo que aumenta independentemente, e uma eleição de líder será reiniciada toda vez que o mandato estiver no cargo;
  3. Election Timeout (tempo limite da eleição): É um período de tempo limite. Quando a multidão não receber o heartbeat do líder, a eleição será refeita.
②Mudança de função

Esta imagem é uma imagem de troca de papéis de líderes, candidatos e as massas. Deixe-me resumir brevemente:
insira a descrição da imagem aqui

  • Multidão -> Candidatos: quando uma eleição começa, ou quando "eleição expirou"
  • Candidato -> Candidato: Quando "tempo de eleição" ou inicia um novo "período"
  • Candidato -> Líder: Ao obter a maioria dos votos
  • Candidato -> Multidão: outros nodos tornam-se líderes, ou iniciam um novo "termo"
  • Líder -> Crowd: Se você achar que seu ID do termo é menor que o de outros nós, você desistirá automaticamente da posição de líder

Observações: Cada caso será explicado em detalhes posteriormente.

1.2.2 Eleição

① Eleição do líder

Para facilitar a explicação subsequente, desenhei um diagrama simples: o "temporizador de eleição" é na verdade o "tempo limite" de cada nó.

insira a descrição da imagem aqui

Torne-se um candidato: cada nó tem seu próprio "tempo limite", porque é aleatório, o valor do intervalo é de 150 ~ 300ms, portanto, a probabilidade do mesmo tempo aleatório é relativamente pequena, porque o nó B é o primeiro a expirar, então torna-se candidato.

insira a descrição da imagem aqui

Eleição dos líderes: O candidato B começa a votar, e voltam a votar as pessoas A e C. Quando o candidato B obtém a maioria dos votos, a eleição é bem-sucedida e o candidato B se torna o líder.

insira a descrição da imagem aqui

Detecção de pulsação: Para jurar seu status de líder o tempo todo, o líder B precisa enviar uma pulsação para a multidão o tempo todo. Quando as multidões A e C recebem a pulsação do líder B, o "tempo limite" das multidões A e C será redefinido para 0 e, em seguida, recontar e repetir por sua vez.

Deve ser explicado aqui que o período de pulsação da transmissão do líder deve ser mais curto do que o período de tempo limite do "temporizador da eleição", caso contrário, as massas frequentemente se tornarão candidatas, ocorrerão eleições frequentes e o líder será trocado.
insira a descrição da imagem aqui

②A situação em que o líder desliga

Quando o líder B desligar, o "temporizador de eleição" das multidões A e C continuará funcionando. Quando a multidão A atingir o tempo limite primeiro, ela se tornará uma candidata e, em seguida, o processo de acompanhamento será o mesmo da "eleição do líder" processo, ou seja, para notificar o voto -> Receber votos -> tornar-se um líder -> detecção de pulsação.

insira a descrição da imagem aqui

③ Existem vários candidatos

Quando houver vários candidatos A e D, os dois candidatos iniciarão a votação ao mesmo tempo. Se o número de votos for diferente, o nó que obtiver a maioria dos votos primeiro será o líder; se o número de votos for o mesmo , uma nova rodada de votação será iniciada .

insira a descrição da imagem aqui

Quando C torna-se um novo candidato, o mandato neste momento é de 5, e uma nova rodada de votação é iniciada. Depois que outros nós iniciam a votação, eles atualizam seus próprios valores de mandato e, finalmente, selecionam um novo líder como nó C.
insira a descrição da imagem aqui

1.2.3 Replicação de Log

①Copiar máquina de estado

A ideia básica da máquina de estado de replicação é uma máquina de estado distribuída. O sistema consiste em várias unidades de replicação. Cada unidade de replicação é uma máquina de estado e seu estado é armazenado no log de operação. Conforme a figura abaixo, o módulo de consistência do servidor é responsável por receber comandos externos e anexá-los ao seu próprio log de operação, ele se comunica com os módulos de consistência de outros servidores para garantir que os logs de operação de cada servidor terminem com o same A sequência contém a mesma diretiva. Depois que as instruções são replicadas corretamente, a máquina de estado de cada servidor as processa na ordem do oplog e retorna a saída para o cliente.

②Processo de sincronização de dados

O processo de sincronização de dados baseia-se na ideia de "máquina de estado de replicação", que é "enviar" primeiro e depois "aplicar". Quando o cliente inicia uma solicitação de atualização de dados, a solicitação irá primeiro para o nó líder C, e o nó C atualizará os dados de log e notificará os nós de multidão para atualizar o log. Quando o nó de multidão atualizar o log com sucesso, ele retornará uma notificação de sucesso para o líder C, concluindo assim a operação ""Enviar"; quando o líder C receber a notificação, ele atualizará os dados locais e notificará o público para atualizar os dados locais, e ao mesmo tempo retornará um sucesso notificação ao Cliente, completando assim a operação "Aplicar". Caso o Cliente tenha novas atualizações de dados posteriormente a operação, o processo acima será repetido.

insira a descrição da imagem aqui

③princípio de registro

O log é organizado na ordem das entradas (entrada) e o log contém campos como índice, termo, tipo e dados. O índice é incrementado com o incremento da entrada de log e o termo é o termo do líder que gerou a entrada naquele momento. type é o campo definido pelo etcd. Atualmente, existem dois tipos, um é o log normal do EntryNormal e EntryConfChange é o log da mudança de configuração do próprio etcd. data é o conteúdo do log.

insira a descrição da imagem aqui
A operação de log na memória é feita principalmente por um objeto do tipo raftLog.A seguir está o código-fonte do raftLog. Como você pode ver, existem dois locais de armazenamento, um é o armazenamento para salvar as entradas de log que foram persistidas. instáveis ​​são entradas de log salvas que ainda não foram persistidas.

type raftLog struct {
    
    
     // storage contains all stable entries since the last snapshot.
     //这里还是一个内存存储,保存了从上一个snapshot起,已经持久化了的日志条目。
     storage Storage
 
     // unstable contains all unstable entries and snapshot.
     // they will be saved into storage.
     // 保存了尚未持久化的日志条目或快照。
     unstable unstable
 
     // committed is the highest log position that is known to be in
     // stable storage on a quorum of nodes.
     //指示当前已经确认的被半数以上节点同步过的最新日志index
     committed uint64
     // applied is the highest log position that the application has
     // been instructed to apply to its state machine.
     // Invariant: applied <= committed
     //指示已经作用到状态机中的最新日志条目的index
     applied uint64
 
     logger Logger

Logs persistentes: WAL e snapshot. A figura abaixo mostra a definição da interface do Storage persistente e a definição dos campos na estrutura do storage. Na verdade, ele contém um WAL para salvar entradas de log e um Snapshotter é responsável por salvar instantâneos de log.

insira a descrição da imagem aqui
WAL é um método de acréscimo para armazenar entradas de log sequencialmente em um arquivo. Os registros armazenados no WAL estão no formato walpb.Record. Type representa o tipo de dados e Crc é o campo de verificação Crc gerado. Dados são dados reais.

Referência: https://mp.weixin.qq.com/s/o_g5z77VZbImgTqjNBSktA

1.2.4 Situação do cérebro dividido (problema de rede, vários mestres aparecem)

Quando um problema de rede leva a um split-brain e ocorre uma situação de dual-Leader, cada rede pode ser entendida como uma rede independente, porque o Leader original está sozinho em uma zona, então os dados enviados a ele não podem ser copiados para a maioria dos nós , então Os dados nunca são confirmados, o que pode ser visto na Figura 4 (SET 3 não é confirmado).

insira a descrição da imagem aqui
Quando a rede é restaurada, o antigo líder descobre que o prazo do novo líder no cluster é maior do que ele, ele fará o downgrade automaticamente para o seguidor e sincronizará os dados do novo líder para obter consistência de dados do cluster

insira a descrição da imagem aqui
A situação de cérebro dividido é, na verdade, apenas um tipo de situação anormal. Quando o Líder notifica o Seguidor para atualizar o log e o Líder envia a atualização, há problemas causados ​​por várias situações anormais. Não vou entrar em detalhes sobre isso. Para detalhes, consulte "Cloud Native Distributed O capítulo "1.4.3 Abnormal Situations" no livro "Storage Cornerstone - In-depth Analysis of etcd" é relativamente claro.

1.3 Instalação

  1. Baixe o pacote compactado (tente escolher ~baixar no diretório)
  • Faça o download diretamente pelo github e, em seguida, faça o upload do ftp para o linux. Endereço do Github: https://github.com/etcd-io/etcd/releases, faça o download de acordo com sua própria versão do linux
  • Se o acesso ao github for muito lento, você pode baixá-lo através do site espelho da Huawei: https://mirrors.huaweicloud.com/etcd/
  • curl download direto; curl -O https://github.com/etcd-io/etcd/releases/download/v3.4.24/etcd-v3.4.24-linux-amd64.tar.gz

PS:curl não suporta Https por padrão, comando #curl -V (V maiúsculo) para verificar se existe https no item Protocolos, caso não, utilize o comando: # yum install openssl-devel para instalar SSL

  1. descompactar
tar -zxvf etcd-v3.4.6-linux-amd64.tar.gz
  1. Configurar variáveis ​​de ambiente

Adicione o caminho do arquivo executável à variável de ambiente PATH para os arquivos etcd e etcdctl na pasta.

  • etcd é o servidor e etcdctl é o terminal de controle operado pelo pessoal de operação e manutenção. Geralmente, você só precisa instalar o etcd. Agora ele é instalado na mesma máquina para aprendizado.
  • PS: Use echo $PATH para visualizar seu próprio caminho de variável de ambiente
# 移动可执行文件位置
mv etcd /usr/local/bin
mv etcdctl /usr/local/bin
# 修改profile文件,
vim /etc/profile
# 在文件最后加入变量,因为etcd默认使用V2版本,我们需要V3版本的API。
export ETCDCTL_API=3
# 使环境变量生效
source /etc/profile

insira a descrição da imagem aqui
4. Veja as informações da versão

etcdctl version

insira a descrição da imagem aqui

  1. Para criar um arquivo de configuração etcd, você deve confirmar se o usuário tem permissões de leitura e gravação no diretório de dados etcd, caso contrário, o serviço pode não iniciar corretamente
[root@Cent0S7 ~]# mkdir -p /var/lib/etcd/
[root@Cent0S7 ~]# cat <<EOF | sudo tee /etc/etcd.conf
#节点名称
ETCD_NAME=$(hostname -s)
#数据存放位置
ETCD_DATA_DIR=/var/lib/etcd/
EOF

注意:5以后的操作根据自己需求可选

  1. Criar um arquivo de inicialização
[root@Cent0S7 ~]# cat <<EOF | sudo tee /etc/systemd/system/etcd.service
 
[Unit]
Description=Etcd Server
Documentation=https://github.com/coreos/etcd
After=network.target
 
[Service]
User=root
Type=notify
#这个文件特别关键,etcd使用的环境变量都需要通过环境变量文件读取
EnvironmentFile=-/etc/etcd.conf
ExecStart=/usr/local/bin/etcd
Restart=on-failure
RestartSec=10s
LimitNOFILE=40000
 
[Install]
WantedBy=multi-user.target
EOF 
  1. Recarregue a configuração e inicialize e inicie o etcd
[root@Cent0S7 ~]# systemctl daemon-reload && systemctl enable etcd && systemctl start etcd

Inicialize e defina o status como ativado:

[root@Cent0S7 ~]# systemctl list-unit-files etcd.service
UNIT FILE    STATE 
etcd.service enabled
 
1 unit files listed.

Veja o status do etcd:

[root@Cent0S7 ~]# systemctl show etcd.service
Type=notify
Restart=on-failure
NotifyAccess=main
RestartUSec=10s
TimeoutStartUSec=1min 30s
TimeoutStopUSec=1min 30s
WatchdogUSec=0
WatchdogTimestamp=Sun 2020-11-29 22:44:07 CST
WatchdogTimestampMonotonic=9160693425
------  剩余内容 (略)  -------
  1. Verifique se a porta está habilitada
[root@Cent0S7 ~]# netstat -an |grep 2379
tcp        0      0 127.0.0.1:2379          0.0.0.0:*               LISTEN    
tcp        0      0 127.0.0.1:53156         127.0.0.1:2379          ESTABLISHED
tcp        0      0 127.0.0.1:2379          127.0.0.1:53156         ESTABLISHED

O CentOS não tem o netstat instalado por padrão, você precisa de # yum install -y net-tools para instalá-lo você mesmo

2 uso

2.1 colocar (novo, modificado)

# 设置值 etcdctl put KEY VALUE
etcdctl put myKey "this is etcd"

# 取值 etcdctl get KEY
etcdctl get myKey

insira a descrição da imagem aqui

2.2 obter (consulta)

# 1. 根据key值查询
 etcdctl get name1
# 2. 返回结果不显示key,只显示value
etcdctl get --print-value-only name1
# 3. 按key前缀查找
etcdctl get --prefix name
# 4. 按key的字节排序查找
etcdctl get --from-key name2
# 5. 查询所有key
etcdctl get --from-key ""

2.3 del (excluir)

# 1. 删除指定key
etcdctl del name11
# 2. 删除指定前缀的key
etcdctl del --prev-kv --prefix name
# 3. 删除所有key
 etcdctl del --prefix ""

3 etcd+grpc realiza registro e descoberta de serviço (windows)

Estrutura do projeto:
insira a descrição da imagem aqui

3.1 A janela de encaixe local inicia o etcd

Instale o ambiente docker localmente ou baixe o docker-desktop diretamente

  • Referência do tutorial de construção: https://editor.csdn.net/md/?articleId=130749488
  1. puxar imagem
docker pull bitnami/etcd
  1. correr
docker run -d --name Etcd-server --publish 2379:2379 --env ALLOW_NONE_AUTHENTICATION=yes --env ETCD_ADVERTISE_CLIENT_URLS=http://localhost:2379 bitnami/etcd:latest

insira a descrição da imagem aqui

3.2 Escrever arquivo proto

servidor.proto

syntax = "proto3";
option go_package = ".;rpc";
message Empty {
    
    

}

message HelloResponse {
    
    
    string hello = 1;
}

message RegisterRequest {
    
    
    string name = 1;
    string password = 2;
}

message RegisterResponse {
    
    
    string uid = 1;
}

service Server {
    
    
    rpc Hello(Empty) returns(HelloResponse);
    rpc Register(RegisterRequest) returns(RegisterResponse);
}

Por meio do script, gere o código go correspondente

Antes de gerar, primeiro crie o diretório rpc nos diretórios do cliente e do servidor, respectivamente

gen.sh:

echo "生成rpc server代码"

# 输出目录
OUT=../server/rpc

# protoc脚本及参数
protoc \
--go_out=${OUT} \
--go-grpc_out=${OUT} \
--go-grpc_opt=require_unimplemented_servers=false \
server.proto

echo "生成rpc client代码"

OUT=../client/rpc
protoc \
--go_out=${OUT} \
--go-grpc_out=${OUT} \
--go-grpc_opt=require_unimplemented_servers=false \
server.proto
# 也可以直接在终端执行命令
# 生成server下相关的
protoc --go_out=../server/rpc --go-grpc_out=../server/rpc --go-grpc_opt=require_unimplemented_servers=false server.proto

# client相关的
protoc --go_out=../client/rpc --go-grpc_out=../client/rpc --go-grpc_opt=require_unimplemented_servers=false server.proto

insira a descrição da imagem aqui

3.3 lado do servidor

①etcd.go:

package main

import (
	"context"
	"fmt"
	clientv3 "go.etcd.io/etcd/client/v3"
	"go.etcd.io/etcd/client/v3/naming/endpoints"
	"log"
)

const etcdUrl = "http://localhost:2379"
const serviceName = "chihuo/server"
const ttl = 10

var etcdClient *clientv3.Client

func etcdRegister(addr string) error {
    
    
	log.Printf("etcdRegister %s\b", addr)
	etcdClient, err := clientv3.NewFromURL(etcdUrl)

	if err != nil {
    
    
		return err
	}

	em, err := endpoints.NewManager(etcdClient, serviceName)
	if err != nil {
    
    
		return err
	}

	lease, _ := etcdClient.Grant(context.TODO(), ttl)

	err = em.AddEndpoint(context.TODO(), fmt.Sprintf("%s/%s", serviceName, addr), endpoints.Endpoint{
    
    Addr: addr}, clientv3.WithLease(lease.ID))
	if err != nil {
    
    
		return err
	}
	//etcdClient.KeepAlive(context.TODO(), lease.ID)
	alive, err := etcdClient.KeepAlive(context.TODO(), lease.ID)
	if err != nil {
    
    
		return err
	}

	go func() {
    
    
		for {
    
    
			<-alive
			fmt.Println("etcd server keep alive")
		}
	}()

	return nil
}

func etcdUnRegister(addr string) error {
    
    
	log.Printf("etcdUnRegister %s\b", addr)
	if etcdClient != nil {
    
    
		em, err := endpoints.NewManager(etcdClient, serviceName)
		if err != nil {
    
    
			return err
		}
		err = em.DeleteEndpoint(context.TODO(), fmt.Sprintf("%s/%s", serviceName, addr))
		if err != nil {
    
    
			return err
		}
		return err
	}

	return nil
}

②server.go:

package main

import (
	"context"
	"fmt"
	"go_code/demo01/study/etcd-grpc/server/rpc"
)

type Server struct {
    
    
}

// server.proto文件中 服务提供的方法
// rpc Hello(Empty) returns(HelloResponse);
func (s Server) Hello(ctx context.Context, request *rpc.Empty) (*rpc.HelloResponse, error) {
    
    
	//server.proto定义的HelloResponse中只有一个string参数
	resp := rpc.HelloResponse{
    
    Hello: "hello client."}
	return &resp, nil
}

/*
server.proto文件中定义的格式,因此设置resp.uid

	message RegisterResponse {
	  string uid = 1;
	}
*/
func (s Server) Register(ctx context.Context, request *rpc.RegisterRequest) (*rpc.RegisterResponse, error) {
    
    
	resp := rpc.RegisterResponse{
    
    }
	resp.Uid = fmt.Sprintf("%s.%s", request.GetName(), request.GetPassword())
	return &resp, nil
}

③main.go:

package main

import (
	"context"
	"flag"
	"fmt"
	"go_code/demo01/study/etcd-grpc/server/rpc"
	"google.golang.org/grpc"
	"log"
	"net"
	"os"
	"os/signal"
	"syscall"
)

func main() {
    
    
	var port int
	flag.IntVar(&port, "port", 8001, "port")
	flag.Parse()
	addr := fmt.Sprintf("localhost:%d", port)

	//关闭信号处理
	ch := make(chan os.Signal, 1)
	signal.Notify(ch, syscall.SIGTERM, syscall.SIGINT, syscall.SIGKILL, syscall.SIGHUP, syscall.SIGQUIT)
	go func() {
    
    
		//开启协程从ch管道中读取,如果有服务停止,则注销etcd中的服务
		s := <-ch
		//处理etcd中服务的注销流程
		etcdUnRegister(addr)
		if i, ok := s.(syscall.Signal); ok {
    
    
			os.Exit(int(i))
		} else {
    
    
			os.Exit(0)
		}
	}()

	//注册服务
	err := etcdRegister(addr)

	if err != nil {
    
    
		panic(err)

	}
	lis, err := net.Listen("tcp", addr)

	if err != nil {
    
    
		panic(err)
	}

	grpcServer := grpc.NewServer(grpc.UnaryInterceptor(UnaryInterceptor()))

	rpc.RegisterServerServer(grpcServer, Server{
    
    })

	log.Printf("service start port %d\n", port)
	if err := grpcServer.Serve(lis); err != nil {
    
    
		panic(err)
	}
}

func UnaryInterceptor() grpc.UnaryServerInterceptor {
    
    
	return func(ctx context.Context, req interface{
    
    }, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{
    
    }, err error) {
    
    
		log.Printf("call %s\n", info.FullMethod)
		resp, err = handler(ctx, req)
		return resp, err
	}
}

3.4 lado do cliente

cliente.go:

package main

import (
	"context"
	"fmt"
	clientv3 "go.etcd.io/etcd/client/v3"
	"go.etcd.io/etcd/client/v3/naming/resolver"
	rpc2 "go_code/demo01/study/etcd-grpc/client/rpc"
	"google.golang.org/grpc/balancer/roundrobin"
	"google.golang.org/grpc/credentials/insecure"
	"log"
	"time"

	"google.golang.org/grpc"
)

const etcdUrl = "http://localhost:2379"
const serviceName = "chihuo/server"

func main() {
    
    
	//bd := &ChihuoBuilder{addrs: map[string][]string{"/api": []string{"localhost:8001", "localhost:8002", "localhost:8003"}}}
	//resolver.Register(bd)
	//获取etcd客户端
	etcdClient, err := clientv3.NewFromURL(etcdUrl)
	if err != nil {
    
    
		panic(err)
	}
	etcdResolver, err := resolver.NewBuilder(etcdClient)

	//通过grpc与服务建立连接
	conn, err := grpc.Dial(fmt.Sprintf("etcd:///%s", serviceName), grpc.WithResolvers(etcdResolver), grpc.WithTransportCredentials(insecure.NewCredentials()), grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, roundrobin.Name)))

	if err != nil {
    
    
		fmt.Printf("err: %v", err)
		return
	}

	//rpc2 "go_code/demo01/study/etcd-grpc/client/rpc"
	//通过连接conn获取ServerClient(与服务器相互通信)
	ServerClient := rpc2.NewServerClient(conn)

	for {
    
    
		//通过客户端发起远程调用【请求服务端的Hello方法】,接受服务器的返回结果
		helloRespone, err := ServerClient.Hello(context.Background(), &rpc2.Empty{
    
    })
		if err != nil {
    
    
			fmt.Printf("err: %v", err)
			return
		}

		log.Println(helloRespone, err)
		time.Sleep(500 * time.Millisecond)
	}

}

3.5 Resultados do teste

  1. Inicie três servidores e registre serviços com o etcd
//1. 进入server/main.go所在目录
go run . --port 8081
go run . --port 8082
go run . --port 8083

insira a descrição da imagem aqui

Sim, veja se iniciamos três servidores e registramos com sucesso no etcd

  1. Inicie um cliente e puxe o serviço por meio do etcd
    insira a descrição da imagem aqui
  2. Observando os prints dos três servidores, verifica-se que as requisições do lado do cliente estão balanceadas, podendo-se acessar cada servidor

insira a descrição da imagem aqui

  1. Paramos o server3 e descobrimos que as solicitações do cliente são distribuídas uniformemente para server1 e server2

Indica que server3 foi expulso do etcd [serviço online e offline]

  • Como a solicitação é muito rápida, o efeito pode não ser óbvio, você pode imprimir a hora com mais detalhes

Entre no interior do etcd implantado pelo docker e consulte todas as chaves:
insira a descrição da imagem aqui

4 alterações na versão do ETCD-V3

4.1 mecanismo de relógio

Depois que a chave no etcdv2 é abolida, para poder rastrear a alteração da chave, o mecanismo de evento é usado para rastrear e manter o estado da chave para evitar que a chave excluída seja restaurada e observada, mas há um limite de tamanho da janela deslizante. Então, se você quiser obter a chave 1000 vezes atrás, não poderá obtê-la. Portanto, não é tão confiável sincronizar os dados através do watch no etcdv2. Após desconectar por um período de tempo, é possível que a alteração da chave intermediária não seja obtida. O histórico de versões arbitrárias para chaves get e watch é suportado no etcdv3.

Além disso, o watch na v2 essencialmente estabelece muitas conexões HTTP, e cada watch estabelece uma conexão de soquete tcp. Quando houver muitos clientes watch, os recursos do servidor serão muito consumidos. Se houver milhares de watch client Se houver milhares de chaves, os recursos de soquete e memória do servidor etcd v2 serão esgotados rapidamente. O relógio na versão v3 pode executar multiplexação de conexão e vários clientes podem compartilhar a mesma conexão TCP, o que reduz bastante a pressão no servidor.

Para resumir, de fato, existem dois pontos principais de otimização aqui:

  • Monitoramento em tempo real de atualizações de chave: Resolva o problema de que o lado do atendimento ao cliente não perceberá a atualização de dados da chave no meio da v2;
  • Multiplexação: Você pode pensar nos modelos select e epool, ou seja, antes um cliente precisava estabelecer várias conexões TCP, mas agora só precisa estabelecer uma.

etcd-V3版本:O número de chaves que podem ser rastreadas é ilimitado e consome menos recursos

Referência:
https://www.cnblogs.com/wutou/p/14056868.htm

https://blog.csdn.net/weixin_34067980/article/details/92961304

Acho que você gosta

Origin blog.csdn.net/weixin_45565886/article/details/130735024
Recomendado
Clasificación