# 短链接系统设计 ## 需求分析和数据量评估 ### 需求分析 - **核心功能**:长链接转短链接、短链接跳转、统计分析 - **业务场景**:短信营销、社交媒体分享、广告推广 - **QPS评估**:日点击量10亿次,峰值QPS 3万+ - **数据规模**:短链接10亿+,日生成1000万+ ### 数据量评估 - **短链接表**:10亿条,日均写入1000万次 - **原始链接表**:10亿条,日均读取10亿次 - **访问统计表**:100亿+条,日增1亿+ - **用户表**:1000万+,日均查询100万次 ## 核心技术难点 ### 1. 高并发写入 - 短链接生成需要高性能 - 避免数据库写入瓶颈 - 分布式ID生成 ### 2. 高性能读取 - 毫秒级响应时间 - 缓存命中率优化 - 全球CDN加速 ### 3. 长链接查重 - 重复链接检测 - 去重策略设计 - 一致性保证 ### 4. 统计准确性 - 实时统计延迟 - 统计数据准确性 - 分布式计数器 ## 系统架构设计 ### 总体架构 ``` ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ CDN/Edge │ │ Load Balance │ │ API Gateway │ │ Cache │◄──►│ (Anycast) │◄──►│ (Gateway) │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ ┌───────────────────────────────────┼───────────────────────────────────┐ │ │ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ 短链接服务 │ │ 统计服务 │ │ 监控服务 │ │ (微服务) │ │ (微服务) │ │ (微服务) │ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ │ │ └───────────────────────────────────┼───────────────────────────────────┘ │ ┌───────────────────────────────────┼───────────────────────────────────┐ │ │ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ Redis集群 │ │ 消息队列 │ │ 数据库集群 │ │ (缓存+计数器)│ │ (Kafka) │ │ (MySQL分库分表)│ └─────────────────┘ └─────────────────┘ └─────────────────┘ │ ┌───────────────────────────────────┼───────────────────────────────────┐ │ │ │ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ 时序数据库 │ │ 数据仓库 │ │ 搜索引擎 │ │ (InfluxDB) │ │ (ClickHouse) │ │ (Elasticsearch)│ └─────────────────┘ └─────────────────┘ └─────────────────┘ ``` ### 关键组件 #### 1. 流量层 - **CDN/Edge**:全球加速,缓存热点短链接 - **负载均衡**:Anycast IP,就近接入 - **API网关**:限流、路由、认证 #### 2. 服务层 - **短链接服务**:核心业务逻辑 - **统计服务**:访问统计和报表 - **管理服务**:后台管理系统 - **监控服务**:实时监控告警 #### 3. 存储层 - **Redis集群**:缓存和计数器 - **MySQL集群**:主从复制,分库分表 - **时序数据库**:时序数据存储 - **搜索引擎**:链接检索和分析 #### 4. 分析层 - **数据仓库**:离线数据分析 - **OLAP引擎**:实时查询分析 - **报表系统**:业务报表展示 ## 数据库设计 ### 短链接表 ```sql CREATE TABLE `short_url` ( `id` bigint NOT NULL AUTO_INCREMENT, `short_code` varchar(10) NOT NULL COMMENT '短链接编码', `long_url` text NOT NULL COMMENT '原始长链接', `domain` varchar(255) NOT NULL COMMENT '自定义域名', `title` varchar(255) DEFAULT NULL COMMENT '页面标题', `description` text COMMENT '页面描述', `keywords` varchar(500) DEFAULT NULL COMMENT '关键词', `user_id` bigint DEFAULT NULL COMMENT '用户ID', `is_custom` tinyint NOT NULL DEFAULT 0 COMMENT '是否自定义', `status` tinyint NOT NULL DEFAULT 1 COMMENT '状态', `expire_at` datetime DEFAULT NULL COMMENT '过期时间', `click_count` int NOT NULL DEFAULT 0 COMMENT '点击次数', `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_short_code` (`short_code`), KEY `idx_long_url` (`long_url`(255)), KEY `idx_user_id` (`user_id`), KEY `idx_expire_at` (`expire_at`), KEY `idx_domain` (`domain`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ``` ### 访问记录表 ```sql CREATE TABLE `url_access_log` ( `id` bigint NOT NULL AUTO_INCREMENT, `short_code` varchar(10) NOT NULL COMMENT '短链接编码', `ip` varchar(45) NOT NULL COMMENT '访问IP', `user_agent` text COMMENT '用户代理', `referer` text COMMENT '来源页面', `country` varchar(50) DEFAULT NULL COMMENT '国家', `region` varchar(50) DEFAULT NULL COMMENT '地区', `city` varchar(50) DEFAULT NULL COMMENT '城市', `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), KEY `idx_short_code` (`short_code`), KEY `idx_created_at` (`created_at`), KEY `idx_ip` (`ip`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ``` ### 统计表 ```sql CREATE TABLE `url_stats` ( `id` bigint NOT NULL AUTO_INCREMENT, `short_code` varchar(10) NOT NULL COMMENT '短链接编码', `date` date NOT NULL COMMENT '统计日期', `total_clicks` int NOT NULL DEFAULT 0 COMMENT '总点击次数', `unique_clicks` int NOT NULL DEFAULT 0 COMMENT '独立点击次数', `by_country` json DEFAULT NULL COMMENT '国家分布', `by_region` json DEFAULT NULL COMMENT '地区分布', `by_device` json DEFAULT NULL COMMENT '设备分布', `by_browser` json DEFAULT NULL COMMENT '浏览器分布', `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_date_code` (`date`, `short_code`), KEY `idx_short_code` (`short_code`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ``` ### 用户表 ```sql CREATE TABLE `short_url_user` ( `id` bigint NOT NULL AUTO_INCREMENT, `user_id` bigint NOT NULL COMMENT '用户ID', `username` varchar(50) NOT NULL COMMENT '用户名', `email` varchar(100) NOT NULL COMMENT '邮箱', `domain` varchar(255) DEFAULT NULL COMMENT '自定义域名', `api_key` varchar(64) DEFAULT NULL COMMENT 'API密钥', `quota` int NOT NULL DEFAULT 1000 COMMENT '配额', `used` int NOT NULL DEFAULT 0 COMMENT '已使用', `status` tinyint NOT NULL DEFAULT 1 COMMENT '状态', `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, PRIMARY KEY (`id`), UNIQUE KEY `uk_user_id` (`user_id`), UNIQUE KEY `uk_api_key` (`api_key`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; ``` ## 缓存策略 ### Redis缓存设计 ```typescript // 短链接缓存 const SHORT_URL_CACHE_PREFIX = 'short_url:'; const SHORT_URL_CACHE_TTL = 86400; // 24小时 // 访问计数器 const CLICK_COUNT_PREFIX = 'click:'; const CLICK_COUNT_TTL = 60; // 1分钟 // 布隆过滤器 const BLOOM_FILTER_PREFIX = 'bloom:'; const BLOOM_FILTER_SIZE = 1000000000; // 10亿 // 限流计数器 const RATE_LIMIT_PREFIX = 'rate_limit:'; const RATE_LIMIT_TTL = 60; // 1分钟 ``` ### 缓存策略 1. **多级缓存**: - 本地缓存:Caffeine - 分布式缓存:Redis Cluster - CDN缓存:边缘节点 2. **缓存更新策略**: - Write Through:写入同时更新缓存 - Write Back:异步更新缓存 - Refresh Ahead:预加载热点数据 3. **缓存预热**: - 热门短链接预加载 - 统计数据预计算 - 静态资源预缓存 ### 布隆过滤器实现 ```java public class BloomFilter { private final BitSet bitSet; private final int size; private final int[] hashSeeds; public BloomFilter(int size, int hashCount) { this.size = size; this.bitSet = new BitSet(size); this.hashSeeds = new int[hashCount]; Random random = new Random(); for (int i = 0; i < hashCount; i++) { hashSeeds[i] = random.nextInt(); } } public void add(String key) { for (int seed : hashSeeds) { int hash = Math.abs((key.hashCode() ^ seed) % size); bitSet.set(hash, true); } } public boolean mightContain(String key) { for (int seed : hashSeeds) { int hash = Math.abs((key.hashCode() ^ seed) % size); if (!bitSet.get(hash)) { return false; } } return true; } } ``` ## 扩展性考虑 ### 1. 水平扩展 - **无状态服务**:短链接服务无状态化 - **数据分片**:按短链接编码分片 - **读写分离**:主库写入,从库读取 ### 2. 垂直扩展 - **服务拆分**:API服务、统计服务、管理服务 - **数据分层**:热数据、温数据、冷数据 - **多级缓存**:本地、Redis、CDN ### 3. 全球化部署 - **CDN加速**:全球节点部署 - **地域化存储**:按地域分片 - **灾备切换**:多机房容灾 ### 4. 监控告警 - **实时监控**:QPS、响应时间、错误率 - **业务监控**:点击量、转化率 - **异常告警**:服务异常、数据异常 ## 实际项目经验 ### 1. 技术栈选择 - **前端**:React + TypeScript - **后端**:Spring Boot + Node.js - **数据库**:MySQL + Redis - **缓存**:Redis Cluster - **消息队列**:Kafka - **监控**:Prometheus + Grafana ### 2. 性能优化 - **短链接生成**:Snowflake算法 - **缓存优化**:多级缓存策略 - **数据库优化**:分库分表、索引优化 - **网络优化**:HTTP/2、Keep-Alive ### 3. 运维部署 - **容器化**:Docker + Kubernetes - **CI/CD**:Jenkins + GitLab - **监控告警**:ELK Stack + AlertManager - **压测**:JMeter + Locust ### 4. 安全设计 - **HTTPS**:全链路加密 - **API限流**:防刷、防攻击 - **数据脱敏**:敏感信息加密 - **访问控制**:API密钥认证 ## 阿里P7加分项 ### 1. 架构设计能力 - **高可用架构**:99.99%可用性 - **高性能架构**:支持亿级QPS - **全球化架构**:全球CDN加速 ### 2. 技术深度 - **分布式算法**:一致性哈希、布隆过滤器 - **缓存优化**:多级缓存策略 - **数据库优化**:分库分表、读写分离 ### 3. 业务理解 - **营销业务**:理解短链接在营销中的应用 - **用户行为**:分析点击行为模式 - **数据统计**:实时统计和离线分析 ### 4. 团队管理 - **技术团队**:带领15人+团队 - **项目管控**:管理亿级用户项目 - **技术方案**:主导技术架构设计 ### 5. 前沿技术 - **Serverless**:短链接函数化 - **边缘计算**:边缘节点处理 - **AI应用**:智能推荐、异常检测 ## 面试常见问题 ### 1. 短链接如何生成? - **随机字符**:生成随机字符串 - **自增序列**:数据库自增ID - **哈希算法**:MD5/SHA1取前几位 - **Base62编码**:数字转62进制 ### 2. 如何避免短链接冲突? - **布隆过滤器**:快速检测重复 - **数据库唯一索引**:保证唯一性 - **重试机制**:冲突时重新生成 ### 3. 如何实现高并发生成? - **预生成**:批量生成短链接 - **分布式ID**:Snowflake算法 - **内存缓存**:减少数据库访问 ### 4. 如何统计点击数据? - **实时统计**:Redis计数器 - **异步处理**:消息队列存储 - **离线分析**:数据仓库计算 ### 5. 如何保证短链接安全? - **链接过滤**:过滤恶意链接 - **访问控制**:黑白名单 - **HTTPS加密**:防止劫持 - **IP限制**:防刷机制