RT,例如假设,每天有 50W IP 的访问,用户进入网站,会随机返回一个 302 的响应,然后跳转到一个随机的 URL。用户第二次进来,会查询数据库中是否存在该 IP,存在,则跳转到第一次访问的随机 URL。
也就是说,要做一个 IP 和 随机 URL 的映射关系表,这个表数据量很大,假设是 50W,这些数据可以在一天后清除的。怎么做才能尽可能实现高性能,不影响网站用户体验?
目前想到 Redis,但是好像 Redis 每秒只能查询 20W 次?那要遍历 50W 次的话,好像挺久的……
非科班设计师出身,轻喷……
我原本以为 Redis 的 Hash 是遍历完成查询的,基础不行啊……
最终采用的方案是 Redis。就用 Redis 里简单的 HSET 和 HGET 就好了。过期时间的话,设置了一个定时任务每次自动清理数据。
1
qiayue 2017-10-11 19:50:28 +08:00
“ Redis 每秒只能查询 20W 次”
这个结论哪里来的? |
2
187j3x1 2017-10-11 19:53:46 +08:00
hash table 原理嘛? 50 万 50 亿都是差不多速度的,吃内存而已
|
3
Loyalsoldier OP |
4
yankebupt 2017-10-11 20:13:28 +08:00
为什么要遍历?由于 ip 地址特性 int32(ipv4)可以加速不用遍历的。
一提到这个就想起最近的动态路由屏蔽表...估计规则数也比你那个不少...那个是真的大访问量...我一直在想那个是怎么跑起来的...有可能是特殊硬件吧?... 我看到第一个回复查询 20W 次,还以为 20W+访问量..... |
5
yankebupt 2017-10-11 20:16:33 +08:00
总有股维和感,我总觉得楼主的意思是不是反过来,是不是想根据 url 记录如果没有随机返回一个 ip 并绑定。
|
6
Loyalsoldier OP |
7
yankebupt 2017-10-11 20:34:40 +08:00
我觉得楼主如果之后回帖:
我发现一个好方法,把库分成两部分,一部分存国内 ip 和 url,一部分存国外 ip 和 url...根据访问热度和管理要求实现不同查询性能......实现 90%以上的满意度... 的话 我会后悔在这个主题回帖的..... 所以楼主,稍微详细一点说明你的实际使用情况? 还有为什么就选定 redis 了 |
8
yankebupt 2017-10-11 20:45:16 +08:00
不要误解我。我是说大多数情况下技术人员会根据热度,分不同的使用用户,高频用户给一个很小的高速查询库,响应极其迅速,查不到再查之外的逐步扩大。但是涉及你这种情况如果这样做实际上是违背网络公平性的,会加大非高频用户的延迟,加之我 redis 基本没碰过,所以完全不能给出有效建议,请见谅。
|
9
xmcp 2017-10-11 20:46:13 +08:00 1
二分查找是 O(logN) 级别的,50W 肯定没问题呀。楼主要是挨个遍历强行卡成 O(N) 肯定就 gg 了呀……
另外不知道你的需求是什么,如果你只需要“清空所有映射”,不需要“删除特定映射”的话,不妨直接弄个 hash 的算法,URL=hash(salt+IP),想要清空的话换个 salt 就行了,查询 O(1),岂不美哉? |
10
Loyalsoldier OP @yankebupt #7
用户从 a.com (入口域名) 访问网站,后端拿到该用户的 IP 地址(假设是 1.1.1.1),随机从可选的 URL 中返回一个给该用户,假设返回 b.com (目标域名),这时候 1.1.1.1 就对应 b.com 。在当天内,用户 1.1.1.1 再次从 a.com 访问进行访问,为了保证用户在当天内看到同样的页面内容,这时候需要给用户返回跟第一次访问时一样的 URL。查询数据库发现,1.1.1.1 对应 b.com ,这时候给用户 1.1.1.1 返回 b.com 但是当一天内访问的用户量足够大的时候,查询“目标域名”的操作就会很慢了吧,所以问,用什么技术方案来实现这个需求,用户能最快访问到目标 URL |
11
Loyalsoldier OP @xmcp #9
用户从 a.com (入口域名) 访问网站,后端拿到该用户的 IP 地址(假设是 1.1.1.1),随机从可选的 URL 中返回一个给该用户,假设返回 b.com (目标域名),这时候 1.1.1.1 就对应 b.com 。在当天内,用户 1.1.1.1 再次从 a.com 访问进行访问,为了保证用户在当天内看到同样的页面内容,这时候需要给用户返回跟第一次访问时一样的 URL。查询数据库发现,1.1.1.1 对应 b.com ,这时候给用户 1.1.1.1 返回 b.com 但是当一天内访问的用户量足够大的时候,查询“目标域名”的操作就会很慢了吧,所以问,用什么技术方案来实现这个需求,用户能最快访问到目标 URL |
12
lianyue 2017-10-11 20:56:27 +08:00
这需要 考虑这么多干嘛 动态网页 基本每次打开都会有查询 正常 以内
其实普通数据库 什么的 id, ip date 就好了 多一个字段超过 24 小时自动过期 根本不需要什么删除 或者每天一个新表 为什么非要操作 删除旧的数据 表名比如 access_2017_10_11 access_2017_10_12 access_2017_10_13 结构 id, ip 实现方式很多 |
13
binux 2017-10-11 20:58:13 +08:00
随机选一个域名是 O(1) 的,查询一个 ip 对应的域名也是 O(1) 的,不管用户量有多大,就算 13 亿它也是一样的速度。
|
14
syhsyh9696 2017-10-11 20:59:32 +08:00
为何不是根据当前的时间和 ip 地址生成当天的 temp url ?
|
15
xmcp 2017-10-11 21:03:25 +08:00 1
@Loyalsoldier 这用什么数据库呀?直接用 IP 地址做种子生成随机数呀。伪(?)代码如下:
SALT='foo' # 改这个数来重置所有用户访问到的网址 WEBSITES=['b.com','c.com','d.com'] def get_url(ip): ___ r=random.Random() ___ r.seed(SALT+str(ip)) ___ return r.choice(WEBSITES) 如果真要上数据库的话 redis 也不是不行,人家 redis 也有 hash 数据结构: http://www.runoob.com/redis/redis-hashes.html,O(logN) 肯定能满足正常网站的速度要求的。 |
16
yankebupt 2017-10-11 21:12:29 +08:00
@Loyalsoldier 但是 ip 可以 hash 的...
不懂 hash 会加速的道理也没关系,这么解释一下,假设你为 0.0.x.x-255.255.x.x 的 ip 建 65536 张表,则每张表最多也就是 65536 个记录(实际每个记录都会很少会更快,因为需要访问一次才有记录)。只查对应的表只需遍历很少的记录.... 不过我愈发觉得楼主可能是在钓鱼...专门钓我们这种不懂 memcached/LRU 的... |
17
yankebupt 2017-10-11 21:17:23 +08:00
@xmcp 也好,但我看到楼主说了每天数据可以清空,可能意味着楼主想在 SALT 里加入当前日期或者有自己的生成算法,咱们继续看看楼主怎么发展吧....
|
18
bydmm 2017-10-11 22:03:24 +08:00 1
楼主你逗我把,
ip 到一段字符串的映射关系根本不用遍历整个 redis 空间啊。 他们之间是 hash 映射的关系。 你用 ip 作为 key,url 作为 value,再多 ip 都是一次好吗。。 |
19
dbw9580 2017-10-11 22:13:12 +08:00 via Android
for ip in seen_ips: if ip != remote_ip, continue; else return ip2urltable[ip]
op 的思考方式 |
20
0ZXYDDu796nVCFxq 2017-10-11 22:30:46 +08:00 via iPhone 1
用 IP 做 key 查询不是 O(n)的,是 O(1)
50 万数据小得可怜,估计几百 M 内存搞定 |
21
nazor 2017-10-11 22:34:31 +08:00
每秒查询 20W 是指每秒遍历数据 20 次,不是说一秒只能遍历 20W 的一次……
|
22
hand515 2017-10-11 22:45:37 +08:00 1
这种情况 redis 单机就能处理得过来,才 50w
set ip domain NX EX 24*60*60 get ip 基本只要这两个命令就能解决你的问题 |
23
johnnie502 2017-10-12 06:58:27 +08:00
这不是一个存放在客户端的 24 小时过期 cookie 吗?除非有特殊的要求必须放在服务器端,不然放在客户端不就完事了
|
24
LeoSocks 2017-10-12 08:35:29 +08:00 via iPhone
那文章写的 11 万次每秒是并发吧!可以支持并发 11 万个用户同时读。而不是 11 万条记录
|
25
blaxmirror 2017-10-12 09:28:37 +08:00 2
直接用 IP+一个每天变化的 seed 做映射不就好了吗?为啥要存储下来呢?
你应该不需要通过 URL 反向查询 IP 的吧? (并不了解技术细节,仅供参考) |
26
Loyalsoldier OP |
27
hand515 2017-10-12 21:30:03 +08:00
@Loyalsoldier #26 别用 hashtable,直接用 set 和 get 命令,配合 expire 设置自动过期,还剩了定时任务
|