高可用架构实战指南:告别半夜被叫醒的噩梦

🔥 高可用架构实战指南:告别半夜被叫醒的噩梦!

从"宕机恐惧症"到"睡得安稳" 💪


🎯 开篇:你是否也有这样的经历?

想象一下这个场景:

🌙 深夜2点,你正在温暖的被窝里做着美梦...

📱 突然! 手机疯狂震动,运维小哥哭着打电话:

"老王!!!服务器又挂了!用户群里都炸锅了!!!"

😱 这种感觉,就像你正在享受火锅时突然被告知厨房着火了一样"酸爽"...

但是! 如果你的系统有了高可用架构,就像给服务器买了"全险",即使某台机器罢工,整个系统依然稳如老狗!

今天,老王就来分享如何打造一个让你安心睡觉的高可用架构!


💡 一、什么是高可用架构?

🎯 核心定义

高可用架构(High Availability) = 让系统在最大限度内保持持续可用的架构设计

用大白话讲:让你的系统像"打不死的小强"一样顽强! 🪳

🚗 生活化理解

高可用架构就像城市的交通系统:

  • 单点故障:只有一条路,堵车了全城瘫痪

  • 高可用设计:多条道路、立交桥、地铁、公交,一条路堵了还有其他选择

📊 可用性指标:几个9的奥秘

| 🎯 可用性 | ⏰ 年停机时间 | 📅 月停机时间 | 📆 周停机时间 | 🕐 日停机时间 |

|-----------|---------------|---------------|---------------|---------------|

| 90% | 36.5天 | 72小时 | 16.8小时 | 2.4小时 |

| 99% | 3.65天 | 7.2小时 | 1.68小时 | 14.4分钟 |

| 99.9% | 8.76小时 | 43.2分钟 | 10.1分钟 | 1.44分钟 |

| 99.99% | 52.56分钟 | 4.32分钟 | 1.01分钟 | 8.64秒 |

| 99.999% | 5.26分钟 | 25.9秒 | 6.05秒 | 0.864秒 |

💰 记住:从99%到99.9%容易,但从99.9%到99.99%,难度和成本会指数级增长!


🛠️ 二、FEMA评估法:高可用设计的四步走

🔍 什么是FEMA?

FEMA不是美国联邦应急管理局,在我们这里是高可用设计的四个关键步骤

🚨 F - Failure(故障识别)

问自己:什么地方可能出问题?

常见故障类型:

  • 💻 硬件故障:服务器宕机、磁盘损坏、网络中断

  • 🐛 软件故障:程序Bug、内存泄漏、死锁

  • 👨‍💻 人为故障:误操作、配置错误、发布事故

  • 🌐 外部故障:机房断电、网络攻击、第三方服务异常

java 复制代码
// 💡 故障场景示例:数据库连接池耗尽

@Service

publicclassDatabaseService {

    @Autowired

privateDataSourcedataSource;

// ❌ 危险:没有超时和重试机制

publicUserfindUser(Longid) {

try (Connectionconn=dataSource.getConnection()) {

// 如果数据库响应慢,连接池很快就会耗尽

PreparedStatementstmt=conn.prepareStatement(

"SELECT * FROM users WHERE id = ?"

            );

stmt.setLong(1, id);

ResultSetrs=stmt.executeQuery();

if (rs.next()) {

returnmapToUser(rs);

            }

        } catch (SQLExceptione) {

// 💥 直接抛异常,没有降级处理

thrownewRuntimeException("数据库查询失败", e);

        }

returnnull;

    }

}
📈 E - Effect(影响评估)

问自己:故障会造成什么影响?

影响评估维度:

  • 🎯 业务影响:核心功能 vs 边缘功能

  • 👥 用户影响:影响用户数量和类型

  • 💰 经济损失:每分钟损失多少钱

  • 🏢 品牌影响:对公司声誉的损害

java 复制代码
// 💡 影响评估工具类

@Component

