Consul

consul 은 팀이 서비스 간 및 프리셋과 멀티 클라우드 환경에서 네트워크 연결을 안전하게 관리할 수 있도록 하는 솔루션으로, 서비스 디스커버리, 서비스 메시, 트래픽 거버넌스, 네트워크 인프라 자동 업데이트 등 일련의 기능을 제공합니다.
공식 문서: Consul by HashiCorp
오픈소스 주소: hashicorp/consul
Consul 은 HashiCorp 사에서 오픈소스로 공개한 서비스 디스커버리 및 등록 도구로, Raft 선거 알고리즘을 사용하며 도구 자체는 Go 언어로 개발되어 배포가 매우 간편합니다. Consul 은 다음과 같은 특징을 가지고 있습니다:
- 서비스 디스커버리
- 서비스 등록
- 헬스체크
- 키 - 값 저장
- 멀티 데이터센터
실제로 consul 이 할 수 있는 일은 서비스 디스커버리 이상이며, 분산 설정 센터로도 사용할 수 있습니다. zookeeper, nacos 와 같은 유사한 오픈소스 도구도 많지만 여기서는 자세히 소개하지 않겠습니다.
설치
Ubuntu 의 경우 아래 명령어를 실행하여 apt 로 설치할 수 있습니다.
$ wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
$ echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
$ sudo apt update && sudo apt install consul또는 공식 웹사이트에서 Install Consul 해당 설치 패키지를 다운로드할 수도 있습니다. consul 은 Go 로 개발되었기 때문에 설치 파일 자체는 바이너리 실행 파일 하나뿐이며 설치도 매우 간편합니다. 설치 성공 후 다음 명령어로 버전을 확인할 수 있습니다.
$ consul version정상적으로 출력되면 문제없습니다.
Consul v1.16.1
Revision e0ab4d29
Build Date 2023-08-05T21:56:29Z
Protocol 2 spoken by default, understands 2 to 3 (agent will automatically use protocol >2 when speaking to compatible agents)빠른 시작
다음은 consul 단일 노드를 빠르게 구축하는 방법을 소개합니다. 일반적으로 단일 노드는 개발 중 테스트용이며, 단일 노드가 문제없이 작동하면 대부분 멀티 노드 클러스터도 문제가 없습니다. 단일 노드 구축은 매우 간단하며 한 줄의 명령어로 완료할 수 있습니다.
$ consul agent -dev -bind=192.168.48.141 -data-dir=/tmp/consul -ui -node=dev01일반적으로 다음과 같은 출력이 있습니다.
==> Starting Consul agent...
Version: '1.16.1'
Build Date: '2023-08-05 21:56:29 +0000 UTC'
Node ID: 'be6f6b8d-9668-f7ff-8709-ed57c72ffdec'
Node name: 'dev01'
Datacenter: 'dc1' (Segment: '<all>')
Server: true (Bootstrap: false)
Client Addr: [127.0.0.1] (HTTP: 8500, HTTPS: -1, gRPC: 8502, gRPC-TLS: 8503, DNS: 8600)
Cluster Addr: 192.168.48.141 (LAN: 8301, WAN: 8302)
Gossip Encryption: false
Auto-Encrypt-TLS: false
ACL Enabled: false
Reporting Enabled: false
ACL Default Policy: allow
HTTPS TLS: Verify Incoming: false, Verify Outgoing: false, Min Version: TLSv1_2
gRPC TLS: Verify Incoming: false, Min Version: TLSv1_2
Internal RPC TLS: Verify Incoming: false, Verify Outgoing: false (Verify Hostname: false), Min Version: TLSv1_2
==> Log data will now stream in as it occurs:
2023-08-25T17:23:33.763+0800 [DEBUG] agent.grpc.balancer: switching server: target=consul://dc1.be6f6b8d-9668-f7ff-8709-ed57c72ffdec/server.dc1 from=<none> to=<none>
2023-08-25T17:23:33.767+0800 [INFO] agent.server.raft: initial configuration: index=1 servers="[{Suffrage:Voter ID:be6f6b8d-9668-f7ff-8709-ed57c72ffdec Address:192.168.48.141:8300}]"간단히 설명하면 다음과 같습니다.
agent는 서브커맨드로 consul 의 핵심 명령어이며,consul agent는 새로운 consul 에이전트를 실행합니다. 각 노드는 하나의 에이전트입니다.dev는 agent 의 실행 모드로 총 세 가지dev,client,server가 있습니다.bind, LAN 통신 주소로 포트는 기본 8301 이며 일반적으로 이 값은 서버의 내부 IP 주소입니다.advertise, WAN 통신 주소로 포트는 기본 8302 이며 일반적으로 이 값은 서버의 외부 IP 주소입니다.data-dir, 데이터 저장 디렉토리입니다.config-dir, 설정 저장 디렉토리로 consul 은 디렉토리 내의 모든 json 파일을 읽습니다.bootstrap, 현재 server 가 가이드 모드로 진입했음을 표시하며 Raft 선거 시 자신에게 투표합니다. 클러스터에서 이 모드의 server 는 하나를 초과할 수 없습니다.bootstrap-expect, 클러스터에서 예상되는 server 수로 지정된 수에 도달하기 전까지 클러스터는 선거 투표를 시작하지 않으며bootstrap과 동시에 사용할 수 없습니다.retry-join, agent 시작 후 지정된 노드에 지속적으로 가입을 시도하며 다음과 같은 일부 서비스 디스커버리 방법도 지원합니다.aliyun aws azure digitalocean gce hcp k8s linode mdns os packet scaleway softlayer tencentcloud triton vsphereui, Web 백그라운드 실행node, 실행 노드 이름으로 클러스터에서 고유해야 합니다.
TIP
더 많은 agent 매개변수 설명은 Agents - CLI Reference | Consul | HashiCorp Developer 를 참조하세요. 일부 매개변수는 엔터프라이즈 버전만 사용할 수 있습니다.
성공적으로 실행된 후 127.0.0.1:8500 에 접속하면 Web 인터페이스를 볼 수 있습니다.

