Sentinel-Go 集成 Nacos 实现外部动态数据源

9.28头图.png

导读:2020年,Sentinel 推出 Go 原生版本Sentinel-Golang,在云原生领域继续突破。本文将从实际出发 结合案例说明 在Sentinel-Golang中如何集成Nacos,使其做为外部动态数据源,将流控规则存储在nacos中,并且实现动态实时更新规则。

本文主要分为两个部分:

  1. 将sentinel流控规则定义在代码内部 实现限流效果。
  2. 将sentinel流控规则定义在nacos配置中心,实现限流效果以及在nacos中动态更新规则,实现动态流控。

下面将详细介绍一下相关的背景知识。

1. Sentinel

随着微服务的流行,服务和服务之间的稳定性变得越来越重要。Sentinel 以流量为切入点,从流量控制、熔断降级、系统负载保护等多个维度保护服务的稳定性。

Sentinel 具有以下特征:

  • 丰富的应用场景:Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景,例如秒杀(即突发流量控制在系统容量可以承受的范围)、消息削峰填谷、集群流量控制、实时熔断下游不可用应用等。
  • 完备的实时监控:Sentinel 同时提供实时的监控功能。您可以在控制台中看到接入应用的单台机器秒级数据,甚至 500 台以下规模的集群的汇总运行情况。
  • 广泛的开源生态:Sentinel 提供开箱即用的与其它开源框架/库的整合模块,例如与 Spring Cloud、Dubbo、gRPC 的整合。您只需要引入相应的依赖并进行简单的配置即可快速地接入 Sentinel。
  • 完善的 SPI 扩展点:Sentinel 提供简单易用、完善的 SPI 扩展接口。您可以通过实现扩展接口来快速地定制逻辑。例如定制规则管理、适配动态数据源等。

1.1 Sentinel 的历史

  • 2012年,Sentinel 诞生,主要功能为入口流量控制。
  • 2013-2017年,Sentinel 在阿里巴巴集团内部迅速发展,成为基础技术模块,覆盖了所有的核心场景。Sentinel 也因此积累了大量的流量归整场景以及生产实践。
  • 2018年,Sentinel 开源,并持续演进。
  • 2019年,Sentinel 在多语言扩展的方向上逐步探索,陆续推出 C++ 原生版本、Envoy 集群流量控制支持。
  • 2020年,Sentinel 推出 Go 原生版本,期待在云原生领域继续突破。https://github.com/alibaba/sentinel-golang

2. Nacos

Nacos是一个更易于构建云原生应用的动态服务发现、配置管理和服务管理的平台,Nacos脱胎于阿里巴巴内部的ConfigServer和Diamond,是它们的开源实现。经历过双十一流量峰值和阿里巴巴经济体超大规模容量的考验,沉淀了阿里巴巴软负载团队在这个领域十年的经验,在稳定性和功能性上都有很好的保障。

1.png
(Sentinel-Go集成Nacos动态数据源架构)

目前 Sentinel 内部的限流、熔断等策略都是基于规则来实现的,提供动态数据源扩展的目的,就是希望将规则数据的加载以及更新操作通过一些配置中心中间件(比如 nacos,etcd,conful,等等)来实现动态更新。

3. Sentinel-Go 限流 Demo

未集成nacos时 规则定义在代码内部,没有使用外部数据源。

3.1 安装

go get github.com/alibaba/sentinel-golang

3.2 Demo样例

使用 Sentinel 主要分为以下几步:

  1. 对 Sentinel 进行相关配置并进行初始化
  2. 埋点(定义资源)
  3. 配置规则
package main

import (
    "fmt"
    "log"
    "math/rand"
    "time"

    sentinel "github.com/alibaba/sentinel-golang/api"
    "github.com/alibaba/sentinel-golang/core/base"
    "github.com/alibaba/sentinel-golang/core/flow"
    "github.com/alibaba/sentinel-golang/util"
)

func main() {
    // We should initialize Sentinel first.
    err := sentinel.InitDefault()
    if err != nil {
        log.Fatalf("Unexpected error: %+v", err)
    }

    _, err = flow.LoadRules([]*flow.FlowRule{
        {
            Resource:        "some-test",
            MetricType:      flow.QPS,
            Count:           10,
            ControlBehavior: flow.Reject,
        },
    })
    if err != nil {
        log.Fatalf("Unexpected error: %+v", err)
        return
    }

    ch := make(chan struct{})

    for i := 0; i < 10; i++ {
        go func() {
            for {
                e, b := sentinel.Entry("some-test", sentinel.WithTrafficType(base.Inbound))
                if b != nil {
                    // Blocked. We could get the block reason from the BlockError.
                    time.Sleep(time.Duration(rand.Uint64()%10) * time.Millisecond)
                } else {
                    // Passed, wrap the logic here.
                    fmt.Println(util.CurrentTimeMillis(), "passed")
                    time.Sleep(time.Duration(rand.Uint64()%10) * time.Millisecond)

                    // Be sure the entry is exited finally.
                    e.Exit()
                }

            }
        }()
    }
    <-ch
}