publicclassFailureImpactCalculator {

publicenumBusinessCriticality {

        CRITICAL("核心业务", 1.0),    // 登录、支付、下单

        IMPORTANT("重要业务", 0.7),   // 搜索、推荐

        NORMAL("一般业务", 0.3),      // 评论、分享

        LOW("边缘业务", 0.1);         // 统计、日志

privatefinalStringdescription;

privatefinaldoubleweight;

BusinessCriticality(Stringdescription, doubleweight) {

this.description= description;

this.weight= weight;

        }

    }

// 计算故障影响分数

publicdoublecalculateImpactScore(

BusinessCriticalitycriticality,

intaffectedUsers,

doublerevenuePerMinute) {

returncriticality.weight* affectedUsers * revenuePerMinute;

    }

}
🛡️ M - Mitigation(缓解措施)

问自己:如何减少故障影响?

常用缓解策略:

  • 🔄 冗余设计:多实例、多机房

  • 快速恢复:自动重启、故障转移

  • 📉 降级处理:关闭非核心功能

  • 🚦 限流保护:防止雪崩效应

java 复制代码
// 💡 自动降级示例

@Service

publicclassRecommendationService {

    @Autowired

privateRedisTemplate<String, Object> redisTemplate;

    @Autowired

privateRecommendationAlgorithmalgorithm;

// ✅ 带降级的推荐服务

    @CircuitBreaker(name ="recommendation", fallbackMethod ="getFallbackRecommendations")

    @TimeLimiter(name ="recommendation")

publicCompletableFuture<List<Product>> getRecommendations(LonguserId) {

returnCompletableFuture.supplyAsync(() -> {

try {

// 先尝试从缓存获取

List<Product> cached=getCachedRecommendations(userId);

if (cached !=null) {

return cached;

                }

// 调用推荐算法

List<Product> recommendations=algorithm.recommend(userId);

// 缓存结果

cacheRecommendations(userId, recommendations);

return recommendations;

            } catch (Exceptione) {

log.warn("推荐服务异常,使用降级方案", e);

throw e; // 触发熔断器

            }

        });

    }

// 🔄 降级方案:返回热门商品

publicCompletableFuture<List<Product>> getFallbackRecommendations(LonguserId, Exceptionex) {

log.info("推荐服务降级,返回热门商品,用户ID: {}", userId);

returnCompletableFuture.supplyAsync(() -> {

// 返回预设的热门商品列表

returngetHotProducts();

        });

    }

}
🎯 A - Availability(可用性目标)

问自己:需要达到什么可用性水平?

设定合理的可用性目标:

  • 💳 支付系统:99.99%(年停机52分钟)

  • 🛒 电商核心:99.9%(年停机8.76小时)

  • 📱 社交功能:99%(年停机3.65天)

java 复制代码
// 💡 可用性监控服务

@Service

publicclassAvailabilityMonitor {

privatefinalMeterRegistrymeterRegistry;

publicAvailabilityMonitor(MeterRegistrymeterRegistry) {

this.meterRegistry= meterRegistry;

    }

// 记录服务可用性

publicvoidrecordServiceAvailability(StringserviceName, booleanisAvailable) {

meterRegistry.gauge("service.availability", 

Tags.of("service", serviceName), 

            isAvailable ?1.0:0.0);

    }

// 计算可用性百分比

    @Scheduled(fixedRate =60000) // 每分钟计算一次

publicvoidcalculateAvailability() {

// 获取过去24小时的数据

doubleavailability=calculateLast24HoursAvailability();

meterRegistry.gauge("system.availability.24h", availability);

// 如果可用性低于目标,发送告警

if (availability <0.999) { // 低于99.9%

sendAvailabilityAlert(availability);

        }

    }

}

🗄️ 三、存储高可用:数据的"保险箱"

🔄 3.1 主备模式(Master-Slave)

原理:一主一备,主库挂了备库顶上

就像公司的正副总经理,正总经理出差时副总经理代理工作!

java 复制代码
// 💡 主备切换配置

@Configuration

publicclassMasterSlaveConfig {

    @Bean

    @Primary

publicDataSourcemasterDataSource() {

HikariConfigconfig=newHikariConfig();

config.setJdbcUrl("jdbc:mysql://master-db:3306/mydb");

config.setUsername("root");

config.setPassword("password");

config.setMaximumPoolSize(20);

// 🔧 连接测试配置

config.setConnectionTestQuery("SELECT 1");

config.setTestWhileIdle(true);

config.setValidationTimeout(3000);

returnnewHikariDataSource(config);

    }

    @Bean

publicDataSourceslaveDataSource() {

HikariConfigconfig=newHikariConfig();

config.setJdbcUrl("jdbc:mysql://slave-db:3306/mydb");

config.setUsername("root");

config.setPassword("password");

config.setMaximumPoolSize(30); // 读库可以配置更多连接

config.setReadOnly(true);

returnnewHikariDataSource(config);

    }

}

