Skip to content

Commit c67c59e

Browse files
Initial commit: System Design documentation site
- Docusaurus v3 site with Chinese architecture design content - GitHub Pages deployment configuration - Custom domain: sd.winterio.com.cn Co-Authored-By: Claude <noreply@anthropic.com>
0 parents  commit c67c59e

File tree

133 files changed

+23431
-0
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

133 files changed

+23431
-0
lines changed

.github/workflows/deploy.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Deploy to GitHub Pages
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
workflow_dispatch:
8+
9+
permissions:
10+
contents: read
11+
pages: write
12+
id-token: write
13+
14+
concurrency:
15+
group: "pages"
16+
cancel-in-progress: false
17+
18+
jobs:
19+
build:
20+
runs-on: ubuntu-latest
21+
steps:
22+
- uses: actions/checkout@v4
23+
- uses: actions/setup-node@v4
24+
with:
25+
node-version: 20
26+
cache: npm
27+
- run: npm ci
28+
- run: npm run build
29+
- uses: actions/upload-pages-artifact@v3
30+
with:
31+
path: build
32+
33+
deploy:
34+
environment:
35+
name: github-pages
36+
url: ${{ steps.deployment.outputs.page_url }}
37+
runs-on: ubuntu-latest
38+
needs: build
39+
steps:
40+
- uses: actions/deploy-pages@v4
41+
id: deployment

.gitignore

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
# Dependencies
2+
/node_modules
3+
4+
# Production
5+
/build
6+
7+
# Generated files
8+
.docusaurus
9+
.cache-loader
10+
11+
# Misc
12+
.DS_Store
13+
.env.local
14+
.env.development.local
15+
.env.test.local
16+
.env.production.local
17+
18+
npm-debug.log*
19+
yarn-debug.log*
20+
yarn-error.log*

README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# Website
2+
3+
This website is built using [Docusaurus](https://docusaurus.io/), a modern static website generator.
4+
5+
## Installation
6+
7+
```bash
8+
yarn
9+
```
10+
11+
## Local Development
12+
13+
```bash
14+
yarn start
15+
```
16+
17+
This command starts a local development server and opens up a browser window. Most changes are reflected live without having to restart the server.
18+
19+
## Build
20+
21+
```bash
22+
yarn build
23+
```
24+
25+
This command generates static content into the `build` directory and can be served using any static contents hosting service.
26+
27+
## Deployment
28+
29+
Using SSH:
30+
31+
```bash
32+
USE_SSH=true yarn deploy
33+
```
34+
35+
Not using SSH:
36+
37+
```bash
38+
GIT_USER=<Your GitHub username> yarn deploy
39+
```
40+
41+
If you are using GitHub pages for hosting, this command is a convenient way to build the website and push to the `gh-pages` branch.

docs/caching/_category_.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"label": "缓存层场景实战",
3+
"position": 2,
4+
"link": {
5+
"type": "generated-index",
6+
"description": "主要讲解大流量时,如何避免流量直接压垮数据库层。学完这部分内容后,当遇到缓存层场景问题,就知道如何进行架构设计了。"
7+
}
8+
}

