DCOS应用案例(一):登陆爬虫——微服务架构典型

今天的小数一本正经,给大家带来的是干货满满的DCOS应用案例集。本系列分为三篇,分别介绍了登录爬虫、在线会议系统与文章分类与热词统计三个案例。本篇登录爬虫向大家展示了如何在DCOS上从头开始设计一个微服务架构的应用,在获得弹性扩展、高可用的特性下,如何进行服务发现。

后续的两篇会在之后为大家奉上,敬请期待!

0.前言

随着 Docker 技术的日渐火热,本就火爆的云计算行业进入了一个加速阶段。云计算最大的特点是弹性和灵活,帮助企业应对复杂的业务需求。由于云计算的IT构架和上一代的IT构架有很大不同,云原生应用(Cloud Native Application)概念应运而生。

云原生应用的优点体现在具有良好的可扩展性、伸缩性和容错性;不过想要享用云原生应用的种种良好特性并不是轻松的事,企业开发人员在开发业务应用的时候,还要考虑未来应用的可扩展性和容错性,不免增加了开发的复杂度。PaaS 的出现,正是要帮助开发人员降低云原生应用的开发复杂度,让开发人员还是专注于业务应用的开发,为开发人员屏蔽底层细节。

早期的 PaaS 平台过于复杂和笨重,没有得到广泛的应用,而基于 Docker 和 Mesos 打造的 DCOS 是下一代轻量级 PaaS 平台的典型代表。DCOS 极大地降低了 PaaS 平台的复杂度,更加方便企业开发人员实现各种业务应用,帮助企业轻松打造基于云计算的软件基础设施。

DCOS 主要带来以下几方面好处:

  • 横向扩展,自动恢复

  • 快速部署,高效迭代

  • 混合部署,提高资源利用率

如果对 PaaS、DCOS 不太了解的人一一解释这些概念,不免有些晦涩。本文将从实际案例出发,结合不同的使用场景,为各位介绍 DCOS 的这些特性。

  • 登陆爬虫

通过本案例说明,如何在DCOS上从头开始设计一个微服务架构的应用,在获得弹性扩展、高可用的特性下,如何进行服务发现

  • 在线会议系统

通过本案例说明,如何改造原有的互联网应用上云,以及借助容器的快速部署特性,架构持续集成

  • 文章分类与热词统计

通过本案例说明,如何在DCOS上实现大数据应用,以及借助 Mesos 实现混合部署,提高资源利用率

名词说明

  • Mesos:Mesos是一个分布式资源管理器,支持在多种计算集群框架(frameworks)间共享服务器集群资源,提高了集群资源占用率的同事,避免了每种框架的资源冲突。为了满足复杂的资源调度方法,Mesos 通过资源提供(resource offer)实现了基于 DRF 算法的二层资源调度机制。Mesos是未来数据中心操作系统(DCOS)的核心。
  • Marathon:Marathon 是一个 Mesos 的框架,能够支持在集群环境中管理长运行服务,可以理解是分布式的 Init.d,它能够运行任何 Linux 二进制发布版本如 Nginx 等,并可以对应用的分布式多进程进行管理。
  • Chronos:Chronos 是一个具备容错特性的作业调度器, 也是一个 Mesos 的框架,支持使用 Mesos Slave 作为作业执行器,用于在分布式环境下替代 cron。
  • 服务发现:服务发现是指,任何一个应用的实例能够以编程的方式获取当前环境的细节,而新的实例可以嵌入到现有的应用环境而不需要人工干预。简单地说,在一个集群环境下,随着应用实例的增减或迁移,服务发现保证该服务仍然可以通过服务访问地址被访问。
  • 持续集成:持续集成(Continuous Integration)是一种实践,可以让团队在持续的基础上收到反馈并进行改进,不必等到开发周期后期才寻找和修复缺陷。通俗一点儿说,就是对于开发人员的代码提交,都自动地把代码库中的代码进行编译、测试、打包。
  • 微服务:微服务是一种新兴的应用软件架构,它通过一组服务的方式来构建一个应用,服务独立部署在不同的进程中,不同服务通过一些轻量级交互机制来通信,例如 REST。每个服务可独立扩展伸缩,并且定义了明确的边界,不同的服务甚至可以采用不同的编程语言来实现,由独立的团队来维护。
  • 数人云DCOS:数人云是国内第一款数据中心操作系统,基于Mesos管理容器生产环境,并集成了 Marathon、Chronos 等组件,对企业数据中心提供集群管理,容器管理,服务发现,持续集成等服务。

1.登陆爬虫-微服务架构典型

该系统是一套实时的登陆爬虫系统,用户输入待爬取网站的用户名和密码,系统会自动登陆账号,并爬取账号内页面数据,以报告的形式提供给用户。这套系统常用于金融征信,评级机构获得用户的登录信息,通过爬虫系统爬取该用户的信用相关信息,形成信用报告。

先了解一下微服务架构的几个主要的设计理念:

  1. 通过服务实现组件化。微服务使用服务的形式来实现各个功能组件模块,各个模块间的依赖通过服务的方式来组织,即一个模块通过远程过程调用来依赖另一个模块,每个模块是一个微服务。

  2. 企业按照业务功能来组织团队,每个团队负责一个微服务,可以做到“谁构建,谁运行”,这将极大降低运维复杂度,缩短上线周期。

  3. 微服务可以方便地做到离散化数据管理。每个微服务可以自行管理各自的数据,包括不同业务的数据、不同微服务的配置等等,更加切实匹配业务需求。

  4. 微服务构架使得持续集成和持续交付变得更加便捷。有了微服务,集成和交付的单元从大而全的整体应用变成了各个微服务,每个微服务都可以灵活地集成和交付。

这个系统在设计之初就考虑采用微服务架构,以便部署在 DCOS 环境,并享受 DCOS 所带来的各种特性。

系统痛点:微服务架构

该系统希望依照微服务架构原则进行设计,将功能模块组件化,每个模块实现一个独立的功能,可单独部署,模块之间松散耦合。每个模块可根据业务负载灵活地增加或缩减可承载容量,同时每个模块由多个实例构成,避免整个系统由于单点故障而造成系统瘫痪。

第一步:系统设计

系统的业务需求大致如下图所示。

在得到授权的情况下,用户输入所要爬取的网站的登陆用户名和密码,提交爬取任务;

模拟用户行为登陆,登陆过程中要判断用户名、密码的正确性,如果有验证码,需要让用户判断验证码图片并输入验证码信息;

成功登陆后,即开始爬取账户页面,根据报告要求,从页面中抽取出有效信息,形成报告;

由于数据是多实例并行爬取的,需要在爬取结束后进行数据整合;

异步获取结果;用户登陆成功后,会提供一个查询码,并提示一段时间后进行查询;待爬取结束并形成后,用户方可查询到数据报告;

根据这些需求,需要以下系统组成:

  1. 一个 web ui,与用户交互;
  2. 模拟登陆模块Loginer;
  3. 爬取模块 Fetcher;
  4. 信息抽取模块 Extractor;
  5. 信息整合模块 Combiner;
  6. ETL 模块:用于清洗数据,形成最终报告;

系统设计如下图所示。

  1. 用户通过 Access portal 输入待爬网站的用户名和密码,有些网站还需要输入验证码;
  2. Loginer 接收到用户信息后,开始模拟用户登陆;模拟登陆可以采用 Selenium 或 Http Client 两种,需要渲染页面时使用 Selenium,否则用 Http Client 就够了;
  3. 登陆成功后,Logginer 会将 cookie 和爬取任务一同写入消息队列,Fetecher 负责领取任务,进行页面爬取; 爬取过程中,Fetcher 需要携带 Cookie 访问网站页面;
  4. Fetcher 将爬取的页面存入消息队列,由 Executor 负责从页面中抽取需要的元素信息,并将这些信息放入缓存系统;
  5. Combiner 负责将缓存中的数据进行拼装,并判断爬取是否结束;若结束,将爬取结果存入数据库;
  6. ETL 模块负责将爬取结果进行清洗和整理,形成最终的报告;
  7. 用户在等待一段时间后,可以查询爬取结果,下载报告。

其中,Fetcher、Extractor、Combiner 三个组件都需要了解本次抓取需要有多少 task,以及每个 task 的状态,以便判断本次任务是否结束。

由于整个系统的每一个处理环节都是多实例的,模块之间都不直接发生依赖关系,而是采用消息队列或者存储系统进行解耦。

注:为了防止被某些网站限制 IP,还需要在 Loginer 前面增加一个代理层,每次使用随机的代理服务器进行网站访问和登陆,这样就避免了被封的风险。

第二步:服务发现

1 为什么需要服务发现

从上面的设计中可以看出,大部分服务之间都通过分布式消息队列或存储系统进行交互,这样做的好处使得服务之间实现了异步交互,降低了耦合性。但这种异步方式并不适应于任何场合,例如 Loginer 的设计就必须采用同步调用的方式,主要原因是:

  • 用户在输入用户名、密码后,需要 Loginer 立刻进行模拟登陆以验证输入的正确性;
  • 如果网站登陆页的验证码是在用户名、密码输入后才显示,则还需要将验证码图片返回给用户,由用户判别并输入验证码信息(有的验证码可通过打码服务直接获取验证码信息,但并这并不适用于所有验证码系统)后,再进行登陆操作;

Loginer 采用 Selenium 或 Http Client 进行模拟登陆,当网站登录页需要进行 JS 渲染的时候,就需要用到 Selenium;Selenium 通过浏览器 driver 打开浏览器,访问登录页,开始进行模拟操作;为了简化浏览器状态的维护,在设计时限定每个 Loginer 实例同时只能处理一个登录请求,直到本次登录完全结束,关闭浏览器,才可以处理下一个登录请求。可见,每个 Loginer 需要维持一个状态机。

正因如此,Loginer 需要部署较多的实例数;另外,由于浏览器 driver 不够稳定,时而出现调用无效的情况,Loginer 需要有重启机制;

2 服务发现

数人云提供了一套完善的面向微服务架构的服务发现方案,如下图所示。

现有服务发现根据 marathon+zookeeper+bamboo+haproxy 一起工作解决,具体说明如下:

  1. 应用动态变化导致 marathon 将状态信息写入 zookeeper(包括所在的主机 IP、端口等),然后把变化事件发给事件订阅用户, bamboo 作为订阅用户, marathon-leader 会将变化事件发送给 bamboo。
  2. bamboo 拿到事件后,按照事件给定的应用标示去 zookeeper 中取对应的状态数据。
  3. bamboo 拿到数据后按照预先设定的 haproxy 模版生成一个临时配置文件。
  4. bamboo 将临时配置文件和现有 haproxy 配置文件进行对比。
  5. bamboo 对比后,如果一致将直接结束任务。如果不一致,检查一下配置文件格式。
  6. bamboo 如果配置文件格式异常,将结束任务。如果正常,将 reload haporxy 加载新配置文件。

    将 Loginer 通过数人云发布,发布应用时指定应用地址,即在 haproxy 上配置一个访问端口,再有服务发现机制将请求转发到具体的应用实例,具体请见数人云用户手册

如果某个 Loginer 实例在处理登陆任务时出现异常,只需要结束进程,该 Docker 容器会自动 stop;Marathon 监听到有应用容器停止,会重新启动一个新容器以保证服务容量。注意,新容器不一定运行在结束运行的旧容器所在的主机,可以是指定集群范围内的任何主机,而服务发现会帮助我们自动发现该容器并进行请求转发。

当然,在横向扩展时,增加 Loginer 的实例数,不仅可以做到快速地平滑扩展(业务不停),也会将新实例通过服务发现加入到转发列表中。

数人云还在 Haproxy 设置了会话保持,如果是基于 cookie 的会话,Haproxy 会将同一会话请求转发到同一容器。

小结

至此,一套具备横向扩展能力,高可用的登陆爬虫系统就设计完了。

回头来看,整个系统就是一个数据处理的 pipeline,每个环节之间松散耦合,具备高可用,可以独自做到横向扩容或缩减,基本符合了微服务架构的特性。这样的架构也为持续集成创造了良好的基础,我们会在下一个案例介绍基于DCOS的持续集成。

注:数人云新版的服务发现功能已经修改了策略,不再需要用户选择将代理部在某几台主机上,而是由系统默认安装在集群除了 Master 之外的所有主机上,构成一个覆盖全计算资源的代理集群,确保服务发现的高可用;同时对 proxy 进行了优化,降低了运行带来的系统开销。