🔗 3.2 主从复制(Master-Slave Replication)

原理:主库负责写,从库负责读,数据实时同步

就像老师讲课(主库写),学生做笔记(从库读)!

java 复制代码
// 💡 读写分离实现

@Repository

publicclassUserRepository {

    @Autowired

    @Qualifier("masterDataSource")

privateDataSourcemasterDataSource;

    @Autowired

    @Qualifier("slaveDataSource")

privateDataSourceslaveDataSource;

// ✍️ 写操作:走主库

    @Transactional

publicvoidsaveUser(Useruser) {

JdbcTemplatemasterTemplate=newJdbcTemplate(masterDataSource);

Stringsql="INSERT INTO users (name, email, created_at) VALUES (?, ?, ?)";

masterTemplate.update(sql, user.getName(), user.getEmail(), newDate());

log.info("用户保存成功,ID: {}", user.getId());

    }

// 📖 读操作:走从库

    @Transactional(readOnly =true)

publicList<User> findActiveUsers() {

JdbcTemplateslaveTemplate=newJdbcTemplate(slaveDataSource);

Stringsql="SELECT * FROM users WHERE status = 'ACTIVE' ORDER BY created_at DESC";

returnslaveTemplate.query(sql, newBeanPropertyRowMapper<>(User.class));

    }

// 🔍 强一致性读取:必须走主库

    @Transactional(readOnly =true)

publicUserfindUserById(Longid) {

JdbcTemplatemasterTemplate=newJdbcTemplate(masterDataSource);

Stringsql="SELECT * FROM users WHERE id = ?";

returnmasterTemplate.queryForObject(sql, newBeanPropertyRowMapper<>(User.class), id);

    }

}

🏘️ 3.3 集群模式(Cluster)

原理:多个节点组成集群,共同提供服务

就像一个小区有多个单元楼,坏了一栋还有其他的!

🎯 集中式 vs 分散式数据集群

🏢 集中式集群:像大型购物中心

  • ✅ 管理简单,数据一致性强

  • ❌ 成本高,扩展性有限

  • 🎯 适合:金融、支付等强一致性场景

🏪 分散式集群:像便利店连锁

  • ✅ 扩展性强,成本相对较低

  • ❌ 管理复杂,最终一致性

  • 🎯 适合:电商、社交等大规模场景

java 复制代码
// 💡 MongoDB分片集群配置

@Configuration

publicclassMongoShardingConfig {

    @Bean

publicMongoClientmongoClient() {

// 分片集群连接

StringconnectionString="mongodb://mongos1:27017,mongos2:27017/mydb";

MongoClientSettingssettings=MongoClientSettings.builder()

            .applyConnectionString(newConnectionString(connectionString))

            .readPreference(ReadPreference.secondaryPreferred()) // 优先读从库

            .writeConcern(WriteConcern.MAJORITY) // 大多数节点确认写入

            .readConcern(ReadConcern.MAJORITY)   // 大多数节点确认读取

            .build();

returnMongoClients.create(settings);

    }

}

// 💡 分片数据访问

@Service

publicclassOrderService {

    @Autowired

privateMongoTemplatemongoTemplate;

// 🔍 基于分片键查询(高效)

publicList<Order> findOrdersByUserId(StringuserId) {

Queryquery=newQuery(Criteria.where("userId").is(userId));

returnmongoTemplate.find(query, Order.class);

    }

// 📊 跨分片查询(相对较慢)

publicList<Order> findOrdersByStatus(Stringstatus) {

Queryquery=newQuery(Criteria.where("status").is(status));

returnmongoTemplate.find(query, Order.class);

    }

}

⚡ 四、计算高可用:让服务"永不宕机"

🔄 4.1 主备模式(Active-Passive)

原理:主服务器处理请求,备服务器待命

