Office 365 架构演变及微服务实践

阅读数:913 2017 年 3 月 20 日

话题:微软语言 & 开发架构

天下大势,分久必合,合久必分。三国演义开头的这句话是对 Office 365 整体架构的演变最生动的概括。

互联网业界的同行,对微软存在偏见甚至鄙视者大概不算少数,也许会觉得标题里的微服务(micro-services)貌似是个多少有点潮的概念,好像和微软的技术形象有点不符,更何况是 Office 365 这样历史悠久的庞然大物。但事实上,微软很多团队都是与时俱进的,而 Office 365 架构的分分合合某种程度上也能侧面反应这一点。

Office 365 是一个多义词,本文讨论的 Office 365 是以 Exchange Online 为核心的一系列 Office online services 产品,从技术范畴上并不包括普通用户所熟悉的 Office 客户端产品,例如 Word 和 Excel,当然也不是微软以每年授权的方式销售给个人用户的套装。

DVD 盒装软件时代

Office 365 的前身是 Exchange Server(以下简称 Exchange),是一个非常典型的 on-premise 的企业电子邮件服务器,早些年和 IBM Lotus Notes 以及 Novell GroupWise 竞争。第一个正式的版本是在 1996 年,可以想象那个时候的软件基本是跑在单台服务器上的,邮件数据也是存在本地硬盘或者 SAN。后来 Active Directory 分离出去成为 Windows Server 2000 的一部分以后,就有了分布式系统的架构,而且 AD Domain Controller 也可以是和 Exchange 独立的 role。Exchange 2000 可以支持 8 个节点的集群。这个时期的架构,已经可以称为 scale out 的一个例子,但每台服务器的角色都是等同的,所以是“合”的时期。

Exchange 2003 开始支持通过 internet 的客户端,包括基于 web 的访问方式,于是有了 Front End 和 Back End 两种 server role。Web 界面的 Outlook Web Access,Outlook 客户端用的 RpcHTTP,IMAP,POP 等协议头被放在了 Front End 上,前面还有 Network Load Balancer。这个时期已经开始了“分”的时期。到 Exchange 2007 和 Exchange 2010 时候,一共有了 Mailbox, Client Access, Hub Transport,Edge Transport, Unified Messaging 多个服务器角色。其中数据主要存放在 Mailbox Server 上,并且用软件实现了 High Availability,包括 replication 和跨地域 failover。之前的 Front End 变成了 Client Access,通过 MAPI RPC 访问 Mailbox Server 上的数据,而邮件中转的处理交给了 Transport 服务器。这个版本的 Exchange 把“分”的模式又增近了一步,而这种架构作为 on-premise 软件来讲已经属于相当现代和成熟的模式。

(点击放大图像)

图片引用自 technet.microsoft.com

软件即服务

Exchange 2010 的代码同时是被用来搭建 Office 365 Exchange Online 云服务的第一个版本。由于 Exchange 2010 本身的企业版本已经能够支持大型跨国公司所需要的大规模跨地域集群,所以放进数据中心里运行的时候核心代码几乎就可以直接工作。最大的修改主要在于客户的组织目录结构的分区上,另外还有身份验证方式的改变。个人认为这个可以作为业内成功的 SaaS 的案例之一,真实地将一个 software 改成了 online service,而且用的同一套代码。值得提及的一点是,这个时候微软的三大云服务部门,Azure,Bing,Office 几乎是互相独立的,从数据中心基础架构到自动化部署,监控等都是各自运行自己的系统。

Exchange 这样的架构在企业客户的环境下是比较容易控制的,但作为在线服务时候,由于自动化工具的不够完善,用户增长和访问峰值的变化,对各个服务器角色所需的数量和硬件配备的预估和计算就有些复杂,尤其在发生紧急情况需要 failover 时候需要兼顾到所有类型服务器的运行和访问模式。另外涉及到用户交互的 Client Access 需要遵循数据最近原则,所以用户最重得到的 URL 都是具体到各个数据中心的,在某些情况下甚至会改变,需要通过 302 重定向,proxy 或者 AutoDiscover 等手段来作补充。

