Organized 50 interview questions into 12 categories: - 01-分布式系统 (9 files): 分布式事务, 分布式锁, 一致性哈希, CAP理论, etc. - 02-数据库 (2 files): MySQL索引优化, MyBatis核心原理 - 03-缓存 (5 files): Redis数据结构, 缓存问题, LRU算法, etc. - 04-消息队列 (1 file): RocketMQ/Kafka - 05-并发编程 (4 files): 线程池, 设计模式, 限流策略, etc. - 06-JVM (1 file): JVM和垃圾回收 - 07-系统设计 (8 files): 秒杀系统, 短链接, IM, Feed流, etc. - 08-算法与数据结构 (4 files): B+树, 红黑树, 跳表, 时间轮 - 09-网络与安全 (3 files): TCP/IP, 加密安全, 性能优化 - 10-中间件 (4 files): Spring Boot, Nacos, Dubbo, Nginx - 11-运维 (4 files): Kubernetes, CI/CD, Docker, 可观测性 - 12-面试技巧 (1 file): 面试技巧和职业规划 All files renamed to Chinese for better accessibility and organized into categorized folders for easier navigation. Generated with [Claude Code](https://claude.com/claude-code) via [Happy](https://happy.engineering) Co-Authored-By: Claude <noreply@anthropic.com> Co-Authored-By: Happy <yesreply@happy.engineering>
359 lines
14 KiB
Markdown
359 lines
14 KiB
Markdown
# 短链接系统设计
|
||
|
||
## 需求分析和数据量评估
|
||
|
||
### 需求分析
|
||
- **核心功能**:长链接转短链接、短链接跳转、统计分析
|
||
- **业务场景**:短信营销、社交媒体分享、广告推广
|
||
- **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限制**:防刷机制 |