就像值班医生,主治医生忙不过来时,备班医生立即顶上!

java 复制代码
// 💡 健康检查服务

@RestController

publicclassHealthCheckController {

    @Autowired

privateDatabaseHealthIndicatordatabaseHealth;

    @Autowired

privateRedisHealthIndicatorredisHealth;

// 🏥 健康检查接口

    @GetMapping("/health")

publicResponseEntity<Map<String, Object>> healthCheck() {

Map<String, Object> health=newHashMap<>();

booleanisHealthy=true;

// 检查数据库

booleandbHealthy=databaseHealth.isHealthy();

health.put("database", dbHealthy ?"UP":"DOWN");

        isHealthy &= dbHealthy;

// 检查Redis

booleanredisHealthy=redisHealth.isHealthy();

health.put("redis", redisHealthy ?"UP":"DOWN");

        isHealthy &= redisHealthy;

// 检查磁盘空间

booleandiskHealthy=checkDiskSpace();

health.put("disk", diskHealthy ?"UP":"DOWN");

        isHealthy &= diskHealthy;

health.put("status", isHealthy ?"UP":"DOWN");

health.put("timestamp", System.currentTimeMillis());

return isHealthy ?

ResponseEntity.ok(health) :

ResponseEntity.status(HttpStatus.SERVICE_UNAVAILABLE).body(health);

    }

privatebooleancheckDiskSpace() {

Fileroot=newFile("/");

longfreeSpace=root.getFreeSpace();

longtotalSpace=root.getTotalSpace();

doublefreePercentage= (double) freeSpace / totalSpace *100;

return freePercentage >10.0; // 剩余空间大于10%

    }

}

⚖️ 4.2 负载均衡(Load Balance)

原理:多个服务器分担请求压力

就像银行的多个窗口,客户可以选择人少的窗口办业务!

java 复制代码
// 💡 自定义负载均衡器

@Component

publicclassCustomLoadBalancer {

privatefinalList<String> serverList=Arrays.asList(

"http://server1:8080",

"http://server2:8080", 

"http://server3:8080"

    );

privatefinalAtomicIntegercounter=newAtomicInteger(0);

privatefinalMap<String, Integer> serverWeights=newHashMap<>();

publicCustomLoadBalancer() {

// 设置服务器权重

serverWeights.put("http://server1:8080", 3); // 高配置服务器

serverWeights.put("http://server2:8080", 2); // 中配置服务器

serverWeights.put("http://server3:8080", 1); // 低配置服务器

    }

// 🔄 轮询算法

publicStringroundRobin() {

intindex=counter.getAndIncrement() %serverList.size();

returnserverList.get(index);

    }

// ⚖️ 加权轮询算法

publicStringweightedRoundRobin() {

inttotalWeight=serverWeights.values().stream().mapToInt(Integer::intValue).sum();

intrandomWeight=newRandom().nextInt(totalWeight);

intcurrentWeight=0;

for (Map.Entry<String, Integer> entry:serverWeights.entrySet()) {

            currentWeight +=entry.getValue();

if (randomWeight < currentWeight) {

returnentry.getKey();

            }

        }

returnserverList.get(0); // 默认返回第一个

    }

// 🎯 最少连接算法

publicStringleastConnections() {

// 实际实现中需要维护每个服务器的连接数

returnserverList.stream()

            .min(Comparator.comparing(this::getConnectionCount))

            .orElse(serverList.get(0));

    }

privateintgetConnectionCount(Stringserver) {

// 这里应该返回实际的连接数

returnnewRandom().nextInt(100);

    }

}

🔗 4.3 集群模式(Cluster)

原理:多个节点协同工作,提供统一服务

就像足球队,每个位置都有人,配合默契!

java 复制代码
// 💡 集群节点管理

@Service

