0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

“逃离”单体,GitHub的微服务架构实践

马哥Linux运维 来源:马哥Linux运维 2023-01-31 10:33 次阅读

1、旅程开启

GitHub 创建于 2008 年,其宗旨是为开发人员托管和分享代码提供便利。GitHub 的创建者也是开源贡献者,他们在 Ruby 社区非常有影响力。正因为如此,GitHub 的架构深深地扎根于 Ruby on Rails。在公司的整个发展历程中,我们雇佣了世界上最好的 Ruby 开发人员,帮助我们扩展和优化代码库。如今,我们的平台上已经有超过 5000 万名开发人员,每年有超过 8000 万个 pull 请求合并,全球各大洲有超过 1 亿个代码存储库。如你所见,这个单体架构已经带我们走得很远。一个演进了 12 年的代码库,每天要协调多次部署。我们有一个规模很大的平台,每天处理 10 亿次 API 调用,我们还提供了一个高性能的用户界面,专注于完成这项工作。

2、内部快速增长

在过去 18 个月中,GitHub 内部经历了快速增长。我们已经有超过 2000 名员工,为代码库做贡献的工程师数量已经是以前的两倍多。这种增长既包括自身的逐步发展,也包括收购,如 Semmle、npm、Dependabot 和 Pull Panda。此外,GitHub 是一个高度分散的团队,在疫情发生前,我们就有超过 70% 的员工是在旧金山总部以外的地方办公。GitHub 的员工和承包商要跨六大洲展开协作,他们工作的时区各不相同。我们有 1000 多名内部开发人员,他们有各种各样的开发技能,涉及到许多不同的技术。显然,我们需要从根本上重新考虑下 GitHub 的软件开发工作。让每个人在参与开发之前都学习 Ruby,让所有人都在同一个单体代码库上进行开发,不再是扩展 GitHub 最高效、最优化的方法。根据康威定律,任何组织设计的系统,其结构都是对组织沟通结构的复制。反之亦然,单体架构会导致更大规模的涉众会议,更复杂的决策过程,因为交织的逻辑和共享的数据会影响所有团队。

3、单体 vs. 微服务

因此我们就想,是不是该从 Ruby on Rails 单体迁出,转向一种微服务架构了?如果是这样的话,我们该如何进行?单体架构和微服务架构各有所长。在单体环境中,配置并运行应用程序更简单,不用考虑复杂的依赖关系,拉取所有必要的依赖项。新建一个 Hubber,只需几个小时就可以在本机上配置好 GitHub 并运行起来。在单体架构中,代码在有些情况下会更简洁。例如,不用添加超时处理逻辑,也不用考虑如何优雅地处理由网络延迟和中断所导致的失败。此外,由于所有人都工作在同一个技术栈上,大家对代码库都很熟悉,所以可以方便地将开发人员和团队调去开发单体的其他特性,有利于实现特性的全局最优。考虑到 GitHub 在过去 18 个月中的增长情况,微服务环境的一部分优点吸引了我们。例如,建立具有系统级所有权的特性团队,通过清晰定义的 API 契约确立职责边界。在遵循 API 契约的前提下,团队有充分的自由选择最适合自己的技术栈。代码库更小意味着阅读更容易、启动速度更快、问题排查更简单。开发人员不用为了提高生产力去理解一整个庞大的代码库的内部运行机制。最重要的是,服务现在可以根据各自的需求单独扩展。

4、务实——以赋能为出发点

在开始迁移 GitHub 之前,我们花了一些时间考虑为什么要这样做,以及这样做的目标是什么。对我们来说,这是文化上的巨大转变,需要做大量的工作。我们得想好,到底要解决什么问题和痛点。在 GitHub,这样做可以让超过一半的开发人员(在过去的 18 个月中加入)在单体代码库之外富有成效地开展工作。我们的目标是赋能而非替代。为此,我们得接受这样一个现实,GitHub 未来的特性将基于一个单体 - 微服务混合的环境。也就是说,对于我们来说,维护和改进现有的单体代码库仍然很重要。有一个很好的例子是,我们最近升级到了 Ruby2.7。感兴趣的话,可以从 GitHub 官方博客上了解我们做了什么,以及我们总体上如何改进系统。

5、良好的架构始于模块化

良好的架构始于模块化。拆分单体的第一步是考虑基于特性功能分割代码和数据。这个过程可以在真正在微服务环境中拆分之前在单体中完成。使代码库易于管理,通常都是一种良好的架构实践。确保每个服务都有自己的数据,并且能够控制对这些数据的访问,而且只能通过明确定义的 API 契约访问。我看到,在很多情况下,人们会首先抽出代码逻辑,但仍然使用单体的共享数据库。这往往会导致分布式单体,这是最糟糕的单体,同时也是最糟糕的分布式。没有获得任何好处(比如,单独快速地向生产环境中部署一组特性),却还要应对微服务的复杂性。

