从组件的角度梳理微服务技术栈(1)

一、服务注册与发现:Nacos

组件定位:微服务架构里的“服务通讯录+配置大管家”,是整个服务体系的基础。

核心价值:主要解决两个头疼问题——一是服务间“找谁通话”的问题:服务提供方启动后会自动把自己的地址信息登记到Nacos上,消费方不用死记硬背对方地址,随时能查到可用的服务实例;二是配置“散养难管”的问题:把多个服务共用的配置集中放在这里管,还能按开发、测试、生产等环境分开存,改配置不用挨个服务改。而且它能把这些数据存起来不会丢,从根上解决了服务地址写死、配置到处藏的麻烦。

1.1 Nacos部署详解

MySQL表准备

Nacos支持将配置数据持久化到MySQL,需要先创建相关表结构:

-- 创建nacos数据库
CREATE DATABASE nacos CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;

-- 使用nacos官方提供的SQL脚本创建表
-- 脚本位置:nacos/conf/nacos-mysql.sql

配置文件详解

custom.env文件配置示例:

# 单机模式运行
MODE=standalone
# 使用MySQL作为数据源
SPRING_DATASOURCE_PLATFORM=mysql
# MySQL连接配置
MYSQL_SERVICE_HOST=192.168.150.101
MYSQL_SERVICE_PORT=3306
MYSQL_SERVICE_DB_NAME=nacos
MYSQL_SERVICE_USER=root
MYSQL_SERVICE_PASSWORD=123456
# 连接池配置
MYSQL_SERVICE_DB_PARAM=characterEncoding=utf8&connectTimeout=1000&socketTimeout=3000&autoReconnect=true&useSSL=false

1.2 服务注册与发现机制

服务提供方 vs 消费方配置差异

虽然双方都配置了Nacos地址,但实际作用不同:

服务提供方

spring:
  application:
    name: item-service
  cloud:
    nacos:
      server-addr: 192.168.150.101:8848
      discovery:
        # 服务注册配置
        namespace: public
        group: DEFAULT_GROUP
        # 心跳间隔,默认5秒
        heart-beat-interval: 5000
        # 健康检查超时时间,默认15秒
        heart-beat-timeout: 15000

服务消费方

spring:
  cloud:
    nacos:
      server-addr: 192.168.150.101:8848
      discovery:
        # 服务发现配置
        server-addr: 192.168.150.101:8848
        # 命名空间隔离
        namespace: public
        # 服务分组
        group: DEFAULT_GROUP

核心区别

  • 提供方:注册自身实例信息到Nacos
  • 消费方:从Nacos订阅服务列表,获取可用实例

二、服务调用:OpenFeign

组件定位:微服务之间的“智能通信秘书”,专门简化服务间的HTTP调用流程。

核心价值:不用手写复杂的HTTP请求代码,只要给接口加几个注解,就能像调本地方法一样调用其他服务。它还自带负载均衡能力(搭配Spring Cloud LoadBalancer),能自动把请求分到不同的服务实例上,避免某一个实例忙不过来。如果配上OKHttp这类工具做连接池优化,还能减少重复建立TCP连接的开销,既让代码好懂好维护,又能提高调用效率。

2.1 负载均衡策略详解

OpenFeign整合了Ribbon(现为Spring Cloud LoadBalancer)提供负载均衡能力:

三种常用负载均衡策略

1. 轮询策略(RoundRobin)

# 默认策略,按顺序轮流访问服务实例
spring:
  cloud:
    loadbalancer:
      configurations: round-robin

2. 随机策略(Random)

spring:
  cloud:
    loadbalancer:
      configurations: random

3. 权重策略(Weighted)

# 根据实例权重分配流量
spring:
  cloud:
    loadbalancer:
      configurations: weighted

自定义负载均衡配置

@Configuration
public class LoadBalancerConfig {
    
