agollo

package module
v1.2.14 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 6, 2023 License: Apache-2.0 Imports: 23 Imported by: 48

README

Agollo - Go Client for Apollo

Build Status Go Report Card GolangCI codebeat badge golang GoDoc GitHub release License

携程Apollo Golang版客户端

针对apollo openapi的golang 客户端封装

快速开始

获取安装
go get -u github.com/shima-park/agollo

Features

  • 实时同步配置,配置改动监听
  • 配置文件容灾
  • 支持多namespace, cluster
  • 客户端SLB
  • 提供Viper配置库的apollo插件
  • 支持通过 ACCESSKEY_SECRET 来实现 client 安全访问
  • 支持自定义签名认证

示例

读取配置

此示例场景适用于程序启动时读取一次。不会额外启动goroutine同步配置

package main

import (
	"fmt"

	"github.com/shima-park/agollo"
)

func main() {
	a, err := agollo.New("localhost:8080", "your_appid", agollo.AutoFetchOnCacheMiss())
	if err != nil {
		panic(err)
	}

	fmt.Println(
		// 默认读取Namespace:application下key: foo的value
		a.Get("foo"),

		// 获取namespace为test.json的所有配置项
		a.GetNameSpace("test.json"),

		// 当key:foo不存在时,提供一个默认值bar
		a.Get("foo", agollo.WithDefault("bar")),

		// 读取Namespace为other_namespace, key: foo的value
		a.Get("foo", agollo.WithNamespace("other_namespace")),
	)
}
实时同步配置

启动一个goroutine实时同步配置, errorCh返回notifications/v2非httpcode(200)的错误信息

a, err := agollo.New("localhost:8080", "your_appid", agollo.PreloadNamespaces("application", "test.json"))
// error handle...

errorCh := a.Start()  // Start后会启动goroutine监听变化,并更新agollo对象内的配置cache
// 或者忽略错误处理直接 a.Start()
配置监听

监听所有namespace配置变更事件

a, err := agollo.New("localhost:8080", "your_appid", agollo.PreloadNamespaces("application", "test.json"))
// error handle...

errorCh := a.Start()  // Start后会启动goroutine监听变化,并更新agollo对象内的配置cache
// 或者忽略错误处理直接 a.Start()

watchCh := a.Watch()

for{
	select{
	case err := <- errorCh:
		// handle error
	case resp := <-watchCh:
		fmt.Println(
			"Namespace:", resp.Namespace,
			"OldValue:", resp.OldValue,
			"NewValue:", resp.NewValue,
			"Error:", resp.Error,
		)
	}
}
配置文件容灾

初始化时增加agollo.FailTolerantOnBackupExists()即可, 在连接apollo失败时,如果在配置的目录下存在.agollo备份配置,会读取备份在服务器无法连接的情况下

a, err := agollo.New("localhost:8080", "your_appid",
		agollo.FailTolerantOnBackupExists(),
		// other options...
	)
// error handle...
支持多namespace

初始化时增加agollo.AutoFetchOnCacheMiss() 当本地缓存中namespace不存在时,尝试去apollo缓存接口去获取

a, err := agollo.New("localhost:8080", "your_appid",
		agollo.AutoFetchOnCacheMiss(),
		// other options...
	)
// error handle...

appNS, aNS, bNS := a.GetNameSpace("application"), a.GetNameSpace("Namespace_A"), a.GetNameSpace("Namespace_B")

a.Get("foo") // 默认从application这个namespace中查找配置项
a.Get("foo", agollo.WithNamespace("Namespace_A")) // 从Namespace_A中获取配置项foo
a.Get("foo", agollo.WithNamespace("Namespace_B")) // 从Namespace_B中获取配置项foo
// ...

或者初始化时增加agollo.PreloadNamespaces("Namespace_A", "Namespace_B", ...)预加载这几个Namespace的配置

a, err := agollo.New("localhost:8080", "your_appid",
		agollo.PreloadNamespaces("Namespace_A", "Namespace_B", ...),
		// other options...
	)
// error handle...

当然两者结合使用也是可以的。

a, err := agollo.New("localhost:8080", "your_appid",
		agollo.PreloadNamespaces("Namespace_A", "Namespace_B", ...),
		agollo.AutoFetchOnCacheMiss(),
		// other options...
	)
// error handle...
如何支持多cluster

初始化时增加agollo.Cluster("your_cluster"),并创建多个Agollo接口实例issue

