trpc.group/trpc-go/trpc-go@v1.0.3/config/README.zh_CN.md (about)

     1  [English](README.md) | 中文
     2  
     3  # 前言
     4  
     5  配置管理是微服务治理体系中非常重要的一环,tRPC 框架为业务程序开发提供了一套支持从多种数据源获取配置,解析配置和感知配置变化的标准接口,框架屏蔽了和数据源对接细节,简化了开发。通过本文的介绍, 旨在为用户提供以下信息:
     6  - 什么是业务配置,它和框架配置的区别
     7  - 业务配置的一些核心概念(比如: provider,codec...)
     8  - 如何使用标准接口获取业务配置
     9  - 如何感知配置项的变化
    10  
    11  # 概念介绍
    12  ## 什么是业务配置
    13  业务配置是供业务使用的配置,它由业务程序定义配置的格式,含义和参数范围,tRPC 框架并不使用业务配置,也不关心配置的含义。框架仅仅关心如何获取配置内容,解析配置,发现配置变化并告知业务程序。
    14  
    15  业务配置和框架配置的区别在于使用配置的主体和管理方式不一样。框架配置是供 tRPC 框架使用的,由框架定义配置的格式和含义。框架配置仅支持从本地文件读取方式,在程序启动是读取配置,用于初始化框架。框架配置不支持动态更新配置,如果需要更新框架配置,则需要重启程序。
    16  
    17  而业务配置则不同,业务配置支持从多种数据源获取配置,比如:本地文件,配置中心,数据库等。如果数据源支持配置项事件监听功能,tRPC 框架则提供了机制以实现配置的动态更新。
    18  
    19  ## 如何管理业务配置
    20  对于业务配置的管理,我们建议最佳实践是使用配置中心来管理业务配置,使用配置中心有以下优点:
    21  - 避免源代码泄露敏感信息
    22  - 服务动态更新配置
    23  - 多服务共享配置,避免一份配置拥有多个副本
    24  - 支持灰度发布,配置回滚,拥有完善的权限管理和操作日志
    25  
    26  业务配置也支持本地文件。对于本地文件,大部分使用场景是客户端作为独立的工具使用,或者程序在开发调试阶段使用。好处在于不需要依赖外部系统就能工作。
    27  
    28  ## 什么是多数据源
    29  数据源就获取配置的来源,配置存储的地方。常见的数据源包括:file,etcd,configmap,env 等。tRPC 框架支持对不同业务配置设定不同的数据源。框架采用插件化方式来扩展对更多数据源的支持。在后面的实现原理章节,我们会详细介绍框架是如何实现对多数据源的支持的。
    30  
    31  ## 什么是 Codec
    32  业务配置中的 Codec 是指从配置源获取到的配置的格式,常见的配置文件格式为:yaml,json,toml 等。框架采用插件化方式来扩展对更多解码格式的支持。
    33  
    34  # 实现原理
    35  为了更好的了解配置接口的使用,以及如何和数据源做对接,我们简单看看配置接口模块是如何实现的。下面这张图是配置模块实现的示意图(非代码实现类图):
    36  
    37  ![trpc](/.resources/user_guide/business_configuration/trpc_cn.png)
    38  
    39  图中的 config 接口为业务代码提供了获取配置项的标准接口,每种数据类型都有一个独立的接口,接口支持返回 default 值。
    40  
    41  Codec 和 DataProvider 这两个模块都提供了标准接口和注册函数以支持编解码和数据源的插件化。以实现多数据源为例,DataProvider 提供了以下三个标准接口,其中 Read 函数提供了如何读取配置的原始数据(未解码),而 Watch 函数提供了 callback 函数,当数据源的数据发生变化时,框架会执行此 callback 函数。
    42  ```go
    43  type DataProvider interface {
    44      Name() string
    45      Read(string) ([]byte, error)
    46      Watch(ProviderCallback)
    47  }
    48  ```
    49  
    50  最后我们来看看,如何通过指定数据源,解码器来获取一个业务配置项:
    51  ```go
    52  // 加载 etcd 配置文件:config.WithProvider("etcd")
    53  c, _ := config.Load("test.yaml", config.WithCodec("yaml"), config.WithProvider("etcd"))
    54  // 读取 String 类型配置
    55  c.GetString("auth.user", "admin")
    56  ```
    57  在这个示例中,数据源为 etcd 配置中心,数据源中的业务配置文件为“test.yaml”。当 ConfigLoader 获取到"test.yaml"业务配置时,指定使用 yaml 格式对数据内容进行解码。最后通过`c.GetString("server.app", "default")`函数来获取 test.yaml 文件中`auth.user`这个配置型的值。
    58  
    59  # 接口使用
    60  本文仅从使用业务配置的角度来介绍相应的接口,如何用户需要开发数据源插件或者 Codec 插件,请参考 [tRPC-Go 开发配置插件](/docs/developer_guide/develop_plugins/config.zh_CN.md)。
    61  
    62  tRPC-Go 框架提供了两套接口分别用于 “读取配置项” 和 “监听配置项”
    63  ## 获取配置项
    64  **第一步:选择插件**
    65  在使用配置接口之前需要提前配置好数据源插件,以及插件配置。tRPC 框架默认支持本地文件数据源。
    66  
    67  **第二步:插件初始化**
    68  由于数据源采用的是插件方式实现的,需要 tRPC 框架在服务端初始化函数中,通过读取“trpc_go.yaml”文件来初始化所有插件。业务配置的读取操作必须在完成`trpc.NewServer()`之后
    69  ```go
    70  import (
    71      trpc "trpc.group/trpc-go/trpc-go"
    72  )
    73  
    74  // 实例化 server 时会初始化插件系统,所有配置读取操作需要在此之后
    75  trpc.NewServer()
    76  ```
    77  
    78  **第三步:加载配置**
    79  从数据源加载配置文件,返回 config 数据结构。可指定数据源类型和编解码格式,框架默认为“file”数据源和“yaml”编解码。接口定义为:
    80  ```go
    81  // 加载配置文件:path 为配置文件路径
    82  func Load(path string, opts ...LoadOption) (Config, error)
    83  // 更改编解码类型,默认为“yaml”格式
    84  func WithCodec(name string) LoadOption
    85  // 更改数据源,默认为“file”
    86  func WithProvider(name string) LoadOption
    87  ```
    88  
    89  示例代码为:
    90  ```go
    91  // 加载 etcd 配置文件:config.WithProvider("etcd")
    92  c, _ := config.Load("test1.yaml", config.WithCodec("yaml"), config.WithProvider("etcd"))
    93  
    94  // 加载本地配置文件,codec 为 json,数据源为 file
    95  c, _ := config.Load("../testdata/auth.yaml", config.WithCodec("json"), config.WithProvider("file"))
    96  
    97  // 加载本地配置文件,默认为 codec 为 yaml,数据源为 file
    98  c, _ := config.Load("../testdata/auth.yaml")
    99  ```
   100  
   101  **第四步:获取配置项**
   102  从 config 数据结构中获取指定配置项值。支持设置默认值,框架提供以下标准接口:
   103  ```go
   104  // Config 配置通用接口
   105  type Config interface {
   106      Load() error
   107      Reload()
   108      Get(string, interface{}) interface{}
   109      Unmarshal(interface{}) error
   110      IsSet(string) bool
   111      GetInt(string, int) int
   112      GetInt32(string, int32) int32
   113      GetInt64(string, int64) int64
   114      GetUint(string, uint) uint
   115      GetUint32(string, uint32) uint32
   116      GetUint64(string, uint64) uint64
   117      GetFloat32(string, float32) float32
   118      GetFloat64(string, float64) float64
   119      GetString(string, string) string
   120      GetBool(string, bool) bool
   121      Bytes() []byte
   122  }
   123  ```
   124  
   125  示例代码为:
   126  ```go
   127  // 读取 bool 类型配置
   128  c.GetBool("server.debug", false)
   129  
   130  // 读取 String 类型配置
   131  c.GetString("server.app", "default")
   132  ```
   133  
   134  ## 监听配置项
   135  对于 KV 型配置中心,框架提供了 Watch 机制供业务程序根据接收的配置项变更事件,自行定义和执行业务逻辑。监控接口设计如下:
   136  ```go
   137  
   138  // Get 根据名字使用 kvconfig
   139  func Get(name string) KVConfig
   140  
   141  // KVConfig kv 配置
   142  type KVConfig interface {
   143      KV
   144      Watcher
   145      Name() string
   146  }
   147  
   148  // 监控接口定义
   149  type Watcher interface {
   150      // Watch 监听配置项 key 的变更事件
   151      Watch(ctx context.Context, key string, opts ...Option) (<-chan Response, error)
   152  }
   153  
   154  // Response 配置中心响应
   155  type Response interface {
   156      // Value 获取配置项对应的值
   157      Value() string
   158      // MetaData 额外元数据信息
   159      // 配置 Option 选项,可用于承载不同配置中心的额外功能实现,例如 namespace,group, 租约等概念
   160      MetaData() map[string]string
   161      // Event 获取 Watch 事件类型
   162      Event() EventType
   163  }
   164  
   165  // EventType 监听配置变更的事件类型
   166  type EventType uint8
   167  const (
   168      // EventTypeNull 空事件
   169      EventTypeNull EventType = 0
   170      // EventTypePut 设置或更新配置事件
   171      EventTypePut EventType = 1
   172      // EventTypeDel 删除配置项事件
   173      EventTypeDel EventType = 2
   174  )
   175  ```
   176  
   177  下面示例展示了业务程序监控 etcd 上的“test.yaml”文件,打印配置项变更事件并更新配置。
   178  ```go
   179  import (
   180      "sync/atomic"
   181      // ...
   182  )
   183  
   184  type yamlFile struct {
   185      Server struct {
   186          App string
   187      }
   188  }
   189  
   190  var cfg atomic.Value // 并发安全的 Value
   191  
   192  // 使用 trpc-go/config 中 Watch 接口监听 etcd 远程配置变化
   193  c, _ := config.Get("etcd").Watch(context.TODO(), "test.yaml")
   194  
   195  go func() {
   196      for r := range c {
   197          yf := &yamlFile{}
   198          fmt.Printf("event: %d, value: %s", r.Event(), r.Value())
   199  
   200          if err := yaml.Unmarshal([]byte(r.Value()), yf); err == nil {
   201              cfg.Store(yf)
   202          }
   203      }
   204  }()
   205  
   206  // 当配置初始化完成后,可以通过 atomic.Value 的 Load 方法获得最新的配置对象
   207  cfg.Load().(*yamlFile)
   208  ```
   209  
   210  # 数据源实现
   211  
   212  参考:[trpc-ecosystem/go-config-etcd](https://github.com/trpc-ecosystem/go-config-etcd)