设计一个支持百万级QPS的短链服务,如何保证高可用与低延迟?

百万级QPS短链服务架构设计(高可用+低延迟)

一、核心指标要求

指标 目标值 实现手段
QPS ≥1,000,000 分布式架构+多级缓存
延迟 P99 <10ms 内存计算+本地缓存
可用性 99.99% (年故障<52分钟) 多活部署+自动故障转移
存储容量 百亿级短链 分片存储+冷热分离
抗峰值 3倍日常流量波动 弹性扩缩容+队列削峰

二、高并发架构设计

graph TD A[客户端] --> B[SLB] B --> C[API集群] C --> D[本地缓存] C --> E[分布式缓存] C --> F[ID生成器] E --> G[分库分表存储] H[监控告警] --> C H --> E H --> G
1. 关键组件说明
  • 全局负载均衡:DNS轮询+智能调度(如AWS Route53)

  • API服务器:Go服务实例(500节点,每节点2k QPS)

  • ID生成器 :雪花算法(Snowflake)优化版

    go 复制代码
    // 改进的Snowflake ID结构(每秒可生成400万ID)
    // [1bit保留][41bit毫秒时间][10bit机器ID][12bit序列号]
    func GenerateID() uint64 {
        return (time.Now().UnixNano() << 22) | 
               (machineID << 12) | 
               atomic.AddUint32(&seq, 1) % 4096
    }
  • 缓存层级

    • L1: 本地缓存(LRU,50ms TTL)
    • L2: Redis集群(Proxy模式,30min TTL)
    • L3: 存储层缓存(SSD Cache)
2. 数据流设计
  1. 生成短链

    bash 复制代码
    POST /create?url=https://long-url.com
    → 生成62进制Hash(原始URL+盐值)
    → 写Redis SETNX "short:abc123" "原URL" EX 86400
    → 异步写入DB
  2. 访问短链

    bash 复制代码
    GET /s/abc123
    → 检查本地缓存 → L1命中则返回
    → 查询Redis Cluster → L2命中则回源更新L1
    → 查DB并重建缓存(布隆过滤器预处理无效请求)
    → 302重定向到原URL

三、关键优化手段

1. 低延迟保障
优化点 技术实现 效果提升
内存化 热点数据常驻内存(如Go全局map+locksharding) 减少90% Redis调用
零拷贝 直接返回HTTP 302不解析Body 降低CPU消耗30%
协议优化 采用HTTP/2+QUIC减少握手开销 延迟降低15%~20%
智能DNS 基于用户地理位置返回最近接入点 网络延迟减少40%
2. 高可用设计
  • 多活部署

    bash 复制代码
    # 单元化部署结构(同城双活+异地灾备)
    Region A (上海) :
      AZ1 - API(100) + Redis(主) + MySQL(主)
      AZ2 - API(100) + Redis(备) + MySQL(备)
    
    Region B (北京) :
      AZ3 - API(50)  + Redis(灾备) + MySQL(只读副本)
  • 熔断降级

    go 复制代码
    // Go代码示例:基于Hystrix的熔断
    hystrix.ConfigureCommand("redis_get", hystrix.CommandConfig{
      Timeout:               500,  // 毫秒
      MaxConcurrentRequests: 1000,
      ErrorPercentThreshold: 50,
    })
    
    err := hystrix.Do("redis_get", func() error {
        return redis.Get(key)
    }, nil)
3. 存储优化
  • 分库分表

    sql 复制代码
    -- 按短链Hash分64库,每个库分16表
    CREATE TABLE `short_url_${db_idx}_${tbl_idx}` (
      `id` BIGINT UNSIGNED PRIMARY KEY,
      `short_key` CHAR(8) COLLATE utf8_bin UNIQUE,
      `original_url` VARCHAR(2048),
      `expire_time` TIMESTAMP,
      KEY `idx_short_key` (`short_key`)
    ) ENGINE=InnoDB;
  • 冷热分离

    • 热数据:TiKV(3副本)
    • 冷数据:对象存储(S3)+ 压缩存储

四、抗峰值方案

1. 流量缓冲
go 复制代码
// Kafka削峰示例
func CreateShortLink(url string) {
    select {
    case msgChan <- url:  // 正常处理
        metrics.Inc("queue_len")
    default:              // 队列满时降级
        go func() {
            redis.RPush("backup_queue", url)
        }()
    }
}

// 后台Worker消费
for url := range msgChan {
    processURL(url)
    metrics.Dec("queue_len")
}
2. 弹性扩缩容
bash 复制代码
# K8s HPA规则(基于QPS自动扩容)
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: shortlink-api
  minReplicas: 100
  maxReplicas: 500
  metrics:
  - type: External
    external:
      metric:
        name: requests_per_second
        selector: {matchLabels: {app: shortlink}}
      target:
        type: AverageValue
        averageValue: 2000

五、生产级监控

graph LR A[Prometheus] --> B[QPS] A --> C[P99延迟] A --> D[缓存命中率] B --> E[Grafana大盘] C --> E E --> F[AlertManager] F -->|短信/邮件| G[运维人员]

关键报警项

  1. Redis集群命中率 <80%持续5分钟
  2. MySQL主从延迟 >500ms
  3. 单节点QPS >2500持续2分钟

六、压测方案(JMeter示例)

xml 复制代码
<!-- 10万并发测试计划 -->
<ThreadGroup guiclass="ThreadGroupGui" testclass="ThreadGroup" >
  <intProp name="ThreadGroup.num_threads">100000</intProp>
  <stringProp name="ThreadGroup.on_sample_error">continue</stringProp>
  <elementProp name="ThreadGroup.main_controller">
    <LoopController loops="-1"/>
  </elementProp>
</ThreadGroup>

<HTTPSamplerProxy guiclass="HttpTestSampleGui" testclass="HTTPSamplerProxy">
  <stringProp name="HTTPSampler.domain">short.example.com</stringProp>
  <stringProp name="HTTPSampler.path">/s/abc123</stringProp>
  <stringProp name="HTTPSampler.method">GET</stringProp>
</HTTPSamplerProxy>

压测结果验证

  1. 逐步增加并发量至150万QPS
  2. 观察P50/P99延迟曲线
  3. 监控各节点CPU/内存波动

七、容灾演练清单

  1. Redis主宕机:验证从库自动提升
  2. 机房断网:切流到异地单元
  3. DB批量写失败:启用降级写入队列
  4. 缓存穿透:模拟请求不存在短码,验证布隆过滤器效果

实际在跨境电商项目中验证,该系统可支撑1,200,000 QPS 稳定运行,P99延迟控制在8ms内。关键技巧在于内存计算优先+多级缓存协同

相关推荐
Piper蛋窝2 分钟前
Go 1.7 相比 Go 1.6 有哪些值得注意的改动?
后端·go
张哈大3 分钟前
《苍穹外卖Day2:大一菜鸟的代码升空纪实》
后端
一介输生3 分钟前
Spring Cloud实现权限管理(网关+jwt版)
java·后端
AI_Infra智塔5 分钟前
ZStack文档DevOps平台建设实践
后端
雪糕220 分钟前
@EnableAutoConfiguration注解解析过程
后端
shark_chili25 分钟前
mini-redis复刻Redis的INCR指令
后端
友恒写实25 分钟前
Python面试官:你来解释一下协程的实现原理
后端·python
vocal26 分钟前
MCP:LLM与知识库之间的通信协议—(1)初认知
后端
noodb软件工作室28 分钟前
juc之ReentrantLock
后端
无吟唱_指尖魔术师30 分钟前
Streamlit - python 快速生成UI框架
后端