You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于Firebase实现用户拉黑功能及查询优化的技术咨询

嘿,这个场景我太熟悉了——做附近陌生人社交类应用,拉黑/屏蔽逻辑的性能优化绝对是绕不开的坎,尤其是你这种需要频繁校验双向拉黑关系的场景,直接查其他用户的拉黑列表完全是死路一条,用户量上来分分钟把数据库打崩。给你几个经过实战验证的解决方案,按优先级排序:

核心解决方案思路

1. 重构拉黑关系的存储结构,反向存储"被拉黑"关系

你现在的问题根源在于,要判断"谁拉黑了我",需要遍历对方的拉黑列表,这是O(n)的低效操作。我们可以把拉黑关系双向存储:

  • 当用户A拉黑用户B时,同时写入两条记录:
    1. blocked_list:A → 存储A拉黑的所有用户ID(用于过滤A要发送消息的对象)
    2. blocked_by_list:B → 存储所有拉黑B的用户ID(用于快速判断哪些用户不能给B发消息)

具体实现(以Redis为例,比关系型数据库更适合这种高频读写场景):

# 用户123拉黑用户456
SADD user:123:blocked 456
SADD user:456:blocked_by 123

# 用户123取消拉黑用户456
SREM user:123:blocked 456
SREM user:456:blocked_by 123

这样你的消息发送逻辑就可以改成:

  1. 随机获取10位附近用户ID列表candidates
  2. 从user:current_user:blocked中获取自己拉黑的用户集合my_blocked,先从candidates中排除这些ID
  3. 对剩余的候选用户,批量检查他们的blocked_by集合是否包含当前用户ID(也就是判断对方有没有拉黑我)
  4. 从最终过滤后的列表里随机选一位发送消息

2. 用批量查询代替循环单查,减少IO次数

不要对每个候选用户单独查一次拉黑关系,用批量命令一次性搞定:

示例(Python+Redis批量校验):

import redis
import random

r = redis.Redis(host="your_redis_host", port=6379)

current_user_id = 123
candidates = [456, 789, 101112, 131415]  # 随机获取的10个附近用户ID

# 第一步:过滤自己拉黑的用户
my_blocked = r.smembers(f"user:{current_user_id}:blocked")
filtered_candidates = [uid for uid in candidates if uid not in my_blocked]

# 第二步:批量检查对方是否拉黑我
pipe = r.pipeline()
for uid in filtered_candidates:
    pipe.sismember(f"user:{uid}:blocked_by", current_user_id)
results = pipe.execute()

# 过滤掉拉黑我的用户
final_candidates = [uid for uid, is_blocked in zip(filtered_candidates, results) if not is_blocked]

# 随机选一位发送消息
if final_candidates:
    target_user = random.choice(final_candidates)
    # 执行消息发送逻辑...

3. 缓存预热+异步更新,降低数据库压力

如果你们用的是关系型数据库存储拉黑关系(比如MySQL),一定要在Redis做缓存:

  • 用户登录/上线时,把自己的blocked和blocked_by列表同步到Redis
  • 当用户拉黑/取消拉黑时,先更新数据库,再异步更新Redis(用消息队列比如RabbitMQ/Kafka,或者直接Redis事务)
  • 给缓存设置合理的过期时间(比如1小时),同时允许主动触发更新(比如用户修改拉黑列表时立即更新)

4. 预计算候选池,减少实时过滤开销

如果附近用户的数量足够多,可以提前预计算符合条件的用户池:

  • 后台异步任务定期(比如每5分钟)给每个用户生成一个"可发送消息的附近用户列表",过滤掉自己拉黑的和拉黑自己的用户
  • 发送消息时直接从这个预计算的列表里随机选,不用实时过滤
  • 注意:当用户修改拉黑列表时,要立即触发该用户和被拉黑用户的候选池更新

5. 退而求其次:放宽过滤逻辑(如果性能压力实在太大)

如果以上方案都暂时没法落地,可以考虑折中:

  • 先过滤自己拉黑的用户,然后随机选一位,发送前再检查对方是否拉黑我
  • 如果对方拉黑了我,就重新选下一位,直到找到符合条件的用户
  • 这种方式的好处是实现简单,但极端情况下可能会多次重试(比如10个候选全拉黑了我),适合用户拉黑率不高的场景

内容的提问来源于stack exchange,提问作者Dridia

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 08:13:31