Featured image of post 微服务配置中心小实验

微服务配置中心小实验

微服务配置中心实战:Spring Cloud Config + Go 客户端实现配置集中管理

本文是个人在学习书籍《Go 语言高并发与微服务实战》第8章内容过程中,动手做的小实验,涉及 Spring Cloud Config 和 YAML 相关知识。

配置中心概念

┌─────────────────────────────────────────────────────────────┐
│                    配置中心架构                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   ┌──────────────┐                                         │
│   │ 配置中心     │                                         │
│   │ Config Server│◀──── Git/SVN/Nacos                     │
│   └──────┬───────┘                                         │
│          │                                                  │
│          │ 拉取/推送                                        │
│          ▼                                                  │
│   ┌─────────────────────────────────────────┐              │
│   │           微服务集群                     │              │
│   │  ┌─────────┐  ┌─────────┐  ┌─────────┐│              │
│   │  │Service A│  │Service B│  │Service C││              │
│   │  └─────────┘  └─────────┘  └─────────┘│              │
│   └─────────────────────────────────────────┘              │
│                                                             │
│   特性:                                                    │
│   • 配置集中管理                                            │
│   • 配置热更新                                              │
│   • 环境隔离(dev/staging/prod)                          │
│   • 版本控制                                                │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Spring Cloud Config 简介

Spring Cloud Config 为分布式系统的外部配置提供了服务端和客户端支持。

核心特性

特性说明
配置集中管理所有配置存储在 Git 仓库
环境隔离dev、test、prod 环境分离
配置加密支持敏感配置加密存储
动态刷新无需重启即可更新配置
高可用支持集群部署

准备 Spring Boot 环境

macOS 安装

# 使用 Homebrew 安装
brew tap spring-io/tap
brew install spring-boot

# 或安装 Spring CLI
brew install springboot

快速开始

创建 app.groovy

@RestController
class ThisWillActuallyRun {
    @RequestMapping("/")
    String home() {
        "Hello World!"
    }
}

运行:

spring run app.groovy

创建配置中心服务端

项目结构

config-server/
├── pom.xml
├── src/main/java/com/example/configserver/
│   └── ConfigServerApplication.java
└── config/
    └── application.yml

Maven 依赖 (pom.xml)

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.5.2</version>
    </parent>
    
    <dependencies>
        <!-- Spring Cloud Config Server -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-config-server</artifactId>
        </dependency>
        
        <!-- Eureka 服务发现(可选)-->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
        </dependency>
    </dependencies>
    
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>2020.0.2</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
</project>

启动类

@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {
    public static void main(String[] args) {
        SpringApplication.run(ConfigServerApplication.class, args);
    }
}

配置文件

# application.yml
server:
  port: 8888

spring:
  application:
    name: config-server
  cloud:
    config:
      server:
        git:
          uri: https://github.com/your-org/config-repo
          search-paths: config/{application}
          username: your-github-username
          default-label: main

配置仓库结构

config-repo/
├── config/
│   ├── user-service/
│   │   ├── application.yml      # 默认配置
│   │   ├── application-dev.yml  # 开发环境
│   │   ├── application-test.yml # 测试环境
│   │   └── application-prod.yml # 生产环境
│   └── order-service/
│       └── application.yml
└── README.md

示例配置

# user-service/application.yml
server:
  port: ${PORT:8080}

spring:
  application:
    name: user-service
  datasource:
    url: jdbc:mysql://localhost:3306/user_db
    username: root
    password: ${DB_PASSWORD}
  redis:
    host: ${REDIS_HOST:localhost}
    port: ${REDIS_PORT:6379}

# 用户服务配置
user:
  cache:
    ttl: 3600
    max-size: 1000
  rate-limit:
    qps: 100
# user-service/application-dev.yml
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/user_db_dev
    password: dev_password
  redis:
    host: localhost

user:
  rate-limit:
    qps: 10  # 开发环境限流放宽

Go 客户端接入

安装依赖

go get github.com/spf13/viper
go get github.com/go-laoji/go-config

Viper 配置

// config/config.go
package config

import (
    "fmt"
    "github.com/spf13/viper"
)

type Config struct {
    App      AppConfig      `mapstructure:"app"`
    Database DatabaseConfig `mapstructure:"database"`
    Redis    RedisConfig    `mapstructure:"redis"`
    User     UserConfig     `mapstructure:"user"`
}

type AppConfig struct {
    Name string `mapstructure:"name"`
    Port int    `mapstructure:"port"`
}

type DatabaseConfig struct {
    Host     string `mapstructure:"host"`
    Port     int    `mapstructure:"port"`
    Username string `mapstructure:"username"`
    Password string `mapstructure:"password"`
    Name     string `mapstructure:"name"`
}

type RedisConfig struct {
    Host     string `mapstructure:"host"`
    Port     int    `mapstructure:"port"`
    Password string `mapstructure:"password"`
    DB       int    `mapstructure:"db"`
}

type UserConfig struct {
    Cache     CacheConfig     `mapstructure:"cache"`
    RateLimit RateLimitConfig `mapstructure:"rate-limit"`
}

type CacheConfig struct {
    TTL      int `mapstructure:"ttl"`
    MaxSize  int `mapstructure:"max-size"`
}

type RateLimitConfig struct {
    QPS int `mapstructure:"qps"`
}

var GlobalConfig *Config

func LoadConfig(configServer, appName, profile string) (*Config, error) {
    v := viper.New()
    
    // 设置配置中心地址
    configURL := fmt.Sprintf("http://%s/%s/%s", configServer, appName, profile)
    v.SetConfigType("yaml")
    
    // 从配置中心获取配置
    if err := v.SafeGetConfigFile(configURL); err != nil {
        // 尝试直接读取
        v.SetConfigFile(fmt.Sprintf("config/%s.yml", profile))
        if err := v.ReadInConfig(); err != nil {
            return nil, err
        }
    }
    
    var cfg Config
    if err := v.Unmarshal(&cfg); err != nil {
        return nil, err
    }
    
    GlobalConfig = &cfg
    return &cfg, nil
}

// 本地配置(备用)
func LoadLocalConfig() (*Config, error) {
    v := viper.New()
    
    v.SetConfigName("config")
    v.SetConfigType("yaml")
    v.AddConfigPath("./config")
    
    if err := v.ReadInConfig(); err != nil {
        return nil, err
    }
    
    var cfg Config
    if err := v.Unmarshal(&cfg); err != nil {
        return nil, err
    }
    
    GlobalConfig = &cfg
    return &cfg, nil
}

若配置中心不可用,LoadLocalConfig() 可作为本地开发与灾备兜底;关键是保证 profile密钥环境变量注入 在流水线与运行时一致。

© 2016-2026 Yison. All rights reserved.
使用 Hugo 构建
主题 StackJimmy 设计