hugo/content/posts/1.Learning/A3.Reflections/DevOps/pic-app.md
2026-03-18 22:36:05 +08:00

365 lines
17 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: "图片服务整体架构"
date: 2022-06-09T15:09:21+08:00
tags: ["CDN"]
categories: ["Learning", "Reflections"]
---
## 1.背景
面向海外用户设计图片类app的后端架构。
## 2. 目标
1. 考虑跨地区访问图片列表。
2. 图片容灾和备份服务。
3. 用户访问突增的解决方案。
4. 海外服务政策相关注意事项。
## 3. 方案(图片)
ps这里先统一考虑图片的设计过程图片解决后再考虑业务后台过程
### 3.1 自研
#### 方案设计
![v1.drawio](https://image.shijinping.cn/picgo/202206101026771.png)
1. 分布式文件系统:采用开源系统进行搭建分布式文件系统
2. 文件系统服务:可以新增图片时可以生成索引返回给业务,当业务只需要根据索引,就能查询到对应的文件内容
3. 业务层:上传服务主要负责图片的上传、而列表服务则是需要根据请求,获取列表及数据
4. 接入层:接收用户的请求,把请求代理到业务上
这么设计,可以实现一个图片类的应用。在实际中会有什么问题?
1. 不同区域的用户,体验不一样,用户离部署的节点越近,用户体验更好
因为根据之前的经验地域对于网络的延迟影响很大。大致从ping上就能体现
| 地区1 | 地区2 | ping时间 |
| ----- | ----- | -------- |
| 上海 | 广州 | 30ms |
| 上海 | 上海 | 10ms |
| 上海 | 美国 | 100ms |
2. 从终端的成功率上看由于网络上的丢包、延迟成功率会低很多特别是图片目前图片13M都是比较正常的这么大的图片在过程中发生丢包、延迟失败率可想而知会特别的高。
这种场景,我们可以考虑下,访问国外某些网站的时候,经常是失败,体验非常差
#### 改进点
那么需要怎么改进呢?
比较容易想到的就是,既然是距离远,那么直接在对应的地方部署一个服务,不就行了么?
![v2.1.drawio](https://image.shijinping.cn/picgo/202206101104619.png)
这样各地的用户通过dns的调度访问对应的接入层接入层只访问当前区域的服务同一个区域这样就减少了网络上的问题。解决了用户体验。但是好像跟需求不是太耦合。。。需求是``跨区域访问``。
那么要怎么样实现跨区域访问呢?
![v2.3.drawio](https://image.shijinping.cn/picgo/202206101109613.png)
从图上可以看出来,如果底层数据实现了数据同步,那么是不是就可以了?
比如亚洲用户发布内容,那么我们把数据同步给其他集群,这样其他集群就可以访问到亚洲用户的信息了
要怎么实现同步呢?目前了解到**``FastDFS``**可以实现分布式任务系统的他是采用binlog进行同步在log中有个标志位用户记录该条记录是``C: 增加 D: 删除 A: 添加 M: 修改 U: 更新整个文件 T: 截断文件`` 等当亚洲区域进行添加时会发送日志给美洲、欧洲他们也会根据binlog的日志添加这里需要注意同步数据采用的标识与写入的是不一样的采用小写目的是为了区别是否需要同步给其他集群。
这里还没有对FastDFS跨区同步进行测试过还不确定具体的延迟能够到达多少有待验证
理论上,上面的方案是可以实现的,那么我们会有什么问题呢?
1. 所有图片数据,都存在多份,每个数据都需要进行公网的同步。
2. 文件传入与数据传输需要保证一致,不能有数据了,没有文件
那么我们有没有其他方案进行呢?下面我们来看下
![v2.4.drawio](https://image.shijinping.cn/picgo/202206101614227.png)
对于图片可以采用CDN加速。
对于API接口了解到市面上有一种产品叫做“全站加速”或者“动态加速”也就是cdn不进行缓存直接访问这样的话我们可以直接让用户访问这样的话所有数据都访问了中心区域的数据通过“动态加速”把用户和源进行连接核心是增加了数据传输的稳定性降低失败率。
这种方式存在什么问题:
1. 数据量问题:
a) 扩容问题:这个也不算特别问题,是项目一般都会遇到
b) 冷热数据:如果统一的采用一套文件系统,那么会导致数据积累越来越多,文件系统会不停的扩大
3. 当然还有其他的一些需要考虑的点,比如高请求量下“文件内容缓存”、容灾备份等还没有详细讲
### 3.2 外部功能
既然自研中,考虑了外部功能,那么市面上是否有外部的功能,可以实现全球图片访问问题呢?
答案是肯定的CDN+文件系统,这个方案目前也是比较成熟。
![V3.drawio](https://image.shijinping.cn/picgo/202206101440291.png)
该方案乍看一下,与自研的最早方案类似(主要关注左侧部分),都是全球直接接入“一层”,但实际上是不一样的:
1. CDN会覆盖全球节点当用户接入时能够就近访问通过CDN的内网访问“文件系统”
2. 文件系统可以自研,也可以采用云产品。
#### 3.2.1 CDN
用一个图来说明下
![V4-cdn.drawio](https://image.shijinping.cn/picgo/202206101455593.png)
访问顺序A -> B -> C -> D -> E
A. 边缘节点A无数据回源-> 中心节点A (无数据,回源)-> 源站 -> 中心节点A缓存-> 边缘节点A缓存
B. 边缘节点A有缓存直接返回
C. 边缘节点B无数据回源-> 中心节点A有缓存直接返回-> 边缘节点B缓存
D. 边缘节点C无数据回源-> 中心节点B (无数据,回源)-> 源站 -> 中心节点B缓存-> 边缘节点C缓存
E. 边缘节点D无数据回源-> 中心节点B有缓存直接返回-> 边缘节点D缓存
所以第一次访问时,会比较慢,但是面向用户群体属于该区域,则大部分的体验,还是挺快的
#### 3.2.2 源站
目前各大云厂商,都提供了存储,并且针对与存储,并且容量没有限制
### 3.3 对比
那么,我们对两种方案价格进行对比下(初步对比,数据可能不准确):
| | 价格 | 技术 |
| ------------- | ------------------------------------------------------------ | --------------------------------------------------------- |
| 自研+数据同步 | 机器500G700元/月)+宽带10M650元/月))* 2 =2700元/月) | 1. 同步数据服务<br>2. 文件系统服务<br>3. 冷热数据分离服务 |
| 自研+CDN分发 | 机器500G700元/月)+宽带10M650元/月)+CDN2T900元/月)=2150元/月) | 1. 文件系统服务<br/>2. 冷热数据分离服务 |
| 云厂商 | Bucket500G200元/月)+回源流量1T300元/月)+CDN2T900元/月)=1400元/月) | 无 |
### 3.4 选型
他们的**``优势``**分别是什么呢?
| | 自研+数据同步 | 自研+CDN分发 | 云厂商 |
| :------------- | ---------------------------------------------- | ------------------------------------------------------------ | ------------------------------------------------------------ |
| 价格 | 高 | 中 | 低 |
| 突发流量(发) | 自主扩容 | 自主扩容 | 自动 |
| 突发流量(查) | 提升带宽、降级 | 自动 | 自动 |
| 访问速度 | 依赖于同步数据时间 | 首次依赖于回源速度,后面速度较快 | 首次依赖于回源速度,后面速度较快 |
| 是否支持容灾 | 多地备份 | 无 | 无 |
| 容灾备份成本 | 已经实现 | 1. 需要把文件系统全量同步到不同的区域,来实现容灾,整体成本,存储量 * 2<br>2. 需要实现文件同步服务代码 | bucket异地备份存储成本*22M以下的内容一般分钟级别的延迟 |
| 冷热数据处理 | 需要开发冷热数据分离(大致方案在最下面问题中) | 需要开发冷热数据分离 | 已提供设置 |
| 负载均衡 | 自主控制 | 自动 | 自动 |
从上面的对比得出:
1. 初期项目+公司内没有对应的技术栈
选择**``云厂商``**
2. 公司已经有成熟的技术栈
选择**``自研+CDN分发``**
3. 公司在全球的节点部署比较成熟,并且有相应的稳定网络
选择**``全部自研``**
## 4. 后台
从图片的架构选型过程,对于后台的架构选型可以有两种
### 4.1 方案
#### 4.1.1 全球加速访问同一个区域
![V4.1.drawio](https://image.shijinping.cn/picgo/202206101644750.png)
该方案整体上没有特别的点,主要是采用了``全球加速``来提升访问服务的稳定性,当访问用户离服务区域远,延迟会比较高
#### 4.1.2 多区域提供服务
![V4.2.drawio](https://image.shijinping.cn/picgo/202206101922413.png)
这里的核心问题,其实就是数据如何同步。
接下来就对这块进行拆解
问1**如果能够控制一个人,都是在同一个区域,那么是不是就会简单很多呢?**
答案是肯定的。如果一个人只是在同一个区域操作,那么只需要把这个人的数据直接同步到其他区域即可。
所以就需要在人身上打上对应的标记那么怎么标记在我的概念中95%的人在一个相对的时间段内,都是在同一个地方。具体哪里看到,有点忘记了)
答1**我们把用户注册,当作该用户所在的区域**
这样做我们基本上可以让95%的用户能够就近访问。那么还有5%的人怎么办的?这个问题后面再讲。
问2各个区域要如何实现同步呢
答2可以同步的有多个地方
存储直接使用存储自带的比如MySQL、Redis都有自己的复制思路
业务用中间件方式比如kafka这种多区域采用不同的消费者来实现数据同步
存储同步,相对技术比较成熟,可以直接使用,可能出现的问题:
1. A->B->A这种情况
2. 如果我关系链同步到了,但是元数据还未同步,这个情况怎么办?
业务同步,由于本身是业务触发,所以对于业务上来说,所以可以解决存储同步的问题
1. 当A发起同步B时B接受到同步则不用发起再像A的同步
2. 可以先同步用户信息变更、再同步元数据变更、最后同步关系链
当然同步也会存在一些共性问题:
1. 网络问题:这个目前来说,我了解的主要有两种:
a打专线让各个区域的网络联通起来。
b利用云厂商的内部网络在他们的基础上进行处理
这两个办法,都是增加网络的稳定性,来减少丢包重传这种情况
2. 数据延迟:比如分钟内的延迟
延迟本身受区域距离、业务复杂度的影响,当前需求的场景下,我觉得如果能够达到这样的延迟,也是可以接受的。
问3: 是否需要全部区域进行复制?
答3: 这个我觉得可以优化
当一个用户所有的订阅者,所属的区域是同一个区域,那么分发到其他区域,是没有意义的。因为其他区域不会找你的信息(没有关系链找到该用户),除非通过搜索这种,对于这种跨区需求,频率非常少,当本地不存在该信息时,可以远程拉取(可能首次出现了没有内容),但是如果存在了订阅该用户,则该用户就会往该区域同步信息。
问4: 上面提到的,假设用户归属是新加坡,但是去欧洲出差半年,那么该用户每次都会需要从接入层转发到另外区域去获取数据么?(图上接入层的虚线部分)
答4: 答案是否定的。如果每次都要从另外区域去拉取,那么这部分用户基本上体验会很差,为了改善这个问题,用户上是可以挂在**``交集属性``** 就是说本来用户属于区域A但是这个时候用户挂在了交集属性“区域B”那么在后续有关注的用户有操作也会同步到该区域。
问5如果数据修改顺序是A->B->C但是同步后到区域B的数据为A->C->B 那么数据就会造成不一致吧?
答5: 该问题也比较容易解决,可以在数据上增加版本好,同步后,用版本号大的覆盖版本号小的
#### 4.2 选型
做一个简单的对比
| | 方案1 | 方案2 |
| -------- | ---------------------------- | ---------------------------------- |
| 技术 | 简单,只考虑单区域即可 | 方案复杂 |
| 容灾方案 | 单区域多AZ | 多区域多AZ |
| 突发流量 | 扩机器(设计上服务无状态) | 突发集群扩机器(设计上服务无状态) |
| 体验 | 非服务所在区域,访问会有延迟 | 相对于1服务会更好 |
那么该选哪个方案呢?
这个还是跟实际场景有关系
方案1刚开始推广能够覆盖大部分的用户。
方案2产品相对比较成熟用户在全球范围内都有比较大的一个占比团队也有一定的规模。或者在现有一个比较大群体下新增的一个业务
## 5 接口设计
#### 5.1 发布
![流程图.drawio](https://image.shijinping.cn/picgo/202206091537135.png)
接口定义
```java
PublishRsp publish(long uid, PublishReq post);
```
注: 图片基于CDN的分发用户上传后给后台的只是一个URI地址。
#### 5.2 订阅列表
![订阅查看.drawio](https://image.shijinping.cn/picgo/202206091641054.png)
接口定义
```java
// 获取用户自己的时间线
TimelineRsp get(long uid, TimelineReq req);
// 获取某个用户target的时间线这里会有两种情况一个是target本人获取一个是其他用户查看target的时间线主要权限区别
TimelineRsp getOneUser(long uid, long target, TimelineReq req);
```
## 6. 关于海外政策相关
1. 预设标签分类,对于每个图片进行分类打标,不同的政策可以根据不同的标签进行过滤
2. 对于访问的图片(服务端吐出去的图片地址),可以进行异步检测。这种场景适用于:
a为了弥补预设标签后又增加了某些标签历史数据特别大如果全量扫可能需要几个月。
b临时性的政策比如国家突然规定封杀某个信息。
## 7. 问题
1. 如果一个用户,被很多人关注,应该分发模式会导致服务压力过大
如果这种情况,其实不适合写扩散,因为量大容易引起服务异常,所以在这种情况下,就需要推拉结合的模式
2. 关于对发表后的内容操作(如评论)如何同步
这块的操作,大体上应该和内容分发类似,但是细节可能不一样,因为这里存在多地写的情况,可以考虑因果关系,全量评论同步。当然同步后,需要做到去重复。(这里相对复杂点)
3. 如何预防黑产利用漏洞,盗用流量资源
a) 对上传资源的监控,通过回掉来确认资源是否被使用
b) 对资源进行加密CDN侧增加鉴权鉴权不通过则直接拒绝
4. 冷热数据分离
根据日期进行分离可以分成1天、7天、30天、半年、一年以上的数据进行统计根据占比和访问请求来规划冷热数据分离冷数据可以采用更低的资源进行存储减少成本
## 其他资料
海外服务政策相关注意事项
a) 采集信息IP信息及地区信息为了让用户更快速的访问
b) 用户内容:昵称等(用户之间的必要通信信息)
c) 日志数据:订阅关系、元数据、访问日期、时间戳等(确保安全的提供服务)
各个区域公网的ping延迟
美国西部 1 (硅谷)
![image-20220610005713371](https://image.shijinping.cn/picgo/202206100057426.png)
美国东部 1 (弗吉尼亚)
![image-20220610005808192](https://image.shijinping.cn/picgo/202206100058236.png)