cluster_a, err := agollo.New("localhost:8080", "your_appid",
		agollo.Cluster("cluster_a"),
		agollo.AutoFetchOnCacheMiss(),
		// other options...
	)

cluster_b, err := agollo.New("localhost:8080", "your_appid",
		agollo.Cluster("cluster_b"),
		agollo.AutoFetchOnCacheMiss(),
		// other options...
	)

cluster_a.Get("foo")
cluster_b.Get("foo")
// ...
客户端SLB

客户端通过MetaServer进行动态SLB的启用逻辑:

//方式1:
    // 使用者主动增加配置项agollo.EnableSLB(true)
    a, err := agollo.New("localhost:8080", "your_appid", agollo.EnableSLB(true))


//方式2:
    // (客户端显示传递的configServerURL) 和 (环境变量中的APOLLO_CONFIGSERVICE) 都为空值
    // export APOLLO_CONFIGSERVICE=""
    // 此方式必须设置 export APOLLO_META="your meta_server address"
    a, err := agollo.New("", "your_appid")

客户端静态SLB(现在支持","分割的多个configServer地址列表):

//方式1:
    // 直接传入","分割的多个configServer地址列表
    a, err := agollo.New("localhost:8080,localhost:8081,localhost:8082", "your_appid")

//方式2:
    // 在环境变量中APOLLO_CONFIGSERVICE设置","分割的多个configServer地址列表
    // export APOLLO_CONFIGSERVICE="localhost:8080,localhost:8081,localhost:8082"
    a, err := agollo.New("", "your_appid")

SLB更新间隔默认是60s和官方java sdk保持一致,可以通过agollo.ConfigServerRefreshIntervalInSecond(time.Second * 90)来修改

    a, err := agollo.New("localhost:8080", "your_appid",
        agollo.EnableSLB(true),
        agollo.ConfigServerRefreshIntervalInSecond(time.Second * 90),
    )

! SLB的MetaServer地址来源(用来调用接口获取configServer列表),取下列表中非空的一项:

  1. 用户显示传递的configServerURL
  2. 环境变量中的APOLLO_META

! SLB的默认采用的算法是RoundRobin

初始化方式

三种package级别初始化,影响默认对象和package提供的静态方法。适用于不做对象传递,单一AppID的场景

// 读取当前目录下app.properties,适用于原始apollo定义的读取固定配置文件同学
agollo.InitWithDefaultConfigFile(opts ...Option) error

agollo.Init(configServerURL, appID string, opts ...Option) (err error)

agollo.InitWithConfigFile(configFilePath string, opts ...Option) (err error)

两种新建对象初始化方法。返回独立的Agollo接口对象。互相之间不会影响,适用于多AppID,Cluser, ConfigServer配置读取 issue

agollo.New(configServerURL, appID string, opts ...Option) (Agollo, error)
agollo.NewWithConfigFile(configFilePath string, opts ...Option) (Agollo, error)
初始化时可选配置项

更多配置请见options.go

        // 打印日志,打印日志注入有效的io.Writer,默认: ioutil.Discard
	agollo.WithLogger(agollo.NewLogger(agollo.LoggerWriter(os.Stdout))),

	// 默认的集群名称,默认:default
	agollo.Cluster(cluster),

	// 预先加载的namespace列表,如果是通过配置启动,会在app.properties配置的基础上追加
	agollo.PreloadNamespaces("Namespace_A", "Namespace_B", ...),

	// 在配置未找到时,去apollo的带缓存的获取配置接口,获取配置
	agollo.AutoFetchOnCacheMiss(),

	// 备份文件存放地址,默认:当前目录下/.agollo,一般结合FailTolerantOnBackupExists使用
	agollo.BackupFile("/tmp/xxx/.agollo")
	// 在连接apollo失败时,如果在配置的目录下存在.agollo备份配置,会读取备份在服务器无法连接的情况下
	agollo.FailTolerantOnBackupExists(),
详细特性展示

请将example/sample下app.properties修改为你本地或者测试的apollo配置。 示例代码

结合viper使用,提高配置读取舒适度

例如apollo中有以下配置:

appsalt = xxx
database.driver = mysql
database.host = localhost
database.port = 3306
database.timeout = 5s
// ...

示例代码:

import (
    "fmt"
	"github.com/shima-park/agollo/viper-remote"
	"github.com/spf13/viper"
)

type Config struct {
	AppSalt string         `mapstructure:"appsalt"`
	DB      DatabaseConfig `mapstructure:"database"`
}