dev01 아이콘이 별이면 leader 노드임을 나타냅니다.
종료 시 다른 노드가 현재 노드의 종료를 인지할 수 있도록 프로세스를 강제로 종료하는 것은 권장되지 않으며 명령어를 사용할 수 있습니다.
consul leave또는
consul force-leavectrl+c 를 사용하여 consul agent 가 우아하게 종료되도록 할 수도 있습니다.
개념
이것은 consul 클러스터 다이어그램으로 그림은 두 부분으로 나뉘며 제어면과 데이터면입니다. consul 은 제어면만 담당하며 서비스 클러스터와 클라이언트로 나뉩니다. 서비스 클러스터는 팔로워와 리더로 나뉘며 전체적으로 consul 클러스터는 하나의 데이터센터를 구성합니다. 다음은 용어에 대한 설명입니다.
- Agent(에이전트): 또는 노드라고 하는 것이 더 적절하며 각 agent 는 장기간 실행되는 데몬 프로세스이며 HTTP 와 DNS 인터페이스를 외부에 노출하고 헬스체크와 서비스 동기화를 담당합니다.
- Server(서비스 에이전트): consul server 로서 Raft 선거 참여, 클러스터 상태 유지, 쿼리 응답, 다른 데이터센터와 데이터 교환, 리더 및 다른 데이터센터에 쿼리 전달 등의职责이 있습니다.
- Client(클라이언트 에이전트): client 는 server 에 비해 상태가 없으며 Raft 선거에 참여하지 않고 모든 요청을 server 로 전달하는 것만 담당하며 백그라운드와 관련된 유일한 일은 LAN 가십 전달 (LAN gossip pool) 입니다.
- Leader(리더): leader 는 모든 server 의 리더이며 리더는 하나만 있어야 합니다. leader 는 Raft 선거 알고리즘을 통해 선출되며 각 leader 는 자신의 임기가 있으며 임기 동안 다른 server 는 어떤 요청을 받든 leader 에게 알려야 하므로 leader 의 데이터가 가장 최신입니다.
- Gossip(가십): Consul 은 Serf(동일 회사의 또 다른 제품) 를 기반으로 구축되었으며 gossip 프로토콜을 사용합니다. 이 프로토콜은 노드 간 무작위 통신에 전용되며 UDP 와 유사하며 consul 은 이 프로토콜을 사용하여 서비스 클러스터 간에 서로 알립니다.
- Data Center(데이터센터): LAN 내의 consul 클러스터를 하나의 데이터센터라고 하며 consul 은 멀티 데이터센터를 지원합니다. 멀티 데이터센터 통신 방식은 WAN gossip 입니다.
TIP
더 많은 단어 및 용어는 Glossary | Consul | HashiCorp Developer 에서 확인할 수 있습니다.
consul 클러스터에서 server 의 수는 엄격하게 제어되어야 합니다. 왜냐하면它们은 LAN gossip 과 WAN gossip, Raft 선거에 직접 참여하며 데이터를 저장해야 하기 때문에 server 가 많을수록 통신 비용이 높아집니다. 반면 client 의 수는 많아도 문제가 없으며 전달만 담당하고 선거에 참여하지 않으며 리소스 점유율이 낮습니다. 그림의 클러스터에서 각 서비스는 client 를 통해 자신을 server 에 등록하며 server 가 다운되면 client 는 다른 사용 가능한 server 를自行 찾습니다.
클러스터 구축 예제
다음은 간단한 consul 멀티 노드 클러스터 구축 예제를 소개합니다. 먼저 4 대의 가상 머신을 준비합니다.