6、数据拆分

正确地拆分数据是从单体架构转向微服务的基础。这里将稍微详细地介绍下 GitHub 的做法。首先,我们在现有的数据库模式中识别功能边界,并按照这些边界将实际的数据库表分组。例如,我们将所有存储库相关的表分到一起,所有用户相关的分到一起,所有项目相关的分到一起。我们将生成的功能分组称为模式域,并记录在 YAML 定义文件中。现在,这个文件就成了事实来源。在数据库模式中添加或删除表,都要更新这个文件。我们通过一种静态分析测试方法来提醒开发人员,在修改数据库模式时,要更新这个文件。接下来,对于每个模式域,我们找了一个分区键。这是一个共享字段,将一个功能组中的所有信息联系在一起。例如,存储库模式域(其中包含所有与存储库相关的数据,如问题、pull 请求、评审意见)使用存储库 ID 作为分区键。最终,创建数据库模式功能组帮助我们将数据拆分到微服务架构所需的不同服务器和集群上。对于当前的跨域查询,我们做了修复,以防数据拆分对产品造成破坏。在 GitHub,我们在单体中实现了一个查询监视器来帮助我们检测,并在发现跨域查询时发出告警信息。我们会根据域边界,把这些查询拆分并重写成多个,并在应用程序层实现必要的连接。在划分完功能组后,我们开始通过一个类似的过程,进一步将数据分片到相应的租户组。GitHub 有超过 5000 万用户和 1 亿个存储库,在这样的规模下,功能组可能会变得非常大。这时,分区键就派上用场了。例如,一种简单的方法是根据数值范围将不同的用户分配到不同的数据存储。更常见的可能是根据每个数据集的特性(如区域和大小)所做的逻辑分组。Tenantizing 是一个很好的方法,可以将数据存储故障的爆炸半径限制在客户的一个子集里,而不是一下子影响到所有人。

7、从核心服务和共享资源入手

我们已经花了很多时间讨论数据拆分的重要性。现在,我们换个话题,介绍下从单体中抽取服务的基础工作。一定要记住,依赖方向只能从单体内到单体外,不能反过来,否则,我们最终会得到一个分布式单体。也就是说,当从单体中抽取服务时,要从核心服务入手,然后逐步到特性层面。接下来,找出开发人员在单体环境中开发时所使用的助力工具。随着时间的推移构建一些共享工具以方便单体开发,这是很常见的。例如,我们的特性标识,可以让单体开发者安心地将新特性从测试环境转到生产环境,因为在这个过程中,他们可以通过这个标识控制谁能看到这些特性。将助力工具转移出来,让开发人员在单体之外也可以使用这些工具。最后,在新服务上线运行后,务必要删除旧的代码路径。通过工具来识别谁在调用这个服务,并规划好如何将流量全部导向新服务,这样你就不用老是为两套代码提供支持了。在 GitHub,我们使用一个名为 Scientist 的工具帮我们处理这种上线,我们可以用它并排运行和比较新旧代码路径。

8、AuthN/AuthZ 抽取

在 GitHub,我们决定首先抽取的核心服务是身份验证和授权。身份验证相当复杂,因为所有东西都依赖于它。网站和 Git 操作之间有一大堆的共享逻辑。也就是说,如果 github.com 宕掉了,那么 Git 系统就无法访问了,即使是使用命令行窗口,也无法执行像 pull、push 这样的 Git 操作。这就是为什么把这些基础部分抽取出来如此重要,那可以让主要功能脱离单体而运行。对于我们来说,身份验证已经很简单,因为我们已经在单体外部将它重写为一个镜像服务。当前的 Rails 应用程序(即我们的单体)使用 Twirp(这是一个 gRPC 风格的服务到服务通信框架)和它通信,依赖方向是由内到外。

9、运营变化

监控、CI/CD、容器化都不是什么新概念,但为了支持从单体到微服务的转型,节省时间,加速向微服务的过渡,运营要做必要的改变。在修改这些工作流时,要时刻记着微服务的特性。与为一个大型单体运行单个高度定制化的管道相比,为众多小型的、独立运行的、基于不同技术栈的服务提供运营支持存在很大的差别。将监控从功能调用指标升级为网络指标和契约接口。推动实现自动化程度更高、更可靠的 CI/CD 管道,并使其可以在服务之间共享。使用容器化技术支持各种语言和技术栈。创建工作流模板以实现重用。例如,在 GitHub,我们创建了一个自助服务运行时平台,可以用于微服务的打包交付。其目的是大幅减轻每个团队创建微服务时的运营负担。它提供了现成的 Kubernetes 模板,可自由使用的 Ingress 负载均衡设置。它可以将日志自动提取到 Splunk,并集成了我们内部的部署流程。这样,任何团队想要试验或上线一个新的微服务都会更容易。

