微服务实战之配置管理

概述

一般来说, 应用由三部分组成

  • 可执行程序
  • 配置
  • 数据

软件系统几乎都有配置,它能灵活地定义软件的关键属性,组件之间的依赖关系与交互方式。

1. 关于配置的思考

1) 多还是少

  • 为了简单,配置当然越少
  • 为了灵活,配置当然越多越好

2) 自动还是手动

能自动当然不要手动,可是现实中少不了人工的参与, 对于配置属性进行添加,修改和删除
最好是一次修改, 到处可用

3) 推送还是拉取

推送与拉取取决于工作量的多少和意外情况的控制, 当服务器数量较多,分布较广,状态不一的时候,推送的方法会有问题, 不一定能推送到目标服务器上, 因为目标服务器可能并未启动,或者由于网络状态不可达, 所以拉取的方式更好一点。

当然不必每次都去配置仓库, 配置服务或配置文件里读取, 而是按需读取。 采用订阅-通知-读取是比较好的方式

4) 内部还是外部

  • 内部配置宜多一点,外部配置宜少一点。
    具体来说, 对外的, 提供给一般使用者的要尽量简单, 尽量少, 而对内的, 提供给高级管理员, 或开发者自己的配置, 可以适当多一点, 最好分个层次,不要堆积一大堆配置把人搞晕

  • 配置信息放在服务外部
    我们开发一个微服务, 服务本身的代码应该就一套, 可以会有多个逻辑分支和功能开关
    可是配置信息可能变化多端, 最好不要都放在一起, 代码和默认配置放在一个代码仓库, 配置信息放在另外一个代码仓库, 这样做的好处是更改配置信息无需发布新的服务版本, 尽量保持服务核心代码的稳定

5) 集中式还是分布式

集中式比较简单, 要注意不要有单点失败, 不支持对于跨数据中心的灾难恢复, 受网络故障的影响比较大
分布式相对复杂一点, 要注意 SSoT(Single Source of Truth), 以一处的配置数据为黄金数据, 其他各处及时同步, 要有对于网络同步不及时的应对措施

2. 配置的版本管理

所有创建软件的东西都应该纳入版本控制

  • 源代码
  • 测试脚本
  • 数据库脚本
  • 构建和部署脚本
  • 文档
  • 依赖的库及工具
    • 依赖当然越少越好,可是现在的库以及工具能做的事,应用程序就能省则省
  • 配置脚本及数据

3. 配置的载体

配置放哪儿呢, 最熟悉的莫过于配置文件,环境变量, 注册表或者数据库了

环境变量

这是一切和环境相关配置的首选,比如网络IP, 数据库地址,数据文件目录等

配置文件

这是最方便, 最常用的配置载体, 配置文件的格式也是五花八门:

  • ini
  • properties
  • json
  • xml
  • yaml

象 lua, python, ruby这样的脚本语言, 直接就用一个单独的脚本表示就好了
在一些特定领域,用 DSL 领域特定语言的配置更加容易理解

在实践中, 最好在读取配置文件之后, 将其配置信息建模 , 以 python + json 举个简单的例子
有一个在线课程系统, 为每个注册用户建立一个配置文件

{
  "username": "walter",
  "password": "xxx",
  "email": "walter@xxx.com",
  "courses": [  ],
  "scores": {  }
}

对应的python 程序如下

import json
import os
import sys

class UserConfig:
    def __init__(self, json_file):
        
        self.read_config(json_file)

        self.username = self.config_data['username']
        self.password = self.config_data['password']
        self.email = self.config_data['email']

    def read_config(self, json_file):
        json_data=open(json_file)
        self.config_data = json.load(json_data)
 


    def dump_config(self):
        print self.config_data
        print "username=", self.username
        print "password=", self.password
        print "email=", self.email

if __name__ == "__main__":
    args = sys.argv
    usage = "usage: python %s  <config_file>" % args[0]
    
    argc = len(args)
    if(argc < 2):
        print usage
    else:
        json_file = args[1]
        print("* the json config file is " + args[1])
        config = UserConfig(json_file)
        config.dump_config()                                                         

执行结果

