关键的一点在于,把超大文件转换为小文件上传。
因此,技术难点就会放在如何保障小文件的合并、不丢失和性能。
我们先解决第一个问题,小文件的合并准确。
小文件在前端采用统一的算法切分,要确保每次切分出来的文件都一样。并小文件和大文件分别生成hash码,用于后端合并后进行小文件和合并后的大文件进行检测。
其次,我们解决不丢失的问题。
部分小文件上传后,前端浏览器崩溃或网络崩溃等导致后续上传不全的情况时,我们需要在后端存储好小文件,保障已上传的小文件不丢失。像OBS本身可以做分片上传,它默认小分片永久保留,为了成本考虑,可以妥协设置3天的过期清理的时间。
最后,我们解决性能问题。
这里性能问题的重点在于保障每次不要重复上传小文件,所以上传小文件时,设置一个上传检查,检验大文件是否有过上传,小文件hash码是否已上传,如果回答都为是,则跳过该小文件上传。
对这类问题,采用基本原理是化大为小,串行变并行。
以前遇到一个相似的问题,是从一个极大的广告池子里获取最贴近用户画像的5条广告。也用了相似的思路,把极大池子按类型分几个小池子,对大量中间广告而言,它触达用户的概率其实没有变化。 假设广告总体是N,用户拿到某一个广告的概率是5/N; 分5个池子后,用户拿到该广告的概率是5*1/5 * 1/N/5 = 5/N 。 可以看到概率是一致的。
不过这里仍有一点业务问题,对一些顶级广告而言,这个概率其实还是变相降低了,本来必定出现的广告现在有了一定概率不出现,不出现的概率是 4/5 * 4/5 * 4/5 *4/5 * 4/5 = 1024/3125 ,这个概率接近1/3,所以对公司来说,它可能造成收益下降。(因为顶级广告能赚更多钱)为了规避,又得建立一个动态的顶级广告池,确保每次一定要先去这个池子里进行一次匹配。这样做了之后,是否能收益最高呢,也不一定,因为是否是顶级广告是一个规则去判定的,它不一定精准。这样看回到一个大池子又很合理,但大池子又会导致性能问题,而丢失一部分曝光流量。
仔细思考后,会发现大到一定程度用分池加分级更有效,反之,在统一池子里更有效。
接着上面的思考,我们发现分级分池仍有一些缺陷,进一步思考,我们发现,如果设置一个多路召回,每次都从小池子里召回5条广告,它就会满足在同一个大池子获取顶级广告的优势;同时,因为每次从小池子中检索,它又避免了大数据导致的计算瓶颈;这个思想接近大数据的map-reduce的处理思维。
这个原理是利用了多级目录检索,首先分小池子,再在小池子冗余获取小部分数据,最后再从汇总数据中排序获取最好的5条广告。
这个思维方式并不罕见,很多数据库都支持分片、分库,都是化大为小的思维。
只是在业务中,数据并不平权,导致这种分片、分库,不一定是最优的策略。
因此也许还可以设计出一种特别的数据库,它支持分片,同时支持多路冗余召回。它不满足传统需要的分页查询,它也不是为了分页查询而设计;而是为了一种特有的场景,用户每次只需要最符合要求的少数数据,但不希望耗时过长,又不希望漏掉最有价值的某些数据。
进一步联想,可以发现它特别适合做RAG数据库。
当前的向量检索数据库Mivuls 正是拥有这一特性的数据库,它支持多路召回,同时每一路都获取TOP k条数据。