publicclassClusterManager {

privatefinalMap<String, ClusterNode> nodes=newConcurrentHashMap<>();

privatefinalScheduledExecutorServicescheduler=Executors.newScheduledThreadPool(2);

    @PostConstruct

publicvoidinit() {

// 启动节点健康检查

scheduler.scheduleAtFixedRate(this::checkNodesHealth, 0, 30, TimeUnit.SECONDS);

// 启动负载均衡

scheduler.scheduleAtFixedRate(this::balanceLoad, 0, 60, TimeUnit.SECONDS);

    }

// 🏥 节点健康检查

privatevoidcheckNodesHealth() {

nodes.values().parallelStream().forEach(node -> {

try {

booleanisHealthy=pingNode(node);

node.setHealthy(isHealthy);

node.setLastCheckTime(System.currentTimeMillis());

if (!isHealthy) {

log.warn("节点 {} 健康检查失败", node.getAddress());

handleUnhealthyNode(node);

                }

            } catch (Exceptione) {

log.error("检查节点 {} 时发生异常", node.getAddress(), e);

node.setHealthy(false);

            }

        });

    }

// 📡 ping节点

privatebooleanpingNode(ClusterNodenode) {

try {

RestTemplaterestTemplate=newRestTemplate();

restTemplate.getForObject(node.getAddress() +"/health", String.class);

returntrue;

        } catch (Exceptione) {

returnfalse;

        }

    }

// 🚨 处理不健康节点

privatevoidhandleUnhealthyNode(ClusterNodenode) {

// 从负载均衡中移除

removeFromLoadBalancer(node);

// 尝试重启节点

if (node.getFailureCount() <3) {

restartNode(node);

        } else {

// 标记为永久下线,需要人工介入

node.setStatus(NodeStatus.OFFLINE);

sendAlert("节点 "+node.getAddress() +" 多次重启失败,需要人工处理");

        }

    }

}

🌐 五、业务高可用:异地多活的艺术

🏢 5.1 同城双活

原理:在同一城市的不同机房部署相同服务

就像在同一个城市开两家分店,一家出问题另一家继续营业!

java 复制代码
// 💡 同城双活配置

@Configuration

publicclassDualActiveConfig {

    @Value("${datacenter.current}")

privateStringcurrentDataCenter;

    @Bean

publicDataCenterRouterdataCenterRouter() {

returnnewDataCenterRouter(currentDataCenter);

    }

}

@Service

publicclassDataCenterRouter {

privatefinalStringcurrentDC;

privatefinalMap<String, String> dcMapping;

publicDataCenterRouter(StringcurrentDC) {

this.currentDC= currentDC;

this.dcMapping=Map.of(

"DC1", "http://dc1.example.com",

"DC2", "http://dc2.example.com"

        );

    }

// 🔀 智能路由

publicStringrouteRequest(StringuserId) {

// 根据用户ID哈希决定路由到哪个数据中心

inthash=userId.hashCode();

StringtargetDC= (hash %2==0) ?"DC1":"DC2";

// 如果目标数据中心不可用,路由到当前数据中心

if (!isDataCenterHealthy(targetDC)) {

log.warn("数据中心 {} 不可用,路由到当前数据中心 {}", targetDC, currentDC);

returndcMapping.get(currentDC);

        }

returndcMapping.get(targetDC);

    }

privatebooleanisDataCenterHealthy(Stringdc) {

// 实际实现中会检查数据中心的健康状态

returntrue;

    }

}

🌍 5.2 异地多活

原理:在不同城市部署服务,实现地理级别的容灾

就像全国连锁店,北京的店关了,上海的店照常营业!

java 复制代码
// 💡 异地多活架构

@Service

publicclassMultiRegionService {

privatefinalMap<String, RegionConfig> regions;

privatefinalConsistentHash<String> hashRing;

publicMultiRegionService() {

this.regions=Map.of(

"beijing", newRegionConfig("北京", "http://bj.api.com", 1),

"shanghai", newRegionConfig("上海", "http://sh.api.com", 1),

"guangzhou", newRegionConfig("广州", "http://gz.api.com", 1)

        );

// 构建一致性哈希环

this.hashRing=newConsistentHash<>(regions.keySet());

    }

// 🎯 根据用户位置路由

publicStringrouteByLocation(StringuserId, StringuserLocation) {

// 优先路由到用户所在地区

StringpreferredRegion=getPreferredRegion(userLocation);

if (regions.containsKey(preferredRegion) &&

isRegionHealthy(preferredRegion)) {

returnregions.get(preferredRegion).getEndpoint();

        }

// 如果首选地区不可用,使用一致性哈希选择备用地区

StringbackupRegion=hashRing.get(userId);

returnregions.get(backupRegion).getEndpoint();

    }

// 📊 数据同步

    @Async

publicvoidsyncDataAcrossRegions(StringdataType, Objectdata) {

regions.values().parallelStream()

            .filter(region ->isRegionHealthy(region.getName()))

            .forEach(region -> {

try {

syncToRegion(region, dataType, data);

                } catch (Exceptione) {

log.error("同步数据到地区 {} 失败", region.getName(), e);

// 加入重试队列

addToRetryQueue(region.getName(), dataType, data);

                }

            });

    }

}

