微服务爬虫架构设计:解耦采集/解析/存储,支持百万级数据并发

发布时间:2026/7/7 18:59:05

微服务爬虫架构设计:解耦采集/解析/存储,支持百万级数据并发 2023年我所在的公司要做一个公共数据采集平台需要对接300多个数据源每天采集100万条数据支持多租户使用最开始我用的是传统的Scrapy-Redis单体架构跑了不到一个月就出现了各种问题模块耦合严重改一个功能影响其他功能扩容困难采集和解析耦合在一起没办法单独扩容故障影响范围大一个数据源出问题导致整个平台都挂了。后来我花了2个月时间把整个架构改成了微服务架构四层解耦K8s容器化部署支持弹性扩缩容现在平台每天可以稳定采集200万条数据支持100租户同时使用资源利用率提升了60%成本降低了40%稳定性达到了99.9%。这篇文章我就把完整的微服务爬虫架构设计分享出来从架构设计、每个服务的实现、K8s部署到性能优化全部是实战经验适合中大型爬虫项目看完你也能搭建出支持百万级并发的爬虫平台。一、传统单体爬虫架构的痛点传统的Scrapy-Redis单体架构虽然简单但是对于中大型项目来说有很多无法解决的痛点模块耦合严重采集、解析、存储逻辑都在同一个项目里改一个功能可能影响其他功能维护难度大无法单独扩容采集是IO密集型解析是CPU密集型耦合在一起的话要么浪费CPU资源要么浪费IO资源没办法根据需求单独扩容故障影响范围大一个数据源的爬虫出问题可能导致整个进程崩溃影响所有数据源的爬取迭代速度慢不同的数据源开发进度不一样耦合在一起的话上线的时候要一起上线影响迭代速度多租户支持差没办法隔离不同租户的任务和资源容易出现资源竞争的情况资源利用率低峰谷明显高峰期资源不够用低峰期资源浪费严重这些痛点在项目小的时候不明显当数据源超过100个日采集量超过10万条的时候就会非常突出严重影响项目的发展。二、微服务爬虫架构核心设计我设计的微服务爬虫架构是四层解耦的云原生架构完全解决了单体架构的痛点┌─────────────────────────────────────────────────────────────────┐ │ API 网关层 │ │ 负责权限认证、流量控制、请求路由、负载均衡 │ └───────────────────┬─────────────────────────┬───────────────────┘ │ │ ┌───────────────────▼───────────────────┐ ┌───▼───────────────────┐ │ 调度服务 │ │ 管理后台 │ │ 负责任务调度、分片、优先级控制、超时管理 │ │ 任务管理、数据查看、监控 │ └───────────────────┬───────────────────┘ └───────────────────────┘ │ ┌───────────────────▼───────────────────┐ │ 消息队列 │ │ Kafka/RocketMQ任务分发、削峰填谷、解耦 │ └─────────┬───────────────┬─────────────┘ │ │ ┌─────────▼───────┐ ┌─────▼─────────┐ ┌──────────────┐ │ 采集服务集群 │ │ 解析服务集群 │ │ 存储服务集群 │ │ IO密集型多副本 │ │ CPU密集型多副本│ │ 多数据源适配 │ └─────────────────┘ └───────────────┘ └──────────────┘整个架构的核心特点是完全解耦、弹性伸缩、高可用、易扩展每个服务都可以独立开发、独立部署、独立扩容互不影响。2.1 API网关层API网关是整个平台的入口负责权限认证所有请求都要经过网关认证校验租户的API Key是否有效权限是否足够流量控制对每个租户的请求做限流、熔断避免单个租户的请求量太大影响其他租户请求路由把不同的请求路由到对应的服务比如任务管理的请求路由到调度服务数据查询的请求路由到存储服务负载均衡把请求均匀的分发到各个服务的多个副本上提高可用性日志收集收集所有请求的日志方便排查问题和统计调用量我用的是APISIX做API网关性能非常高每秒可以处理几万次请求完全满足需求。2.2 调度服务调度服务是整个平台的大脑负责任务管理接收用户提交的爬取任务管理任务的生命周期包括待调度、运行中、完成、失败等状态任务分片把大的任务拆分成多个小的子任务比如爬取100万条数据拆成1000个任务每个任务爬1000条分发到不同的采集节点优先级控制支持任务优先级高优先级的任务先执行比如实时爬取的任务优先级高于离线爬取的任务超时管理监控任务的执行时间超过超时时间的任务自动重新调度避免任务卡住失败重试任务执行失败的时候自动重试最多重试3次重试失败的任务进入死信队列通知人工处理增量爬取支持增量爬取自动判断哪些数据需要更新不需要全量重新爬调度服务是无状态的可以部署多个副本提高可用性我用的是Go语言开发性能非常高每秒可以调度上万个任务。2.3 消息队列层消息队列是整个架构的核心用来解耦各个服务削峰填谷解耦采集服务、解析服务、存储服务之间通过消息队列通信不需要互相调用修改一个服务不会影响其他服务削峰填谷高峰期任务量很大的时候消息队列可以缓存任务避免服务被打垮低峰期的时候慢慢消费提高资源利用率保证任务不丢失消息队列支持持久化就算服务挂了消息也不会丢失重启之后可以继续消费顺序消费支持任务的顺序消费比如同一个网站的任务按顺序执行避免请求太频繁被封我用的是Kafka集群3节点多副本吞吐量非常高每秒可以处理几十万条消息完全满足百万级并发的需求。2.4 采集服务层采集服务是IO密集型服务负责从各个数据源采集数据多数据源适配支持网页、API、数据库、FTP等多种数据源的采集每种数据源对应一个采集插件新的数据源只要开发对应的插件就可以不需要修改核心代码无状态设计采集服务是无状态的不存任何本地数据可以随意扩容缩容反爬对抗内置内置代理池、UA池、指纹混淆、验证码识别等反爬对抗功能所有采集任务都可以复用这些功能不需要重复开发可观测性每个采集任务的状态、耗时、成功率都有监控方便排查问题采集服务我用的是PythonGolang混合开发简单的采集任务用Python开发效率高性能要求高的任务用Golang开发速度快。2.5 解析服务层解析服务是CPU密集型服务负责把采集到的原始数据解析成结构化数据多解析方式支持支持XPath、CSS、正则、大模型等多种解析方式用户可以根据需求选择解析模板管理用户可以自定义解析模板不需要写代码通过可视化配置就能解析数据自动适配改版内置大模型解析网页改版之后不需要修改模板自动适配新的结构数据清洗内置数据清洗、去重、标准化功能解析之后直接输出干净的结构化数据解析服务是无状态的可以根据负载自动扩容高峰期可以扩容到几十个副本低峰期缩减到几个副本节省成本。2.6 存储服务层存储服务负责把解析好的结构化数据存储到对应的存储介质里多存储介质适配支持MySQL、PostgreSQL、MongoDB、Elasticsearch、OSS等多种存储介质用户可以根据需求选择数据同步支持数据同步到其他系统比如用户的数据库、数仓、大数据平台查询接口提供统一的查询接口用户可以通过API查询采集到的数据数据质量管理内置数据质量校验错误的数据自动告警保证数据的准确性2.7 管理后台管理后台给用户提供可视化的操作界面任务管理用户可以在后台创建、修改、删除爬取任务查看任务的运行状态数据查询用户可以查询、导出采集到的数据解析模板配置可视化配置解析模板不需要写代码监控面板查看任务的运行情况、资源使用情况、成功率、耗时等指标租户管理管理员可以管理租户分配权限设置配额三、核心功能实现我把几个核心功能的实现思路分享出来大家可以参考。3.1 任务调度实现调度服务用的是CeleryRedis的分布式任务调度支持定时任务、一次性任务、周期任务fromceleryimportCeleryimportredis appCelery(crawler,brokerredis://redis:6379/0,backendredis://redis:6379/0)app.task(bindTrue,max_retries3)defcrawl_task(self,task_id,url,config):爬取任务try:# 执行爬取任务resultcrawler.crawl(url,config)# 把结果发送到解析队列send_to_kafka(parse_topic,{task_id:task_id,raw_data:result,parse_config:config[parse_config]})return{status:success,task_id:task_id}exceptExceptionase:# 重试self.retry(exce,countdown60)任务执行失败的时候自动重试最多重试3次重试失败的任务进入死信队列。3.2 弹性扩缩容实现我用的是K8s的HPAHorizontal Pod Autoscaler实现自动扩缩容根据服务的CPU、内存使用率或者队列的消息积压量自动调整副本数apiVersion:autoscaling/v2kind:HorizontalPodAutoscalermetadata:name:crawler-hpaspec:scaleTargetRef:apiVersion:apps/v1kind:Deploymentname:crawler-serviceminReplicas:2maxReplicas:50metrics:-type:Resourceresource:name:cputarget:type:UtilizationaverageUtilization:70-type:Podspods:metric:name:kafka_consumergroup_lagtarget:type:AverageValueaverageValue:1000这个配置表示当CPU使用率超过70%或者Kafka消费组的滞后量超过1000的时候自动扩容采集服务的副本数最多扩容到50个低峰期的时候自动缩容到2个大大提高了资源利用率降低了成本。3.3 多租户隔离实现为了避免不同租户的任务互相影响我做了三层隔离资源隔离每个租户的任务有独立的资源配额CPU、内存、请求量都有限制不会占用其他租户的资源队列隔离每个租户的任务发到独立的Kafka Topic不会和其他租户的任务混在一起数据隔离每个租户的数据存在独立的数据库Schema或者表互相不可见保证数据安全这样就算某个租户的任务出问题也不会影响其他租户的正常使用。3.4 可观测性实现整个架构的所有服务都有完善的监控指标监控用Prometheus采集所有服务的CPU、内存、QPS、延迟、成功率等指标用Grafana做可视化面板日志收集用ELK stack收集所有服务的日志统一存储方便排查问题链路追踪用Jaeger做分布式链路追踪一个请求从网关到调度服务到采集服务到解析服务整个链路都可以追踪出了问题可以快速定位到是哪个服务出了问题告警用Alertmanager做告警指标异常的时候自动发送钉钉、邮件通知比如CPU使用率过高、Kafka消息积压、任务成功率过低等四、百万级日采集量性能测试我对整个架构做了压力测试测试结果如下指标测试结果日最大采集量320万条峰值QPS3500次/秒任务调度延迟50ms采集成功率98.5%解析成功率97%平均响应时间200ms服务可用性99.92%测试的时候采集服务的副本数从2个自动扩容到35个解析服务从1个扩容到15个测试完成之后自动缩容到原来的数量整个过程不需要人工干预非常方便。成本对比和原来的单体架构相比微服务架构的成本降低了40%原来的单体架构需要20台4核8G的服务器每个月成本6000元现在的微服务架构高峰期最多用到35个采集副本15个解析副本但是大部分时间只有52个副本每个月成本3600元降低了40%而且性能提升了3倍从原来的每天100万条提升到320万条五、成本优化方案微服务架构虽然性能高但是如果不优化的话成本也会很高我总结了几个成本优化的技巧5.1 弹性扩缩容这是成本优化的核心根据实际的负载自动调整副本数高峰期扩容低峰期缩容我用了弹性扩缩容之后成本直接降了一半。对于非实时的任务可以安排在晚上或者凌晨运行这时候服务器的成本更低还可以利用闲置资源用抢占式实例价格是普通实例的1/3就算被回收了也没关系因为任务是无状态的重新调度就可以了5.2 冷热数据分离热数据最近7天的数据存在性能好的SSD盘查询速度快冷数据超过7天的数据存在便宜的对象存储或者归档存储成本只有SSD的1/10定期把冷数据备份到对象存储节省磁盘成本5.3 资源复用多个服务可以部署在同一个节点上只要资源足够提高资源利用率用K8s的资源配额和限制避免服务占用过多的资源对于非核心的服务可以用低配置的节点降低成本5.4 开源组件优先所有的组件都用开源的不需要付费licenseAPI网关用APISIX比Kong便宜性能更好消息队列用Kafka开源免费性能高监控用PrometheusGrafana完全免费存储用MySQL、MongoDB、Elasticsearch都是开源的这样一年可以节省十几万的软件 license 费用。六、踩坑经验总结微服务爬虫架构虽然好处很多但是开发和运维的复杂度也比单体架构高很多我踩了很多坑分享给大家坑1服务之间的调用关系复杂排查问题困难最开始没有做链路追踪出了问题不知道是哪个服务的问题排查非常困难。解决方案加入分布式链路追踪每个请求都有唯一的trace ID贯穿整个调用链路出了问题可以直接用trace ID查到整个链路的日志完善监控每个服务的指标都采集有异常立刻告警规范日志格式所有服务的日志都包含trace ID、用户ID、任务ID等关键字段方便排查坑2消息队列积压服务被打垮最开始没有做限流和熔断高峰期任务量太大解析服务处理不过来消息队列积压了几百万条消息导致整个集群都卡住了。解决方案加入限流熔断机制每个服务的消费速度超过阈值的时候自动限制生产速度避免消息积压动态扩缩容消息队列积压的时候自动扩容消费服务的副本数加快消费速度消息设置过期时间超过24小时还没消费的消息自动丢弃避免无限积压坑3分布式事务问题数据不一致最开始没有考虑分布式事务的问题采集成功了但是解析或者存储失败了导致数据丢失数据不一致。解决方案用消息队列的ACK机制只有消息处理成功了才提交ACK失败的话会重新消费加入对账机制每天统计采集的任务数、解析成功的数量、存储成功的数量对账不一致的时候自动补全重要的数据做双写同时存到两个存储介质避免数据丢失坑4运维复杂度高需要专门的运维人员微服务架构的服务很多部署、监控、运维都比单体架构复杂很多最开始需要专门的运维人员维护成本很高。解决方案用K8s做容器编排自动部署、自动扩容、自动恢复大大降低运维复杂度用DevOps流程代码提交之后自动构建、自动测试、自动部署不需要人工干预做完善的监控和告警大部分问题可以自动恢复不需要人工处理七、考点/技巧提炼1. 什么样的项目适合用微服务爬虫架构中大型爬虫项目数据源超过50个日采集量超过10万条需要支持多租户多个团队或者用户使用迭代速度快需要频繁上线新功能对可用性要求高不能经常出故障峰谷明显需要弹性扩缩容降低成本如果是小型的爬虫项目数据源少采集量小用单体架构就足够了不需要用微服务增加复杂度。2. 微服务爬虫架构的优势是什么解耦各个服务独立开发、独立部署、独立运维互不影响弹性扩容每个服务可以根据负载单独扩容资源利用率高成本低高可用没有单点故障一个服务挂了不会影响其他服务易扩展新的数据源、新的功能只要开发对应的插件就可以不需要修改核心代码多租户支持可以隔离不同租户的资源和数据适合做SaaS化的爬虫平台3. 微服务架构是不是比单体架构性能高不一定如果是小型项目微服务架构因为有网络调用的开销性能反而不如单体架构但是对于中大型项目微服务架构可以水平扩展性能可以做到比单体架构高很多。4. 微服务爬虫架构的技术选型需要注意什么优先选云原生的组件支持容器化部署方便在K8s上运行优先选开源、社区活跃的组件遇到问题容易解决不需要自己踩坑各个服务之间的通信协议要统一比如用HTTP或者gRPC方便调用要考虑整个团队的技术栈不要选团队不熟悉的技术增加学习成本总结微服务爬虫架构是中大型爬虫项目的最佳实践虽然开发和运维的复杂度比单体架构高但是带来的好处也是非常明显的解耦、弹性扩缩容、高可用、易扩展可以支撑百万级甚至千万级的日采集量。我这个架构已经在公司的生产环境跑了一年多了非常稳定支撑了几十个业务方的爬虫需求大大降低了开发成本提高了资源利用率。当然微服务架构也不是银弹要根据自己的项目规模和需求选择合适的架构不要为了用微服务而用微服务适合自己的才是最好的。

相关新闻