精华内容
下载资源
问答
  • 凌云时刻 · 故事导读:《饿了么技术往事》分为上、中、下 3 篇,今日推送中篇,欢迎持续关注。点击此处阅读上篇。作者 |脉坤来源 | 阿里巴巴中间件前言在《饿了么技术往事(上)》中,...

     

    凌云时刻 · 故事

    导读:《饿了么技术往事》分为上、中、下 3 篇,今日推送中篇,欢迎持续关注。点击此处阅读上篇。

    作者 | 脉坤

    来源 | 阿里巴巴中间件

    前言

    《饿了么技术往事(上)》中,我介绍了饿了么最早期 All in One 阶段的架构,以及第二阶段业务系统拆分与团队运营的一些思考,以及我对于架构师职责的感受,接下来我会详细介绍饿了么全面服务化的架构演进历程。

    第二阶段:拆迁和基建

     中间件

    业务线的工程师深陷到快速的迭代和业务复杂性当中,业务的快速增长、外卖行业午晚高峰业务特点带来的并发挑战,领域拆分后所需的服务体系框架支撑,责任自然落到了中间件团队。

    当时中间件团队主要负责的三件事就是发布系统、SOA 框架、统一的数据访问层。

    1. 发布系统

    外卖业务周末的单量通常比工作日要高,但是工作日事故率要高于周末,为什么?变更是万恶之源,周末很少发布。所以,发布系统接手管控,取消手动发布的模式,解决发布回滚的问题,通过发布自动化提高效率的同时,回收服务器的权限,降低安全和稳定性的隐患。当然发布系统的作用远不止于此,后续这个体系及其团队充当起了基础架构演进的核心角色。这个是后话了。

    2. SOA 框架

    SOA 框架是支撑业务服务的骨架。和多数类似框架一样,为应对复杂的服务体系,服务注册和发现,常见的基于 Design for failure 的设计,熔断、限流、舱壁、多集群隔离这些功能都一样。但是,较特殊的地方在于——我们有两套 SOA 框架,Java 版和 Python 版。前面提到,我们有两个主要的技术栈——Java 和 Python,使得我们凡是需要 SDK 的地方,都需要支持两种语言,毫无疑问会对增加中间件团队负担。在当时确实是个难题,这个现在当然也有解,后面会提到。

     体会和教训——是否应该统一技术栈?

    关于是否应该统一技术栈,没有一个标准的答案。每个公司的技术栈和技术体系,有其形成的背景,如同架构一样,不放在上下文里面讨论合理性,往往没有结果,烟囱型也好、L 型也好,只要是适合自己的技术和架构就好。

    Python 技术栈当时已经支撑了很多核心系统,推翻现有系统,换技术栈的时间成本不可忽视。而当时市场竞争非常激烈,对于饿了么这样的创业公司,数据、时间和人是最宝贵的。而且,有一支能力非常强的 Python 技术团队,从里面抽调部分工程师,支撑 Python 技术栈的中间件建设,也不会带来额外的人力成本。维护两个技术栈,中间件团队的负担会增加,但是,换取的是时间和优秀的工程师,还是划算。这些 Python 工程师里面,负责业务系统的很多人后来也成长为独挡一面的角色,跟上了业务快速增长的步伐(后续会有相关的内容分享)。而负责中间件的 Python 工程师,他们的一些创造性实践,也为我们后续架构演进奠定了基础。

    好的技术体系和架构,起决定性的不是技术栈,最终还是优秀的工程师。

    3. 数据访问层

    因为多技术栈的存在,DAL 层选择了中心化的方案,而没有采取 SDK 。统一的数据访问层为后续分库分表、限流保护、多数据中心上线后的数据纠偏打下了基础。为了保证系统有足够强的吞吐能力,DAL 层采取了异步 IO 的方案来处理出入流量,中间件的最高境界是大家会忘记它的存在,DAL 层涉及到底层和数据库的交互,尤为敏感,而这个中间件几乎做到了,没有出现过重大事故,也很少有开发吐槽这一层的问题。后来,这个一直稳健的团队在饿了么多数据中心建设当中,负责了核心的流量调度及容灾切换管控体系。大家都习惯了叫 DAL,很多人不知道这个系统叫 Athena。

    基于 DAL 的上线,DBA 和 DA 这个时期就忙着给各个团队做分库分表的事情:

    • 按业务功能领域切分——拆库

    • 按照访问频率、动静态属性等等规则——垂直分表

    • 基于 Hash Partition(需要注意的是避免热点和 Rebalance 带来的成本)——水平 Sharding

    总之就是选择合适的 Partition 策略,降低数据库单个实例的负载。存储后来能支撑住千万级单量,除了上游队列的削峰、缓存的缓冲、数据库读写分离以外,也得益于适当的 Data Partition 策略。

     大前端

    其他团队还在拼命追赶业务、填坑补课的时候,大前端团队满足业务需求的同时,还为开源社区贡献出了非常优秀的产品 Element。就在大家认为这支团队会继续在前端领域上一骑绝尘下去的时候,令人没有想到的是,这个团队几年后会爆发出巨大的潜力,成为整个架构体系升级中一个举足轻重的角色。为什么叫大前端,因为他们和传统的前端团队做的事情不太一样,后面会讲到。

     体会和教训——找到优秀的工程师多么不容易

    招聘优秀的工程师,持续招聘优秀的工程师,这是一句正确的废话。但是有多难,带过团队的应该都深有体会,特别是你的公司还没有自带光环的情况下。优秀的工程师会吸引来更多更优秀的工程师,反之亦然,面试这个过程是双向的,尤其是优秀的工程师。有业务压力的时候,主管很容易扛不住,降低要求。当时大前端团队校招淘汰率还是挺惊人的,换来的是这个团队的工程师很高的技术素养和基本功,为后面成为一个真正的全栈团队打下了的基础。

    Leader 的个人能力,决定了他(她)是这个团队的地基还是天花板。

     大数据

    基于 Hadoop、Spark、HBase 的经典大数据架构这个时候也搭建起来了,因为是自建的数据中心,所以这些产品都需要有一个专业的团队来运维,因此大数据也有了自己的运维和中间件团队。在这个阶段,在线和离线数据同步、数据治理上面还不完善,因为产品化还在路上,很多工具缺失,导致很多团队都要自己直接去从数仓取数,不得不维持运营团队支撑定制化的手工取数需求。各个团队喊得最多的就是大数据的人不够,想要自己做。核心还是业务发展太快。后面随着大数据团队逐渐壮大,更多强援加入,各个产品相继成熟才得以缓解。

     风控安全

    这是一个不得不说,但是也不能说太多的团队,所以这部分只能务虚一些,任何一个到了一定规模的企业,风控安全团队是“真”底线。其他技术团队在面对这个同样是负责技术的团队面前,有时候确实也挺一言难尽的,这个时候高层的支持至关重要。尤其是从 0 开始建设这个团队,对内的扫盲和对外风控,一样艰难。

    如果说一个技术公司,系统毁了,有什么还能留下来,就还能重建,那肯定是数据(现在可能还要加一个算法模型)。有什么缺失了,随时都可能垮掉,那肯定是风控安全。

    饿了么的这支风控安全团队,对内、对外、对线上、对线下、对其他……都面临很多挑战和冲突,堪称业务专家的羊毛党和无孔不入的黑客,确实令人叹为观止。而我们的风控也经历了从开始的粗粒度约束、到依赖业务规则针对各种补贴、账期等场景兜底、再到依赖算法模型实时风控主动拦截的阶段。

    如果大家身边有做风控安全的同学,请珍惜,哪怕他们有时候看到系统到处是窟窿的时候,脾气暴躁。因为他们整天面对这么多黑暗面,还能对这个世界报以希望。开个玩笑,从人道的角度出发,这个团队需要定期的心理按摩。

    这个阶段,我们初尝了算法的威力。一开始只有搜索,但是还没有推荐召回系统,当时给推荐系统的物理机是我们能拿得出手的最好的物理机,其他业务系统分配的大都是虚机。系统上线以后,效果、转化率都还不错。之后不久这一待遇被另一个团队承包——负责配送履约的智能调度团队,大数据、机器学习、算法模型需要充分发挥功效,需要长时间紧贴业务、深刻理解业务,在智能调度领域我们也做过不少艰难的尝试、吃过不小苦头,直到我们有了自己的算法专家团队。

    这个阶段我们还经历了第一次外卖行业的大促——517 大促,让大家真切感受到了这个市场的巨大潜力,同时系统的一系列短板也暴露无遗,除了积累了大促的经验以外,更大的收获是让我们看到架构还有很大的升级空间。还收获了一支全链路压测团队,他们在今后架构升级以及系统质量、容量等稳定性保障过程中,扮演了关键角色。

    《饿了么技术往事》系列文章的开篇,我提到了饿了么的技术体系经历了以下四个阶段:

    1. 核心系统 All in one 的早期架构

    2. 以系统领域化拆分、业务系统和中间件等基础设施分离为基础的全面服务化的架构

    3. 随着自动化平台、容器调度体系成熟,治理从传统运维向 DevOps 转变的基础设施体系

    4. 多数据中心体系基础上的 Cloud Ready 架构成型

    现在我们前两个阶段基本完成了,开始了相对而言最艰难的阶段了……

    第三阶段:脆弱的系统,苦逼的运维

    这个阶段,我们的业务已经发展到一定规模,系统的长时间抖动或者崩溃,很容易上热搜,尤其是饭点时段。发生事故时候,冲在第一线的除了各业务线的工程师,还有运维团队,他们往往是最先响应,排障冲在第一线的团队。这个阶段说是靠他们生扛顶住了稳定性的压力也不为过:日常基础设施部署、事故发生时的应急响应、事故发生后的基础设施优化和改进措施落地,他们都承担了很多。

    事故的教训,也让我们学会了遵循一系列业界积累下来的设计原则,为架构演进到下一阶段打下基础。

    业务领域拆分、基础设施和业务系统分别建设后,给业务快速发展解绑了。但是包括稳定性在内的一系列挑战依然需要面对:

    • 基础设施部署的标准化

    • 系统的生命周期怎么管理?

    • 每次故障都是昂贵的学费,故障可以避免吗?

    • 复杂性带来的挑战:团队里面几乎没有人面临过这个体量的业务、这个复杂度的系统。快速交付的同时,如何保证系统的稳定和健壮?

    • 我们的系统架构接下来如何演进?

     DevOps

    因为云上资源的灵活性,我们在云上搭建了两个测试环境:alpha 作为开发环境,用于软件工程师日常开发调试;beta 作为集成测试环境,用于测试工程师完成系统交付上线前的集成、回归测试。费了九牛二虎之力才达成所有团队的共识,推动 beta 环境的系统和数据的完整性建设。在这里面发挥重要作用的,除了各个业务的开发、测试、运维团队,还有一个就是之前提到的负责发布系统的团队,这个团队不仅仅提供了一个简单的发布系统,基于持续集成和持续部署实现的开发、测试、生产环境相似化,是我们的系统架构继续演进的开端。

    技术团队职责细分后,运维团队提供了保姆式的服务,这把双刃剑的另一面,就是开发团队很容易形成惰性,对自己的系统管生不管养,对系统的容量、治理关心不够,因为有运维团队。这就带来很多问题,代码不是运维工程师写的,但是有些团队系统甚至是运维工程师部署的。因为开发团队最贴近业务需求,需求变更可能带来未来的潜在容量风险,他们比较有发言权;而容量水位的现状反过来是运维团队更了解。因为这个时候,很多基础设施运维还没完全自动化,所以难以统一化、标准化,每个运维工程师都有自己的运维风格,日常排障上,有时候需要开发和运维一起才能完成。

    此外,只生不养的思维方式,客观上也容易造成算力成本变成糊涂账。这个时候,开发、部署、系统运营(治理)角色的不统一带来的问题就会凸显。

    应用 Owner 要成为名副其实的 Owner,需要有应用的全景视角,对应用生命周期的把控能力。这个阶段,开始推动从虚拟化到容器化的转型,发布系统从一个简单的 CI、CD 的体系,延伸到了算力和调度的领域。基于一系列运维自动化工具的建设和全面容器化调度的实施,从而带来标准化的运维,才能把开发工程师(应用的 Owner)推到应用完整的生命周期运营的位置上,胜任 DevOps 的角色。这个时候,事实上底层的算力平台,已经具备云上 PaaS 的雏形了。

    在这个过程中,也做了不少尝试,比如,为了提高 alpha/beta 这两个测试环境的基础设施交付效率,有过一段时间基于 slack 的 ChatOps 实践,工程师都比较欢迎;还有过 Infrastructure as Code 和 GitOps 的实践,很可惜当时各方面条件和时机都不够成熟,没有持续推广。

     体会和教训 1——DevOps

    1. alpha 和 beta 环境

    工程师在开发机上自测是不是就可以了,“在我机器上是好的”这句话估计开发工程师都说过或者听过,在开发阶段提供 alpha 环境,目的就是为了开发、测试、生产环境的尽量接近,避免由于开发、测试、生产三个阶段由于环境差异巨大带来的问题。解决不了“在我机器上是好的”这个问题,没有办法大规模顺利上云。工程师自己的电脑,某种程度上是一台“mommy server”,上面运行着需要的一切环境,而且每个工程师的祖传环境还不一样,这类环境在生产上是不可复制的。

    2. Build & Release

    怎么做到高质量快速交付,保证系统的稳定?

    在快速迭代的同时,做到快速试错、快速纠错、快速回退。需要发布系统做到每个编译的版本、每次发布的版本,像代码一样,可回溯可跟踪。关键在于 build 和 release 是 immutable 的。

    首先,build 和 release 有唯一的 ID,才可追溯,可回滚。

    其次是配置分离,把和环境(dev/test/product)相关的 config 从代码中剥离开来,否则系统很难迁移,更不用说大规模上云。第一反应可能是,把和环境相关的 config 写在 xml 或者 yaml 文件就可以了,但是,这些文件也是代码。

    类似的,将这些随环境变化的 config 写在发布流水线的脚本里面,都不是彻底分离的方式。因为发布环境会发生变化,可能将来有更多的测试环境、更多的数据中心、每个数据中心里面可能还有多泳道。

    因此,要做到“build once, deploy many times/every where”,config 要存储在环境的上下文中,比如开发、测试、生产环境各自有一个配置中心,线上系统拉起的时候,先从配置中心拉取配置信息。要衡量环境相关的 config 和代码是否已经分离,看看能不能开源就知道了(抛开价值和代码质量不谈)。

    3. OPS

    接触过传统的运维工程师都知道,这是一群责任心极强的人(删库跑路,铲平数据中心的事情是不可能干出来的,虽然有能力……),他们维护着系统的底线,第一次 517 大促事故的时候,我们靠运维工程师救了大家一命。

    但是,即使有操作的 SOP,只要是人,执行重复任务的次数足够多,总会犯错。而每个资深的运维工程师,都有自己祖传的脚本,一夫当关万夫莫开,但是休假就麻烦了,特别是在高铁上信号不好的时候……最佳实践→SOP→脚本→自动化工具产品,沿着这个路径迭代似乎不可避免。

    传统的运维工程师角色的演进方向,一个是为云上的 IaaS/PaaS 服务,对操作系统和底层硬件有着丰富经验的,还是运维工程师,他们当中开发能力强的,转型 SRE,对运维产品理解深的,可以选择 Technical Product Manager 的角色,为云上运维相关平台产品提供解决方案,或者凭借丰富的云上系统落地实施经验,为各上云企业提供实施方案。

    另一个方向,由于合规和其他原因,还有部分没有上云的企业,依然需要基础设施运维工程师。随着云逐渐变成和水电煤一样的社会基础设施,运维工程师只写操作系统脚本、实施部署的时代已经渐行渐远了。

    架构的历次演进,和几次事故或者险些酿成事故的“冒烟”事件,有着很大的关系:

    • 交易系统崩溃的“饿死了”事故,我们开始分离关键路径和非关键路径,建设了非关键路径的降级能力。故障应急响应常规三板斧:重启、回滚、降级,至此完备。

    • 第一次 517 大促入口崩溃的事故,是我们核心系统上云的开端。

    • F5 的 CPU 被打满,让我们意识到网关作为入口难以扩展的巨大风险,从而基于重新构建的大网关体系,取代了 F5 这一层硬件负载均衡。大网关体系是我们多数据中心架构最核心的系统之一。

    • 基于 VIP 的 keepalived+HaProxy 负载均衡体系下,各种 failover 和上下游频繁扩缩容过程中,相关的稳定性冒烟或者事故频发,促成了充当 data plane 的 sidecar  上线,这是我们构建类 Service Mesh 架构体系最重要的组件。

    • 核心交换机 bug 引发的数据中心故障,对我们下决心建设多数据中心体系有着很大的影响。

    关于这些事故和架构的故事,随着架构的演进,后面会逐个展开。

    那个时候,我们常常自嘲是“事故驱动”型开发(Disaster Driven Development)。很多工程师除了自己的工位,在公司里面最有“感情”的就是整面墙都是监控大屏的 NOC 作战室,大小事故、各种大促活动值守,熬夜全链路压测,里面常常挤满熟悉的面孔。

     体会和教训 2——事故复盘

    事故复盘和定期的故障验尸总结会是一个很好的机制。很容易被忽略的是,除了找到事故发生的 root cause,还需要从中发现存在的隐患,而不是 case by case 的解决问题,复盘的目的是阻止类似的事情再次发生,必要的时候,可以引入业务、产品、技术共同解决。

    另一个陷阱是,故障复盘变成追责的过程,那么参与复盘的各方就很容易陷入互相指责、洗脱责任的怪圈,反而忘记了复盘的根本目的,也容易浪费大量时间,引起不必要的内耗。只要是参与复盘的人,都是有责任在身上的,为将来的故障负责,如果类似事故再次发生,或者没有在复盘中发现应该发现的隐患,参与的人都难辞其咎。

    复盘结果要避免惩罚为目的——除非违反了规章制度(底线,不排除有些是恶法,但不在讨论范围内)。否则甩锅、不作为的氛围会日渐滋生,自省有担当和有作为的个人或者团队,很容易成为吃亏的一方。事故复盘的过程,是了解各个团队甚至组织文化的一个视角。

     体会和教训 3——弹性设计

    物流、交易经历事故后,各自采取的措施再次印证了,反脆弱的设计是我们的应用发展到今天的核心设计思路之一。

    传统思路是基于一个上下文可控的理想系统环境下做出的设计,尽量避免一切意外的发生。而反脆弱的设计,恰恰假设黑天鹅事件一定发生,是墨菲定律的信徒,开句玩笑话,云厂商如果承诺你“我们一定会挂”,你一定要珍惜,你面对的是一个坦诚相待的乙方,值得托付。这不是推责给云厂商,这是由云上基础设施的特征决定的,大多数场景下,云上提供的服务是基于大规模标准化服务器(Off-the-shelf hardware)构建的虚拟化、容器化基础设施(Immutable Servers),而不是超高规格的个性化定制独占设备(Snowflake Servers)——无法规模化,成本也会大规模上升,因此,会更注重快速恢复能力,水平扩展能力,整体的健壮性,而不是具体某一个单机 SLA。

    所以云上系统更强调算力的抽象,CPU 核数、内存、网络带宽,把数据中心看作一个超级计算机,和 CPU 具备纠错机制一样,云上基础设施不是不会发生错误,只是结合它的“操作系统”(比如 Kubernetes),提供的是纠错能力(比如容器的故障转移——故障容器销毁,新容器拉起,本质上也是冗余),而云上业务系统需要适配这类纠错机制实现自己的自愈——面向云编程——接受短时间的抖动(Transient Fault)会不时发生的这一个事实。

    物流通过补偿机制增强自己的健壮性,交易引入 chaos engineering,都是基于这个上下文。要求应用是 stateless 或者 disposable 的,目的是为了 crash 后能够迅速拉起,快速自愈——所以,尽量分布式缓存,尽量少本地缓存,应用拉起时初始化的工作尽量少,交给独立的服务干这些事。业界的很多模式实践:bulkhead, circuit breaker, compensation transaction, retry都是指向提升系统的弹性(resilience),足够健壮的系统能够在经历系统抖动后,迅速自愈。

    故障和意外一样,难以避免。我们能做的是减少人祸,敬畏生产环境,因为一次故障影响的可能是骑手一天的生计、商户一天的营收、用户的一日三餐。同时,提高系统的健壮性和自愈的能力,在故障发生的时候,尽可能的避免演变成更大的灾难,及时止损。

     黑天鹅

    这个阶段,我们经历了一个大事故,起因就是核心交换机挂了,可能有人问,不都堆叠的吗,不都有主备吗,不都自动切换的吗,说得都对,但是都挂了。因为交换机的一个 bug,主备切换后,备机也很快被网络风暴打挂,没经历过我们也不相信。这次又“饿死了”,我们只能坐等供应商的工程师抱着设备打车到机房更换,这个时候,一群人挤在应急响应指挥室(NOC 作战室)里一点办法都没有。

    在第一次 517 大促之后,我们就开始第一次容灾尝试了,当时采取的是最快最简单粗暴的方案,用最短的时间,在云上搭建一个了灾备环境并跑通了业务链路。但这是一个冷备的环境,冷备最大的风险,就是日常没有流量,真正 failover 切换的时候,有比较大的不确定性。这次事故再加上另一个因素,我们下决心将技术体系推进到下一个阶段。

     体会和教训——上云

    2016 年第一次 517 大促,10 点开抢的瞬间,我们系统崩掉了,要不是当时一个很稳的运维工程师,淡定操作限流,可能不少人在饿了么的职业生涯当时就结束了。因为对当时的基于 Nginx 和部分自研插件的网关层比较自信,不相信网关层会顶不住,所以全链路压测的时候根本没有压这一层,事后复盘的时候发现是操作系统一个参数配置的问题,如果压测一定能重现。

    因为业务的效果很好,大促就成为常态,事实上第一次大促,我们是在自己的 IDC 里面用常规业务系统来扛的,所以影响到了非大促的正常交易。后面专门针对大促高并发大流量的场景设计了一套系统,也是隔离、排队、CDN、限流这些常规的套路,没什么特别的。但是,对我们影响更深远的在于,这套体系完全是在云上搭建的,2016 年之前虽然云上有系统,但是生产环境流量很少,顶多是短信触达这类系统在上面,更多是用于搭建测试环境。在当时看来,云上强大的流量清洗、资源 scale out 能力,很适合大促的场景,后面,这套体系经历了多次大促,没有波澜。

    在云上搭建大促体系以及灾备节点的经历,让我们后续在云上搭建全站的网关,并进一步构建整个数据中心,有了非常大的信心。下一篇我将继续介绍饿了么架构演变到了 Cloud-Ready 的状态,技术体系演进为业务发展提供了更多可能性。

    END

    往期精彩文章回顾

    饿了么技术往事(上)

    阿里云落地全球最大云原生实践:双11核心系统全面云原生化

    云上自动化部署和运维的正确姿势

    【cherry键盘白送】有人在云上送来一波双十一福利

    一位阿里云小哥要感谢“双11”,于是说了一段脱口秀……

    微服务框架 Go-Micro 集成 Nacos 实战之服务注册与发现

    如何做到数百万台车联网设备同时在线 0 故障

    2020CID|阿里云韩伟东:云原生底层系统思考

    如何将 KVM 异构虚拟机启动效率提升 6~10 倍?

    云湖共生,下一代数据湖来了?


    长按扫描二维码关注凌云时刻

    每日收获前沿技术与科技洞见

    展开全文
  • 大数据自 2009 年走向人们的视野,亦如所有新技术的发展,经历了一波炒作后,由风口回归理性发展。我们可以看到,随着 IOT 技术的发展和成熟,以及 5G 业务的全面铺开,数据规模还将持续增长。 新晋技术风口 AI、...

    大数据自 2009 年走向人们的视野,亦如所有新技术的发展,经历了一波炒作后,由风口回归理性发展。我们可以看到,随着 IOT 技术的发展和成熟,以及 5G 业务的全面铺开,数据规模还将持续增长。

    新晋技术风口 AI、区块链、RPA 的发展也都离不开大数据技术。大数据技术将作为一项通用技术,应用在各个角落。同时,大数据技术的发展也由解决数据规模问题,发展到如何更高效地消费大数据,数据的实时性、云上迁移等成为大数据圈的新挑战。我们挑选了一些能应对这些新挑战的有代表性的技术栈,绘制了如下大数据圈生态图,并在下文对主流的技术栈进行了介绍:

     

    OLAP 分析引擎:Apache Kylin™

    Apache Kylin™ 是一个开源的分布式分析引擎,提供 Hadoop/Spark 之上的 SQL 查询接口及多维分析(OLAP)能力以支持超大规模数据。Apache Kylin™ 仅需三步,即可实现超大数据集上的亚秒级查询:

    1. 定义数据集上的一个星形或雪花形模型
    2. 在定义的数据表上构建 Cube
    3. 使用标准 SQL 通过 ODBC、JDBC 或 RESTFUL API 进行查询

    Kylin 提供与多种数据可视化工具的整合能力,如 Tableau,PowerBI 等。

    Kylin 官方社区推荐必读好文:

    都是 HBase 上的 SQL 引擎,Kylin 和 Phoenix 有什么不同?

    Kylin 在携程百亿级数据分析中的实践

    从 ES 到 Kylin,斗鱼客户端性能分析平台进化之旅

    如何在 1 秒内做到大数据精准去重?

    想做大数据实时分析?且看 Kylin 如何解决

    新一代大数据计算引擎:Apache Flink

    ApacheFlink 是一款开源分布式大数据处理引擎, 可对有限数据流和无限数据流进行有状态计算。Flink在流处理方面具有绝对的优势,提供高吞吐、低延时的计算能力,如果你对大数据开发感兴趣,想系统学习大数据的话,可以加入大数据技术学习交流扣群:458数字345数字782获取学习资源,Exactly-once 语义保证数据的准确性,亚秒级别的处理延迟确保业务的快速响应,成为类似阿里巴巴、腾讯、华为、eBay、字节跳动、滴滴、美团点评、字节跳动等知名公司建设流处理平台的首选。

    Flink 官方社区推荐必读好文:

    如果你也想做实时数仓...

    Flink 客户端操作的 5 种模式

    Flink 状态管理及容错机制

    Flink SQL 编程实践

    Flink Runtime 核心机制剖析

    下一代云原生分布式流数据平台:Apache Pulsar

    实用干货!大数据入门的常用技术栈全在这里了

    Apache Pulsar 源于 Yahoo,2016 年开源,2018 年正式成为 Apache 顶级项目,集消息、存储和函数式轻量化计算的流数据平台。

    技术上采用业界领先的计算和存储分离架构,使用 Apache BookKeeper 作为其分片存储,配合层级存储,具备“高吞吐、低延时、分布式强一致、瞬时弹性扩容、Balance-Free、故障自恢复的高可用” 等核心特性。

    Pulsar 官方社区推荐必读好文:

    Apache Pulsar 介绍

    Apache Pulsar:从消息系统到流原生平台

    Apache Pulsar 项目和社区分享

    Apache Pulsar 的跨地域复制机制介绍

    Flink 和 Pulsar 的批流融合

    开源的非关系型分布式数据库:Apache HBase

    Apache HBase 是一个高可靠、高性能、面向列、可伸缩的分布式数据库,是谷歌 BigTable 的开源实现,主要用来存储非结构化和半结构化的松散数据。HBase 的目标是处理非常庞大的表,可以通过水平扩展的方式,利用廉价计算机集群处理由超过 10 亿行数据和数百万列元素组成的数据表。

    HBase 官方社区推荐必读好文:

    再谈 HBase 八大应用场景

    HBase 原理|HBase 内存管理之 MemStore 进化论

    HBase 抗战总结|阿里巴巴 HBase 高可用8年抗战回忆录

    HBase 实践|说好不哭,但 HBase 2.0 真的好用到哭

    HBase 分享 | 基于 HBase 和 Spark 构建企业级数据处理平台

    开源分布式 NoSQL 数据库系统:Apache Cassandra

     

    Apache Cassandra 最初由 Facebook 开发,于 2008 年开源。它集 Google BigTable 的数据模型与Amazon Dynamo的完全分布式架构于一身,表现出良好的可扩展性和性能。在数据库排行榜“DB-Engines Ranking”中位于宽列存储模型数据库第一名, 同时也被 Apple, eBay, Netflix, 360,饿了么等知名国内外公司广泛使用,是当下一种流行的分布式结构化数据存储方案。

    展开全文
  • 饿了么并入阿里集团,为了能高效与集团内部系统协同对接,同时方便利用集团优势技术资源,更好的融入阿里集团技术生态圈,饿了么交易中台在上半年启动了交易领域的四大应用语言转型项目,为阿里集团本地生活服务...

    前言:
    本文介绍了饿了么交付中心由python语言栈转换到java语言栈大致过程,一来是对前段时间的工作做下总结,另外也是想通过此次总结为其他应用服务转型提供些借鉴。写的不好,欢迎板砖。

    背景

    饿了么并入阿里集团,为了能高效与集团内部系统协同对接,同时方便利用集团优势技术资源,更好的融入阿里集团技术生态圈,饿了么交易中台在上半年启动了交易领域的四大应用语言栈转型项目,为阿里集团本地生活服务平台打好技术平台基础做准备。另外,随着业务量的激增,饿了么平台支持的品类不仅仅是最初的外卖单品,整个交易中台也需要一次相对大的重构来快速应对复杂多变的业务需求。而本文中的交付中心即是饿了么交易领域四大应用之一。

    准备

    在开展相关工作之前,首先必须得清楚我们是要将一个系统从什么样变成什么样,新的系统相较老的系统在哪些方面做的更好,同时必须保证新老系统的无缝切换,做到业务无感不影响交易系统的稳定性。

    系统价值

    外卖订单的业务特点是重交易,c端用户从下单选餐到骑手完成餐品交付过程,目前大部分都能在半小时左右完成,对即时配送实时性要求较高。整个订单交易过程大致划分为:1.添加购物车确认订单,2.订单生成及订单支付,3.接单及订单交付,4.可能的售后退单。而要更好的服务用户,对四个系统稳定的协同能力提出很高的要求。

    如前文所述,我们知道履约环节对交易订单的价值是什么,即是将外卖订单对应的餐品交付到用户手中,技术层面上来讲,交付对交易订单屏蔽了一切其他履约细节,使订单更专注订单领域业务。

    内核分析

    接下来,我们再进一步详细的剖析下转型前交付系统所承载的功能。
      

    如上图所示,原交付履约领域中包含了三个较大板块:

    • 1.订单对接运力线模块
    • 2.商户订单信息模块
    • 3.部分金额计算模块

    可以看出原系统所承载功能并非真正聚焦在订单交付过程。怎么办?转型重构是个契机。商户订单回归到订单,金额计算下沉至结算,这两部分的相关转型重构这里不再赘述,相关部分也已由兄弟团队完成。其实到这里交付履约应该关注的已经很明显:把外卖订单给运力线,使其完成交付履约。

    基于刚才提取后的交付履约核心领域,我们对主要的场景用例进行了详细的梳理。如下图所示,可以看到:

    • 参与交付过程的主要角色有四个:

      • 1.商户
      • 2.订单
      • 3.履约运力线
      • 4.用户
    • 交付提供的主要支撑能力有:

      • 1.乎单交付能力
      • 2.运单状态同步能力
      • 3.运单信息透出能力
      • 4.履约方式切换能力
      • 5.运单状态广播触达下游能力等。
    • 部分运单取消或异常管理。

    系统核心用例分析如下图所示:

    更详细的系统用例梳理或系统上下游交互时序这里不再一一列举,需要说明一点,当大流量系统转型遇到重构,要想走的够远够稳,前期的仔细调研工作及功能对齐过程非常重要。特别是生产环境已经跑了好几年核心功能系统,实际业务情况错综复杂。例如要转型重构系统接口能力,接口含义,场景必须都要详细掌握。

    设计

    至此,我们的目标已经很明确:1.语言栈转型,2.过程中要将不属于交付的东西从原系统中分离出去,使得交付领域更干净。结合交付未来可能的发展方向,其中交付能力可复用的,履约运力线可扩展的。这对整个交付可快速迭代对接提出了更高要求。另外,我们也在领域建模设计思想指导下做了些实践尝试,于是有了以下框架结构。

    系统设计

    转型是把python方言转换到java方言,交付系统核心能力不会有变化。能力的复用是通过接口维度的抽象聚合产生,履约运力线能力可扩展通过利用业务框架扩展点特性满足。拆分后的业务框架应如下图所示:

    系统架构

    业务框架结合当前饿场基础组件支持我们不难给出以下系统内部模块划分:

    简单对各组成模块做简要说明:

    • api:处于业务框架中上游系统接入层,对外暴漏契约屏蔽细节,对内定义系统能力。
    • starter:启动项目
    • service:rpc服务暴漏
    • domain:核心业务能力实现,聚合层
    • infra:基础数据支撑能力层
    • extension:履约能力扩展层
    • tester:单元测试包

    到此,我们可以按照设计与既定的计划撸代码了。

    嗯,代码撸完了测完了,从调研到开发完成历时两个半月,代码仓库总行数约4.7w行,提交1000次左右,完成63个接口+16个消息消费入口转型迁移,共计测出117+bug,期间有喜有忧,奋战两点多是常态。职业生涯中浓重的一笔。此时尤记起与超哥@邹超周末代理联调于北14楼小黑屋之畔,和明龙@张明龙并肩作战对接服务接口,还有晓波@俞晓波凌晨一同压测观察总结问题第二天分析反馈提升优化,当然还有杰哥@汤良杰的用例设计全面不失细节、对bug常常究其根本,对代码review逻辑核对一丝不苟明察秋毫。凡此种种,历历在目。一起走来,真心感谢。
                        ------  不由自主的感概下  ≧◇≦

    平稳过渡

    代码撸完测完才做好转型工作的第一步,将流量稳步平滑过渡到新的服务中,做到上下游无感是转型过程中面临的另一大挑战。
    说到这里,要达到系统的语言转型前后的平稳过渡其实是在说转型前后对我们系统的用户SLA(Service Level Agreement)提供一致性的保证。这里先简单聊聊系统服务的SLA。

    服务可用性级别服务正常运行时间百分比年宕机时间日宕机时间
    190%36.5day2.4 hour
    299%3.65day14 min
    399.9%8.76day86sec
    499.99%52.6min8.6sec
    599.999%5.25min0.86sec
    699.9999%31.5sec8.6msec

    上表格是业界服务高可用的几个级别的衡量标准,例如:服务可用性是3个9时,全年宕机时长约为8.76天的统计概率。另外,我们需要明确的是不同的系统,不同的场景以及不同的用户规模对系统可用性要求是不一样的。如:某些业务的支付链路场景可能tps不是很高,但是作为交易的核型链路必须得保证高级别的可用性。
    怎么保证或者提升系统服务的SLA呢?在明确我们目标后,接下来就是拆解目标量化目标。

    you cant measure it,you cant fix it and improve it.

    一般来说,影响系统服务可用性有两个重要因子:

    • MTBF:Mean Time Between Failures,系统服务平均故障时间间隔。
    • MTTR:Mean Time To Recover,系统服务平均故障恢复时间时长。

    所以大致可以简单归纳为这样的一个函数关系:

    QzpcVXNlcnNcd2Itd3h5NTg0MzIzXEFwcERhdGFcUm9hbWluZ1xEaW5nVGFsa1w2ODY4MzMyNzFfdjJcSW1hZ2VGaWxlc1wxNTczMTc3ODA3NjI5XzY2OTU3MDk0LUMyQ0EtNGRlZi1CRjVFLTYyN0ExODgxMDkyMi5wbmc_
                                            
    可能无法给到一个精确的数学描述,但是可以做定性的分析:恢复时长因子与系统可用度成正相关,故障间隔因子与系统可用度成逆相关。也即:_问题出现时恢复时长要尽可能的短,尽可能降低故障频率以增大故障间隔。
    基于以上理论,我们在做系统平稳过渡无缝切换时,无论资源使用,业务内部逻辑实现及灰度方案,我们都需要着眼于这两个方面。接下来我们将从这两个点出发分析转型过程存在的挑战及我们的应对方式。

    快速响应,降低恢复时长

    要做到恢复时长尽可能的短,首先我们需要保证在前期出现问题时流量切换过程中流量规模尽可能的小,即需要一个相对的合理的灰度梯度方案。其次当问题出现后我门需要能立即回切到原系统,不至于反应过慢导致大量增量问题产生,即需要一个响应高效的开关回滚方案。由于转型过程中涉及的接口和消息消费入口较多,另外我们还需要考虑到后期问题排障和快速定位的可能耗时。

    • 针对灰度梯度合理制定,根据业务特征,开始阶段我们选择了较冷门城市(订单量较低)进行了各个运力标品业务的逻辑验证。标品验证完后说明我们新迁移实现的逻辑和原系统具有一致性。随后我们拉取了当前订单城市分布,根据城市订单分布占比制定灰度梯度,由小到大逐步增加。
    • 针对回切需要响应高效,我们应该有一个总的开关可以控制流量,回切应该是一键控制的。
    • 针对排障快速定位,灰度单生命周期内的操作能在单应用内自闭合,不至于排障时还需要确认灰度单某个状态到底走的原系统服务还是新系统服务。另外我们还希望,写操作灰度和查询灰度能单独隔离开,等写数据完全一致的情况下我们再开启新数据新接口查的灰度,将风险控制到最低。

    所以我们采用了如下的老系统服务代理方案:

    如上图所示,订单系统创建订单时根据既定的灰度计划读取配置给订单打标,灰度计划分为前期分标品,门店维度验证,后期按城市订单分布维度配置。若新系统服务出现问题可一键切掉灰度流量,止血增量问题。接着,原交付老服务识别标记做代理转发,订单不存在迁移标记则原流程操作处理,否则转发到新交付中心新服务操作处理,相应的消息监听处理同样也是参照订单标记,这样保证了同一个订单的交付过程能在一个应用中完成,有利于后期处理流量上来后的快速问题定位。
    另外,我们的接口灰度过程是写与查分离的,整个迁移过程大致分为三个阶段,如下图所示:

    • 第一阶段 灰度写阶段,灰度策略:餐厅维度,城市维度小范围灰度,读流量以老服务为准,问题出现及时切掉灰度写流量,逻辑回滚至老服务。
    • 第二阶段 灰度查询阶段,灰度标记流量以新服务为准,非灰度标记以老服务透出为准,灰度策略:各个查询接口按照百分比逐步增加灰度占比。
    • 第三阶段 迁移阶段,完成读写灰度,原系统老服务只是代理的一层皮,接下来就是上游系统迁移到新服务,去掉对原原系统服务的依赖,迁移完成。

    最大努力降低故障风险

    平均故障间隔是一个后验时长数据,要做到间隔时长尽可能的长,日常里就需做好发布控制,风险巡检及持续监控等工作。

    1.发布控制

    转型期间新系统服务必须遵循发布sop,饿场发布sop已经形成共识,我们只需严格遵守,这里不再赘述。

    2.风险巡检

    • 系统逻辑核对,多人多次code review。
    • 变更发布前主干场景自动化用例全通过。
    • 周期性压测。

    3.多层次持续监控

    • 部署机器,缓存集群,消息队列,数据库表等基础资源的基准监控。
    • 业务曲线成功率,日同比,周同比,曲线波动比,及主要接口入口流量到下游出口流量转换率监控,业务系统成熟后还应对各个服务响应时间指标做监控等。
    • 系统中很多情况下重试都是以异常中断为依据,这必然会对系统异常点带来较大的噪音。为此我们还需要细化各个中断异常的打点,排除不必要的干扰。

    一致性问题

    转型过程中我们实际上同时做了数据模型优化迁移,对外为了保证新老系统行为属性的一致性,我们还面临以下几个挑战:

    • 灰度数据需要双写新老交付系统库表,如何保证双侧底层数据的一致性?
    • 底层数据一致不等于对外服务接口数据透出一致,双侧服务应用层面怎么保证数据的一致性?
    • 订单阿波罗履约线和交付的上下游数据数据最终一致性怎么保证怎么验证?

    一致性的保证,别无他法,只能通过比对来做。但在做比对的时候我们还需要考虑到比对本身只是我们验证迁移系统正确性及稳定性的一部分属旁路,并非生产环境的必须功能。即我们得考虑这部分功能对现有系统可能造成的压力。这部分压力应该是随着系统验证完毕是可开关的,压力大小应随系统的表现可随时调节。不至于因为验证拖垮了生产应用。所以我们对比对的基本要求是:能一键开关,可监控可追溯。除了这些共性,具体还应做到以下几点:

    • 针对底层数据比对:

      • 比对应是准实时的,如只比对30分钟前的数据。
      • 比对数据是基于时间可分段采样的,如只比对10分钟以内产生的数据。
      • 为了方便控制,根据情况以上策略又可以是及时调节的。即准实时偏移量可调节,分段采样窗口大小可调节。

    具体实施方案如下:

    • 针对应用层数据比对:

      • 代理层接收请求后,比对应是异步的,不影响接口响应耗时。
      • 比对粒度要小,应细化到接口。
      • 识别灰度数据,只做有效比对。

    具体实施方案如下:

    无论数据层面还是接口层面出现比对不一致,应立刻去分析是什么原因导致不一致。解决根因逐步降噪,只至比对差异在我们认为可接受的范围内。

    • 针对上下游数据最终一致性:

      • 全量数据核对
      • 主干链路最终一致性核对

    经过数据准实时比对,接口实时异步比对,其实基本可以确认新老系统能力行为属性对等性。然而稳定大于一切,要百分百确定还需要t+1数据核验。即从全局数据角度看新老系统转换的影响。这里以主干链路呼单多日成功率为例做简要说明。如下图所示,多日乎单成功率基本在99.9977%左右,可以认为新老系统代理切换交付成功率基本表现稳定。

    未来

    截止此文攥写时间,饿了么交付中心已经完成了整个系统的语言转换,流量也已经100%切换代理到新系统,处于流量切换的第三阶段。结合日常系统维护与需求迭代实践,我们仍需要再以下几个方面进行更深入的思考:

    • 转型过程中为了在易测,可核对同时与python的“魔法”姿势斗争中找平衡,部分逻辑是"纯翻译"的,后期维护过程很痛苦,所以我们需要几次不小的重构来达到代码层面的和谐。
    • 不断监控降噪,持续细化监控粒度,监控是服务稳定基石。
    • 交付中心数据大盘建设,从数据层面量化观测我们的交付质量。数据驱动,数字运营从数据化思维优化我们的流程,提高我们的服务。

    方法论沉淀

    凡此以上,服务系统转型迁移归结于开发者理解与认知,项目的稳定实施归结于开发者套路方法运用。可以简单进一步提炼为以下方法论:

    • 详细调研,客观问题及满足业务的系统是复杂的,详细调研做好准备是必须的。
    • 持续监控,感知系统的质量是服务质量度量的第一步,不断持续的监控才能走的更稳。
    • 稳步过渡,互联网系统服务高可用稳定不容商量。
    • 问题发现根因解决,小的问题可能隐藏大的bug,认真对待究其根本,复盘->总结->提升。
    • 归纳总结业务再认知。

    关于认知提升的几个小点:

    • 对于每一位工程师,开发高并发大流量系统是挑战也是机遇。时刻保持进取学习心态,增强自身软素质。
    • 分布式情况下,承认系统并非绝对100%可靠,每一个环节都要考虑“失败”了怎么办,不同的场景我们需要在AP和CP之间作出抉择。如双链路调用保证可靠,异步重试保证顺序最终一致等。
    • 出了问题快速恢复是个永恒的话题,没有“怎么样“最快只有”这样”更快。精准定位立即恢复,如何将这个过程耗时降到更低值得深入思考。


    原文链接
    本文为云栖社区原创内容,未经允许不得转载。

    展开全文
  • 互联网大厂的后端技术栈

    千次阅读 2020-02-22 10:28:04
    最近公司招聘海外后端研发,所以整理一份技术栈的资料给他们,但是想来这份整理也适用于所有后端研发,所以去掉了敏感内容,把它呈现于此,本文重在概述,毕竟篇幅有限,欢迎【关注】...后续可能把单点拓展成文,详细地...

    最近公司招聘海外后端研发,所以整理一份技术栈的资料给他们,但是想来这份整理也适用于所有后端研发,所以去掉了敏感内容,把它呈现于此,本文重在概述,毕竟篇幅有限,欢迎【关注】https://www.zhihu.com/people/wenxi.zhang,后续可能把单点拓展成文,详细地一一阐述,另外笔者见识有限,毕竟也没有可能在所有大厂工作过,所以如果有疏漏可以在留言处赐教

    目录

    后端开发概述

    负载均衡 - Load Balance(LB)

    微服务生态

    Thrift

    服务发现

    Consul

    微服务框架

    数据库(Database)

    Mysql

    Mycat

    DRC

    缓存(Cache)

    Redis

    Redis 集群方案

    KV-DB

    消息队列(MQ)

    RocketMQ

    Kafka

    对象存储

    Elastic Search


    后端开发概述

    何为后端开发?以一个网站为例,通常来说,前端研发注重页面的展示,交互逻辑。而后端研发,则注重在发生在前端背后(backend)的逻辑上,例如给前端返回数据,存储数据。对于一个电商网站,一个简单的下单动作,后端可能包括商品数据查询,优惠信息计算,库存维护,用户优惠券维护,订单生成,商家通知触发等等。在很多大公司前后端的配比是1:3甚至更高,因为一个复杂的业务系统,前端的展示仅仅是冰山一角,更复杂的业务逻辑都隐藏在后端。

    通常来说,当用户触发某个行为后,客户端会通过http/https请求,和我们的服务器建立连接,发送请求,往往这个请求首先会被链接到负载均衡(LB)上,负载均衡根据配置,将请求转发到内部的API服务上。这些API服务,根据不同的业务逻辑会请求其他服务(Service),这些服务各司其职,例如读写某 Mysql 表、读写缓存,甚至请求搜索引擎来完成相应的任务。而API服务在完成相应的步骤后,也会将数据返回给客户端,客户端根据前端逻辑完成相关的展示。

    下面这个图,简单的展示了服务端研发可能使用服务组织方式和相关技术栈,后续会对所有技术栈和大厂使用场景一一简述。

     

    负载均衡 - Load Balance(LB)

    负载均衡作为连接内外的门户,在分布式系统中,有这非常核心的作用。下面的图是负载均衡最直观的呈现:

    它将流量从外部转发到内部系统,对于同样的请求内容,不同时序的请求会被转发到不同的服务实例上。对每个服务实例而言,它只需要承担系统总流量的 1/N 从而降低了单个服务的负载,提升了服务整体相应速度和系统稳定性。负载均衡器会保持跟踪所有下游服务的状态,如果服务不可用,则会被从调度移除。

    一个最常用的负载均衡就是Nignx反向代理,在上图中,如果使用Nginx做负载均衡,最简单的方法就是配置 upstream,例如下:

    #配置负载均衡实例 
    
    upstream user_api 
    { 
        server 10.0.6.108:7080; 
        server 10.0.0.85:8980; 
    } 
    
    #配置转发到 
    user_api upstream location /user 
    { 
        proxy_pass http://user_api; 
    }

     

    显然,这份配置中要指定 user api 服务已经部署实例的 IP 地址和端口。如果没有自动化的发布方案,意味着每次开发新的API都需要在服务发布好以后,更新 Nginx 配置,然后通过 reload nginx 的方式将API发布上线。如果API不经常变动,这种做法也能支撑业务发展;但是如果公司业务快速发展,经常频繁发布API风险就会比较大了。在服务重启切换配置的过程中,可能导致一些请求处理被丢弃,就连服务扩容和缩容(增加减少负载均衡实例),也要变更相应的nginx配置。

    所以很多大厂,都会建设自己的 LB 平台,在这里你可以配置需要暴露出去的 URL,提供服务的内部服务标识,也会支持一些额外的配置,包括限流、熔断参数等。而要做到这些,往往需要对 Nginx 原生的负载均衡能力做拓展,例如使用 dyups 模块支持动态上下线配置;需要一个额外的管理平台,来管理所有对外API;需要服务注册中心维护所有的服务对应的集群和实例。

    同时需要启动一个 API Watch的在线常驻服务,负责监听API配置变更和注册中心每个服务实例的上下线变更,生成 dyups 模块可以识别的 Nginx 配置,在线 load 到 Nginx 就可以完成服务动态上下线了。原理如下图:

    当然,这只是一个最基本的功能和原理展示,大厂们往往根据不同的在线使用场景会有很多优化和系统设计的考量。

     

    微服务生态

    微服务 - 也被称为微服务架构 - 一种将整个后端服务,按照领域、模块分解为若干独立小应用的一种架构方式。微服务有如下特点

    • 服务可以单独编写、发布、测试、部署,相比于所有功能集中于一体的单体服务,可维护性更强

    • 服务彼此之间依赖服务通信的方式松耦合

    • 按照业务领域来组织服务,每个团队维护各自的服务

    下图直观的阐述微服务的概念:

    既然微服务体系是按照组织结构、功能模块独立进行开发、测试、部署的,那么微服务架构就要解决因为独立部署带来一些问题,例如通讯协议,远程调用(RPC),服务发现,服务治理等。有能力的大厂往往会有自己的框架来解决上面的问题,例如淘宝的HSF、阿里开源的 dubbo,能力不足的小厂也可以从开源社区中选择合适技术为我所用,“拼凑”出合理的解决方案,下面主要从开源社区选择一些可用为我所用的技术来介绍。

     

    Thrift

    Thrift不仅仅是一个轻量的,高性能的远程调用(RPC)通讯协议,也是一个优秀的RPC框架。Thrift 使用一种被称为 IDL 的接口定义语言,来定义远程调用的接口。使用官方提供的工具可以将IDL文件生成微服务服务端(Server)和客户端(Client)代码。这里 Server 端指提供服务的一方,而 Client 则指服务调用方,Client 通过 RPC 对 Server进行调用。

    利用这份生成的代码,就可以实现Client通过指定IP和端口的调用Server服务了。个人感觉 Thrift 最大的优势是高性能,跨语言,以及足够轻量。跨语言是很好的特性,因为一个大公司的不同部门,可能语言技术栈会有差异,使用 Thrift 可以屏蔽这种差异,让彼此专注。

     

    服务发现

    上面提到,如果只依赖 Thrift 我们可以实现通过指定IP端口的方式进行服务调用,但是显然这是不可行的,我们需要 Client 动态感知 Server 端服务的存在以及提供服务的所有实例。服务注册中心就是解决这个问题而诞生的概念,可以简单理解注册中心就是一个保存着服务状态的”数据库“,服务成功启动后到注册中心去注册,并且保持和注册中心的心跳以维持服务在注册中心的最新状态,当服务下线或者异常退出,服务可以主动通知注册中心下线或者被注册中心通过心跳失败感知到。

    常见的服务注册中心例如 Spring Cloud 框架中官方提供的 Eureka,Dubbo 默认使用的 Zookeeper。Spring Cloud 和 Dubbo 也对 Consul 增加了原生支持,这里也主要介绍下Consul。具体对比可以参考[1]

     

    Consul

    Consul是基于GO语言开发的开源工具,主要面向分布式,服务化的系统提供服务注册、服务发现和配置管理的功能。Consul的功能都很实用,其中包括:服务注册/发现、健康检查、Key/Value存储、多数据中心和分布式一致性保证等特性。Consul本身只是一个二进制的可执行文件,所以安装和部署都非常简单,只需要从官网下载后,在执行对应的启动脚本即可。

    如果使用 Spring Cloud 或者 Dubbo 等微服务框架,可以通过配置实现使用 Consul 作为服务注册中心,服务启动后,在Consul提供的Web界面就可以查到相应的服务。服务客户端可以在第一次调用服务端前,通过Consul进行服务端实例的查询然后按照查询奥的服务实例进行远程调用。

    Consul 的 web界面:

     

    微服务框架

    开源社区中知名的微服务框架包括 Spring Cloud, Dubbo 等,这些框架配合生态中的一切其他组件可以解决例如服务注册&发现、负载均衡、熔断限流、调用链追踪等绝大多数问题。不过当业务发展到一定阶段,还会有更多问题要解决,例如服务调用鉴权等问题。

    所以各个大厂几乎都自研自己的微服务框架,但是基本的做法都是在开源社区选择一部分,自己扩展一部分,例如通讯协议和RPC选择Thrift,服务注册中心选 Zookeeper/Consul,然后需要自研扩展的部分就是例如服务注册,服务发现,负载均衡,统一监控,鉴权等公司特色的需求。

     

    数据库(Database)

    对于一个小公司而言,可能会选择把所有数据保存在 Mysql 中,因为全部业务数据的容量可能也只有百G。但是对于大厂,每天产生的数据可能都是T级别的,如果都保存在Mysql中会有诸多问题,例如存储成本、后续的修改查询效率、高并发场景下存储的极限能力等。

    数据有它不同业务特性和使用场景,业务特性很好理解,例如我们不容忍交易数据发生丢失并且在很多操作它的场景,要求强一致性;而用户评论,则能容忍很小比例丢失,并且评论计数器和评论数目之前的如果出现微小差距,用户也很难察觉到;而服务日志数据,则能容忍更大程度的丢失,只要不影响开发Debug可能就不会有人追究。

    数据不同的使用场景,也对存储有不同方面的要求。例如同样是用户资料,用户资料查看自己的资料,一定要保证资料是用户最新更新的,并且不能容忍出错,哪怕是页面相应速度略微慢一点;但是用在推荐场景作为用户画像作为模型输入的时候,就能容忍这个数据不是最新的,但是要求数据访问速度要高,因为推荐场景往往对成千上万个候选排序,画像数据访问慢则直接拖累了整个推荐系统的效率。

     

    Mysql

    对于Web应用而言,关系型数据库的选型中 Mysql 无疑是最佳选择。它体积小、速度快、开源授权使得它拥有成本低,支持多种操作系统,有丰富的社区支持,支持多种语言连接和操作。

    Mysql是保存业务数据的理想之选,首先关系型数据库在设计之初,从概念上就在支持业务数据建模的概念,关系型数据库能结构化的描述业务需求。Mysql 对ACID属性的支持,也能满足不同业务场景下对数据操作的不同诉求。但是在大厂背景下,Mysql也有它的限制。

    首先,对于在线大表DDL几乎不太可能,DDL指表结构变更之类的操作。对于一张动辄几千万数据的表,Alter Table 可能需要几小时,除非提供备案方案,否则服务在这段时间将不可用。

    其次,在线查询要注意性能优化,避免慢SQL拖垮DB的场景。常见的性能问题包括查询未命中索引而触发全表扫描;使用了聚合查询(group by)触发全表扫描等

    还有,大厂特别是ToC常见的大厂,每天产生的业务数据异常的大,Mysql存储超过几千万性能会下降,所以需要使用分库分表的方式来解决海量数据场景下的存储问题。

     

    Mycat

    Mycat就是一个解决数据库分库分表等问题的数据库中间件,也可以理解为是数据库代理。在架构体系中是位于数据库和应用层之间的一个组件,Mycat 实现了 Mysql 的原生协议,对于应用它感知不到连接了 Mycat,因为从协议来讲,两者是一样的。而Mycat将应用的请求转发给它后面的数据库,对应用屏蔽了分库分表的细节。Mycat的三大功能:分表、读写分离、主从切换。

    下图通过 Mycat schema 配置和实际 DB 部署来简要说明 Mycat 分库分表功能的实现:

    例如表 A,配置中它有两个数据节点,分别是 datanode1 和 datanode2,含义是逻辑表 A实际对应了两个物理存储,分别是 db1 和 db2。对于应用而言,应用连接 Mycat 感知到的时候逻辑表 A,而在底层 A 被拆分,存储在两个 db 中。

     

    DRC

    DRC 是 Data Replication Center 的缩写,在使用Mysql作为核心存储的场景下,我们可以使用Mysql原生的主备方案,实现同城灾备。但是如果 Mysql 部署在跨国,跨洲的场景下,原生的灾备方案就有诸多问题了,所以各大厂几乎都有自己的DRC方案。

    不过,虽然各自有不同的实现,但是原理和依赖的核心组件基本相同,本文从互联网上找到饿了么DRC组件阐述其原理。

    本图中,异地机房分别为北京机房和上海机房。本地机房(图中为北京机房)会启动一个 DRC Replicator,它和Master节点通信并在通信协议上模拟 Mysql Slave,Replicator将Master数据库的binlog变更实时拉取到本地。然后把binlog解析,通过消息中间件将变更发送到异地机房(北京机房)。异地机房启动一个DRC Applier的应用消费数据变更消息,然后把这个变更操作同步到本机房的Master上,就完成了异地数据同步的操作。图中展示的是北京机房数据同步到上海机房的场景,实际反过来也是一样。

    DRC在设计和实践中最常见的问题就是DB自增类型主键冲突,以及数据因为同步消息丢失而最后导致的不一致,前者可以通过强制使用ID生成器或者自增ID设置相同的增加值和不同的初始值等方式解决。而后者要么采用一个规则同步最终数据,或者进行人为数据干预。

     

    缓存(Cache)

    如果稍微深入研究Mysql的存储原理,我们不难发现,数据是存储在磁盘中的,虽然我们可以通过索引等数据结构,降低每次查找数据的响应时间,但是对于高并发的在线应用,直接查找数据库依然很容易触碰Mysql性能瓶颈,所以我们需要缓存来缓解DB查询的压力,当要查询的数据命中缓存后,直接从缓存中获取数据,从而降低DB的访问压力。常见的缓存有两种策略:

    本地缓存:不需要序列化,速度快,缓存的数量与大小受限于本机内存,很多语言提供一些框架来支持内存缓存,例如 guava cache,spring默认集成的 Ehcache。

    分布式缓存:需要序列化,速度相较于本地缓存较慢,但是理论上缓存的数量与容量无限制(因为分布式缓存机器可以不断扩展),常见的分布式缓存包括 Redis 和 Memcache。本文主要介绍下 Redis。

     

    Redis

    Redis 是基于内存的缓存中间件,正因为基于内存,所以具有非常快的相应速度。支持丰富的数据结构,例如 string、hashes、list、set、sorted set等等,应用非常广泛的应用。

    常见的缓存读写策略包括Cache-Aside,Read Through,Write Through,具体可以参考[2],不过文中缺少一种Cache 读写方案,这也是很多高并发在线应用比较常用的一种方式。

    Write Behind Caching模式

    Write Behind Caching 这种模式通常是先将数据写入到缓存里面,然后再异步地将DB更新的数据写入到cache中,这样的设计既可以直接的减少我们对于数据的database里面的直接访问,降低压力,同时对于database的多次修改可以进行合并操作,极大的提升了系统的承载能力。这个模式下,应用在读数据的时候,不感知DB,只感知Cache,优势在于简化了设计,缺点在于强依赖Cache,如果Cache出现问题例如宕机,则读会失效。

     

    Redis 集群方案

    伴随着需要缓存的数据量增加和高可用的依赖,大厂的Redis都是需要集群化方式部署的。一方面通过主从模式提升了系统的高可用,另一方面通过集群模式将系统演化为可用无限扩容的模式。

    Redis 从 3.0 版本开始,原生的支持了集群模式,通过 Sentinel 集群实现动态的主从模式[3];原生的集群模式,将所有的数据划分到 16384 slots中,而集群中的每个节点,会分配若干 slots。然而原生集群的方案,虽然简化了集群的设计,但是却增加了客户端的负担,需要客户端对Moved/ASK [4] 事件做封装处理,同时需要维护路由表提高访问效率,增加了客户端设计的复杂度。

    所以大厂往往不会选择 Redis 原生的集群化方案,而是使用基于Proxy的集群化方案,业界比较知名开源 Proxy 有 Twemproxy 和 Codis [5],本文简要介绍下 Codis,实际上很多知名大厂的 Proxy 都来源于Codis。

    Codis 引入了Group的概念,每个Group包括 1 个 Redis Master 及至少1个 Redis Slave,可以认为每个Group是一个系统分片(Shard),与 Redis-cluster 一样,Codis 也采用预分片的机制,整个集群分成 1024 个 slots,通过一致性哈希算法,将Key映射到某个 slot,再通过维护在 Zookeeper 里的分片路由表,将Key的请求转发到对应的Group上。

    Codis 提供了一套运营监控界面,运维人员可通过 Dashboard “自助式”地进行主从切换。

    而对于应用而言,访问 codis 和访问原生的 Redis 并没有任何区别,节点的动态上下线,slot 分配的变更都在 Proxy 层完美的对应用屏蔽了。

     

    KV-DB

    前文讲述了 Mysql 和 Redis,或许对于大多数公司,这两类存储已经足够。前者用于保存业务数据,后者用于集中式缓存。但是对于大厂,还有若干场景上面两种存储无法满足:例如推荐系统在线预测场景,需要将用户画像、商品画像、商家画像、用户商户交叉画像在线加载预测上下文,特征处理后给到模型做预测打分。ToC的互联网产品的注册用户很可能过亿,所以用户画像总存储很可能百G甚至T。

    如果是这样规模的数据,Mysql的读性能肯定扛不住在线预测场景;Redis 是内存缓存,存储昂贵,同时在容灾恢复时候,Redis需要将AOF或者RDB数据载入内存后才能提供服务,数据量过大需要很长的恢复时间。所以需要另外一种存储能解决这个问题。

    几乎所有大厂都有属于自己的KV-DB,例如360开源的Pika,饿了么通过购买Tikv封装而成Ekv,字节跳动的 Abase。Pika 和 Tikv在存储底层都使用了RocksDB作为数据存储,而RocksDB它是将数据存储在硬盘上的,Pika 和Tikv在上层构建的都是集群化方案,主从模式等,基于内存的一致性Cache等。下图是Pika架构图:

     

    消息队列(MQ)

    伴随着业务的复杂,我们往往会遇到这个场景,一个数据操作后,需要触发下游若干个子操作。例如外卖场景,用户下订单成功,要通知商家用户订单,要物流平台对订单进行调度和派单,要触发一些后置的风控逻辑对订单合法性进行校验等。如果是同步的设计,需要在订单完成后对后续的操作一一进行API调用,这样的做法让订单流程依赖更多外部服务,提升了业务复杂度,降低了服务的稳定性,所以我们需要消息中间件来解耦操作。依赖的服务依赖下单消息,而不是在下单结束后,通过接口调用的方式触发。

    我们可以把消息队列(MQ)比作是一个存放消息的容器,Producer 负责生产消息,将消息发送到MQ,Consumer取出消息供自己使用。如图所示:

    消息队列是分布式系统中重要的组件,使用消息队列主要是为了通过异步处理降低系统耦合性,除此之外,还可以依赖消息队列提高系统性能和削峰填谷。

    关于削峰填谷这里我举一个应用场景 —— 抢购。抢购是很多网站促销的重要场景,呈现方式往往是通过倒计时的方式,在某个固定时间放出限量的优惠产品。开放时间到来时,会有大量用户触发购买动作,我们知道下订单往往是一个耗时比较久的操作,需要对库存,营销信息,用户等多方面数据做查询、校验、计算操作,同时为了控制超卖,可能会引入锁机制。如果处理不好抢购的瞬时流量,可能会打垮系统。一种优化思路是可以将瞬间的购买请求转发到消息队列中,再由消息队列的消费者消费消息,进行后续的订单操作,从而对系统进行流量削峰。

    从大的应用场景上,我们可以将消息队列的应用拆分成两类,一类是业务场景,例如上文提到查到用户订单消息,这类场景的吞吐量未必很大,但是需要消息中间件具有一些更高级的易于业务使用的特性,例如支持消息持久化,延迟消息等。另外一类是大数据场景,该类场景对吞吐量有极高的诉求,例如用户行为搜集(User Behavior Tracking)等。这里只介绍两种上面场景适合的消息队列中间件。

     

    RocketMQ

    RocketMQ是一款分布式、队列模型的消息中间件,是由阿里巴巴设计的,经过多次双十一流量洪峰的洗礼,让它更有光环效应;RocketMQ是纯java编写,基于通信框架Netty这也让它拥有更好的社区基础和可改造的空间。相比于Kafka,RocketMQ支持很多业务友好的特性,具有以下特点: 支持严格的消息顺序,支持Topic与Queue两种模式,亿级消息堆积能力,比较友好的分布式特性,同时支持Push与Pull方式消费消息

     

    Kafka

    Kafka 的特点其实很明显,就是仅仅提供较少的核心功能,但是提供超高的吞吐量,毫秒级的延迟,极高的可用性以及可靠性,而且分布式可以任意扩展。同时 kafka 最好是支撑较少的 topic 数量即可,保证其超高吞吐量。kafka 唯一的一点劣势是有可能消息重复消费,那么对数据准确性会造成极其轻微的影响,在大数据领域中以及日志采集中,这点轻微影响可以忽略。

     

    对象存储

    对象存储是面向对象/文件的、海量的互联网存储,它也可以直接被称为“云存储”。对象尽管是文件,它是已被封装的文件,也就是说,在对象存储系统里,你不能直接打开/修改文件,但可以像ftp一样上传文件,下载文件等。另外对象存储没有像文件系统那样有一个很多层级的文件结构,而是只有一个“桶”(bucket)的概念(也就是存储空间),“桶”里面全部都是对象,是一种非常扁平化的存储方式。其最大的特点就是它的对象名称就是一个域名地址,一旦对象被设置为“公开”,所有网民都可以访问到它;它的拥有者还可以通过REST API的方式访问其中的对象。因此,对象存储最主流的使用场景,就是存储网站、移动app等互联网/移动互联网应用的静态内容(视频、图片、文件、软件安装包等)

    不过自建对象存储成本很高,很多中等规模的厂,都会选择商业化对象存储方案,例如七牛云,阿里OSS等,用来降低研发和维护成本。

     

    Elastic Search

    无论是在线应用还是管理后台,都有模糊搜索的需求,例如用户搜索感兴趣的帖子,评论,视频。管理员对命中一些关键词的内容进行批量下架等处理。这种模糊搜索,如果使用Mysql原生的查询,效率是非常低的,能想到的朴素做法可能先将用户Query进行分词处理,然后用分词的结果依次提交到Mysql做某字段的Contains条件查询。Contains操作会对表进行全扫描,如果有千万数据,效率难以想象。

    针对这样的场景,倒排索引是非常理想的方案,倒排索引(Inverted Index)是实现“单词-文档矩阵”的一种具体存储形式,通过倒排索引,可以根据单词快速获取包含这个单词的文档列表。

    如果需要索引的数据不多,索引更新频率也不高,简单的做法可以使用 Apache Lucene 构建一个非常轻量的倒排索引,将需要倒排的数据,通过 Lucene 提供的API 灌到索引文件中,而该索引文件可以在后续的搜索服务中被 Lucene 加载,提供查询服务。

    但是大厂场景往往是拥有海量需要索引的数据,同时要支持在线构建索引文件和灾备能力,在开源社区中 Elastic Search 就是非常好的选择之一,ES 底层也是基于 Lucene,但是它提供分布式的文档存储引擎,分布式的搜索引擎和分析引擎,支持PB级数据。

     

    Reference:

    [1] 主流微服务注册中心浅析和对比

    [2] Caching Strategies and How to Choose the Right One

    [4] redis 集群详解及搭建过程

    [5] Redis 的 MOVED 转向与 ASK 转向

    [6] 基于 Twemproxy 与 Codis 的 redis 集群方案比较

    [7] Rocketmq原理&最佳实践

    [8] 对象存储(云存储)概述

    展开全文
  • 作为一个互联网创业公司,饿了么从初创到壮大,在移动互联网时代,业务量和技术团队的体量经历了10倍增长,这其中的经历,是互联网领域许多创业公司技术团队的一个缩影。在这里把我们成长过程中的体...
  • 不知不觉已经写到了最后一部分,回顾经历的这段架构演进历程,内心还是非常感慨。在商业竞争中,技术团队和其他团队一样,作为组织的一部分,应该是荣辱与共的。但是,就行业而言,饿了么创造的社会价...
  • 来自:文西| 责编:乐乐链接:tinyurl.com/uzlgatz 正文 最近公司招聘海外后端研发,所以整理一份技术栈的资料给他们,但是想来这份整理也适用于所有后端...
  • 下面这个图,简单的展示了服务端研发可能使用服务组织方式和相关技术栈,后续会对所有技术栈和大厂使用场景一一简述。 image 负载均衡 - Load Balance(LB) 负载均衡作为连接内外的门户,在分布式系统中,有这非常...
  • 前端项目技术栈总结

    千次阅读 2018-11-17 20:18:00
    本篇文章将对作者目前正在使用的前端技术栈做一个总结与梳理,如果你对基本的JS/HTML/CSS框架有所了解,但是又对目前流行的web框架,更直接说是能够就业的技术不甚了解或是感到迷茫,那么相信大家看了本文之后会够...
  • (楞头萌新拨通饿了么订餐电话)嘟...嘟...嘟...您好,这里是饿了么点餐平台请问您需要什么点餐服务?你好,我要一份饿了么您需要什么?~我要一份饿了么饿了么的商家餐品有...
  • 作为互联网技术的进化,物联网开发并非孤立的技术栈,而是向上承接了互联网,向下统领了嵌入式硬件开发的一个承上启下的全栈开发技术。作为正在快速进化中的新互联网技术,我们并不能预测物联网技术栈最终的样子:...
  • 1、学校、专业 2、技术栈 3、职业履历 4、最近一家公司的贡献 千万不要和面试官说,和产品、后台很好的配合,完成公司的项目之类。因为完全是废话! 自我介绍一般是两分钟左右,你确定你能两分钟,把上面四个问题给...
  • 通过他制作这个简历的过程,聊一聊我创业公司的使用的技术栈,因为比较契合。 在切入正题之前,先看看这个小伙子做的简历,到底炫酷不炫酷呢?如下: 是不是感觉非常的炫酷和高大上呢?这其中他使用的技术正好跟我们...
  • 0 引言 时代演进,技术也随之发展。到今天,APP已然成为绝大多数互联网企业用来获取用户的核心渠道。...饿了么移动APP就是这样一个挑战,多用户量、多业务量,在接受着更多更挑剔用户的同时,默默地、不断地演进着移
  • 原文:tinyurl.com/uzlgatz最近公司招聘海外后端研发,所以整理一份技术栈的资料给他们,但是想来这份整理也适用于所有后端研发,所以去掉了敏感内容,把它呈现于此,本文重在概述...
  • 我们的技术栈基于 , , , 和 ,可以提前了解和学习这些知识使用本项目有很大的帮助。 同时配套一个系列的教程文章,如何从零整合后一个完整的后台项目,建议大家先看完这些文章再来实践本项目 相应需求,开了一个...
  • 大数据自 2009 年走向人们的视野,亦如所有新技术的发展,经历了一波炒作后,由风口回归理性发展。我们可以看到,随着 IOT 技术的发展和成熟,以及 5G 业务的全面铺开,数据规模还将持续增长。新晋技术风口 AI、...
  • 外卖红包小程序 美团外卖小程序 饿了么外卖小...技术栈 服务端api基于Node.js+ThinkJS+MySQL 后台管理 基于VUE.js+element-ui 成品展示 后台地址 http://q.mybei.cn/ 演示账号:18512341234 演示密码:123456 裂
  • 它使用了最新的前端技术栈,内置了 i18n 国际化解决方案,动态路由,权限验证,提炼了典型的业务模型,提供了丰富的功能组件,它可以帮助你快速搭建企业级中后台产品原型。相信不管你的需求是什么,本项目都能帮助到...
  • 今年初拿了个饿了么P7的offer,于此同时大家顺便看看我怎么途虎一轮游的。废话不多说,直接上题吧。一面首先上来就是自我介绍,简单的说下自己的项目经验,涉及的技术栈之类的。然后每一轮必问...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,690
精华内容 676
关键字:

饿了么开发技术栈