🛡️ 六、接口级故障方案:最后一道防线

📉 6.1 服务降级(Degradation)

原理:关闭非核心功能,保证核心功能正常

就像手机没电时关闭蓝牙、WiFi,保证通话功能!

java 复制代码
// 💡 智能降级服务

@Service

publicclassDegradationService {

privatefinalMap<String, Boolean> featureFlags=newConcurrentHashMap<>();

privatefinalRedisTemplate<String, Object> redisTemplate;

// 🎛️ 功能开关

publicbooleanisFeatureEnabled(StringfeatureName) {

// 先检查本地缓存

BooleanlocalFlag=featureFlags.get(featureName);

if (localFlag !=null) {

return localFlag;

        }

// 再检查Redis

try {

BooleanredisFlag= (Boolean) redisTemplate.opsForValue()

                .get("feature:"+ featureName);

if (redisFlag !=null) {

featureFlags.put(featureName, redisFlag); // 更新本地缓存

return redisFlag;

            }

        } catch (Exceptione) {

log.warn("获取功能开关失败,使用默认值", e);

        }

// 默认开启

returntrue;

    }

// 🔧 动态调整功能开关

publicvoidsetFeatureFlag(StringfeatureName, booleanenabled) {

try {

// 更新Redis

redisTemplate.opsForValue().set("feature:"+ featureName, enabled);

// 更新本地缓存

featureFlags.put(featureName, enabled);

log.info("功能开关已更新: {} = {}", featureName, enabled);

        } catch (Exceptione) {

log.error("更新功能开关失败", e);

        }

    }

}

// 💡 使用降级的推荐服务

@Service

publicclassRecommendationService {

    @Autowired

privateDegradationServicedegradationService;

publicList<Product> getRecommendations(LonguserId) {

// 🎯 检查推荐功能是否开启

if (!degradationService.isFeatureEnabled("recommendation")) {

log.info("推荐功能已降级,返回热门商品");

returngetHotProducts(); // 降级方案

        }

try {

// 正常推荐逻辑

returncalculateRecommendations(userId);

        } catch (Exceptione) {

log.error("推荐计算失败,自动降级", e);

// 自动降级

degradationService.setFeatureFlag("recommendation", false);

returngetHotProducts();

        }

    }

}

⚡ 6.2 熔断器(Circuit Breaker)

原理:当服务异常率过高时,暂时停止调用

就像家里的保险丝,电流过大时自动断开保护电器!

java 复制代码
// 💡 自定义熔断器

@Component

publicclassCustomCircuitBreaker {

privateenumState {

        CLOSED,    // 关闭状态:正常调用

        OPEN,      // 打开状态:拒绝调用

        HALF_OPEN  // 半开状态:尝试恢复

    }

privateStatestate=State.CLOSED;

privateintfailureCount=0;

privatelonglastFailureTime=0;

privatefinalintfailureThreshold=5;      // 失败阈值

privatefinallongtimeout=60000;          // 超时时间(毫秒)

// 🔄 执行带熔断保护的调用

public <T> Texecute(Supplier<T> operation, Supplier<T> fallback) {

if (state ==State.OPEN) {

// 检查是否可以尝试恢复

if (System.currentTimeMillis() - lastFailureTime > timeout) {

                state =State.HALF_OPEN;

log.info("熔断器进入半开状态,尝试恢复");

            } else {

log.warn("熔断器开启中,执行降级逻辑");

returnfallback.get();

            }

        }

try {

Tresult=operation.get();

// 调用成功,重置计数器

if (state ==State.HALF_OPEN) {

                state =State.CLOSED;

log.info("熔断器恢复正常");

            }

            failureCount =0;

return result;

        } catch (Exceptione) {

// 调用失败,增加失败计数

            failureCount++;

            lastFailureTime =System.currentTimeMillis();

if (failureCount >= failureThreshold) {

                state =State.OPEN;

log.error("熔断器开启,失败次数: {}", failureCount);

            }

log.warn("服务调用失败,执行降级逻辑", e);

returnfallback.get();

        }

    }

}

