概述

紧跟上一章内容,微服务中每一个服务都会部署多个节点,并且根据实际情况我们还可能临时新增或摘除节点, 通常节点选择是结合业务而定的,因此灵活的节点选择器是框架必备的功能

用法

mqant的节点选择器(selector)是从go-mirco移植而来的,其使用规则可参考go-mirco实现

默认选择器

mqant默认的选择器是一个随机负载均衡选择器

RPC级别

如果需要针对某一个RPC调用定制选择器可以这样做

RpcCall 函数可选参数中支持设置选择器

rstr,err:=mqrpc.String(
    self.RpcCall(
        ctx,
    "helloworld",    //要访问的moduleType
    "/say/hi",            //访问模块中handler路径
    mqrpc.Param(r.Form.Get("name")),
    selector.WithStrategy(func(services []*registry.Service) selector.Next {
        var nodes []*registry.Node

        // Filter the nodes for datacenter
        for _, service := range services {
            if service.Version!= "1.0.0"{
                continue
            }
            for _, node := range service.Nodes {
                nodes = append(nodes, node)
                if node.Metadata["state"] == "alive" || node.Metadata["state"] == "" {
                    nodes = append(nodes, node)
                }
            }
        }

        var mtx sync.Mutex
        //log.Info("services[0] $v",services[0].Nodes[0])
        return func() (*registry.Node, error) {
            mtx.Lock()
            defer mtx.Unlock()
            if len(nodes) == 0 {
                return nil, fmt.Errorf("no node")
            }
            index := rand.Intn(int(len(nodes)))
            return nodes[index], nil
        }
    }),
    ),
)

应用级别

大部分情况下,我们只需要定制一个全局统一的通用选择器,那么可以在应用(app)级别设置

app := mqant.CreateApp(
        module.Debug(false),
    )

_ = app.Options().Selector.Init(selector.SetStrategy(func(services []*registry.Service) selector.Next {
    var nodes []WeightNode
    // Filter the nodes for datacenter
    for _, service := range services {
        for _, node := range service.Nodes {
            weight := 100
            if w, ok := node.Metadata["weight"]; ok {
                wint, err := strconv.Atoi(w)
                if err == nil {
                    weight = wint
                }
            }
            if state, ok := node.Metadata["state"]; ok {
                if state != "forbidden" {
                    nodes = append(nodes, WeightNode{
                        Node:   node,
                        Weight: weight,
                    })
                }
            } else {
                nodes = append(nodes, WeightNode{
                    Node:   node,
                    Weight: weight,
                })
            }
        }
    }
    //log.Info("services[0] $v",services[0].Nodes[0])
    return func() (*registry.Node, error) {
        if len(nodes) == 0 {
            return nil, fmt.Errorf("no node")
        }
        rand.Seed(time.Now().UnixNano())
        //按权重选
        total := 0
        for _, n := range nodes {
            total += n.Weight
        }
        if total > 0 {
            weight := rand.Intn(total)
            togo := 0
            for _, a := range nodes {
                if (togo <= weight) && (weight < (togo + a.Weight)) {
                    return a.Node, nil
                } else {
                    togo += a.Weight
                }
            }
        }
        //降级为随机
        index := rand.Intn(int(len(nodes)))
        return nodes[index].Node, nil
    }
}))

以上的选择器利用节点元数据(Metadata)定制了一个节点选择规则

  • 按权重(weight)
  • 按节点当前状态(forbidden)
  • 最后降级为随机

Copyright © 梁大帅 2020 all right reserved,powered by Gitbook该文件修订时间: 2020-05-06 14:22:46

results matching ""

    No results matching ""