4 대의 가상 머신 중 3 대는 server, 1 대는 client 입니다. 공식 권장 사항은 server 의 수가 홀수이며 3 대 이상이어야 합니다. 여기서는 vm00-vm02 를 server 로, vm03 을 client 로 사용합니다.
server 의 경우 다음 명령어를 실행하여 server agent 를 생성합니다.
consul agent -server -bind=vm_address -client=0.0.0.0 -data-dir=/tmp/consul/ -node=agent_name -uiclient 의 경우 다음 명령어를 실행하여 client agent 를 생성합니다.
consul agent -client=0.0.0.0 -bind=vm_address -data-dir=/tmp/consul/ -node=agent_name -ui실행할 명령어는 다음과 같습니다.
# vm00
consul agent -server -bind=192.168.48.138 -client=0.0.0.0 -data-dir=/tmp/consul/ -node=agent01 -ui -bootstrap
# vm01
consul agent -server -bind=192.168.48.139 -client=0.0.0.0 -data-dir=/tmp/consul/ -node=agent02 -ui -retry-join=192.168.48.138
# vm02
consul agent -server -bind=192.168.48.140 -client=0.0.0.0 -data-dir=/tmp/consul/ -node=agent03 -ui -retry-join=192.168.48.138
# vm03
consul agent -bind=192.168.48.140 -client=0.0.0.0 -data-dir=/tmp/consul/ -node=agent03 -ui -retry-join=192.168.48.138일부 매개변수 설명
client,0.0.0.0은 모든 출처의 요청을 허용함을 의미하며 server 매개변수 없이 client 매개변수만 있는 경우 agent 가 client 모드로 실행됨을 나타냅니다.
모든 agent 가 실행된 후 retry-join의 역할은 join 명령어를 자동으로 실행하는 것과 같으며 실패 후 지속적으로 시도합니다. 기본 재시도 시간은 30 초입니다.
$ consul join 192.168.48.138join 완료 후 각 노드는 상대방의 존재를 알게 되며 vm00 이 bootstrap 모드로 지정되었으므로 기본 leader 가 됩니다. bootstrap 모드를 지정하지 않은 경우 모든 노드가 join 시 지정한 노드가 기본 leader 가 됩니다. leader 가 선출되기 전까지 클러스터는 정상적으로 작동할 수 없으며 Web 인터페이스 접속 시 500 이 반환되고 일부 명령어도 정상적으로 작동하지 않습니다. 클러스터에 bootstrap 모드로 지정된 노드가 있는 경우 클러스터의 다른 노드는 더 이상 bootstrap 모드로 지정되어서는 안 되며 동시에 다른 노드는 bootstrap-expect 매개변수를 사용해서는 안 됩니다. 사용하면 자동으로 비활성화됩니다.
이때 leader 노드에서 (실제로 이때는 어떤 노드에서든 확인할 수 있습니다) 데이터센터의 구성원 정보를 확인하는 명령어를 실행합니다.
$ consul members
Node Address Status Type Build Protocol DC Partition Segment
agent01 192.168.48.138:8301 alive server 1.16.1 2 dc1 default <all>
agent02 192.168.48.139:8301 alive server 1.16.1 2 dc1 default <all>
agent03 192.168.48.140:8301 alive server 1.16.1 2 dc1 default <all>
client01 192.168.48.141:8301 alive client 1.16.1 2 dc1 default <default>- Node, 노드 이름
- Address, 통신 주소
- Status,
alive는存活,left는 오프라인 - Type, agent 종류로 server 와 client 두 가지 모드가 있습니다.
- Build, 해당 노드가 사용하는 consul 버전으로 consul 은 일정 범위 내에서 다른 버전의 노드와 함께 작동할 수 있습니다.
- Protocol, 사용하는 Raft 프로토콜 버전으로 이 프로토콜은 모든 노드가 일치해야 합니다.
- DC, Data Center, 데이터센터로 출력의 모든 노드가 dc1 데이터센터에 속합니다.
- Partition, 노드가 속한 파티션으로 엔터프라이즈 버전 기능이며 각 노드는 동일한 파티션의 노드와만 통신할 수 있습니다.
- Segment, 노드가 속한 세그먼트로 엔터프라이즈 버전 기능입니다.