官方expmale:https://github.com/alibaba/sentinel-golang/tree/master/example

4. Sentinel-Go 集成Nacos

Sentinel-Go集成Nacos实现外部动态数据源功能.

4.1 部署Nacos

4.1.1 版本选择

您可以在Nacos的release notes博客中找到每个版本支持的功能的介绍,当前推荐的稳定版本为1.3.1。

4.1.2 预备环境准备

Nacos 依赖 Java 环境来运行。如果您是从代码开始构建并运行Nacos,还需要为此配置 Maven环境,请确保是在以下版本环境中安装使用:

  1. 64 bit OS,支持 Linux/Unix/Mac/Windows,推荐选用 Linux/Unix/Mac。
  2. 64 bit JDK 1.8+;下载 & 配置
  3. Maven 3.2.x+;下载 & 配置

4.1.3 下载源码或者安装包

你可以通过源码和发行包两种方式来获取 Nacos。

从 Github 上下载源码方式

git clone https://github.com/alibaba/nacos.git
cd nacos/
mvn -Prelease-nacos -Dmaven.test.skip=true clean install -U  
ls -al distribution/target/
// change the $version to your actual path
cd distribution/target/nacos-server-$version/nacos/bin

下载编译后压缩包方式

您可以从 最新稳定版本 下载 nacos-server-$version.zip 包。

unzip nacos-server-$version.zip 或者 tar -xvf nacos-server-$version.tar.gz
  cd nacos/bin

4.1.4 启动服务器

