具体场景是,每个用户有个推荐列表,推荐列表是千级别的物品 ID,但物品是高频度变更的,下架、失效、用户屏蔽等等,所以希望是近实时在线的去判断这几千个 ID 的状态。
目前有尝试使用 elasticsearch 进行实时的请求,但实际发现在峰值请求下,每次 request 都是千级别的 ID 过滤,es 还是扛不住,查了下 Google,es 官方也表示不适合这种超多的过滤场景。
因此想请教更合适的技术方案是什么?
1
li24361 2020-09-15 11:30:56 +08:00
bloom filter
|
2
chihiro2014 2020-09-15 11:38:06 +08:00
布隆过滤器,宁错杀不放过,可以用 Guava 里面的。
前段时间一朋友的电网项目里就用了这个,因为机器原因,处理几十万条还是扛得住的 |
3
Nillouise 2020-09-15 11:39:59 +08:00
虽然不了解这个场景,但没看明白难点是什么?几千个商品放在内存里处理不就行了吗?还是每个用户的推荐商品都不一样,要实时处理每个用户*1000 个商品的数量?
|
4
Morriaty OP |
6
vZexc0m 2020-09-15 14:57:44 +08:00
Redis 集合(Set)
|
7
Nillouise 2020-09-15 15:17:54 +08:00
我理解了,你是每次查询的时时候要把 1000 个 id 拿去给 elasticsearch 查。但这里做一个分布式查询不是很简单吗? id 为 1 就只查第一台机器,id 为 2 就查第二台机器。布隆过滤器应该很难处理用户屏蔽这种功能。
|
9
mymike 2020-09-15 15:21:26 +08:00
物品状态和用户屏蔽可以做缓存(两种缓存的策略要单独考虑),如果需要做到强一致必然会影响整体性能,而大量的过滤肯定是不可取的,推荐列表是否可分页,降低过滤范围
|
10
ychost 2020-09-15 15:21:53 +08:00
布隆过滤器
|
11
Morriaty OP @Nillouise 实际是有个千万级的 item 索引,每次查询 1000 个左右的 item_id 的 status,对应的 es query 是:
{ "query": { "bool": { "filter": [ { "term": { "status": { "value": "1" } } }, { "terms": { "item_id": ["id1", "id2", ..., "id1000"] } } ] } } } 流量大峰值的时段,其中 terms 那个查询 es 扛不住 |
12
Morriaty OP @mymike 终于有人说到点上了,朋友你应该也是做搜索推荐的吧。你说的这种后过滤有个比较麻烦的问题是,分页后请求,被过滤掉的部分,就得补全,补全的部分还要从下个分页里去掉,导致分页逻辑极其复杂
|
13
mymike 2020-09-15 17:06:07 +08:00
可以考虑客户端来补全,后端仅负责过滤,不保证每个分页的内容数量
|
14
Nillouise 2020-09-15 17:14:18 +08:00
这种过滤在应用服务器上做不就行了吗,一次从数据库把 1000 个 id 相关的信息全部提取出来,用 habse 之类应该没啥问题把。这种需求分布式系统要做到线性增加吞吐量有何难点?我学过一点分布式,但没实践过,希望有大佬说明一下。
|
15
wysnylc 2020-09-15 17:14:38 +08:00
bloom filter 用之前得用普通的 map 搞个白名单,要不然误判是无法处理的
|
16
whp1473 2020-09-16 17:11:37 +08:00
实时性高效率查询,只有用内存才能办到,对 item_id 的状态进行保存,比如 Redis 使用 Hash 结构,key 保存用户 ID,Map 里保存推荐商品 ID 和状态,每个用户持有不同的推荐商品状态。Redis 和数据库同步可以考虑同步代码,也可以用消息中间件解耦,但要考虑消息的消费速率。
|
17
whp1473 2020-09-16 17:18:37 +08:00
对于 es,数据过多深度分页时,可以考虑通过游标来进行查询,比直接使用分页效率高。
|
19
licn 2020-09-17 10:41:44 +08:00
这个还是和客户端一起处理,被用户屏蔽的可以由客户端在做过滤
|