마찬가지로 노드를 종료하려면 consul leave 를 사용하여 노드가 우아하게 종료되고 다른 노드에게 자신이 종료될 것임을 알려야 합니다. 멀티 노드 환경에서 노드의 우아한 종료는 데이터 일관성과 관련되므로 특히 중요합니다.
TIP
가상 머신은 데모 시 모든 방화벽을 껐지만 실제 프로덕션 환경에서는 보안을 위해 방화벽을 켜야 합니다. 따라서 consul 이 사용하는 모든 포트에 주목해야 합니다: Required Ports | Consul | HashiCorp Developer.
다음으로 데이터 일관성을 간단히 테스트해 보겠습니다. vm00 가상 머신에서 다음 데이터를 추가합니다.
$ consul kv put sys_confg {"name":"consul"}
Success! Data written to: sys_confg저장 후 HTTP API 를 통해 다른 노드에 접속하면 데이터가 동일하게 존재함을 확인할 수 있습니다 (그 중 value 는 base64 인코딩됨).
$ curl http://192.168.48.138:8500/v1/kv/sys_confg
[{"LockIndex":0,"Key":"sys_confg","Flags":0,"Value":"ewogICJuYW1lIjoiY29uc3VsIgp9","CreateIndex":2518,"ModifyIndex":2518}]
$ curl http://192.168.48.139:8500/v1/kv/sys_confg
[{"LockIndex":0,"Key":"sys_confg","Flags":0,"Value":"ewogICJuYW1lIjoiY29uc3VsIgp9","CreateIndex":2518,"ModifyIndex":2518}]
$ curl http://192.168.48.140:8500/v1/kv/sys_confg
[{"LockIndex":0,"Key":"sys_confg","Flags":0,"Value":"ewogICJuYW1lIjoiY29uc3VsIgp9","CreateIndex":2518,"ModifyIndex":2518}]실제로 consul 이 제공하는 서비스 디스커버리 및 등록 기능은 gossip 프로토콜을 통해 다른 노드에 브로드캐스트되며 임의의 노드가 현재 데이터센터에 가입할 때 모든 노드가 이 변화를 감지합니다.
멀티 데이터센터 구축 예제
5 대의 가상 머신을 준비합니다. vm00-vm02 는 이전 예제의 클러스터로 dc1 데이터센터에 속하며 건드리지 않습니다. vm03-vm04 는 dc2 데이터센터에 속하며 데이터센터는 agent 시작 시 기본값이 dc1 입니다.

