分布式缓存的切片模式-hash一致性切片

本文探讨了使用缓存如Redis的原因,解释了为何需要分布式缓存,介绍了主从复制和切片模式。重点讨论了常规切片模式的弊端,提出了一致性Hash的解决方案,以应对数据倾斜问题。通过创建数据库副本,实现了数据的均衡分布,提高了系统的稳定性和扩展性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一 为什么使用缓存

当前,我们通常使用Redis缓存,因为它有更多的数据类型,并且支持事物。之所以要使用缓存,是为了缓解查询数据库时的IO压力,我们将经常查的热点数据放到缓存里(内存中),当然比存在磁盘上的mysql数据库快了。

二 为什么使用分布式

那为什么要使用分布式架构呢?第一就是解决一台redis服务器容量不一定够啊,那无限扩容不行吗?当然不行,难道每次容量不够了就换一台容量更大的redis服务器?另外如果押宝在一台缓存数据库上,如果它坏了,岂不是gg?综上所述,分布式缓存就来啦

三 使用什么模式

部署分布式架构时有很多模式,这里主要介绍两种:主从复制模式,切片模式。
所谓主从复制模式/主从备份模式,很简单,例如设置一个主库,两个从库,进行写操作时对主库进行操作,主库自动同步,进行读操作时从从库读。想必大家可以看出来,这样很费容量,无法起到缓解内存大小压力的作用。
另一种模式就是切片模式,什么是切片模式,很简单,每一个数据用hash算法算完后对库数取模,放到对应的库中,这样每一个库都可以得到使用,即便挂了一个库也不会完全停摆。

四 常规切片模式的弊端

我们在开发一个项目时,扩展性是我们考虑的重点,部署数据库时也是一样。对于我们的项目,考虑到热点数据量可能超过我们当前的几个缓存数据库的总容量是有可能发生的,我们必然要增加更多数据库,但是按照切片模式的规则,一旦增加一个数据库,每个数据库保存的数据都可能要进行迁移,如果数据量过大,这一瞬间产生的数据移动就够系统喝一壶了,更别说redis数据库还是单线程的,如果大量被占用处理这件事,其他操作必然会遭到滞后。

五 更加犀利的切片模式-hash一致性切片

在这里插入图片描述
使用hash一致性算法,例如这个圆环上一共2^32个节点,我们将对数据库的ip和序号进行hash,放到这些节点中的一个里,当有数据时对数据进行hash,也放到某个节点,如上图
椭圆的是数据库,圆形的是数据,我们将当前数据库前那一部分数据放进当前数据库,如图中颜色标记,当我们增加一个数据库Redis3,如下图:
在这里插入图片描述我们不再需要移动所有数据,而只是将原本应该放进Redis1中的两个标红数据放进Redis3,完美!!!但是,真的完美吗?

六 不完美的数据倾斜以及解决方案

6.1 数据倾斜

我们看到在第一幅图中,大部分数据被放进Redis1,少部分数据被放入Redis2中,不均匀了,这会导致每个数据库不能充分利用,旱的旱死,涝的涝死,这就是数据倾斜。

6.2 解决办法

解决办法很简单,给每个数据库创建n个副本,如下图:
在这里插入图片描述这里需要注意,虽然创建多个副本,但并不意味着数据库数量增加了,只是逻辑上数据被这两个数据库均匀的瓜分了。