    @Bean
    public ReactorLoadBalancer<ServiceInstance> randomLoadBalancer(
            Environment environment, LoadBalancerClientFactory factory) {
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new RandomLoadBalancer(factory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
    }
}

2.2 连接池化思想

为什么需要连接池?

  • 减少TCP握手开销:TCP三次握手耗时约1.5RTT
  • 资源复用:避免频繁创建销毁连接
  • 连接管理:统一管理连接生命周期

OKHttp连接池配置

feign:
  okhttp:
    enabled: true
    # 连接池配置
    max-connections: 200
    max-connections-per-route: 50
    # 连接超时
    connect-timeout: 3000
    # 读取超时
    read-timeout: 10000
    # 写入超时
    write-timeout: 10000

连接池参数调优

@Configuration
public class OkHttpConfig {
    
    @Bean
    public okhttp3.OkHttpClient okHttpClient() {
        return new okhttp3.OkHttpClient.Builder()
                .connectionPool(new ConnectionPool(200, 5, TimeUnit.MINUTES))
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(30, TimeUnit.SECONDS)
                .retryOnConnectionFailure(true)
                .build();
    }
}

三、API网关:Gateway

组件定位:微服务集群的“大门卫+流量调度中心”,所有外部请求都得从它这里进系统。

核心价值:主要干三件事:一是“指路”,把请求精准转发到对应的微服务,比如把下单请求转给订单服务,支付请求转给支付服务;二是“安检”,帮着做登录鉴权、记录请求日志、处理跨域问题,不让非法请求进来;三是“限流”,遇到突发大流量时能控制请求速度,还能修改请求路径、加请求头信息。对前端来说不用记一堆服务地址,对后端来说能把服务藏在网关后面,安全性更有保障。

3.1 网关核心功能详解

路由配置增强

spring:
  cloud:
    gateway:
      routes:
        - id: user-service
          uri: lb://user-service
          predicates:
            - Path=/user/**
            - Method=GET,POST
            - Header=X-Request-Id, \d+
            - Query=version, v1
          filters:
            - StripPrefix=1  # 去除路径前缀
            - AddRequestHeader=X-Gateway-Request, true
            - AddResponseHeader=X-Gateway-Response, true
            - PrefixPath=/api  # 添加路径前缀

全局过滤器链详解

@Component
public class GlobalFilterChain implements GlobalFilter, Ordered {
    
    private final List<GlobalFilter> filters;
    
    public GlobalFilterChain(List<GlobalFilter> filters) {
        this.filters = filters.stream()
                .sorted(Comparator.comparingInt(Ordered::getOrder))
                .collect(Collectors.toList());
    }
    
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        return Flux.fromIterable(filters)
                .reduce(chain, (currentChain, filter) -> 
                    new GatewayFilterChain() {
                        @Override
                        public Mono<Void> filter(ServerWebExchange exchange) {
                            return filter.filter(exchange, currentChain);
                        }
                    })
                .filter(exchange);
    }
}

3.2 用户信息传递机制

ThreadLocal使用详解

public class UserContext {
    private static final ThreadLocal<Long> USER_CONTEXT = new ThreadLocal<>();
    
    public static void setUserId(Long userId) {
        USER_CONTEXT.set(userId);
    }
    
    public static Long getUserId() {
        return USER_CONTEXT.get();
    }
    
    public static void clear() {
        USER_CONTEXT.remove();
    }
}

拦截器配置

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new UserInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/login", "/register");
    }
}

public class UserInterceptor implements HandlerInterceptor {
    
    @Override
    public boolean preHandle(HttpServletRequest request, 
                           HttpServletResponse response, 
                           Object handler) {
        String userId = request.getHeader("user-id");
        if (userId != null && !userId.trim().isEmpty()) {
            try {
                UserContext.setUserId(Long.valueOf(userId));
            } catch (NumberFormatException e) {
                // 记录日志,但不中断请求
                log.warn("Invalid user-id header: {}", userId);
            }
        }
        return true;
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request,
                              HttpServletResponse response,
                              Object handler, Exception ex) {
        // 必须清理,防止内存泄漏
        UserContext.clear();
    }
}

四、配置中心:Nacos进阶使用

组件定位:基于Nacos升级的“配置动态管理平台”,专治配置重复、改配置要重启服务的毛病。

核心价值:把多个服务都要用的配置(比如数据库连接信息)抽出来统一管理,不用每个服务都写一遍。支持按环境隔离配置,开发环境改配置不会影响生产环境;最关键的是配置改完能实时生效,不用重启服务,比如改个限流阈值、开关参数,立马就能用。还能监听配置变化,业务需要动态调参时特别方便。

4.1 配置共享原理

配置加载优先级

Spring Cloud配置加载顺序:

  1. bootstrap.yml(最高优先级)
  2. Nacos共享配置(shared-configs
  3. Nacos扩展配置(extension-configs
  4. 应用专属配置(spring.application.name
  5. application.yml(最低优先级)

多环境配置管理

# bootstrap.yaml
spring:
  application:
    name: order-service
  profiles:
    active: dev  # 环境标识
  cloud:
    nacos:
      config:
        file-extension: yaml
        shared-configs:
          - dataId: shared-jdbc-${spring.profiles.active}.yaml
          - dataId: shared-log-${spring.profiles.active}.yaml
        extension-configs:
          - dataId: ${spring.application.name}-${spring.profiles.active}.yaml
            group: DEFAULT_GROUP
            refresh: true

4.2 配置热更新原理

@ConfigurationProperties工作原理

@ConfigurationProperties(prefix = "business")
@Data
@Component
@RefreshScope  // 关键注解,启用配置刷新
public class BusinessProperties {
    
    /**
     * 最大数量限制
     * 配置示例:business.max-count=100
     */
    private Integer maxCount = 10;  // 默认值
    