TIP
여기서는 데모를 위해 server 만 구축하고 client 는 생략합니다.
먼저 vm03 을 각각 시작하여 기본 leader 로 설정합니다.
$ consul agent -server -datacenter=dc2 -bind=192.168.48.141 -client=0.0.0.0 -data-dir=/tmp/consul/ -node=agent04 -ui -bootstrapvm04 를 시작하여 vm03 노드에 자동으로 join 하도록 합니다.
$ consul agent -server -datacenter=dc2 -bind=192.168.48.142 -client=0.0.0.0 -data-dir=/tmp/consul/ -node=agent05 -ui -retry-join=192.168.48.141이때 vm00 과 vm03 에서 각각 members 를 확인합니다.
# vm00-vm02
$ consul members
Node Address Status Type Build Protocol DC Partition Segment
agent01 192.168.48.138:8301 alive server 1.16.1 2 dc1 default <all>
agent02 192.168.48.139:8301 alive server 1.16.1 2 dc1 default <all>
agent03 192.168.48.140:8301 alive server 1.16.1 2 dc1 default <all>
# vm03-vm04
$ consul members
Node Address Status Type Build Protocol DC Partition Segment
agent04 192.168.48.141:8301 alive server 1.16.1 2 dc2 default <all>
agent05 192.168.48.142:8301 alive server 1.16.1 2 dc2 default <all>DC 필드가 다른 것을 볼 수 있습니다. 여기서는 가상 머신 데모이므로 모두 동일한 서브넷에 있지만 현실에서는 두 데이터센터가 원격지의 서버 클러스터일 수 있습니다. 다음으로 dc1 의 임의의 노드가 dc2 의 임의의 노드에 join 하도록 합니다. 여기서는 vm01 이 vm03 에 join 하도록 합니다.
$ consul join -wan 192.168.48.141
Successfully joined cluster by contacting 1 nodes.join 성공 후 WAN members 를 확인하는 명령어를 실행합니다.
$ consul members -wan
Node Address Status Type Build Protocol DC Partition Segment
agent01.dc1 192.168.48.138:8302 alive server 1.16.1 2 dc1 default <all>
agent02.dc1 192.168.48.139:8302 alive server 1.16.1 2 dc1 default <all>
agent03.dc1 192.168.48.140:8302 alive server 1.16.1 2 dc1 default <all>
agent04.dc2 192.168.48.141:8302 alive server 1.16.1 2 dc2 default <all>
agent05.dc2 192.168.48.142:8302 alive server 1.16.1 2 dc2 default <all>
$ consul catalog datacenters
dc2
dc1dc1 의 임의의 노드가 dc2 의 임의의 노드에 join 하기만 하면 두 데이터센터의 모든 노드가 이 변화를 감지하며 members 를 확인할 때 두 데이터센터의 노드를 모두 볼 수 있습니다.
다음으로 vm00 노드에서 KV 데이터를 추가해 봅니다.
$ consul kv put name consul
Success! Data written to: namevm01 노드에서 데이터를 읽어보면 동일한 데이터센터의 데이터가 동기화됨을 확인할 수 있습니다.
$ consul kv get name
consul그런 다음 다른 데이터센터의 vm03 에서 데이터를 읽어보면 다른 데이터센터의 데이터는 동기화되지 않음을 확인할 수 있습니다.
$ consul kv get name
Error! No key exists at: name멀티 데이터센터 데이터 동기화를 원하면 hashicorp/consul-replicate: Consul cross-DC KV replication daemon 를 참조할 수 있습니다.
서비스 등록 및 디스커버리

