本文目录导读:

在 Laravel 中实现去重,使用 Redis 的 SET 是非常常见且高效的做法,不过具体用不用、怎么用,取决于你的业务场景和去重的粒度。
下面我分几种情况帮你分析,并给出代码示例。
为什么 Redis SET 适合去重?
- 天然无序、元素唯一:
SADD添加重复元素会返回 0,利用这一点可以判断是否已存在。 - 内存高效:对于几百万甚至上千万的 ID 或字符串,Redis SET 性能依然很好。
- 原子操作:
SADD+ 判断是否新增一步到位,避免竞态条件。
典型场景:防止重复消费消息
比如队列消费者收到消息后,先判断该消息是否处理过。
use Illuminate\Support\Facades\Redis;
public function handle(array $data)
{
$uniqueKey = $data['order_id']; // 或 md5(序列化)
// 尝试加入 SET,如果已存在则跳过
$added = Redis::sadd('processed_orders', $uniqueKey);
if (! $added) {
Log::info('已处理过,跳过', $orderId);
return;
}
// 业务逻辑...
}
注意:SADD 返回 1 表示成功添加,返回 0 表示已存在。
场景:每日去重(带有效期)
去重通常需要设置过期时间,避免 SET 无限增长,Redis SET 本身不支持单个元素过期,但可以对整个 Key 设置 TTL。
$date = now()->format('Y-m-d');
$key = "unique_visitors:{$date}";
// 添加用户 ID
$isNew = Redis::sadd($key, $userId);
// 如果是当天首次添加,设置过期时间(48 小时)
if ($isNew) {
Redis::expire($key, 48 * 3600); // 48小时自动清理
}
大规模去重(亿级)的优化建议
如果单日数据量极大(比如上亿),Redis SET 的内存压力会很大,此时可以考虑:
| 方案 | 说明 | 推荐场景 |
|---|---|---|
| Redis HyperLogLog | 只统计唯一数,不能取出具体元素,内存极小 | 统计 UV、不关心具体谁访问过 |
| Redis Bloom Filter | 概率性去重,有误判率,但内存固定 | 大流量过滤、消息去重可接受极低误判 |
| 分片 SET | 将 ID 按哈希分散到多个 SET,降低单 Key 大小 | 百亿级 ID,内存仍可承受 |
示例:使用 HyperLogLog 统计唯一数量(不关心具体元素)
// 添加
Redis::pfadd('uv_page_1', $userId);
// 获取近似唯一数
$count = Redis::pfcount('uv_page_1');
常见陷阱 & 最佳实践
❌ 不要用 SMEMBERS 检查是否存在
SMEMBERS会返回所有元素,O(n) 操作,数据量大时会阻塞 Redis。- ✅ 应使用
SISMEMBER或SADD返回值。
✅ 使用 Pipeline 批量去重
批量添加多条数据时,用 Pipeline 减少网络开销:
Redis::pipeline(function ($pipe) use ($items) {
foreach ($items as $item) {
$pipe->sadd('batch_set', $item);
}
});
✅ 设置合理过期策略
- 如果业务允许,给 SET 加 TTL,避免长期占用内存。
- 如果需要长期保留,考虑将数据转存到 MySQL 或归档。
- 一般场景:直接使用 Redis
SET去重,简单高效。 - 需要统计唯一数:用
HyperLogLog。 - 海量数据、可容忍极低误判:用
Bloom Filter(Laravel 需安装predis/predis或 phpredis 扩展,并借助第三方库实现)。 - 核心思路:利用
SADD的返回值判断是否首次插入。
如果你能具体描述一下你的业务场景(比如大概的并发量、数据量、去重依据是什么),我可以给你更精准的建议。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播
英超直播