从 Exchange 2013 开始,虽然 online 和 on-premise 的代码还是同一份,大量的开发工作开始集中于云服务下的场景,而这个时期的架构又发生了重大的调整。首先把 Client Access, Hub Transport 和 UM 都搬到了 Mailbox Server 上,成为一个统一的 shard,进一步强调数据就近原则,并提出了每个服务器都是孤岛的原则,要求跨节点的访问必须通过 HTTP 而并非 RPC。这个版本里引入了一个专门用来做 HTTP 反向代理的部件,用来分发所有 HTTP 的协议,代替了之前 L7 硬件 Load Balancer 的大部分工作,也实现了 URL 的全球统一域名。

(点击放大图像)

图片引用自 technet.microsoft.com

这种设计相比之前多个 server role 极大地简化了部署和扩容模型,被称为“砖块”架构,用来形容每台服务器的同质化和标准化。就像盖房子只需要一种砖块一样,新的集装箱式服务器运到数据中心后可以很简单完成部署,加入集群。负载均衡也被统一和简化成基于用户数据所在的 shard 为核心,也就是说,当服务器上的某些进程开始有 CPU 或者内存压力的时候,只需要简单地将原先分配到这个 shard 上的一些用户无断点迁移到另一些服务器组上。当然,所谓用户所在的 shard 也是一个动态的概念,由于新版本部署等原因用户数据所在的物理机器其实每天都可能改变数次。在“分”了大概十年以后,数据单元的计算和存储又被“合”到了一起作为一个整体架构,回到了有点类似刚开始的状态。

联邦化的服务

与此同时,Office 365 整条云计算产品线在紧密地相互整合,包括原有的 SharePoint, Lync,One Drive 等,加上收购的 Skype,Yammer,还有新开发的 Teams 等。这些产品从宏观来看都是和 Exchange 类似的,基于用户或者群组,都可以通过 Azure Active Directory 来统一描述客户的用户组织结构。一个用户或者群组的邮件,日历,文档,联系人,聊天信息和记录,博客和通告牌等信息其实在数据的本质上是一样。Exchange 也慢慢成为了整个系统的数据及计算的核心,演变为超越电子邮件服务器的 Office 365 Substrate 战略平台。

在这种情况下,添加新的功能时候,尤其对于非 Exchange 团队出身的项目组,所面临的第一个问题是,代码应该在哪里运行?是应该放到现有的框架下,运行在 Mailbox Server 上作为整体架构的一部分,还是别的选择?理论上来讲,在一台服务器上能够运行的进程数量和内存大小是有极限的,即便能 scale out,无限制地添加新功能也是不现实的。另一方面,从开发的角度上,整体架构各个层之间是互相耦合的,使用的是同一个代码分支,而部署的时候也必须将整个 build 统一部署,影响了开发运维的敏捷性。这样的整体架构对于这样一个有很多工程师协同工作的产品来讲已经开始暴露出一些弊端。同时,随着 Azure 的成熟和完善,Azure 平台也成为微软内部开发和运行平台的一个主要选项,迫切需要一套新的架构方案。

这个问题的解决方案就是“分”,将整体架构拆分成一种更趋向于 SOA 的结构。这一次拆分的维度,并不是简单重复历史,单纯地垂直切割,或者回到之前的多角色服务器。拆分的原则是将各个部件按照核心服务和微服务来分类,类似于操作系统的核心模式和用户模式之间的关系,形成一种行星形的结构。核心服务主要包括数据库和核心 API 等,而微服务是那些可以围绕这些 API 搭建起来的用户功能。这里的 API 是指分布式的 API,大多数情况下是 HTTP 的和 REST 的,甚至是完全和暴露给第三方的公有 API 一致的。一个新的功能也许需要一些核心 API 的改动,但大部分的业务逻辑可以通过微服务来实现。微服务的开发和部署环境也变得非常灵活,可以根据自身使用 Azure,也可以使用内部一种基于 Bing 所使用的 Auto Pilot 的混合平台。基础设施组会提供相应的工具来解决 Azure 和 Auto Pilot 方案的容量计算,容器化部署,监控和 compliance 相关的问题。

