/zhihuTag

Primary LanguagePython

zhihuTag

技术工具:Python/BeautifulSoup/Redis/Mysql/RestAPI

技术实现:通过Redis**队列的形式,对知乎的标签页进行广度优先遍历,通过FIFO,实现分布式爬虫,并协同抓取全知乎的标签及子标签的树状结构,将此全量树状结构存储入MySQL数据库。此机制保证任何一个爬虫技能单独而协同。

测试机器总览

典型问题样本

获取连接耗时26秒.

响应数据入库19秒

性能损耗分析

*各阶段IO损耗

HTTP请求:通信链路如下图所示,经历12次网络IO。

上述12个步骤都是串行关系,粗略计算,基本IO损耗 : >3倍

损耗成本:百毫秒-秒级(主要)

*NDS网关损耗

发生阶段:4,10

NDS网关是最大不可控因素, 问题如下:

  1. 高并发情况下,连接数耗尽,导致大量请求超时, 超时时间可调.

    在测试环境,多网关实例效果更优,如:2实例 250连接数 > 1实例 500连接数**

  2. 决定连接数因素有二:NDS实例连接数 ,NDS全局总连接数.

​ 在测试环境,网关实例存在总连接数限制,如:开通2个实例,1000连接数, 实际Mysql检测到的连接数不足。

  1. 驱动包偶发空指针异常;NetPackage对象占用内存,致使OOM异常风险.

序列化,反序列化

发生阶段:3,5,8,10

措施:

  • 平台标准JSON序列化工具
  • 并行执行

轮询间隔

发生阶段:5,10

措施:

  • 外网轮询间隔, 等待响应

    • 有请求时,不间断循环
    • 无请求时,休眠,等待唤醒
  • 内网轮询, 等待请求

    • 无请求时休眠5ms(参数配置)

    • 批量获得http请求,线程池并行处理(参数配置),获取响应即时入库

数据库交互

发生阶段:3,4,9,10

主要瓶颈:

  • 数据库连接获取,连接数耗尽
  • 大请求,大响应写入数据库

措施:

  • 仅基于一张表,无任何关联查询
  • 请求处理完成后,记录实时清除,数据库表始终维持在 0 ~ 并发数之间
  • 所有语句均基于索引
  • 使用连接池

测试结果数据

数据包大小变化对比

数据大小 并发数 平均响应时间 错误率
1k 10 0.36 0%
1k 50 0.67 0%
1k 100 1.22 0%
1k 200 3.39 0%
5k 10 0.59 0%
5k 50 0.82 0%
5k 100 1.56 0%
5k 200 4.18 0%
10K 10 0.66 0%
10k 50 0.87 0%
10K 100 1.86 0%
10K 200 4.91 0%
200K 10 0.93 0%
200K 50 1.15 0%
200K 100 2.11 0%
200K 200 5.14 0%
1024k 10 1.69 0%
1024k 50 5.93 0%
1024k 100 14.02 0%
1024k 200 21.98 0%
1024k 250 8.847 11%

随着总传输数据上升突破某节点,错误率突然显现

单实例,多实例对比

单实例

数据大小 并发数 平均响应时间 错误率
10K 300 4.847 11%
10K 400 8.496 16%
10K 500 10.55 52.50%

双实例

数据大小 并发数 平均响应时间 错误率
10K 300 3.214 0%
10K 400 3.784 0%
10K 500 2.694 5.13%

总数据库连接数相同的情况下,双实例的错误率区别明显

有网闸,无网闸对比

网闸

数据大小 并发数 平均响应时间 错误率
10K 500 4.847 11%

直连Mysql

数据大小 并发数 平均响应时间 错误率
10K 500 3.388 0%

通过网闸与否,在性能上存在波动,数据不明显,但错误率区别明显

本迭代改进项目

  1. 不恰当的建立连接,导致连接数耗尽
  2. 生产者空转,在没有请求的情况下去获取响应
  3. 不恰当清除,consumer启动时清空数据库
  4. 增加心跳,防止网闸启动休眠断线机制,长时间没流量半关闭socket,

建议&结论

  1. 一个网闸通道可以支持200并发1M的请求数,无法通过配置网闸参数再提高
  2. 多通道,多实例部署:测试机器,最多可以支持2网闸通道400并发1M的请求数,再提高会出现OOM,或者超长的延迟

措施总览

内容 损耗 措施&备注 实现情况 效果
请求,响应序列化,反序列化 并行处理 已实现 *
NDS网关基本损耗 主要,秒级 添加连接数,添加实例 现场实施 *****
轮询间隔 轮询间隔参数化 已实现 *
各阶段IO 主要,秒级 HTTP协议用GZIP传输 现场实施 **
数据库交互 索引,单表,记录数少,连接池 已实现 **

日志关键节点

0 [P] 到达
1 [P] 准备连接
2 [P] 连接获取
3 [P] 完成入库
4 [C] 准备连接 (批处理)
5 [C] 连接完成 (批处理)
6 [C] 请求序列化 (批处理)
7 [C] 请求状态更新 (批处理)
8 [C] HTTP准备发送
9 [C] HTTP响应获取
10 [C] HTTP响应入库
11 [P] 准备连接【批】
12 [P] 连接完成【批】
13 [P] 响应读取【批】
14 [P] 响应序列化
15 [P] 返回前端并完成