type DatabaseConfig struct {
	Driver   string        `mapstructure:"driver"`
	Host     string        `mapstructure:"host"`
	Port     int           `mapstructure:"port"`
	Timeout time.Duration  `mapstructure:"timeout"`
	// ...
}

func main(){
    remote.SetAppID("your_appid")
    v := viper.New()
    v.SetConfigType("prop") // 根据namespace实际格式设置对应type
    err := v.AddRemoteProvider("apollo", "your_apollo_endpoint", "your_apollo_namespace")
    // error handle...
    err = v.ReadRemoteConfig()
    // error handle...

    // 直接反序列化到结构体中
    var conf Config
    err = v.Unmarshal(&conf)
    // error handle...
    fmt.Printf("%+v\n", conf)

    // 各种基础类型配置项读取
    fmt.Println("Host:", v.GetString("db.host"))
    fmt.Println("Port:", v.GetInt("db.port"))
    fmt.Println("Timeout:", v.GetDuration("db.timeout"))

    // 获取所有key,所有配置
    fmt.Println("AllKeys", v.AllKeys(), "AllSettings",  v.AllSettings())
}
viper配置同步

基于轮训的配置同步

    remote.SetAppID("your_appid")
    v := viper.New()
    v.SetConfigType("prop")
    err := v.AddRemoteProvider("apollo", "your_apollo_endpoint", "your_apollo_namespace")
    // error handle...
    err = v.ReadRemoteConfig()
    // error handle...

    for {
	time.Sleep(10 * time.Second)

	err := v.WatchRemoteConfig() // 每次调用该方法,会从apollo缓存接口获取一次配置,并更新viper
	if err != nil {
		panic(err)
	}

	fmt.Println("AllSettings:", v.AllSettings())
     }

基于事件监听配置同步

    remote.SetAppID("your_appid")
    v := viper.New()
    v.SetConfigType("prop")
    err := v.AddRemoteProvider("apollo", "your_apollo_endpoint", "your_apollo_namespace")
    // error handle...
    err = v.ReadRemoteConfig()
    // error handle...

    v.WatchRemoteConfigOnChannel() // 启动一个goroutine来同步配置更改

    for {
	time.Sleep(1 * time.Second)
	fmt.Println("AllSettings:", v.AllSettings())
     }

License

The project is licensed under the Apache 2 license.

Documentation

Index

Constants

View Source
const (
	AUTHORIZATION_FORMAT      = "Apollo %s:%s"
	DELIMITER                 = "\n"
	HTTP_HEADER_AUTHORIZATION = "Authorization"
	HTTP_HEADER_TIMESTAMP     = "Timestamp"
)
View Source
const (
	// ENV_APOLLO_ACCESS_KEY 默认从环境变量中读取Apollo的AccessKey
	// 会被显示传入的AccessKey所覆盖
	ENV_APOLLO_ACCESS_KEY = "APOLLO_ACCESS_KEY"
)

Variables

View Source
var (
	ErrNoConfigServerAvailable = errors.New("no config server availbale")
)

Functions

func Get

func Get(key string, opts ...GetOption) string

func Init

func Init(configServerURL, appID string, opts ...Option) (err error)

func InitWithConfigFile

func InitWithConfigFile(configFilePath string, opts ...Option) (err error)

func InitWithDefaultConfigFile

func InitWithDefaultConfigFile(opts ...Option) error

func Start

func Start() <-chan *LongPollerError

func Stop

func Stop()

func ToStringE added in v1.0.1

func ToStringE(i interface{}) (string, error)

ToStringE casts an interface to a string type.

func Watch

func Watch() <-chan *ApolloResponse

func WatchNamespace

func WatchNamespace(namespace string, stop chan bool) <-chan *ApolloResponse

Types

type Agollo

type Agollo interface {
	Start() <-chan *LongPollerError
	Stop()
	Get(key string, opts ...GetOption) string
	GetNameSpace(namespace string) Configurations
	Watch() <-chan *ApolloResponse
	WatchNamespace(namespace string, stop chan bool) <-chan *ApolloResponse
	Options() Options
}

func GetAgollo

func GetAgollo() Agollo

func New

func New(configServerURL, appID string, opts ...Option) (Agollo, error)

func NewWithConfigFile

func NewWithConfigFile(configFilePath string, opts ...Option) (Agollo, error)

type ApolloClient

