微服务实战之配置管理

概述

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

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

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

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 形式

列名 类型
id uuid
name varchar(256)
value varchar(256)
create_time timestamp
update_time timestamp

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

环境管理

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

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

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

  • Ansible
  • Chef
  • Fabric
  • Puppet
  • SaltStack

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

配置服务

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

例如下图

Configure Service

它的好处在于

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

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

项目 组织/社区 语言 特点
Consul hashicorp go 提供健值存取, 服务发现和服务配置管理功能, 提供好用的命令行和网页界面
ZooKeeper apache java 老牌产品, 经久耐用, 提供集中式的服务接口, 可用于分布式系统中配置信息, 服务注册信息的同步, 使用 ZAB 协议
Etcd coreos go 提供服务发现和分布式键值存取功能, 使用 Raft 协议, 速度快, 安装配置容易简单
Eureka netflix java 提供服务发现和分布式键值存取功能, 并提供服务器端动态刷新, 网飞出口, 必属精品, 连 AWS 也在用它
Spring Cloud Config spring java Spring 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

参考文档

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,539评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,594评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,871评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,963评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,984评论 6 393
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,763评论 1 307
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,468评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,357评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,850评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,002评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,144评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,823评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,483评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,026评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,150评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,415评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,092评论 2 355

推荐阅读更多精彩内容