API 为桥梁

这种架构的最关键部分在于 API 的完整和成熟度。目前的手机应用 Outlook Mobile 的前身是一个加州的公司,叫做 Accompli,完全通过 Exchange Online 公有的第三方 API 开发出来的。这个 app 非常出色以至于后来被 Office 365 收购,代替了自己内部的产品。而目前的 Mac Outlook 也是基于同一套 API 开发出来的,也就是说任何开发者都可以自己开发出一个和 Mac Outlook 和 Outlook Mobile 一样功能的产品来。我个人一直秉持的观点认为,微服务架构的一大益处就是在某种程度上迫使内部和第一方团队以第三方的方式来思考,甚至感受到第三方开发者的痛处,这样对产品整体生态圈的建设有很好的促进作用。

去年发布并且引起业内很大关注的 Teams,也是采用了一种和传统 Office Server 服务不一样的架构。Teams 并没有很清晰独立的后端服务,而完全是基于 Skype,Exchange 和 SharePoint 的现有功能而搭建的微服务集合。

微之敏捷

微服务架构的思想之一是用最适合需求的编程语言和 stack 来完成工作。我本人所负责的项目中需要一个 RSS feed parser,但因为现实中各大内容网站的 RSS 实现并不严格遵守协议,.net framework 所带的库只能处理大概 80% 左右的 feed,需要一个更 robust 的替代品。在进行调研后,我们选择了 GitHub 上评分较高的 NodeJS 和 Java 的开源 RSS 库。考虑到运行环境的因素,以及 20% 的非交互式应用场景,我们选择了不在本地运行,而是采用了 Azure Functions (类似 AWS Lambda) 作为微服务来调用,也即所谓的 serverless computing 的模式,效果很理想。类似这样的方案在一些应用场景下可以让开发团队有很多选择,提升开发和运维过程的灵活和敏捷性。

挑战与思考

如果我在这里说 Office 365 是一个庞大而复杂的系统,不知道大部分读者是不是会同意,或者有部分读者会觉得不以为然,甚至认为我有王婆卖瓜之嫌。如果单纯从体量,用户数量和访问峰值来看,行业内很多的佼佼者都能给出非常让人敬佩和称赞的数据。这里我想强调的,是系统开发和运维的时候由于规模所带来的一些独特的问题。Office 365 在几乎全球都有部署和运营,其中包括很多有特殊要求的国家和地区,也包括一些国家的政府和国防等敏感部门。每隔一两年,都会有新开发或者收购的产品加入 Office 365 家族中,甚至运行在 AWS 上的外部产品,能够被很快地整合成为一个整体。

之前面向个人免费用户的 Hotmail,即 Outlook.com, 后台也被无缝地替换成了 Exchange。很多客户其实是在使用一种 on-premise 和云计算混合的方式,包括私有云,而 Office 365 的一个卖点就是保证这种混合配置的无缝运行,因此带给开发运维的包袱也不小。参与整套产品线设计,开发和运维的工程师数量,也是行业内少有的规模,可以想象协同工作过程中面临的挑战。总而言之,同众多云服务相比,Office 365 有其自身独特的任务和挑战。

在新 CEO 纳德拉的带领下,秉持“云为先”和“一个微软”的方针,微软比任何时候都更加开放和谦虚,内部协作也更紧密。Office 365 发展到现在,在经过各种用户看得见和看不见的变迁和进化后,已经成为一套比较成熟的云服务,而各种进步和创新还在继续。各位读者在关注互联网和云计算的群雄逐鹿之时,可以给微软一些目光,也许能给大家带去一些思考和启发。

作者简介

虞雷 (Jason Yu), 微软 Office 365 Core 部门首席软件工程师,在生态系统项目组主要负责 Connectors,Actionable Message 和 Bots 等项目的架构设计。


感谢郭蕾对本文的审校。

给 InfoQ 中文站投稿或者参与内容翻译工作,请邮件至editors@cn.infoq.com。也欢迎大家通过新浪微博(@InfoQ@丁晓昀),微信(微信号:InfoQChina)关注我们。