type ApolloClient interface {
	Apply(opts ...ApolloClientOption)

	Notifications(configServerURL, appID, clusterName string, notifications []Notification) (int, []Notification, error)

	// 该接口会直接从数据库中获取配置,可以配合配置推送通知实现实时更新配置。
	GetConfigsFromNonCache(configServerURL, appID, cluster, namespace string, opts ...NotificationsOption) (int, *Config, error)

	// 该接口会从缓存中获取配置,适合频率较高的配置拉取请求,如简单的每30秒轮询一次配置。
	GetConfigsFromCache(configServerURL, appID, cluster, namespace string) (Configurations, error)

	// 该接口从MetaServer获取ConfigServer列表
	GetConfigServers(metaServerURL, appID string) (int, []ConfigServer, error)
}

https://github.com/ctripcorp/apollo/wiki/%E5%85%B6%E5%AE%83%E8%AF%AD%E8%A8%80%E5%AE%A2%E6%88%B7%E7%AB%AF%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97

func NewApolloClient

func NewApolloClient(opts ...ApolloClientOption) ApolloClient

type ApolloClientOption

type ApolloClientOption func(*apolloClient)

func WithAccessKey added in v1.1.12

func WithAccessKey(accessKey string) ApolloClientOption

func WithConfigType

func WithConfigType(configType string) ApolloClientOption

func WithDoer

func WithDoer(d Doer) ApolloClientOption

func WithIP

func WithIP(ip string) ApolloClientOption

func WithSignatureFunc added in v1.2.10

func WithSignatureFunc(sf SignatureFunc) ApolloClientOption

type ApolloResponse

type ApolloResponse struct {
	Namespace string
	OldValue  Configurations
	NewValue  Configurations
	Changes   Changes
	Error     error
}

type Balancer added in v1.1.4

type Balancer interface {
	Select() (string, error)
	Stop()
}

func NewAutoFetchBalancer added in v1.1.4

func NewAutoFetchBalancer(configServerURL, appID string, getConfigServers GetConfigServersFunc,
	refreshIntervalInSecond time.Duration, logger Logger) (Balancer, error)

func NewRoundRobin added in v1.1.4

func NewRoundRobin(ss []string) Balancer

type Change added in v1.0.5

type Change struct {
	Type  ChangeType
	Key   string
	Value interface{}
}

type ChangeType added in v1.0.5

type ChangeType string
const (
	ChangeTypeAdd    ChangeType = "add"
	ChangeTypeUpdate ChangeType = "update"
	ChangeTypeDelete ChangeType = "delete"
)

type Changes added in v1.0.5

type Changes []Change

func (Changes) Len added in v1.0.5

func (cs Changes) Len() int

Len is part of sort.Interface.

func (Changes) Less added in v1.0.5

func (cs Changes) Less(i, j int) bool

Less is part of sort.Interface. It is implemented by calling the "by" closure in the sorter.

func (Changes) Swap added in v1.0.5

func (cs Changes) Swap(i, j int)

Swap is part of sort.Interface.

type Config

type Config struct {
	AppID          string         `json:"appId"`          // appId: "AppTest",
	Cluster        string         `json:"cluster"`        // cluster: "default",
	NamespaceName  string         `json:"namespaceName"`  // namespaceName: "TEST.Namespace1",
	Configurations Configurations `json:"configurations"` // configurations: {Name: "Foo"},
	ReleaseKey     string         `json:"releaseKey"`     // releaseKey: "20181017110222-5ce3b2da895720e8"
}

type ConfigServer added in v1.1.4

type ConfigServer struct {
	AppName     string `json:"appName"`
	InstanceID  string `json:"instanceId"`
	HomePageURL string `json:"homepageUrl"`
}

type Configurations

type Configurations map[string]interface{}

func GetNameSpace

func GetNameSpace(namespace string) Configurations

func (Configurations) Different added in v1.0.5

func (old Configurations) Different(new Configurations) Changes

type Doer

type Doer interface {
	Do(*http.Request) (*http.Response, error)
}

type GetConfigServersFunc added in v1.1.4

type GetConfigServersFunc func(metaServerURL, appID string) (int, []ConfigServer, error)

type GetOption

type GetOption func(*GetOptions)

func WithDefault

func WithDefault(defVal string) GetOption

func WithNamespace

func WithNamespace(namespace string) GetOption

type GetOptions

type GetOptions struct {
	// Get时,如果key不存在将返回此值
	DefaultValue string

	// Get时,显示的指定需要获取那个Namespace中的key。非空情况下,优先级顺序为:
	// GetOptions.Namespace > Options.DefaultNamespace > "application"
	Namespace string
}
type Header map[string]string

