用redis来存储标签和用户的对应关系.
key: 标签
value: 每个用户一个比特位, 1表示有该标签属性, 0 表示没有该标签属性.
操作逻辑例如:
1. 取出带有某几个标签的用户.
比特与操作, 取出最终结果为1的比特位置.
例如
postgres=# select bit '10' & bit '11';
?column?
----------
10
(1 row)
2. 取出不带某个标签的用户.
以上结果与比特异或操作,
postgres=# select bit '10' & (bit '10' # bit '11');
?column?
----------
00
(1 row)
建立用户和比特位置的对应关系.
用户ID, 比特位置
通过对应关系取出用户ID.
分库方案 :
假设总共不会超过20万个标签.
内存为256GB
x为用户数, (1000000*x)/8为消耗的内存字节数.
256GB可以存储约1000万用户.
(1000000*x)/8=256*1024*1024*1024
x=10995115
那么如果我们有10亿用户的话, 需要100台这样的服务器来支撑.
每台服务器存储20万个标签, 1000万个用户, 每个键值需要1374389字节.
对于带权重的标签, 本方案不合适.
本方案只适合布尔逻辑值的标签.
如果资源紧张的话, 可以考虑PostgreSQL的解决方案.
PostgreSQL存储持久化数据, 并将redis的比特位操作函数移植到PostgreSQL.
在PostgreSQL中使用大对象存储用户比特位的信息.
必须注意, PostgreSQL的多版本并发控制, 更新会产生新的版本. 所以必须搞清楚大对象的操作会不会产生多版本, 如果产生多版本, 那么是不是仅仅产生chunk的多版本. 应该尽量避免多版本的产生, 否则PostgreSQL可能不适合用于此场景.
大对象的操作接口如下 :
http://www.postgresql.org/docs/9.4/static/largeobjects.html
[参考]
1. http://blog.getspool.com/2011/11/29/fast-easy-realtime-metrics-using-redis-bitmaps/