简介:面向中国传媒大学信息与通信工程学院学生的《媒体数据库与云存储》实验(四)实验报告,聚焦OpenStack云计算平台搭建与Swift对象存储实践,涵盖VMware虚拟网络配置、Dashboard管理、云主机实例创建、网络服务查看及Swift容器/对象/元数据操作,并附有课后思考题解答。实验报告详细记录了从已有镜像生成OpenStack主机、以test/demo用户登录、使用ifconfig确认IP到创建Inst_demo实例的过程;Swift实践部分逐步演示了CLI认证、新建容器、上传本地文件、查看与修改对象元数据等关键操作,并针对OpenStack与其他云计算软件的优势对比给出了完整分析。资源为1份PDF文档,压缩包大小3.66MB,内含完整操作命令、运行结果截图及思考题解析,适合正在学习云存储与云计算课程的本科学生对照实操或复习备考。已有84人学习下载,尤其适合需要完成同类实验报告或深入掌握OpenStack对象存储的读者。
1. 媒体数据库与云存储实验(四):这门实验课到底在让我们练什么
第一次做「媒体数据库与云存储」实验(四),十有八九会栽在一个念头上:把视频、图片直接塞进数据库当字段存。真这么干,几百 MB 的库就能把 MySQL 拖慢,备份更是按十分钟计。这个实验真正要练的是分工——数据库只记录媒体文件的元数据(名称、大小、归属、存储位置),云存储只负责用对象方式保管文件本体。想明白这一条,后面全是顺水推舟。
它适合正在跟课做媒体系统设计的同学,也适合手里有大量图片、视频要管理,却在「存库还是存盘」之间反复横跳的开发者。读完你会拿到一套能直接复现的最小闭环:MinIO 充当云存储,MySQL 充当媒体数据库,用脚本完成上传、回读和异常处理,最后组织成一份能讲清楚设计取舍的实验报告。
2. 实验选型:媒体数据库存元数据,云存储管文件,为什么必须分开
2.1 媒体数据库不是「把视频塞进数据库」
先算一笔账。一段 10 分钟的 1080p 视频,体积通常在 1GB 上下,一张高清图片也有几兆到几十兆。如果把这些二进制直接写进 MySQL 的 BLOB 字段,数据库文件会急剧膨胀,每次全量备份都要拷贝这几个 GB 的二进制块;查询时只要需要回读这些字段,网络和磁盘 IO 立刻成为瓶颈;更重要的是,数据库连接数和内存都被大字段拖垮,连普通元数据查询也会跟着变慢。所以真正意义上的媒体数据库,核心职责从来不是持有文件,而是持有「关于文件的描述」。
媒体数据库这个说法,在工程实践中通常指「媒体资产管理系统」的存储底座:它管理的是媒体对象的元数据——标题、类型(视频/音频/图片)、时长、码率、宽高、上传者、上传时间、存储位置。用户在前端看到的搜索、分类、权限控制,最终都落在这些结构化字段上;媒体文件本体则交给另一个系统去存。实验(四)把「媒体数据库」和「云存储」并列,本身就暗示了这一层分工。
这套「元数据入库、文件入存储」的设计,早在云存储普及之前就是媒体行业的标配。过去没有对象存储的时候,文件放在磁盘阵列上,数据库记录文件路径;现在有了云存储,只不过把磁盘阵列换成了带 API、带权限、带容灾的对象存储桶。实验课让你亲手搭一遍,就是要让这套分工从「听说过」变成「做过」。
2.2 云存储选型:为什么兼容 S3 的 MinIO 是实验首选
实验环境里要接云存储,第一个实际问题是没有公有云账号,或者有账号但机房带宽不够、安全策略不允许外网访问。常见做法是本地起一个兼容 S3 协议的对象存储服务来模拟云端,最常用的是 MinIO。S3 协议如今是对象存储的事实标准,公有云厂商的对象存储接口基本都兼容它,所以本地用 MinIO 写的代码,换到公有云上只需要改 endpoint 和密钥,业务逻辑一行都不用动。
MinIO 的部署形态是单个二进制或容器,它对外的端口有两个:一个走 S3 API 用于程序读写,另一个是浏览器控制台用于查看桶和对象。实验里我习惯把它和 MySQL 一起用容器编排拉起来,这样环境可销毁、可重建。整个实验的「云存储」概念,就落在三个元素上:endpoint(服务地址)、bucket(桶)、object(对象),再加一组 AccessKey 和 SecretKey 做身份认证。记住这个三元组加一对密钥,后面所有代码都在跟它们打交道。
选择 MinIO 而不是别的方案,还有一层考量:它支持分片上传、预签名 URL、生命周期规则这些生产级能力。也就是说,你在实验报告里写「支持大文件分片」「临时访问凭证」不是纸上谈兵,而是真能在本地配出来、截图为证的。这一点对实验报告的含金量影响很大。
2.3 实验(四)的完整链路:上传、转存、回读,请求走一遍
把前面两张图合并成一条链路。上传一个媒体文件时,客户端把文件先发给应用服务,应用服务做两件事:第一件是把文件流转向对象存储,调用 put 接口把数据写入指定桶;第二件是在文件确认写入后,把标题、类型、大小、存储位置(桶名 + 对象键)等元数据写入 MySQL。两件事完成后,前端通过唯一标识查询元数据、拿到对象键,再向对象存储发起回读请求。
前端上传时还常带一个 Content-Type,应用服务应该把它透传给对象存储并写进元数据表。这样浏览器回读时能正确识别类型,而不是把 MP4 当二进制下载。对象键的命名也值得花两分钟设计,常见做法是按「媒体类型/年月/随机串」分层,比如 video/2025/03/a1b2c3.mp4,避免把所有文件平铺在桶根目录。这个习惯在实验里虽然看不出差别,但对真实项目影响很大。
回读路径现在有两种常见做法。第一种是应用服务把对象从对象存储下载下来,再转发给客户端,适合文件小、访问频率低的情况;第二种是应用服务不对文件流做中转,只生成一个带有效期的预签名下载地址返回给前端,浏览器直接对着桶拉文件。实验(四)建议直接上第二种,它能明显降低服务器带宽压力,也能让你在报告中多谈一段「临时凭证」的设计考量。
这条链路里最容易被忽视的是时序。我的习惯是「先文件,后记录」:文件没有写进桶之前,绝不先写数据库;反过来删除的时候,先删数据库记录,再删对象。这样即使中途失败,最坏情况是留下一个孤儿文件,可以通过对账清理,而不会出现「数据库有记录、文件却不存在」这种更糟糕的状态。时序问题在后面避坑章节还会重点展开。
3. 把实验跑起来:MinIO + MySQL 从零搭建媒体存取最小闭环
3.1 用容器拉起 MinIO 与 MySQL:实验环境的前 10 分钟
实验环境推荐用 docker-compose 一次性拉起两个服务。先在工作目录建 docker-compose.yml:
version: "3.8" services: minio: image: minio/minio:latest ports: - "9000:9000" # S3 API 端口,程序读写走这里 - "9001:9001" # 控制台端口,浏览器管理界面 environment: MINIO_ROOT_USER: minioadmin MINIO_ROOT_PASSWORD: minioadmin volumes: - ./minio-data:/data command: server /data --console-address ":9001" mysql: image: mysql:8 ports: - "3306:3306" environment: MYSQL_ROOT_PASSWORD: root123 MYSQL_DATABASE: media_db volumes: - ./mysql-data:/var/lib/mysql然后执行:
docker compose up -d docker compose ps第一个代码块里有两个容易踩的参数:MINIO_ROOT_USER 和 MINIO_ROOT_PASSWORD 是 MinIO 的初始管理员账号,同时也是程序访问用的 AccessKey 和 SecretKey,实验里为了方便都设成 minioadmin,但报告里应当注明「生产环境必须使用随机强密码并最小化权限」。第二个是 command 里的 --console-address,它把控制台端口从默认的 9000 分流到 9001,否则会和 S3 API 端口冲突。容器起来后,打开 http://localhost:9001 能看到 MinIO 控制台,说明环境就绪。
MySQL 这边要注意 MYSQL_DATABASE 会自动创建一个名为 media_db 的空库,后面的建表脚本直接在这个库里执行。两个服务都依赖宿主端口,如果 3306 或 9000 被占用,docker compose ps 会报端口错误,先把占用进程找出来或者换端口再启动。这十分钟里翻车最多的就是端口冲突和时间不同步,后者在第 5 章避坑里单说。
提示:容器启动后,如果 9001 控制台访问不了,先看 docker compose logs minio,而不是急着改代码。日志里通常直接给出端口监听失败或磁盘权限错误。
3.2 媒体元数据表设计:一张表说清楚文件在哪、多大、属于谁
服务起来后在 media_db 建一张元数据表,SQL 如下:
CREATE TABLE media_asset ( id BIGINT AUTO_INCREMENT PRIMARY KEY, title VARCHAR(255) NOT NULL COMMENT '媒体标题', media_type VARCHAR(32) NOT NULL COMMENT '类型:video/audio/image', bucket_name VARCHAR(128) NOT NULL COMMENT '对象存储桶名', object_key VARCHAR(512) NOT NULL COMMENT '对象键,如 video/2025/03/abc.mp4', content_type VARCHAR(128) COMMENT 'Content-Type,回读时告诉浏览器', size_bytes BIGINT COMMENT '文件字节数', duration_ms INT COMMENT '视频/音频时长,可选', uploader VARCHAR(64) COMMENT '上传人', created_at DATETIME DEFAULT CURRENT_TIMESTAMP, UNIQUE KEY uk_bucket_key (bucket_name, object_key) ) COMMENT '媒体资产元数据表';这张表的设计核心是 bucket_name 和 object_key 两个字段:它们是文件在对象存储中的「地址」。注意我特意没有存一个完整的 URL,因为对象存储的访问 URL 会随着 endpoint 变化、预签名参数变化而失效,不如存桶名和对象键,需要时现场拼 URL,这个设计在报告里值得写一句。uk_bucket_key 唯一索引防止同一文件被重复录入,实际操作时也可以用它做幂等校验。
media_type 和 content_type 的差别需要注意:media_type 是业务层面的分类(是视频还是图片),content_type 是 MIME 类型(video/mp4、image/jpeg),两者都存,回读时优先用后者。上传者 uploader 字段在单机实验里可能用不上,但保留它能让权限相关的讨论在报告里有落点。最后,created_at 走数据库默认时间,比代码里传时间更可靠,避免服务器时钟偏差污染数据。
3.3 上传链路:先传对象存储再写数据库(代码)
环境和服务名称有点长,我直接给最小可跑的 Python 脚本。先装依赖:
pip install boto3 pymysql然后把下面脚本存成 upload.py 运行(注意替换环境变量):
import os import boto3 import pymysql # 从环境变量读配置,避免密钥硬编码 endpoint = os.environ["S3_ENDPOINT"] # 如 http://localhost:9000 access_key = os.environ["S3_ACCESS_KEY"] # 如 minioadmin secret_key = os.environ["S3_SECRET_KEY"] # 如 minioadmin bucket_name = "media-assets" # 初始化 S3 客户端;这里的接口与公有云对象存储一致 s3 = boto3.client( "s3", endpoint_url=endpoint, aws_access_key_id=access_key, aws_secret_access_key=secret_key, region_name="us-east-1", # MinIO 默认区域 ) file_path = "sample.mp4" object_key = f"video/2025/03/{os.path.basename(file_path)}" # 第一步:确保桶存在(已存在会忽略) s3.create_bucket(Bucket=bucket_name) # 第二步:把媒体文件本体写入对象存储 with open(file_path, "rb") as f: s3.put_object( Bucket=bucket_name, Key=object_key, Body=f, ContentType="video/mp4", # 透传类型,回读时浏览器才能正确播放 ) # 第三步:文件写成功后,再写元数据 conn = pymysql.connect( host="127.0.0.1", user="root", password="root123", database="media_db", charset="utf8mb4", ) with conn.cursor() as cur: cur.execute( """INSERT INTO media_asset (title, media_type, bucket_name, object_key, content_type, size_bytes) VALUES (%s, %s, %s, %s, %s, %s)""", ("测试视频", "video", bucket_name, object_key, "video/mp4", os.path.getsize(file_path)), ) conn.commit() conn.close()脚本里有三个关键点。第一,boto3 是云对象存储生态里通用的 Python SDK,但 endpoint_url 指向 MinIO 后,所有请求都打到本地服务,这行代码就是「本地模拟云」的核心;以后迁到公有云,只需要改 endpoint 和密钥。第二,上传用的 put_object 适合 100MB 以内的文件,更大文件要用分片,参数玩法在第 4 章展开。第三,执行顺序严格是「先 put_object 后 INSERT」,如果 INSERT 抛异常,应该补一步删除刚上传的对象,避免留下脏数据。
运行前记得设置环境变量。Windows PowerShell 用 $env:S3_ENDPOINT="http://localhost:9000",Linux/macOS 直接 export 即可。首次运行如果报「The request signature we calculated does not match」,九成是系统时间和 MinIO 容器时间偏差超过 15 分钟,同步时间后重试。这一步是实验(四)开跑后最常见的翻车点。
3.4 回读链路:不经过应用服务中转,用预签名 URL 直接下载
文件传上去之后,要做的事是把它取回来。回读我建议直接用预签名 URL,代码很短:
import boto3 import os s3 = boto3.client( "s3", endpoint_url=os.environ["S3_ENDPOINT"], # http://localhost:9000 aws_access_key_id=os.environ["S3_ACCESS_KEY"], aws_secret_access_key=os.environ["S3_SECRET_KEY"], region_name="us-east-1", ) # 从数据库查出 object_key(略),然后生成 10 分钟有效的下载链接 url = s3.generate_presigned_url( "get_object", Params={"Bucket": "media-assets", "Key": "video/2025/03/sample.mp4"}, ExpiresIn=600, # 单位是秒,600 秒 = 10 分钟 ) print(url)把 url 贴到浏览器就能直接下载视频。这里的重点是:应用服务没有把文件流读进内存再转发,而是生成了一个带签名的临时 URL 交给前端。这样大文件下载不占用应用服务的内存和带宽,对象存储直接面对客户端,这是云存储架构里很标准的姿势。
参数 ExpiresIn 值得多说两句:它控制临时链接的有效期,实验里设 600 秒够了,但真实系统要考虑下载大文件耗时长,比如 2GB 文件在慢速网络下可能要几分钟,有效期设太短会让下载中途失效。另外,桶本身要保持 private,否则预签名 URL 就失去了意义——人人都能拼 URL 直接下载,签名就成了摆设。这个权限细节在第 4 章细讲。
4. 必调参数与边界:从能跑到跑稳的配置细节
4.1 桶的权限模型与 AccessKey:private 桶下怎么安全读文件
实验做到回读成功,很多人会顺手把桶策略改成 public 图省事。我的建议是:宁可麻烦,也要保持 private。对象存储的安全模型大致分两层:第一层是桶/对象级别的访问策略,第二层是访问者的身份凭证(AccessKey)。public 桶意味着任何人拿到 URL 都能读,对公开内容没问题,但实验里通常有上传者的概念,一旦涉及「谁能看这个视频」,public 就管不住了。
在 private 桶下读文件有两条路:一是用前面说的预签名 URL,二是用临时凭证(临时 AccessKey + 会话 Token)。实验阶段用预签名 URL 足够,因为它的签名本身就携带了 AccessKey 的身份信息,服务端验证通过才放行。代码里要注意的是,generate_presigned_url 默认使用创建客户端时的密钥来签名,所以如果创建客户端用的是管理员密钥,这个 URL 就拥有管理员权限,实践中应当使用只读权限的专用 AccessKey 来签发,避免 URL 泄露后对方能枚举桶里其他对象。
还有一类常见的权限翻车:MinIO 控制台里创建的 access key 和用 docker-compose 环境变量设的 root 账号不是一回事。如果代码里用的是 root 账号,但你在控制台改了密码,API 请求会立刻报 403。实验报告里最好把一个清晰的密钥表画出来:谁在用、权限到哪、用于什么操作。
4.2 大媒体文件的分片参数:超过 100MB 就别用一把梭的 put_object
实验中上传的视频超过一两百 MB 是常态。put_object 是一次性把整个对象发给服务端,文件一大,网络抖动就会导致整个请求重来。生产级的做法是分片上传(Multipart Upload):把对象切成若干片,一片一片传,每片独立校验,失败只重传该片。在 boto3 里,分片由 TransferConfig 自动控制,但要手动调参数:
from boto3.s3.transfer import TransferConfig config = TransferConfig( multipart_threshold=8 * 1024 * 1024, # 超过 8MB 自动走分片 multipart_chunksize=8 * 1024 * 1024, # 每片大小 8MB max_concurrency=4, # 同时传 4 片 use_threads=True, # 开启并发线程 ) s3.upload_file( "large_video.mp4", "media-assets", "video/2025/03/large.mp4", Config=config, )分片参数的选取有三个经验值。multipart_threshold 建议设在 8~32MB 之间,设太小会让小文件也走分片流程,增加请求次数;multipart_chunksize 决定每片大小,网络差就调小(比如 4MB)、网络好可以调大到 16MB,目的是让单片传输能在超时时间内完成;max_concurrency 控制并发片数,实验机器一般 4 够用,调太高可能把网卡打满。注意 upload_file 内部会自动用分片和断点续传,比手动 put_object 适合大文件,失败时还会保留已传的分片,不能重复调用会报「已在执行」的错,需要调用 abort_multipart_upload 清理。
4.3 事务边界:数据库与对象存储之间没有两阶段提交
上传链路里「先写对象存储还是先写数据库」看似只是顺序问题,实际是分布式系统的经典难题:两个独立的存储之间没有事务。顺序选错了,各有一类脏数据。两种顺序的失败后果和补偿方式可以放在一张表里看:
| 写入顺序 | 失败后果 | 补偿方式 |
|---|---|---|
| 先写数据库,再传文件 | 记录存在但文件 404 | 任务重传文件,或标记记录异常 |
| 先传文件,再写数据库 | 对象存在但记录缺失(孤儿文件) | 删除对象或补写元数据 |
我的做法是「先对象、后数据库、失败补偿」。对象写入成功后,数据库写入失败或进程崩溃,就用 delete_object 把刚传的对象删掉;反过来如果删除了对象、数据库删除失败,就再插一条记录标记异常。这些补偿逻辑在实验里可能用不到,但报告里画出这段「补偿路径」,老师一眼能看出你理解了这个边界。更彻底的对账方案是定时任务扫描:每天比对数据库记录的 object_key 是否在桶里,反过来再扫桶里的对象是否都有记录,发现不一致就告警或清理。
这一段讨论也是实验报告里最值得写「设计反思」的地方:什么时候能接受最终一致性,什么时候必须强一致,取决于业务是「内容发布」还是「订单支付」。媒体管理大多能接受秒级的最终一致,所以「先对象、后数据库」的补偿方案足够。
4.4 存储成本与生命周期:实验数据也要学会自动过期
对象存储便宜的错觉常常让人忽略垃圾数据的积累。实验里反复上传几 GB 的视频、图片,一段时间后磁盘就被占满,MinIO 直接拒绝写入。生产上一个常见的治理手段是生命周期规则:按前缀或标签设置过期时间,对象到时自动删除。MinIO 控制台里就可以配,也可以用 API 下发,这里给一个简化版:
s3.put_bucket_lifecycle_configuration( Bucket="media-assets", LifecycleConfiguration={ "Rules": [{ "ID": "expire-temp", "Filter": {"Prefix": "temp/"}, "Status": "Enabled", "Expiration": {"Days": 7}, }] } )这条规则的意思是:temp/ 前缀下的对象 7 天后自动删除。实验里可以把临时转码产物、失败重传的半成品丢进这个前缀,正式素材放在 media/ 前缀下不设过期。把这部分写进实验报告,能够展示你对「存储成本」有意识,而不只是把功能跑通。另外注意生命周期规则删除是不可逆的,配置时先在小范围的测试桶上跑几天验证,别拿装正式数据的桶当试验田。
5. 实验报告避坑指南:五个翻车现场与排查路径
5.1 上传成功但列表查不到:写入顺序与一致性问题
现象:脚本执行完没有报错,MinIO 控制台桶里也有对象,但数据库里查不到记录,或者反过来数据库有记录、回读时对象 404。
原因:最常见的是写入顺序没统一——有的分支先写库再传文件,有的先传文件再写库,一旦中途抛异常没有补偿,两边就永久不一致。另一种可能是 bucket 名大小写写错(S3 的桶名必须小写),传到了另一个桶里。
解决:统一「先对象、后记录、失败删对象」的流程;在脚本结束前加一段校验,传完文件后立刻 SELECT 元数据表确认记录存在;如果发现不一致,宁可删掉重传,也不要手工 INSERT 一条「看起来对」的记录。控制台里看不到对象时,第一件事不是查代码,而是确认 endpoint 到底指向哪台机器。
5.2 预签名 URL 几秒就失效:时钟偏移与有效期参数
现象:生成的下载链接,粘贴到浏览器打开立刻提示签名过期,明明设置了 ExpiresIn=600。
原因:预签名 URL 的签名依赖时间戳。MinIO 容器和宿主机时间相差超过 15 分钟时,签名直接判定无效;另一个常见原因是 Windows 宿主机时间时区没设置好,容器拿到的是 UTC,和本地时间相差 8 小时,看起来就是「刚生成就过期」。
解决:先执行 date -u 和容器内时间对比,相差超过 1 分钟就同步时间或重启容器;确认 ExpiresIn 的单位是秒,不是毫秒;如果链接要在浏览器里测试,注意别用缓存模式,换个无痕窗口再验证。
5.3 大视频上传超时:网关超时与未分片
现象:传 1GB 视频时,脚本跑到一半报 requests 超时,或者网关层提示 504。
原因:底层 Socket 超时设得太短,大文件传输超过默认超时时间就被掐断;或者没走分片上传,一个几 GB 的 put_object 请求在网关层直接超时。
解决:boto3 显式设置更大的连接和读取超时(如 connect_timeout=10, read_timeout=300,单位秒),同时用 4.2 节的分片上传;如果走了反向代理,把代理的读取超时调到 600 以上。排查时先用小文件测通,再逐步加压,分不清是网络问题还是服务端问题时,用 curl -v 直接测一个 200MB 的文件传一遍。
5.4 删了数据库记录但桶里还有文件:孤儿文件与存储泄漏
现象:在管理页面删掉媒体记录,MinIO 里对象还在,磁盘占用不减,甚至因为反复上传、删除导致磁盘一点点涨满。
原因:删除逻辑只删了 MySQL 里的行,没调 delete_object。这是实验报告里最明显的设计缺口,任何人都会问一句「文件呢」。
解决:实现删除接口时,先查数据库拿到 bucket_name 和 object_key,再调用 s3.delete_object,最后删数据库行。两步之间如果失败,要有一个补偿标记(比如 status 字段置为 deleted,由定时任务补删对象)。实验里至少要把「先删对象、后删记录」的顺序写进代码注释,并在报告的数据流图上标出来。
5.5 局域网内下载速度上不去:内网域名与 Region 配置
现象:同一局域网内,浏览器下载 500MB 视频只有几 MB/s,但直接到服务器上用工具下载却很快。
原因:客户端用了公网 endpoint 回源,流量绕了一圈;或者 boto3 客户端 region_name 和 MinIO 实际配置不一致,请求被重定向。
解决:实验环境把 endpoint 配成服务器内网 IP 或主机名(如 http://192.168.x.x:9000),别用 localhost 或公网域名;确保 S3 客户端 region_name 是 us-east-1 或者与 MinIO 环境变量 MINIO_REGION 一致。如果 MinIO 部署在 Docker 里,宿主机访问用 localhost 没问题,但其他机器访问必须用宿主机 IP,容器内部 IP 对外不可达,这也是「本机能下、别人不能下」的常见原因。
6. 从实验报告到真正项目:验证实验结论的三个进阶动作
6.1 「删库跑路」验证独立性
实验做完功能验证后,我习惯多做一个「破坏性测试」:把 MySQL 里 media_asset 表清空,然后去 MinIO 控制台确认对象还在;再把桶里的对象删掉一部分,回到数据库看记录还在。这个测试直观地证明「数据库和对象存储是两个独立系统」,这正是实验(四)想要的结论。报告里写这一步时,把测试前后的控制台截图放上去,比写十行空话有力得多。做完测试别忘了恢复数据:对象没丢就重新导入记录,文件丢了就重传,别带着脏数据交实验。
6.2 给媒体加一个处理管道:缩略图与转码
真实媒体系统不会只存原片,通常还会在对象存储里保留多个衍生文件。实验可以加一步:上传视频后,用 ffmpeg 截一帧作为缩略图,再用 Pillow 压缩成小图,把缩略图的 object_key 写进元数据表的一个新字段。这样前端列表页只加载几十 KB 的缩略图,点开详情才拉原视频。核心代码其实只有两行:ffmpeg 截帧命令和一张表的 ALTER 语句,但它把一个单机实验带到了「媒体处理管道」的高度。
6.3 实验报告数据流图必画的四个节点
如果只画一张图,画四节点五条线的数据流:客户端、应用服务、对象存储、媒体数据库,四者之间标出上传路径、元数据写入路径、下载路径、删除路径和补偿路径。重点标注「先文件后记录」的顺序和「删除时先对象后记录」的时序,把 5.4 节的孤儿文件问题、4.3 节的补偿逻辑画在虚线路径上。这张图能看出你是否理解「媒体数据库与云存储」的分工本质,也是答辩时被追问最多的部分。
做实验这几年,我最大的血泪经验是:功能跑通不算什么,能把边界条件想清楚、能把失败路径画出来,才算真的把实验吃透。写报告时宁可多画一条补偿路径,也别堆功能截图。希望帮到你。
本文还有配套的精品资源,点击获取