10、小处着手,考虑产品 / 业务价值

到目前为止,我们主要讨论的还是结构性变化,以及从单体成功过渡到微服务架构所需要的基础工作。此后,任何新特性都应该创建成单体外的一个微服务。下一步,找一些简单的小特性从单体中迁移出来,例如,那些没有复杂依赖和共享逻辑的特性。在 GitHub,我们是从 webhook 推送和语法高亮开始的。我们希望在迁移更多更大的单体功能之前,找出常见的模式和两种架构之间的差别。我们是根据产品和业务价值来确定微服务的大小。我们通过查找经常一起更改和部署的代码和数据,来确定耦合度较高的特性或功能,并以此为基础,自然地划分成可以独立于其他部分单独迭代和部署的分组。此外,专注于产品和业务价值,还有助于组织内跨工程团队、产品和设计开展紧密合作。请注意,拆分得太小往往会增加不必要的复杂度和开销。例如,需要维护单独的部署密钥,更多的服务台职责,以及由于缺少知识共享而导致的单点故障。

11、实现异步性和弹性代码

从单体转向微服务是重大的模式转变。在这个过程中,不管是软件开发流程,还是实际的代码库,都会发生很大的变化。在最后一部分内容中,我们将快速了解下服务之间的通信以及失败机制(designing for failure),这两个都是微服务开发中非常重要的概念。服务之间的通信方式有两种:同步和异步。使用同步通信,客户端在发送请求后会等待服务器的响应。使用异步通信, 客户端在发送请求后不会等待响应,每条消息都可以由多个接收者处理。在 GitHub,我们使用 Twirp 实现单体与单体外部核心服务(如授权)之间的同步通信。然而,随着越来越多的服务移到单体之外,同步通信开始变得非常低效。而且,那还导致了服务之间的紧耦合,背离了迁移到微服务架构的初衷。更好的做法是创建一个共享的事件管道,协调多个生产者和消费者之间的消息。在 SendGrid,我们使用的就是这种架构。由于服务不再是运行在一台服务器上,所以考虑网络通信中的延迟和故障非常重要。对于大部分暂时的网络问题,使用一种简单的重试机制,定义好重试频率和最大重试次数,就足够了。可以考虑使用指数退避让重试逻辑变得更加智能。例如,随着重试次数的增加延长等待时间,而不是间隔同样的时间,从而缓解那些因为过载而无法响应的服务器的压力。作为一种自我保护和自愈机制,还可以在服务之间增加断路器。例如,在多次尝试失败之后,断路器会打开,在服务恢复之前,不再允许额外的请求进入。为服务设置超时时间,这样服务就不会一直等待外部服务的响应。设法实现优雅的失败,可以向用户展示友好的提示信息,或者恢复到缓存中上一个已知的良好状态。关注用户体验,做对企业有益的事。

12、小结

本文前 4 部分主要介绍了在开启从单体到微服务的旅程之前应该了解的基础内容。关注迁移原因。考虑模块化和数据拆分。从核心服务和共享资源入手,做必要的运营调整。做好这些准备,整个组织的微服务转型之旅就会更加令人愉快。接下来,我们讨论了从哪里入手,以及如何将微服务与产品和业务价值联系起来。最后,我们介绍了微服务的两个关键概念:服务之间的通信和构建弹性系统。

编辑:黄飞

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • GitHub
    +关注

    关注

    3

    文章

    468

    浏览量

    16398

原文标题:“逃离”单体,GitHub的微服务架构实践

