代碼位址
https://github.com/wanmei002/grpc-learn/tree/master/ch09
介紹
我工作中,請求一個接口,會先從去負載均衡器中擷取一個ip,然後直接拿着ip去通路接口,在這裡呢我們相當于把負載均衡器內建到用戶端服務中,用戶端發起請求的時候,會獲得一個ip清單,根據特定的算法,選取一個IP, 向服務端發起請求
實作邏輯
- grpc.Dial 的時候輸入我們的服務名
- 實作 resolver.go/Builder接口,連接配接的時候會調用這個接口裡的方法 Build Scheme 方法
- 在 Build 方法裡我們根據服務名,擷取服務的ip位址清單
- 傳入負載均衡算法,實作用戶端負載均衡
用戶端
grpc.Dial 傳參
dl, err := grpc.Dial(fmt.Sprintf("%s:///%s", "order", "Order"),
grpc.WithDefaultServiceConfig(fmt.Sprintf(`{"LoadBalancingPolicy": "%s"}`, roundrobin.Name)),
grpc.WithInsecure())
-
第一個fmt.Sprintf("%s:///%s", "order", "Order")
是服務解析器的名字,後面要通過這個名字找到對應的 實作order
這個接口的服務解析器, 後一個Builder
是微服務名 , 這兩個參數都是可以自定義的Order
-
{“LoadBalancingPolicy”: “%s”}grpc.WithDefaultServiceConfig(fmt.Sprintf(
負載均衡算法,我們這裡使用的是, roundrobin.Name))
自帶的輪詢算法。grpc
實作服務解析器
// 提供服務的機器
var addrs = []string{":8093", ":8094"}
type loopBuilder struct{}
// 實作 Builder 接口, 這個接口的主要作用是把提供服務的IP清單,裝載進撥号清單中
func (lb *loopBuilder) Build(target resolver.Target, cc resolver.ClientConn,
opts resolver.BuildOptions) (resolver.Resolver, error) {
log.Println("i am build")
ll := &loopResolver{
target: target,
cc: cc,
addrsStore: map[string][]string{
LoopServiceName: addrs,
},
}
ll.start()
return ll, nil
}
// 這個是注冊服務解析器的時候提供的注冊名
func (*loopBuilder) Scheme() string {
log.Println("i am scheme")
return LoopScheme
}
// 實作 resolver.Resolver ,主要用于更新服務端IP清單
type loopResolver struct {
target resolver.Target
cc resolver.ClientConn
addrsStore map[string][]string
}
// 更新撥号清單
func (ll *loopResolver) start() {
addrList := ll.addrsStore[ll.target.Endpoint]
log.Printf("loop resolver %+v\n", ll)
addr := make([]resolver.Address, 0)
for _, s := range addrList {
addr = append(addr, resolver.Address{Addr: s})
}
log.Println("start start")
ll.cc.UpdateState(resolver.State{Addresses: addr})
}
func (*loopResolver) ResolveNow(o resolver.ResolveNowOptions) {
log.Println(" i am in resolveNew")
}
func (*loopResolver) Close(){
log.Println(" i am in close ")
}
func init(){
resolver.Register(&loopBuilder{})
}
服務端
注冊多個ip提供服務
func main(){
log.Println("loop register server")
var wg = &sync.WaitGroup{}
wg.Add(len(addrList))
for _, addr := range addrList {
go StartServer(addr, wg) // 提供服務
}
wg.Wait()
log.Println("over")
}