consul 서비스 등록 방식에는 두 가지가 있습니다. 설정 파일 등록과 API 등록입니다. 테스트의 편의를 위해 미리 Hello World 서비스 (gRPC 문서의 예제) 를 준비하고 두 개를 배포하며 각각 다른 위치에 있습니다. 설정 파일 등록 방식은 Register external services with Consul service discovery | Consul | HashiCorp Developer 에서 확인할 수 있으며 여기서는 HTTP API 를 통한 등록만 소개합니다.
TIP
로컬 서비스 (consul client 와 함께 있는) 의 경우 agent service 등록을 직접 사용할 수 있으며 그렇지 않은 경우 catalog register 를 사용하여 등록해야 합니다.
consul 은 HTTP API 의 SDK 를 제공하며 다른 언어의 SDK 는 Libraries and SDKs - HTTP API | Consul | HashiCorp Developer 에서 확인할 수 있습니다. 여기서는 go 의존성을 다운로드합니다.
go get github.com/hashicorp/consul/api서비스 시작 시 consul 에 서비스를 능동적으로 등록하고 서비스 종료 시 consul 에 서비스를 등록 해제합니다. 다음은 예제입니다.
package main
import (
consulapi "github.com/hashicorp/consul/api"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
pb "grpc_learn/helloworld/hello"
"log"
"net"
)
var (
server01 = &consulapi.AgentService{
// 必须保持唯一
ID: "hello-service1",
Service: "hello-service",
// 部署两份,一份的端口是 8080,一份的端口是 8081
Port: 8080,
}
)
// 注册服务
func Register() {
client, _ := consulapi.NewClient(&consulapi.Config{Address: "192.168.48.138:8500"})
_, _ = client.Catalog().Register(&consulapi.CatalogRegistration{
Node: "hello-server",
Address: "192.168.2.10",
Service: server01,
}, nil)
}
// 注销服务
func DeRegister() {
client, _ := consulapi.NewClient(&consulapi.Config{Address: "192.168.48.138:8500"})
_, _ = client.Catalog().Deregister(&consulapi.CatalogDeregistration{
Node: "hello-server",
Address: "192.168.2.10",
ServiceID: server01.ID,
}, nil)
}
func main() {
Register()
defer DeRegister()
// 监听端口
listen, err := net.Listen("tcp", ":8080")
if err != nil {
panic(err)
}
// 创建 gprc 服务器
server := grpc.NewServer(
grpc.Creds(insecure.NewCredentials()),
)
// 注册服务
pb.RegisterSayHelloServer(server, &HelloRpc{})
log.Println("server running...")
// 运行
err = server.Serve(listen)
if err != nil {
panic(err)
}
}클라이언트 코드는 consul 사용자 정의 리졸버를 사용하여 등록 센터에 해당하는 서비스를 조회하고 실제 주소로 해석합니다.
package myresolver
import (
"fmt"
consulapi "github.com/hashicorp/consul/api"
"google.golang.org/grpc/resolver"
)
func NewConsulResolverBuilder(address string) ConsulResolverBuilder {
return ConsulResolverBuilder{consulAddress: address}
}
type ConsulResolverBuilder struct {
consulAddress string
}
func (c ConsulResolverBuilder) Build(target resolver.Target, cc resolver.ClientConn, opts resolver.BuildOptions) (resolver.Resolver, error) {
consulResolver, err := newConsulResolver(c.consulAddress, target, cc)
if err != nil {
return nil, err
}
consulResolver.resolve()
return consulResolver, nil
}
func (c ConsulResolverBuilder) Scheme() string {
return "consul"
}
func newConsulResolver(address string, target resolver.Target, cc resolver.ClientConn) (ConsulResolver, error) {
var reso ConsulResolver
client, err := consulapi.NewClient(&consulapi.Config{Address: address})
if err != nil {
return reso, err
}
return ConsulResolver{
target: target,
cc: cc,
client: client,
}, nil
}
type ConsulResolver struct {
target resolver.Target
cc resolver.ClientConn
client *consulapi.Client
}
func (c ConsulResolver) resolve() {
service := c.target.URL.Opaque
services, _, err := c.client.Catalog().Service(service, "", nil)
if err != nil {
c.cc.ReportError(err)
return
}
var adds []resolver.Address
for _, catalogService := range services {
adds = append(adds, resolver.Address{Addr: fmt.Sprintf(fmt.Sprintf("%s:%d", catalogService.Address, catalogService.ServicePort))})
}
c.cc.UpdateState(resolver.State{
Addresses: adds,
// 轮询策略
ServiceConfig: c.cc.ParseServiceConfig(
`{"loadBalancingPolicy":"round_robin"}`),
})
}
func (c ConsulResolver) ResolveNow(options resolver.ResolveNowOptions) {
c.resolve()
}
func (c ConsulResolver) Close() {
}클라이언트는 시작 시 리졸버를 등록합니다.
package main
import (
"context"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
"google.golang.org/grpc/resolver"
"grpc_learn/helloworld/client/myresolver"
hello2 "grpc_learn/helloworld/hello"
"log"
"time"
)
func init() {
// 注册 builder
resolver.Register(
// 注册自定义的 consul 解析器
myresolver.NewConsulResolverBuilder("192.168.48.138:8500"),
)
}
func main() {
// 建立连接,没有加密验证
conn, err := grpc.Dial("consul:hello-service",
grpc.WithTransportCredentials(insecure.NewCredentials()),
)
if err != nil {
panic(err)
}
defer conn.Close()
// 创建客户端
client := hello2.NewSayHelloClient(conn)
for range time.Tick(time.Second) {
// 远程调用
helloRep, err := client.Hello(context.Background(), &hello2.HelloReq{Name: "client"})
if err != nil {
panic(err)
}
log.Printf("received grpc resp: %+v", helloRep.String())
}
}서버端을 먼저 시작하고 클라이언트를 시작합니다. 서버端은 두 개이며 동일한 서비스를 제공하지만 주소가 다릅니다. 클라이언트의 로드밸런싱 전략은 라운드 로빈이며 서버端의 로그 간격으로 전략이生效되었음을 알 수 있습니다.
2023/08/29 17:39:54 server running...
2023/08/29 21:03:46 received grpc req: name:"client"
2023/08/29 21:03:48 received grpc req: name:"client"
2023/08/29 21:03:50 received grpc req: name:"client"
2023/08/29 21:03:52 received grpc req: name:"client"
2023/08/29 21:03:54 received grpc req: name:"client"
2023/08/29 21:03:56 received grpc req: name:"client"
2023/08/29 21:03:58 received grpc req: name:"client"
2023/08/29 21:04:00 received grpc req: name:"client"이상은 consul 과 gRPC 를 결합하여 서비스 등록 및 디스커버리를 구현한 간단한 사례입니다.