    /**
     * 超时时间(毫秒)
     */
    private Integer timeout = 3000;
    
    /**
     * 是否启用功能
     */
    private Boolean enabled = true;
}

配置变更监听机制

@Component
public class ConfigChangeListener {
    
    @Autowired
    private BusinessProperties businessProperties;
    
    @EventListener
    public void handleRefreshEvent(EnvironmentChangeEvent event) {
        // 配置变更时的处理逻辑
        log.info("配置发生变化: {}", event.getKeys());
        
        // 重新加载相关配置
        reloadBusinessConfig();
    }
    
    private void reloadBusinessConfig() {
        log.info("当前配置 - maxCount: {}, timeout: {}", 
                businessProperties.getMaxCount(), 
                businessProperties.getTimeout());
    }
}

五、服务保护:Sentinel

组件定位:微服务的“安全卫士”,专门守护服务不被流量冲垮,保障系统高可用。

核心价值:有三大核心技能:一是限流,比如限制某个接口每秒最多处理100个请求,避免请求太多把服务压崩;二是熔断降级,要是某个依赖的服务挂了,不会一直等着它响应,而是快速返回失败,防止故障像多米诺骨牌一样扩散;三是线程隔离,给每个依赖服务分配独立的线程池,就算A服务故障,也不会占用B服务的资源。支持多种限流和熔断策略,能精准保护每个服务节点。

5.1 Sentinel核心概念详解

请求限流(Flow Control)

限流算法对比

算法 特点 适用场景
漏桶算法 恒定速率处理,平滑流量 保护系统不被突发流量冲垮
令牌桶算法 允许突发流量,有弹性 保证系统处理能力的同时允许突发
计数器算法 简单粗暴,固定窗口 简单限流场景

配置示例

// 资源定义
@SentinelResource(value = "getUserInfo", 
                  blockHandler = "handleBlock",
                  fallback = "handleFallback")
public UserInfo getUserInfo(Long userId) {
    // 业务逻辑
}

// 限流处理
public UserInfo handleBlock(Long userId, BlockException ex) {
    log.warn("触发限流保护,userId: {}", userId);
    return UserInfo.defaultUser();
}