$ python user_config.py user_config.json
* the json config file is user_config.json
{u'username': u'walter', u'courses': [], u'password': u'xxx', u'email': u'walter@xxx.com', u'scores': {}}
username= walter
password= xxx
email= walter@xxx.com

配置数据库

数据库常用来存储复杂的配置,在建立复杂关系方面优势明显
最常用是表结构就是经典的 key/value 形式

列名类型
iduuid
namevarchar(256)
valuevarchar(256)
create_timetimestamp
update_timetimestamp

当然 Cassandra, Redis 等 NOSQL 就更简单了

环境管理

一般来说, 我们会有很多不同的测试环境和产品环境来发布我们的服务
比如我们常用的环境有如下几种

  • lab env
  • ats env
  • bts env
  • production env

每种环境就有多台服务器协同工作, 手工配置显示太麻烦, 于是众多配置管理的运维工具应运而生

  • Ansible
  • Chef
  • Fabric
  • Puppet
  • SaltStack

Puppet 以前用得很多, Ansible 最近比较火, 我比较喜欢用轻量级的Fabric, 参见以前写的 程序员瑞士军刀之Fabric

配置服务

把具体的配置项及业务相关的配置信息包装成资源, 以REST API的形式暴露读取和修改接口, 大型系统中的复杂的配置甚至可以单独作为一个微服务存在

例如下图

1598924-0863dcfaedf560a5.png
Configure Service

它的好处在于

  • 可以将配置信息很好进行建模,在API层面就嵌入AAA 管理
    Authentication认证, Authorization授权 和 Auditing审计, 防止非法操作
  • 可以基于 API 将配置流程自动化
  • 以服务作为配置数据的真正单个来源 SSoT (Single Source of Truth)
  • 提供订阅和通知服务, 在配置有改动时立即通知其他相关的微服务和系统

很多开源项目都可以用来构建Configure Service

项目组织/社区语言特点
Consulhashicorpgo提供健值存取, 服务发现和服务配置管理功能, 提供好用的命令行和网页界面
ZooKeeperapachejava老牌产品, 经久耐用, 提供集中式的服务接口, 可用于分布式系统中配置信息, 服务注册信息的同步, 使用 ZAB 协议
Etcdcoreosgo提供服务发现和分布式键值存取功能, 使用 Raft 协议, 速度快, 安装配置容易简单
Eurekanetflixjava提供服务发现和分布式键值存取功能, 并提供服务器端动态刷新, 网飞出口, 必属精品, 连 AWS 也在用它
Spring Cloud ConfigspringjavaSpring Cloud 大家庭中的一员, 和其他 Spring 项目无缝集成, 后端可以用文件系统, git, 及 Eureka 和 Consul

下面我们来用 Spring Cloud Config 来举个例子

Spring Cloud Config 很灵活, 配置信息可以使用本地文件系统, 也可以从远程 git 仓库中拉取, 从Database 及 key-value 系统获取, 或者与 Eureka , Consul 这样的系统集成.

建立一个微服务: config-service

启动类 ConfigServiceApplication

package com.github.walterfan.helloworld.configservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;

@SpringBootApplication
@EnableConfigServer
public class ConfigServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(ConfigServiceApplication.class, args);
    }
}

配置文件 src/main/resources/application.yml

server:
  port: 9002

  
logging:
  level:
    org.springframework.cloud: 'DEBUG'

spring:
  application:
    name: config-service
  cloud:
    config:
      server:
        native:
          search-locations: classpath:/config
        #git:
        #  uri: https://github.com/walterfan/helloworld
  profiles:
    active: native


Config service 可为其他 Micro Service 提供配置信息, 配置文件命名格式如下:

/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties

我们为 taskservice 建立两个配置文件

  1. taskservice-dev.yml
database:
    name: SQLite
    driver: org.sqlite.JDBC
    url: jdbc:sqlite:/home/walter/data/wfdb.s3db
    username: walter
    password: pass1234

  1. taskservice-prod.yml
database:
    name: MySQL
    driver: com.mysql.jdbc.Driver
    url: jdbc:mysql://waltersite/wfdb?useUnicode=true&characterEncoding=utf8
    username: walter
    password: pass1234

参考文档

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值