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

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

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


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

想象一下这个场景:

🌙 深夜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后端 #架构师 #技术分享

相关推荐
LONGZETECH2 分钟前
无人机组装调试实训高损耗痛点分析与虚拟仿真教学落地方案
c语言·开发语言·架构·无人机
雪隐2 小时前
个人电脑玩AI-16让5060 Ti给你打工——5060Ti 16G 跑 MiniMax-Music-3:从下载到 60s 出歌的全流程
前端·人工智能·后端
Dawson Zhu2 小时前
面向AI自动化分析的数据仓库建模实践
人工智能·语言模型·架构·制造
黄焖鸡能干四碗2 小时前
信息安全保障方案(Word文件)
大数据·网络·人工智能·架构·区块链
报错小能手2 小时前
Go 语言结构 基础语法
开发语言·后端·golang
暗黑小白2 小时前
参数从哪来、何时来 —— 提取时机与平台化 Slot 管理
人工智能·后端·大模型·ai agent
剩下了什么2 小时前
go语言 Ctx:「错误三:在 Context 中存储可变值」
开发语言·后端·golang
AI枫林晚3 小时前
DeepSeek Harness 功能与特性解析:一个“一切皆插件“的 Agent 运行时
架构
晴天163 小时前
DeepSeek Harness 插件开发:从零到跑起来-Day18
ai·架构·deepseek
程序员鱼皮3 小时前
DeepSeek Harness 最新邪修曝光!被吹成核弹的极简模式,真的夯吗?
前端·后端·ai编程