func DefaultSignatureFunc added in v1.2.10

func DefaultSignatureFunc(ctx *SignatureContext) Header

type Logger

type Logger interface {
	Log(kvs ...interface{})
}

func NewLogger

func NewLogger(opts ...LoggerOption) Logger

type LoggerOption

type LoggerOption func(*logger)

func LoggerWriter

func LoggerWriter(w io.Writer) LoggerOption

type LongPollerError

type LongPollerError struct {
	ConfigServerURL string
	AppID           string
	Cluster         string
	Notifications   []Notification
	Namespace       string // 服务响应200后去非缓存接口拉取时的namespace
	Err             error
}

type Notification

type Notification struct {
	NamespaceName  string `json:"namespaceName"`  // namespaceName: "application",
	NotificationID int    `json:"notificationId"` // notificationId: 107
}

type Notifications

type Notifications []Notification

func (Notifications) String

func (n Notifications) String() string

type NotificationsOption

type NotificationsOption func(*NotificationsOptions)

func ReleaseKey

func ReleaseKey(releaseKey string) NotificationsOption

type NotificationsOptions

type NotificationsOptions struct {
	ReleaseKey string
}

type Option

type Option func(*Options)

func AccessKey added in v1.1.12

func AccessKey(accessKey string) Option

func AutoFetchOnCacheMiss

func AutoFetchOnCacheMiss() Option

func BackupFile

func BackupFile(backupFile string) Option

func Cluster

func Cluster(cluster string) Option

func ConfigServerRefreshIntervalInSecond added in v1.1.4

func ConfigServerRefreshIntervalInSecond(refreshIntervalInSecond time.Duration) Option

func DefaultNamespace

func DefaultNamespace(defaultNamespace string) Option

func EnableHeartBeat added in v1.2.12

func EnableHeartBeat(b bool) Option

func EnableSLB added in v1.1.4

func EnableSLB(b bool) Option

func FailTolerantOnBackupExists

func FailTolerantOnBackupExists() Option

func HeartBeatInterval added in v1.2.12

func HeartBeatInterval(i time.Duration) Option

func LongPollerInterval

func LongPollerInterval(i time.Duration) Option

func PreloadNamespaces

func PreloadNamespaces(namespaces ...string) Option

func WithApolloClient

func WithApolloClient(c ApolloClient) Option

func WithBalancer added in v1.1.4

func WithBalancer(b Balancer) Option

func WithClientOptions added in v1.2.6

func WithClientOptions(opts ...ApolloClientOption) Option

func WithLogger

func WithLogger(l Logger) Option

type Options

type Options struct {
	AppID                      string               // appid
	Cluster                    string               // 默认的集群名称,默认:default
	DefaultNamespace           string               // Get时默认使用的命名空间,如果设置了该值,而不在PreloadNamespaces中,默认也会加入初始化逻辑中
	PreloadNamespaces          []string             // 预加载命名空间,默认:为空
	ApolloClient               ApolloClient         // apollo HTTP api实现
	Logger                     Logger               // 日志实现类,可以设置自定义实现或者通过NewLogger()创建并设置有效的io.Writer,默认: ioutil.Discard
	AutoFetchOnCacheMiss       bool                 // 自动获取非预设以外的Namespace的配置,默认:false
	LongPollerInterval         time.Duration        // 轮训间隔时间,默认:1s
	BackupFile                 string               // 备份文件存放地址,默认:.agollo
	FailTolerantOnBackupExists bool                 // 服务器连接失败时允许读取备份,默认:false
	Balancer                   Balancer             // ConfigServer负载均衡
	EnableSLB                  bool                 // 启用ConfigServer负载均衡
	RefreshIntervalInSecond    time.Duration        // ConfigServer刷新间隔
	ClientOptions              []ApolloClientOption // 设置apollo HTTP api的配置项
	EnableHeartBeat            bool                 // 是否允许兜底检查,默认:false
	HeartBeatInterval          time.Duration        // 兜底检查间隔时间,默认:300s
}

type SignatureContext added in v1.2.10

type SignatureContext struct {
	AppID           string // appid
	AccessKey       string // 服务启动时缓存的access key
	ConfigServerURL string // 当前访问配置使用的apollo config server的url
	RequestURI      string // 请求的uri,domain之后的路径
	Cluster         string // 请求的集群,默认情况下: default,请求GetConfigServers接口时为""
}

type SignatureFunc added in v1.2.10

type SignatureFunc func(ctx *SignatureContext) Header

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL