【编者按】互联网从诞生到现在,网站的规模不断扩大,存储和处理的数据量也远远超出了人们的想象,又随着对信息实时性、多媒体需求大幅增长的现象,互联网架构面临越来越大的挑战。CSDN致力于解决这一问题,在刚刚结束的 SDCC 2015中国软件开发者大会上,特举办了架构专场( 上午报报道、 下午报道),以及《程序员》电子刊10月B开设了 架构专题。在接下来也将继续深耕架构师、服务于开发者,推出更多的大牛访谈、知名互联网公司架构实践、技术公开课等,敬请期待。
日前,笔者采访了当当网架构师、当当技术委员会成员张亮,在本次采访中他主要分享了对架构师的理解,以及重点解读了分布式作业调度框架Elastic-job是什么、架构设计思路、具体模块的底层及如何实现等。
张亮对架构设计、消息中间件、分布式等领域兴趣浓厚。目前主导当当应用框架ddframe研发和推广以及技术白皮书撰写。其中ddframe的分布式作业部分elastic-job已经正式开源。
CSDN:请简单介绍下您和目前的工作,以及说说您自己曾经的计算机经历?
张亮:我目前在当当架构部任职,主要的工作是ddframe的设计、开发和推广;技术白皮书撰写;重点项目的跟进支持,如:TMS,WMS重构;还有一些零散的技术调研工作,如,消息中间件,日志中心,图数据库等。
职业生涯初期我在外企工作。外企对技术人员要求更多的是设计,规范和对业务的理解能力。一般外企都有成型的技术组织架构,相对较重。流程规范但缺乏灵活性,对新技术使用非常谨慎。我本人更喜欢技术本身,所以于三年前加入互联网行业。在我看来,灵活性、高性能、轻量级、分布式、高可用是互联网企业更关注的东西。
CSDN:当当有自己架构部,并设有架构师一职,作为其中的一员,能够谈谈什么是架构?什么是架构师?
张亮:架构种类很多,从公司宏观看,可分为业务架构,数据架构,技术架构,运维架构;微观看,每个系统都会有自己的应用架构。既然架构的种类很多,那么架构师的种类就更多,共同点是架构师一般都会以更高的视点关注一些通用的东西,或者在从无到有的演进中规划合理的蓝图。
CSDN:架构师的工作是什么?又该有着怎样的素养?
张亮:架构师的主要工作是提供面向抽象的较高层级解决方案,而非面向具体业务,对细节点进行处理。拿我们公司举例,主要是划分系统边界,设计系统交互路径,规划底层框架,规范开发流程等。
架构师对素质的要求比较均衡,不能有短板。前瞻性和领悟力,将决定系统是否符合潮流,便于演进。如何时实行SOA,何时推进微服务等;对业务的理解将决定系统能否贴近公司实情;对技术的理解力和阐述力将直接影响系统的设计;协调力和沟通力将影响系统的开发和实施,毕竟任何系统都不能由个人完成。
CSDN:当当在今年9月份开源了分布式作业调度框架elastic-job,能够简单介绍下它是什么、来历、架构设计思路等?和ddframe是怎样的关系?以及该项目的团队情况?
张亮:elastic-job原本是当当java应用框架ddframe的一部分,本名dd-job。ddframe包括编码规范,开发框架,技术规范,监控以及分布式组件。ddframe规划分为4个演进阶段,目前处于第2阶段。3、4阶段涉及的技术组件不代表当当没有使用,只是ddframe还未统一规划。
ddframe由各种模块组成,均已dd-开头,如dd-container、dd-soa、dd-rdb、dd-job等。当当希望将ddframe的各个模块与公司环境解耦并开源以反馈社区。之前开源的Dubbo扩展版本DubboX即是dd-soa的核心模块。而本次介绍的elastic-job则是dd-job的开源部分,其中监控(但开源了监控方法)和ddframe核心接入等部分并未开源。
elastic-job主要的设计理念是无中心化的分布式定时调度框架,思路来源于Quartz的基于数据库的高可用方案。但数据库毕竟没有分布式协调功能,所以在高可用方案的基础上增加了弹性扩容和数据分片的思路,以便于更大限度的利用分布式服务器的资源。
团队目前由3个部分组成,第一部分是开发团队,由架构部的架构师曹昊、高洪涛和我组成,主要负责设计和编码;第二部分是来自于各个研发团队的应用架构师、开发工程师和架构部总监史海峰,他们负责推广落地,整理需求并贡献当当已经存在的最佳实践代码;第三部分由架构部性能测试团队组成,负责框架的性能和稳定性测试。
另,如果你精通Java,并具备大型项目、复杂系统架构经验,欢迎加入当当架构部,简历发送邮箱:shihaifeng@dangdang.com
CSDN:能不能和我们详细的介绍下elastic-job具体模块的底层及如何实现以及它们的作用?
张亮:elastic-job的主要分为注册中心、数据分片、分布式协调,定时任务处理和多作业模式等模块。
注册中心模块目前直接使用Zookeeper,用于记录作业的配置,服务器信息以及作业运行状态。Zookeeper虽然很成熟,但原理复杂,使用较难,在海量数据支持的情况下也会有性能和网络问题。目前elastic-job已经抽象出注册中心的接口,下一步将会考虑支持多注册中心,如etcd,或由用户自行实现注册中心。无临时节点和监听机制的注册中心需要自行实现定时心跳监测等功能。
数据分片是elastic-job中实现分布式的重要概念,将真实数据和逻辑分片对应,用于解耦作业框架和数据的关系。作业框架只负责将分片合理的分配给相关的作业服务器,而作业服务器需要根据所分配的分片匹配数据进行处理。服务器分片目前都存储在注册中心中,各个服务器根据自己的IP地址拉取分片。
分布式协调模块用于处理作业服务器的动态扩容缩容。一旦集群中有服务器发生变化,分布式协调将自动监测并将变化结果通知给各个仍存活的作业服务器。协调时将会涉及主节点选举,重分片等操作。目前使用的Zookeeper的临时节点和监听器实现主动检查和通知功能。
定时任务处理根据cron表达式定时触发任务,目前有防止任务同时触发,错过任务重出发等功能。主要还是使用Quartz本身的定时调度功能,为了便于控制,每个任务都使用独立的线程池。
多作业模式将定时任务分为多种流程,有不经任何修饰的简单任务;有用于处理数据的fetchData/processData的数据流任务;以后还将增加消息流任务,文件任务,工作流任务等。用户能以插件的形式扩展并贡献代码。
CSDN:elastic-job是分布式作业调度框架,何为分布式作业?以及为什么需要作业?
张亮:作业即定时任务。一般来说,系统可使用消息传递代替部分使用作业的场景。两者确有相似之处。可互相替换的场景,如队列表。将待处理的数据放入队列表,然后使用频率极短的定时任务拉取队列表的数据并处理。这种情况使用消息中间件的推送模式可更好的处理实时性数据。而且基于数据库的消息存储吞吐量远远小于基于文件的顺序追加消息存储。
但在某些场景下则不能互换:
- 时间驱动 OR 事件驱动:内部系统一般可以通过事件来驱动,但涉及到外部系统,则只能使用时间驱动。如:抓取外部系统价格。每小时抓取,由于是外部系统,不能像内部系统一样发送事件触发事件。
- 批量处理 OR 逐条处理:批量处理堆积的数据更加高效,在不需要实时性的情况下比消息中间件更有优势。而且有的业务逻辑只能批量处理,如:电商公司与快递公司结算,一个月结算一次,并且根据送货的数量有提成。比如,当月送货超过1000则额外给快递公司多1%的快递费。
- 非实时性 OR 实时性:虽然消息中间件可以做到实时处理数据,但有的情况并不需要。如:VIP用户降级,如果超过1年无购买行为,则自动降级。这类需求没有强烈的时间要求,不需要按照时间精确的降级VIP用户。
系统内部 OR 系统解耦。作业一般封装在系统内部,而消息中间件可用于系统间解耦。
CSDN:elastic-job的主要功能有哪些以及目前的部署和使用情况如何?可否用具体数据来说明。
张亮:
- 主要功能
- 分布式:重写Quartz基于数据库的分布式功能,改用Zookeeper实现注册中心。
- 并行调度:采用任务分片方式实现。将一个任务拆分为n个独立的任务项,由分布式的服务器并行执行各自分配到的分片项。
- 弹性扩容缩容:将任务拆分为n个任务项后,各个服务器分别执行各自分配到的任务项。一旦有新的服务器加入集群,或现有服务器下线,elastic-job将在保留本次任务执行不变的情况下,下次任务开始前触发任务重分片。
- 集中管理:采用基于Zookeeper的注册中心,集中管理和协调分布式作业的状态,分配和监听。外部系统可直接根据Zookeeper的数据管理和监控elastic-job。
- 定制化流程型任务:作业可分为简单和数据流处理两种模式,数据流又分为高吞吐处理模式和顺序性处理模式,其中高吞吐处理模式可以开启足够多的线程快速的处理数据,而顺序性处理模式将每个分片项分配到一个独立线程,用于保证同一分片的顺序性,这点类似于kafka的分区顺序性。
- 其他功能
- 失效转移:弹性扩容缩容在下次作业运行前重分片,但本次作业执行的过程中,下线的服务器所分配的作业将不会重新被分配。失效转移功能可以在本次作业运行中用空闲服务器抓取孤儿作业分片执行。同样失效转移功能也会牺牲部分性能。
- Spring命名空间支持:elastic-job可以不依赖于spring直接运行,但是也提供了自定义的命名空间方便与spring集成。
- 运维平台:提供web控制台用于管理作业。
- 非功能需求
- 稳定性:在服务器无波动的情况下,并不会重新分片;即使服务器有波动,下次分片的结果也会根据服务器IP和作业名称哈希值算出稳定的分片顺序,尽量不做大的变动。
- 高性能:同一服务器的批量数据处理采用自动切割并多线程并行处理。
- 灵活性:所有在功能和性能之间的权衡,都可通过配置开启/关闭。如:elastic-job会将作业运行状态的必要信息更新到注册中心。如果作业执行频度很高,会造成大量Zookeeper写操作,而分布式Zookeeper同步数据可能引起网络风暴。因此为了考虑性能问题,可以牺牲一些功能,而换取性能的提升。
- 幂等性:elastic-job可牺牲部分性能用以保证同一分片项不会同时在两个服务器上运行。
- 容错性:作业服务器和Zookeeper断开连接则立即停止作业运行,用于防止分片已经重新分配,而脑裂的服务器仍在继续执行,导致重复执行。
Elastic-job在当当内部也是刚刚进行推广,目前支付系统、订单系统、发票系统、促销系统都有使用,快递系统和仓储系统也即将使用。开源后也得知不少公司有使用计划。
CSDN:对该开源项目的未来有什么期待?
张亮:elastic-job的开源主要是为了反馈社区。开源短短两个月,我们收到了很多朋友的反馈和支持,非常感谢。目前的elastic-job定位是一个基于Java的定时任务调度框架,未来想发展成为支持异构语言,高度灵活,可自定制的定时任务调度产品。
未来的展望主要包括几个方面:
- 异构语言支持。目前采用的无中心设计,难于支持多语言,考虑调度中心的可行性。
- 完善监控体系。增加监控维度,metrics统计,全量历史数据对接输出等。
- 更多作业类型和分片策略的支持。
CSDN:最后,能否就开源产品谈下你的开发理念?
张亮:技术类开源项目和一般的业务型项目不同,更需要对代码和质量的控制,我们总结出以下几点:
- 用心写代码,用代码讲故事。代码是项目的唯一核心和产出,任何一行的代码都需要用心思考优雅性,可读性,合理性。
- 代码整洁干净到极致。简单点说就是重度代码洁癖患者。只有代码漂亮整洁,其他开源爱好者才愿意阅读代码,进而找出项目中的bug和贡献高质量代码。
- 极简代码, 高度复用,无重复代码和配置。Java生态圈的特点是高质量的开源产品极多。我们尽量考虑复用轮子,比如项目中大量用到lombok简化代码;但也不会无原则的使用开源产品,我们倾向于把开源产品分为积木类和大厦类。项目中一般只考虑使用积木类搭建属于我们自己的大厦,而不会直接用其他已成型的大厦。
- 单一需求可不考虑扩展性;两个类似需求时再提炼。
- 模块抽象划分合理。
- 如无特殊理由, 测试需全覆盖。elastic-job核心模块的测试覆盖率是95%以上。虽然单元测试覆盖率在分布式的复杂环境中并无太大说服力,但至少证明项目中很少出现低级逻辑错误。
- 对质量的定义。代码可读性 > 代码可测性 > 模块解耦设计 > 功能正确性 > 性能 > 功能可扩展性。只有代码可读,可测试,可100%掌控,项目才可持续发展。功能有缺陷可以修复,性能不够可以优化,而代码不清晰则项目会渐渐变为黑盒。所以对于框架类产品,我们认为质量 > 时间 > 成本。
- 文档清晰。