docs/caching/data-collection.md

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
---
2+
sidebar_position: 3
3+
title: 第6章 数据收集
4+
description: 日亿万级请求日志收集架构设计,解决长期高频插入数据的问题
5+
keywords: [数据收集, Kafka, Flink, Logstash, 日志采集, 实时计算, Elasticsearch, HBase]
6+
---
7+
8+
# 第6章 数据收集
9+
10+
上一章详细讨论了写缓存的架构解决方案,它虽然可以减少数据库写操作的压力,但也存在一些不足。比如**需要长期高频插入数据**时,这个方案就无法满足,接下来将围绕这个问题逐步提出解决方案。
11+
12+
![数据收集概念](/img/chapter6/01_data_collection_concept.png)
13+
14+
## 6.1 业务背景:日亿万级请求日志收集如何不影响主业务
15+
16+
因业务快速发展,某天某公司的日活用户高达 **500万**,基于当时的业务模式,业务侧要求根据用户的行为做埋点,旨在记录用户在特定页面的所有行为,以便开展数据分析,以及与第三方进行费用结算。
17+
18+
### 业务需求
19+
20+
在数据埋点的过程中,业务侧还要求在后台能**准实时**查询用户行为数据及统计报表。
21+
22+
需收集的原始数据结构:
23+
24+
| 字段 | 说明 |
25+
|------|------|
26+
| 用户ID | 用户唯一标识 |
27+
| 时间戳 | 事件发生时间 |
28+
| 经纬度 | 用户位置信息 |
29+
| 目标类型 | 页面/按钮/链接等 |
30+
| 目标ID | 具体目标标识 |
31+
| 事件动作 | 点击/浏览/滑动等 |
32+
33+
通过以上数据结构,业务侧可以:
34+
- 将城市、性别、年龄、目标类型、目标ID、事件动作等作为查询条件
35+
- 从时间、性别、年龄等维度查看统计报表
36+
37+
## 6.2 技术选型思路
38+
39+
根据业务场景,项目组提炼出了 6 点业务需求:
40+
41+
| 业务需求 | 技术选型思路 |
42+
|----------|--------------|
43+
| 原始数据海量 | 使用 HBase 进行持久化 |
44+
| 埋点记录请求响应要快 | 存放到缓存层(本地日志) |
45+
| 可通过后台查询原始数据 | 使用 Elasticsearch 保存查询条件字段 |
46+
| 各种统计报表需求 | 自己设计功能(灵活性高) |
47+
| 根据埋点日志生成费用结算数据 | 保存在 MySQL 中 |
48+
| 需要处理框架将数据迁移到持久化层 | 实时处理工具(Flink) |
49+
50+
![日志存储](/img/chapter6/02_log_storage.png)
51+
52+
### 6.2.1 使用什么技术保存埋点数据的第一现场
53+
54+
目前快速保存埋点数据的技术主要分为 3 种:
55+
56+
| 技术 | 优点 | 缺点 |
57+
|------|------|------|
58+
| Redis | 读写快 | 需要配置持久化,响应要求高时性能受影响 |
59+
| Kafka | 吞吐量大 | 需要等待数据同步,响应可能变慢 |
60+
| **本地日志** | 响应最快 | 需要额外收集 |
61+
62+
**Redis 的 AOF 机制分析**
63+
- `appendfsync=everysec`:每秒落盘一次,可能丢失一秒数据
64+
- `appendfsync=always`:每次操作落盘后返回,系统运行会很慢
65+
66+
**Kafka 的 acks 配置分析**
67+
- `acks=0`:不等落盘直接返回,响应快但数据无保障
68+
- `acks=1`:等 Leader 落盘,不等 Follower 同步
69+
- `acks=all`:等所有副本同步,数据有保障但响应慢
70+
71+
最终决定把埋点数据保存到**本地日志**中——性能和可靠性兼得。
72+
73+
### 6.2.2 使用什么技术收集日志数据到持久化层
74+
75+
最简单的方式是通过 Logstash 直接把日志文件迁移到 Elasticsearch,但会有问题:
76+
77+
- Elasticsearch 需要包含城市、性别、年龄等业务数据
78+
- 这些数据日志文件中没有,需要调用业务系统获取
79+
80+
不直接使用 Logstash 到持久化层的原因:
81+
82+
1. 需要同时输出到 Elasticsearch 和 HBase 两个源,一个出错会影响另一个
83+
2. MySQL 中需要动态计算费用结算数据,Logstash 不适用
84+
85+
**最终方案**:引入计算框架
86+
- 通过 Logstash 把日志文件迁移到 MQ
87+
- 通过实时计算框架处理 MQ 中的数据
88+
- 保存处理后的数据到持久层
89+
90+
:::tip 提示
91+
Logstash 资源消耗大(Ruby 语言编写),官方推出了轻量化的 Filebeat。但 Filebeat 使用轮询方式采集,存在一定延时,所以该项目最终选择继续使用 Logstash。
92+
:::
93+
94+
### 6.2.3 为什么使用 Kafka
95+
96+
![Kafka结构](/img/chapter6/03_kafka_structure.png)
97+
98+
Kafka 是 LinkedIn 推出的开源消息中间件,它天生是为收集日志而设计的,具备:
99+
- **超高吞吐量**:3台便宜的机器每秒写入两百万条记录
100+
- **数据量扩展性**:被称作无限堆积
101+
102+
**Kafka 为什么吞吐量这么高?**
103+
104+
Kafka 的存储结构:
105+
- 每个 Topic 分区相当于一个巨型文件
106+
- 每个巨型文件由多个 Segment 小文件组成
107+
- Producer 负责对该巨型文件进行"**顺序写**"
108+
- Consumer 负责对该文件进行"**顺序读**"
109+
110+
**好处**:读操作不会阻塞写操作,这也是其吞吐量大的原因。
111+
112+
### 6.2.4 使用什么技术把 Kafka 的数据迁移到持久化层
113+
114+
需要使用一个**分布式实时计算框架**,原因有两点:
115+
1. 数据量特别大,需要多个节点并发处理
116+
2. 业务要求实时查询统计报表数据
117+
118+
![Flink特性](/img/chapter6/04_flink_features.png)
119+
120+
目前流行的分布式实时计算框架:
121+
122+
| 框架 | 特点 |
123+
|------|------|
124+
| Storm | 最早的流处理框架 |
125+
| Spark Streaming | 微批处理 |
126+
| **Apache Flink** | 性能强、容错好、时间窗口支持 |
127+
128+
**选择 Apache Flink 的原因**
129+
130+
1. **性能强**:阿里活动期间一秒内能够处理 17 亿条数据
131+
2. **容错机制**:能保证每条数据仅仅处理一次(Exactly-Once)
132+
3. **时间窗口**:基于消息的事件时间,而不是处理时间
133+
134+
#### 流处理的容错机制
135+
136+
| 容错级别 | 说明 |
137+
|----------|------|
138+
| At-Most-Once | 至多一次,可能丢失数据 |
139+
| **Exactly-Once** | 精确一次,最优选择 |
140+
| At-Least-Once | 至少一次,可能重复消费 |
141+
142+
#### 时间窗口计算
143+
144+
日志中事件发生的时间可能与计算框架处理消息的时间不一致。
145+
146+
**示例**:一条消息事件时间是 6:30,处理时间延后 2 秒变成 6:32
147+
- 如果按处理时间统计 6:01~6:30 的数据,这条消息不会被计算在内
148+
- Apache Flink 使用**事件时间**,确保统计准确
149+
150+
## 6.3 整体方案
151+
152+
![整体方案总结](/img/chapter6/05_summary.png)
153+
154+
整个架构的流程如下:
155+
156+
1. **后台服务端**记录所有的请求数据,存放到本地的日志文件
157+
2. 使用数据收集框架 **Logstash**,从日志文件抽取原始的日志数据,不加工直接存放到 Kafka
158+
3. 通过 **Apache Flink** 从 Kafka 中拉取原始的日志数据,并且经过业务加工
159+
4. 分别存放到 **Elasticsearch****HBase****MySQL**
160+
161+
各存储的用途:
162+
163+
| 存储 | 用途 |
164+
|------|------|
165+
| Elasticsearch | 处理用户针对请求日志的查询请求,存放查询关键字段和请求ID |
166+
| HBase | 存放详细的请求数据 |
167+
| MySQL | 存放组合加工后的结算数据 |
168+
169+
**查询流程**
170+
1. 根据查询关键字在 Elasticsearch 中获得结果 ID 列表
171+
2. 通过结果 ID 去 HBase 中获取详细的请求数据
172+
173+
## 6.4 小结
174+
175+
本章并没有讲解特别深入的架构设计方面的注意事项,而是主要阐述**技术选型背后的思考过程**
176+
177+
学架构的过程就是经历一些基础的场景,而那些复杂的场景其实是简单场景的叠加复用。
178+
179+
**方案落地后的效果**
180+
- 丢数据的情况并不多
181+
- 架构的扩展性很好
182+
- 之后日活达到了几千万,系统仍然可以使用(需多加机器,定时清理旧数据)
183+
184+
### 写缓存解决的问题回顾
185+
186+
| 问题 | 解决章节 |
187+
|------|----------|
188+
| 长期高并发写数据 | 本章已解决 |
189+
| 高并发且请求需要抢资源 | [秒杀架构](./seckill-architecture.md) |

0 commit comments

Comments
 (0)