// 💡 使用熔断器的服务

@Service

publicclassPaymentService {

    @Autowired

privateCustomCircuitBreakercircuitBreaker;

    @Autowired

privateThirdPartyPaymentAPIpaymentAPI;

publicPaymentResultprocessPayment(PaymentRequestrequest) {

returncircuitBreaker.execute(

// 🎯 正常逻辑

            () -> {

returnpaymentAPI.pay(request);

            },

// 🔄 降级逻辑

            () -> {

log.warn("支付服务熔断,订单进入待处理队列");

// 将订单放入队列,稍后重试

addToRetryQueue(request);

returnPaymentResult.builder()

                    .status("PENDING")

                    .message("支付请求已提交,请稍后查看结果")

                    .build();

            }

        );

    }

}

🚦 6.3 限流(Rate Limiting)

原理:控制请求速率,防止系统过载

就像高速公路收费站,控制车流量防止拥堵!

java 复制代码
// 💡 令牌桶限流器

@Component

publicclassTokenBucketRateLimiter {

privatefinalMap<String, TokenBucket> buckets=newConcurrentHashMap<>();

// 🪣 令牌桶

privatestaticclassTokenBucket {

privatefinalintcapacity;        // 桶容量

privatefinaldoublerefillRate;   // 令牌生成速率(每秒)

privatedoubletokens;             // 当前令牌数

privatelonglastRefillTime;       // 上次补充时间

publicTokenBucket(intcapacity, doublerefillRate) {

this.capacity= capacity;

this.refillRate= refillRate;

this.tokens= capacity;

this.lastRefillTime=System.currentTimeMillis();

        }

// 🎫 尝试获取令牌

publicsynchronizedbooleantryAcquire(intpermits) {

refill(); // 先补充令牌

if (tokens >= permits) {

                tokens -= permits;

returntrue;

            }

returnfalse;

        }

// 🔄 补充令牌

privatevoidrefill() {

longnow=System.currentTimeMillis();

doubletokensToAdd= (now - lastRefillTime) /1000.0* refillRate;

            tokens =Math.min(capacity, tokens + tokensToAdd);

            lastRefillTime = now;

        }

    }

// 🎯 获取或创建令牌桶

publicTokenBucketgetBucket(Stringkey, intcapacity, doublerefillRate) {

returnbuckets.computeIfAbsent(key, 

            k ->newTokenBucket(capacity, refillRate));

    }

// ✅ 检查是否允许请求

publicbooleanisAllowed(Stringkey, intpermits) {

TokenBucketbucket=getBucket(key, 100, 10.0); // 默认配置

returnbucket.tryAcquire(permits);

    }

}

// 💡 限流拦截器

@Component

publicclassRateLimitInterceptorimplementsHandlerInterceptor {

    @Autowired

privateTokenBucketRateLimiterrateLimiter;

    @Override

publicbooleanpreHandle(HttpServletRequestrequest, 

HttpServletResponseresponse, 

Objecthandler) throwsException {

// 🔍 获取限流key(可以是IP、用户ID等)

StringclientIP=getClientIP(request);

StringrateLimitKey="ip:"+ clientIP;

// 🚦 检查限流

if (!rateLimiter.isAllowed(rateLimitKey, 1)) {

log.warn("请求被限流,IP: {}", clientIP);

response.setStatus(HttpStatus.TOO_MANY_REQUESTS.value());

response.setContentType("application/json;charset=UTF-8");

StringerrorResponse="""

                {

                    "error": "请求过于频繁",

                    "message": "请稍后再试",

                    "code": 429

                }

                """;

response.getWriter().write(errorResponse);

returnfalse;

        }

returntrue;

    }

privateStringgetClientIP(HttpServletRequestrequest) {

StringxForwardedFor=request.getHeader("X-Forwarded-For");

if (xForwardedFor !=null&&!xForwardedFor.isEmpty()) {

returnxForwardedFor.split(",")[0].trim();

        }

StringxRealIP=request.getHeader("X-Real-IP");

if (xRealIP !=null&&!xRealIP.isEmpty()) {

return xRealIP;

        }

returnrequest.getRemoteAddr();

    }

}