// 降级处理
public UserInfo handleFallback(Long userId, Throwable ex) {
    log.error("服务降级,userId: {}", userId, ex);
    return UserInfo.defaultUser();
}

线程隔离(Thread Isolation)

线程池隔离 vs 信号量隔离

# 线程池隔离配置
spring:
  cloud:
    sentinel:
      filter:
        enabled: false
      thread-pool:
        # 核心线程数
        core-size: 20
        # 最大线程数  
        max-size: 50
        # 队列容量
        queue-capacity: 100
        # 线程存活时间
        keep-alive-time: 60s

信号量隔离配置

// 使用@SentinelResource配置信号量隔离
@SentinelResource(value = "queryOrder",
                  fallback = "queryOrderFallback",
                  blockHandler = "queryOrderBlockHandler",
                  // 信号量隔离
                  execution: 
                    isolation:
                      strategy: SEMAPHORE
                      semaphore:
                        maxConcurrentRequests: 100)
public OrderInfo queryOrder(Long orderId) {
    // 业务逻辑
}

服务熔断和降级策略

熔断器三种状态

  • 关闭状态:正常处理请求
  • 打开状态:所有请求被熔断,直接降级
  • 半开状态:尝试放行部分请求,测试服务是否恢复

熔断策略配置

// 基于响应时间的熔断
DegradeRule rule = new DegradeRule("resourceName")
    .setGrade(RuleConstant.DEGRADE_GRADE_RT)  // 响应时间模式
    .setCount(100)  // 响应时间阈值(ms)
    .setTimeWindow(10)  // 熔断时间窗口(s)
    .setRtSlowRequestAmount(5)  // 最小请求数
    .setMinRequestAmount(5);  // 触发熔断的最小请求数

// 基于异常比例的熔断
DegradeRule rule2 = new DegradeRule("resourceName")
    .setGrade(RuleConstant.DEGRADE_GRADE_EXCEPTION_RATIO)
    .setCount(0.5)  // 异常比例阈值(0.5=50%)
    .setTimeWindow(10)
    .setMinRequestAmount(10);

六、分布式事务:Seata

组件定位:微服务跨服务操作的“数据一致性管家”,解决多个服务操作时“要么都成,要么都败”的问题。

核心价值:比如下单时,要同时扣减库存(库存服务)和扣减余额(用户服务),这两个操作必须同时成功或同时失败,不然就会出现“订单建好了但库存没扣”“钱扣了但订单没生成”的烂账。Seata支持两种模式:AT模式不用改太多代码,自动帮你管事务;TCC模式更灵活,适合复杂业务场景。它通过全局事务协调器,统一指挥各个服务的本地事务提交或回滚,保证跨服务操作的数据一致。

6.1 Seata分布式事务模式

AT模式(自动模式)原理

工作流程

  1. 一阶段

    • 解析SQL,生成前后镜像
    • 执行业务SQL
    • 提交前镜像到undo_log
    • 本地事务提交
  2. 二阶段提交

    • 删除undo_log记录
    • 异步清理
  3. 二阶段回滚

    • 根据undo_log生成反向SQL
    • 执行回滚操作
    • 删除undo_log记录

配置示例

@Service
public class OrderService {
    
    @GlobalTransactional  // 开启全局事务
    public void createOrder(OrderDTO orderDTO) {
        // 1. 扣减库存
        stockFeignClient.reduceStock(orderDTO.getSkuId(), orderDTO.getCount());
        
        // 2. 创建订单
        orderMapper.insert(orderDTO);
        
        // 3. 扣减余额
        accountFeignClient.reduceBalance(orderDTO.getUserId(), orderDTO.getAmount());
    }
}

TCC模式(手动模式)

Try-Confirm-Cancel三个阶段

public interface TccOrderService {
    