<think>嗯,用户问的是在UniApp中实现文件上传切片的功能。首先,我得回忆一下UniApp的文件处理机制。UniApp支持多端运行,所以得考虑跨平台的兼容性,比如H5和微信小程序可能有些API不同。然后,文件切片通常需要用到File对象的slice方法,但UniApp里可能要用UniFile对象,或者需要适配不同平台的差异。 接下来,用户可能需要分片上传的具体步骤。首先,如何将大文件切成小片。可能需要用到Blob对象的slice方法,比如H5环境下,但在小程序里可能需要不同的处理方式。然后,每个分片需要上传到服务器,并且记录上传进度,可能需要用到Promise.all或者队列控制并发数。 然后,考虑到后端需要接收这些分片,可能需要一个唯一标识符来合并文件。前端生成fileId,比如用md5或者随机字符串,每个分片上传时携带这个fileId和分片索引chunkIndex。后端根据这些信息将分片存储,并在所有分片上传完成后合并。 另外,用户可能还关心断点续传和进度显示。进度显示可以通过监听每个分片的上传进度,然后计算总体进度。断点续传则需要检查哪些分片已经上传,避免重复上传,可能需要用到本地缓存或者后端返回已上传的分片列表。 还要注意UniApp中的API使用,比如uni.uploadFile,这个API在小程序和H5中的表现是否一致。可能需要处理不同平台的兼容性问题,比如在H5中使用标准的FormData,而在小程序中可能需要不同的方式。 代码示例方面,需要展示如何选择文件、切片、上传分片、处理并发、合并请求等步骤。可能还需要使用第三方库如spark-md5来生成文件哈希,确保唯一性。同时,进度更新可能需要结合Vue的数据响应式,实时更新界面上的进度条。 最后,要确保引用的参考资料相关,比如提到的使用Hash结构存储上传进度,这来自引用3和4,需要在回答中正确标注引用。同时,用户可能没有说出来的深层需求,比如上传失败的重试机制,或者网络不稳定时的处理,这些也可以在相关问题和优化建议中提到。</think>以下是在UniApp中实现文件上传切片功能的详细实现方案: ### 一、核心实现步骤 1. **文件切片处理** ```javascript function createFileChunks(file, chunkSize = 5 * 1024 * 1024) { const chunks = [] let start = 0 while (start < file.size) { const end = Math.min(start + chunkSize, file.size) const chunk = file.slice(start, end) // 使用HTML5 File API chunks.push({ index: chunks.length, chunk: chunk, fileSize: file.size }) start = end } return chunks } ``` 2. **生成文件唯一标识(使用SparkMD5库)** ```javascript import SparkMD5 from 'spark-md5' async function generateFileHash(file) { return new Promise((resolve) => { const spark = new SparkMD5.ArrayBuffer() const reader = new FileReader() reader.onload = (e) => { spark.append(e.target.result) resolve(spark.end()) } reader.readAsArrayBuffer(file) }) } ``` 3. **分片上传实现** ```javascript async function uploadChunks(file, chunks) { const fileHash = await generateFileHash(file) const requests = chunks.map((chunkItem) => { const formData = new FormData() formData.append('file', chunkItem.chunk) formData.append('chunkIndex', chunkItem.index) formData.append('fileHash', fileHash) formData.append('totalChunks', chunks.length) return uni.uploadFile({ url: 'https://your-api.com/upload', filePath: chunkItem.chunk, name: 'file', formData: formData }) }) // 控制并发数量 const maxConcurrent = 3 const pool = [] for (let i = 0; i < requests.length; i++) { const task = requests[i] const result = await task pool.push(result) if (pool.length >= maxConcurrent) { await Promise.race(pool) } } await Promise.all(pool) } ``` ### 二、进度监控实现 ```javascript // 在data中定义 data() { return { uploadProgress: 0, uploadedChunks: new Set() } } // 修改上传方法 uni.uploadFile({ success: () => { this.uploadedChunks.add(chunkIndex) this.uploadProgress = Math.floor( (this.uploadedChunks.size / totalChunks) * 100 ) } }) ``` ### 三、断点续传实现 ```javascript async function checkUploadStatus(fileHash) { const res = await uni.request({ url: 'https://your-api.com/check-status', data: { fileHash } }) return res.data.uploadedIndexes // 返回已上传的分片索引数组[^3] } // 上传前检查 const uploadedIndexes = await checkUploadStatus(fileHash) const filteredChunks = chunks.filter( chunk => !uploadedIndexes.includes(chunk.index) ) ``` ### 四、服务端对接要点 1. 使用Redis存储上传状态: ```javascript // 伪代码示例 redis.hset(`file:${fileHash}`, chunkIndex, 'true') // 记录分片状态 ``` 2. 合并文件时需按分片索引顺序拼接二进制数据 **注意事项:** - 微信小程序需使用`uni.chooseMessageFile`获取文件 - iOS系统需处理相册权限`scope.writePhotosAlbum` - 大文件处理建议使用Web Worker防止界面卡顿
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

油光发亮的小猛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值