Linux/Unix/Mac
启动命令(standalone代表着单机模式运行,非集群模式):
sh startup.sh -m standalone
如果您使用的是ubuntu系统,或者运行脚本报错提示[[符号找不到,可尝试如下运行:
bash startup.sh -m standalone

Windows
启动命令:
cmd startup.cmd
或者双击startup.cmd运行文件。

部署成功访问 http://127.0.0.1:8848/nacos  
用户名/密码:nacos/nacos

4.2 Sentinel限流配置到Nacos

  1. 登录到nacos web
  2. 在配置管理中,新建配置
  3. 输入dataId,group(dataId,group 创建时可以自定义,本文创建的dataId=flow,group=sentinel-go)
  4. 将数据源样例粘贴到配置内容中。

4.2.1 Nacos 外部数据源样例

此样例是流量控制的Demo配置。当流量并发数大于100直接拒绝。

配置内容说明可参考https://github.com/alibaba/sentinel-golang/wiki/流量控制

[
    {
        "resource": "some-test",
        "metricType": 1,
        "count": 100.0,
        "controlBehavior":0
    }
]

创建完成后,在nacos配置列表中可以看到对应的限流配置。

2.png

4.3 Nacos数据源集成

4.3.1 创建项目

  1. 版本
    1. sentinel-golang 版本使用0.6.0,nacos-sdk-go 使用1.0.0
  2. go.mod
module sentinel-go-nacos-example

go 1.13

require (
    github.com/alibaba/sentinel-golang v0.6.0
    github.com/nacos-group/nacos-sdk-go v1.0.0
)
  1. main.go
package main

import (
    "fmt"
    "math/rand"
    "sync/atomic"
    "time"

    sentinel "github.com/alibaba/sentinel-golang/api"
    "github.com/alibaba/sentinel-golang/core/base"
    "github.com/alibaba/sentinel-golang/ext/datasource/nacos"
    "github.com/alibaba/sentinel-golang/util"
    "github.com/nacos-group/nacos-sdk-go/clients"

    "github.com/alibaba/sentinel-golang/ext/datasource"
    "github.com/nacos-group/nacos-sdk-go/common/constant"
)

type Counter struct {
    pass  *int64
    block *int64
    total *int64
}

func main() {
    //流量计数器,为了流控打印日志更直观,和集成nacos数据源无关。
    counter := Counter{pass: new(int64), block: new(int64), total: new(int64)}

    //nacos server地址
    sc := []constant.ServerConfig{
        {
            ContextPath: "/nacos",
            Port:        8848,
            IpAddr:      "127.0.0.1",
        },
    }
    //nacos client 相关参数配置,具体配置可参考https://github.com/nacos-group/nacos-sdk-go
    cc := constant.ClientConfig{
        TimeoutMs: 5000,
    }
    //生成nacos config client(配置中心客户端)
    client, err := clients.CreateConfigClient(map[string]interface{}{
        "serverConfigs": sc,
        "clientConfig":  cc,
    })
    if err != nil {
        fmt.Printf("Fail to create client, err: %+v", err)
        return
    }
    //注册流控规则Handler
    h := datasource.NewFlowRulesHandler(datasource.FlowRuleJsonArrayParser)
    //创建NacosDataSource数据源
    //sentinel-go 对应在nacos中创建配置文件的group
    //flow 对应在nacos中创建配置文件的dataId
    nds, err := nacos.NewNacosDataSource(client, "sentinel-go", "flow", h)
    if err != nil {
        fmt.Printf("Fail to create nacos data source client, err: %+v", err)
        return
    }
    //nacos数据源初始化
    err = nds.Initialize()
    if err != nil {
        fmt.Printf("Fail to initialize nacos data source client, err: %+v", err)
        return
    }
    //启动统计
    go timerTask(&counter)

    //模拟流量
    ch := make(chan struct{})
    for i := 0; i < 10; i++ {
        go func() {
            for {
                atomic.AddInt64(counter.total, 1)
                //some-test 对应在nacos 流控配置文件中的resource
                e, b := sentinel.Entry("some-test", sentinel.WithTrafficType(base.Inbound))
                if b != nil {
                    atomic.AddInt64(counter.block, 1)
                    // Blocked. We could get the block reason from the BlockError.
                    time.Sleep(time.Duration(rand.Uint64()%10) * time.Millisecond)
                } else {
                    atomic.AddInt64(counter.pass, 1)
                    time.Sleep(time.Duration(rand.Uint64()%10) * time.Millisecond)

                    // Be sure the entry is exited finally.
                    e.Exit()
                }

            }
        }()
    }
    <-ch
}

//statistic print
func timerTask(counter *Counter) {
    fmt.Println("begin to statistic!!!")
    var (
        oldTotal, oldPass, oldBlock int64
    )
    for {
        time.Sleep(1 * time.Second)
        globalTotal := atomic.LoadInt64(counter.total)
        oneSecondTotal := globalTotal - oldTotal
        oldTotal = globalTotal

        globalPass := atomic.LoadInt64(counter.pass)
        oneSecondPass := globalPass - oldPass
        oldPass = globalPass

        globalBlock := atomic.LoadInt64(counter.block)
        oneSecondBlock := globalBlock - oldBlock
        oldBlock = globalBlock
        fmt.Println(util.CurrentTimeMillis()/1000, "total:", oneSecondTotal, " pass:", oneSecondPass, " block:", oneSecondBlock)
    }
}

4.3.2 运行结果

3.png

4.3.3 动态更新限流配置

在项目启动过程中,在nacos中修改流控配置参数。将count 从100->400

4.png

可以看到打印了重新loadRule的日志,流量控制动态的由100->400

5.png

总结

在sentinel-go中使用nacos作为外部动态数据源,只需要将原来声明Rule以及加载Rule的部分 变成从nacos数据源读取。

在本文中只介绍了流量控制的集成,熔断,warmup,热点参数的集成也是相同的,只要按需修改配置的内容即可

配置内容参考地址:https://github.com/alibaba/sentinel-golang/wiki

关键代码:

    h := datasource.NewFlowRulesHandler(datasource.FlowRulesJsonConverter)
    nds, err := nacos.NewNacosDataSource(client, "sentinel-go", "flow", h)
    if err != nil {
        fmt.Printf("Fail to create nacos data source client, err: %+v", err)
        return
    }
    err = nds.Initialize()
    if err != nil {
        fmt.Printf("Fail to initialize nacos data source client, err: %+v", err)
        return
    }

相关链接

作者简介

张斌斌 Github 账号:sanxun0325,Nacos Commiter,Sentinel-Golang Contributor,现任职 OpenJaw 微服务团队。目前主要负责 Nacos、Sentinel-Golang 社区相关项目的开发工作,以及 Nacos 在 Golang 微服务生态中的推广集成工作。

阿里巴巴云原生关注微服务、Serverless、容器、Service Mesh 等技术领域、聚焦云原生流行技术趋势、云原生大规模的落地实践,做最懂云原生开发者的公众号。”

K8S中文社区微信公众号

评论 1

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址
  1. #1

    Contact him for any type of hacking, he is a professional hacker that specializes in exposing cheating spouses, and every other hacking related issues. he is a cyber guru, he helps catch cheating spouses by hacking their communications like call, Facebook, text, emails, Skype, whats-app and many more. I have used this service before and he did a very good job, he gave me every proof I needed to know that my fiancee was cheating. You can contact him on his email to help you catch your cheating spouse, or for any other hacking related problems, like hacking websites, bank statement, grades and many more. he will definitely help you, he has helped a lot of people, contact him on, Henryclarkethicalhacker@gmail.com, and you can Text/Call &WhatsApp: +1 (262)-236-7526, and figure out your relationship status. I wish you the best.

    Lucy Janet2周前 (11-13)回复