🎯 七、总结与实践建议

📝 核心要点回顾

1.🎯 FEMA评估法:系统化的高可用设计方法

-Failure:识别可能的故障点

-Effect:评估故障影响范围

-Mitigation:制定缓解措施

-Availability:设定可用性目标

2.🗄️ 存储高可用:数据的安全保障

  • 主备模式:简单可靠

  • 主从复制:读写分离

  • 集群模式:水平扩展

3.⚡ 计算高可用:服务的稳定运行

  • 负载均衡:分散压力

  • 健康检查:及时发现问题

  • 自动故障转移:快速恢复

4.🌐 业务高可用:地理级别容灾

  • 同城双活:本地容灾

  • 异地多活:地理容灾

  • 数据同步:保证一致性

5.🛡️ 接口级保护:最后一道防线

  • 服务降级:保证核心功能

  • 熔断器:防止雪崩

  • 限流:控制访问速率

💡 实践建议

🚀 新手入门

1.从监控开始:先能看到问题,再解决问题

2.单点改造:识别系统中的单点故障,逐一改造

3.渐进式改进:不要一次性大改,小步快跑

🎯 进阶优化

1.自动化运维:减少人为操作,提高响应速度

2.容量规划:提前预估系统容量,避免突发流量

3.演练验证:定期进行故障演练,验证高可用方案

🏆 高级实践

1.混沌工程:主动注入故障,测试系统韧性

2.全链路监控:端到端的性能和可用性监控

3.智能运维:基于AI的故障预测和自动修复

🤔 思考题

1.💭 场景题:如果你的电商系统在双11期间遇到数据库主库宕机,你会如何应对?

2.🔧 设计题:设计一个支持100万QPS的秒杀系统,需要考虑哪些高可用措施?

3.📊 分析题:比较集中式和分散式数据集群在不同业务场景下的优劣势?


🎉 结语

高可用架构不是一蹴而就的,它需要我们:

  • 🎯 系统性思考:用FEMA方法全面分析

  • 🔧 渐进式改进:从最关键的地方开始

  • 📊 持续监控:数据驱动的优化决策

  • 🚀 不断演练:实战中验证和完善

记住:高可用架构的目标不是追求100%的完美,而是在成本和收益之间找到最佳平衡点。

从今天开始,给你的系统加上这些"保险"吧!让我们一起告别半夜被叫醒的噩梦,享受安稳的睡眠! 😴


📢 互动时间

👍 觉得有用请点赞,让更多同学看到这篇干货!

💬 留言区聊聊:你在工作中遇到过哪些高可用的坑?是怎么解决的?

🔄 转发分享:帮助更多技术同学告别"宕机恐惧症"!

📱 关注我:更多架构干货持续更新中...

作者简介:张小黑,互联网大厂高级开发,专注分享实用的技术干货。让复杂的技术变得简单易懂!


🏷️ 标签#高可用架构 #系统设计 #Java后端 #架构师 #技术分享

相关推荐
用户4099322502127 小时前
PostgreSQL 17安装总翻车?Windows/macOS/Linux避坑指南帮你搞定?
后端·ai编程·trae
橙序员小站7 小时前
搞定系统设计题:如何设计一个订单系统?
java·后端·面试
IT_陈寒9 小时前
React 18新特性全解析:这5个隐藏API让你的性能飙升200%!
前端·人工智能·后端
IT小番茄9 小时前
Docker:macvlan实现容器跨主机通信[十四]
架构
追逐时光者10 小时前
一款基于 .NET 开源、免费、命令行式的哔哩哔哩视频内容下载工具
后端·.net
小研说技术11 小时前
AI生成SQL并返回数据
后端
AI_in_BSP11 小时前
CPU那些事儿 - Cache(上)
架构
阑梦清川11 小时前
面向linux新手的OrcaTerm AI 最佳实践
后端
庄小焱11 小时前
风控域——美团点评业务风控系统设计
后端