    @TwoPhaseBusinessAction(name = "createOrder", commitMethod = "confirm", rollbackMethod = "cancel")
    boolean tryCreateOrder(BusinessActionContext actionContext,
                          @BusinessActionContextParameter(paramName = "orderId") Long orderId,
                          @BusinessActionContextParameter(paramName = "amount") BigDecimal amount);
    
    boolean confirm(BusinessActionContext actionContext);
    
    boolean cancel(BusinessActionContext actionContext);
}

6.2 Seata表结构说明

全局事务表(global_table)

CREATE TABLE `global_table` (
  `xid` varchar(128) NOT NULL,
  `transaction_id` bigint(20) DEFAULT NULL,
  `status` tinyint(4) NOT NULL,
  `application_id` varchar(32) DEFAULT NULL,
  `transaction_service_group` varchar(32) DEFAULT NULL,
  `transaction_name` varchar(128) DEFAULT NULL,
  `timeout` int(11) DEFAULT NULL,
  `begin_time` bigint(20) DEFAULT NULL,
  `application_data` varchar(2000) DEFAULT NULL,
  `gmt_create` datetime DEFAULT NULL,
  `gmt_modified` datetime DEFAULT NULL,
  PRIMARY KEY (`xid`),
  KEY `idx_status_gmt_modified` (`status`,`gmt_modified`),
  KEY `idx_transaction_id` (`transaction_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

分支事务表(branch_table)

CREATE TABLE `branch_table` (
  `xid` varchar(128) NOT NULL,
  `branch_id` bigint(20) NOT NULL,
  `transaction_id` bigint(20) DEFAULT NULL,
  `resource_group_id` varchar(32) DEFAULT NULL,
  `resource_id` varchar(256) DEFAULT NULL,
  `branch_type` varchar(8) DEFAULT NULL,
  `status` tinyint(4) DEFAULT NULL,
  `client_id` varchar(64) DEFAULT NULL,
  `application_data` varchar(2000) DEFAULT NULL,
  `gmt_create` datetime DEFAULT NULL,
  `gmt_modified` datetime DEFAULT NULL,
  PRIMARY KEY (`branch_id`),
  KEY `idx_xid` (`xid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

undo_log表(每个业务数据库)

CREATE TABLE `undo_log` (
  `id` bigint(20) NOT NULL AUTO_INCREMENT,
  `branch_id` bigint(20) NOT NULL,
  `xid` varchar(100) NOT NULL,
  `context` varchar(128) NOT NULL,
  `rollback_info` longblob NOT NULL,
  `log_status` int(11) NOT NULL,
  `log_created` datetime NOT NULL,
  `log_modified` datetime NOT NULL,
  `ext` varchar(100) DEFAULT NULL,
  PRIMARY KEY (`id`),
  UNIQUE KEY `ux_undo_log` (`xid`,`branch_id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

七、微服务技术栈整合实践

7.1 完整的微服务架构

前端/客户端
    ↓
Gateway网关(统一入口、鉴权、限流)
    ↓
微服务集群
    ├── 用户服务(Nacos注册 + Config配置)
    ├── 商品服务(Feign调用 + Sentinel保护)  
    ├── 订单服务(Seata分布式事务)
    └── 库存服务(负载均衡 + 熔断降级)
    ↓
数据层
    ├── MySQL(主从复制)
    ├── Redis(缓存)
    └── Elasticsearch(搜索)

7.2 最佳实践总结

  1. 服务治理:Nacos实现服务注册发现和配置管理
  2. 服务通信:OpenFeign + LoadBalancer实现声明式调用
  3. 流量控制:Gateway统一入口 + Sentinel多层次保护
  4. 数据一致性:Seata AT/TCC模式保障分布式事务
  5. 可观测性:整合链路追踪、监控告警体系

通过以上组件的有机结合,可以构建出高可用、可扩展、易维护的微服务架构体系。

posted @ 2025-11-22 17:36  谁来着?  阅读(47)  评论(0)    收藏  举报