2016 年底,Evernote 对他们的服务进行了一次大规模的迁移。他们将 Evernote 服务从自有数据中心迁移到了 Google Cloud Platform 上。他们在短短的 70 天内完成了整个迁移过程,包括 Evernote 服务、存储数据和其他配套服务。参与这次迁移的工程师们在 Evernote 官方博客上分享了这次迁移的过程。文章包含了 5 个部分。以下译文已获得翻译授权。
第一部分:Evernote 服务和迁移到 Google 云平台的可选方案
Evernote 服务在 2008 年开始投入使用,我们一直维护着自己的服务器和网络。我们有很大的自由度来构建服务,但同时也面临着一些挑战:伸缩困难、升级缓慢、高昂的维护成本。虽然我们的基础设施在过去为 Evernote 提供了很好的支持,但在未来,我们需要更快的速度和更大的灵活性,而这些正是目前的基础设施所缺乏的。
迁移到公有云这一决定让 Evernote 的每一位员工都兴奋不已。在首次发布迁移声明之后,我们便在幕后启动了从物理数据中心到Google 云平台(GCP)的迁移工作。经过70 天日以继夜的奋战,我们完成了迁移。
可能有些人想了解我们的迁移过程,又或者想进行类似的迁移,所以我们决定把迁移过程分享出来。我们会告诉大家在迁移过程中我们都做了哪些事情,以及如何能够快速地完成迁移。这不是一个完整的迁移手册,不过它涵盖了我们做出的所有关键决策,以及我们是如何实现它们的。
先让我们来了解一下Evernote 服务的概况。
Evernote 服务
我们的服务由以下几个组件组成。
分片(NoteStore)
分片是 Evernote 服务的核心单元,用于存储用户的笔记。每个分片最多可以支撑 30 万个 Evernote 用户,并包含了如下几个组件。
- 基于 Tomcat 的前端 Web 服务层:Evernote 客户端会连接到这个层。
- 数据存储层:用于存储用户笔记的 MySQL 数据库。
- 搜索索引:基于 Lucene 的服务端搜索索引,用于搜索用户的笔记内容。
我们总共有 762 个分片,存储着 2 亿个用户账号和大约 50 亿个用户笔记。
UserStore
UserStore 使用 MySQL 数据库来存储用户信息,包括他们的认证信息。因为数据库管理着所有用户的状态和认证信息,所以它是最为关键也是最为复杂的一个组件,在迁移过程中我们需要格外小心。
用户附件存储(资源)
我们有一个单独的文件存储层,用于存储 50 亿个用户附件(我们把这些附件称为资源)。这个层由 206 个自包含的 WebDav 服务器组成。每个用户附件有三个副本,其中两个分别被保存到本地的两个不同的 WebDev 服务器上,另外一个被发送到远程灾备数据中心的 WebDav 服务器上。
前端负载均衡
我们的高可用负载均衡器集群负责将用户请求路由到特定的分片上。
配套服务
我们还有 200 多台 Linux 服务器用于缓存和执行批处理任务,比如笔迹识别和文本识别。
我们的迁移可选方案
Evernote 服务规模庞大,向云端迁移是一项复杂的工程,我们需要作出很多与依赖项有关的决策。我们希望能够尽快完成迁移,所以我们为关键性决策制定了一个草案。
我们要先理清楚需要做出哪些变更。我们知道,有些组件无法直接被简单地迁移到云端,所以我们把组件分为两类。
- 转移:有些组件在 CGP 上能够找到几乎一样的替代品,分片、UserStore 以及大部分配套服务都属于这一类。在我们的物理数据中心,这些组件都是基于 Linux 的,所以我们将会直接把它们迁移到云端的 Linux 虚拟机上。
- 转换:在迁移过程中需要对用户附件存储、负载均衡层和识别服务(Reco)做一些重大的转换。对于这些组件来说,要么在云端找不到相应的替代方案,要么云端已经存在更好的替代方案。
迁移方法
接下来我们要开始计划如何进行迁移,我们有两种选择。
- 一次性迁移:迁移项目里存在着一个分界点,跨过这个分界点就等于完成了 100% 的切换。对于自有数据中心和采用了单体架构的组织来说,这种方式会更适合(这或许也是唯一可行的方案)。
- 阶段性迁移:这是一种分而治之的方法,根据类型或用户将服务分组,进行阶段性的迁移。采用这种方式可以在提交阶段性工作之前对其进行测试和验证。
从我们的情况来看,一次性迁移的方案并不适合我们。即使做了详尽的计划,一次性迁移完所有的组件仍然存在很大的风险。况且,我们的应用并非为多站点运行而设计的,尽管我们的环境在很早之前就已经支持多站点运行。
所以,我们需要在上述的两种极端之间找到一个折衷的方案,我们决定采取“增速阶段性切换”的方案。整个迁移过程要在短短的 20 天内完成,它包含了多个阶段,每个阶段的风险需要被降到最低。如果某些阶段的工作无法达到预期的效果,可以进行回滚。
第二部分:保护 GCP 上的用户数据
我们的安全团队负责保护用户数据的安全。在向云端迁移的过程中,我们要考虑如何保证用户数据的安全。我们面临两个主要的问题。
- 我们即将把数据交由 Google 来看管,他们是否拥有足够成熟的安控措施,能够避免给我们的服务带来新的风险?
- GCP 是否提供了等价的或者更好的安控措施来保证数据的安全?
厂商信任
我们内部有一个厂商审查流程,由我们的法律团队和安全团队共同执行这个流程。我们在与新的服务提供商展开合作之前,会对相关的隐私和安全问题进行审查。
在厂商审查过程中,我们会检查 60 多项与隐私和安全有关的问题。这些内容与我们内部程序的结构保持一致,通过这些审查,我们就可以知道厂商是否符合我们的预期。审查内容可以被分为几类。
- 组织层面的控制措施
- 基础设施的安全
- 产品安全
- 物理设施安全
- 与隐私有关的数据使用
我们和 Google 一起对他们的审计报告进行了评审,发现他们在各个方面都能够满足我们的预期。
接下来,我们将注意力放在他们是否提供了用于保护用户数据安全的安控措施上。
云安全控制措施
首先,我们对现有的所有用于保护用户数据的安全措施进行了评审。这些安控措施包括使用了双因子认证的远程访问 VPN 和提供了流量过滤功能的防火墙。还有其他一些物理安控措施,比如物理外围、生物技术认证、探头,以及用于防止物理数据被盗的警报系统。我们在安全主页上有很多关于基础设施安全防护的讨论。
我们列出了一个表格,记录了迁移过程中需要注意的安全问题,下面是一些主要内容。
- 外围网络安全(向内流量和向外流量过滤)
- 内部隔离
- 多因子认证
- 传输加密
- 缺陷管理
- 身份信息和访问控制
- 诊断日志
- 入侵检测
- 变更监控
我们还需要考虑多租户云环境可能会出现新的威胁模型。内存和存储的使用方式与过去也不一样。我们还要考虑来自其他用户的威胁,这些用户与我们处在同一虚拟层上。好在 Google 已经考虑到了这些问题,他们在博客上就如何解决这些问题进行过讨论。
我们在 GCP 上为我们的大部分安控措施找到了等价的替代方案。我们还为静态数据加密找到了一种更好的替代方案。而对于其他一些安控措施,比如 IP 白名单,我们只能通过改造我们的架构,让它不再依赖传统的网络安控。我们使用包含了 Google 托管密钥的 CGP 服务账号来实现这一改造。
如何安全地使用 GCP 服务账号
迁移到云平台之后,原先的静态 CIDR 块被静态公共 IP 和动态公共 IP 的混合体所替代。维护 IP 白名单的成本非常高,而且在 CGP 的其他服务里并不存在这样的功能。
在我们的安控架构里,网络和用户数据之间包含至少两个安全层。内部服务全部被部署在一个安全的网络外围里,服务之间通过 API 密钥进行交互。我们以一种安全的方式来存储和分发这些密钥,不过仍然存在泄露或被盗的风险。如果真的发生泄露或被盗,我们还有第二个安全层。在我们的生产环境之外,秘钥失去了它们的作用,而要想进入生产环境使用这些秘钥,必须先通过双因子认证。
每一个 GCP 服务都是互联网服务,它们并没有提供面向用户的白名单安控机制用于访问 Google 计算引擎(GCE)项目里的主机。我们需要在密钥和用户数据之间添加另一个安全层。
我们使用 GCP 服务账号解决了这个问题。每个 GCE 项目都有一个默认的服务账号,在 GCE 中启动的实例可以通过这个账号来访问其他服务。Google 提供了一组公钥 / 私钥对,密钥对每 24 小时自动翻转一次。对于自定义的服务账号,也会执行相同的操作。我们可以为每个主机角色创建一个自定义服务账号,并通过配置虚拟实例来使用这些账号。现在,那些运行在这些虚拟实例上的应用就可以使用内置的 Google 托管密钥。
我们的运维工程师没有必要访问这些密钥,因为 Google 每天都会自动翻转这些密钥。要想访问到这些密钥只能通过渗透我们的基础设施,不过我们目前已经具备了相应的防护能力。
总的来说,我们对云平台的安全充满了信心。我们还会继续加强平台的安全,把不断变化的安全威胁甩在身后。
评论