文章出处:【微信号:magedu-Linux,微信公众号:马哥Linux运维】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    微服务架构和CQRS架构基本概念介绍

    微服务架构现在很热,到处可以看到各大互联网公司的微服务实践的分享总结。但是,我今天的分享和微服务没有关系,希望可以带给大家一些新的东西。如果一定要说
    发表于 05-22 09:03

    微服务与容器技术实践

    基于微服务架构的技术实践(点击下载演讲PPT) 普元信息主任架构师顾伟在演讲中,分享了他们对微服务架构
    发表于 10-10 10:23 1次下载
    <b class='flag-5'>微服务</b>与容器技术<b class='flag-5'>实践</b>

    微服务架构实践摘要

    本文主要类容是对微服务架构实践摘要解析。微服务架构中的 “微” 体现了其核心要素,即服务的微型
    的头像 发表于 02-07 16:57 6116次阅读
    <b class='flag-5'>微服务</b><b class='flag-5'>架构</b>与<b class='flag-5'>实践</b>摘要

    微服务优势_微服务架构的好处与不足

    ,我们需要根据项目业务和团队情况来选择合适的架构。 构建复杂的应用真的是非常困难。单体式的架构更适合轻量级的简单应用。如果你用它来开发复杂应用,那真的会很糟糕。微服务
    发表于 02-23 11:24 4389次阅读

    微服务架构实践基础篇

    微服务架构中,应用程序由多个服务组成,每个服务都是高度自治的独立业务实体,可以运行在独立的进程中,不同的服务能非常容易地部署到不同的主机上
    的头像 发表于 04-10 14:23 4225次阅读
    <b class='flag-5'>微服务</b><b class='flag-5'>架构</b>与<b class='flag-5'>实践</b>基础篇

    什么是微服务和容器?微服务和容器的作用是什么

    微服务是将应用程序拆分为多个服务的一种架构类型,这些服务具备构成整个应用程序的细粒度功能。每个微服务将具备针对您的应用程序的不同逻辑功能。与
    的头像 发表于 01-13 10:54 3.2w次阅读
    什么是<b class='flag-5'>微服务</b>和容器?<b class='flag-5'>微服务</b>和容器的作用是什么

    什么是微服务架构_微服务架构的优缺点及应用

    什么是微服务架构 简单地说,微服务是系统架构上的一种设计风格, 它的主旨是将一个原本独立的系统拆分成多个小型服务,这些小型
    的头像 发表于 06-02 10:03 1.7w次阅读
    什么是<b class='flag-5'>微服务</b><b class='flag-5'>架构</b>_<b class='flag-5'>微服务</b><b class='flag-5'>架构</b>的优缺点及应用

    微服务架构有哪些_微服务架构设计模式

    小伙伴们知道常用的微服务架构框架有哪些吗?上回我们介绍了一些常用的微服务架构设计模式,这次我们就来了解一下一些常用的微服务
    的头像 发表于 05-17 17:06 2.9w次阅读
    <b class='flag-5'>微服务</b><b class='flag-5'>架构</b>有哪些_<b class='flag-5'>微服务</b><b class='flag-5'>架构</b>设计模式

    微服务架构的特点_微服务架构适用场景

     微服务架构是一项在云中部署应用和服务的新技术。
    的头像 发表于 05-17 17:28 5083次阅读

    微服务软件架构应用研究综述

    自2014年,微服务架构概念经Martin Flower提出以来,受到广泛关注,为更好了解微服务架构风格,本文首先分析、梳理了软件架构的发展
    发表于 05-26 09:26 2次下载

    什么是微服务架构

    在Medium,我们的技术堆栈始于2012年的单片Node.js应用程序。我们已经构建了几个卫星服务,但我们还没有制定一个系统地采用微服务架构的策略。随着系统变得越来越复杂并且团队不断发展,我们在2018年初转向了
    的头像 发表于 02-24 11:15 1327次阅读
    什么是<b class='flag-5'>微服务</b><b class='flag-5'>架构</b>?

    从分层架构微服务架构介绍(五)

    本文要介绍的是 服务架构 (Service-Based Architecture, SBA )。 SBA 可以看成是单体架构微服务
    的头像 发表于 05-10 17:02 826次阅读
    从分层<b class='flag-5'>架构</b>到<b class='flag-5'>微服务</b><b class='flag-5'>架构</b>介绍(五)

    springcloud微服务架构

    Spring Cloud是一个开源的微服务架构框架,它提供了一系列工具和组件,用于构建和管理分布式系统中的微服务。它基于Spring框架,旨在通过简化开发过程和降低系统复杂性来帮助开发人员构建弹性
    的头像 发表于 11-23 09:24 1248次阅读

    docker微服务架构实战

    的容器化技术,为微服务架构的实施提供了强大的支持。本文将介绍Docker微服务架构的实战经验,包括Docker的概述、微服务
    的头像 发表于 11-23 09:26 637次阅读

    设计微服务架构的原则

    微服务是一种软件架构策略,有利于改善整体性能和可扩展性。你可能会想,我的团队需不需要采用微服务,设计微服务架构有哪些原则?本文会给你一些灵感
    的头像 发表于 11-26 08:05 570次阅读
    设计<b class='flag-5'>微服务</b><b class='flag-5'>架构</b>的原则