容器云平台、灰度发布系统、微服务网关的高可用实践
系统高可用是互联网企业系统架构的基础要求之一,一个好的高可用架构可以以最低的成本、更灵活的方式,满足企业用户需求。相反,糟糕的架构,不但花费了重金,而且架构过于复杂、过于笨重,线上故障不断,架构灵活性差,阻碍业务的发展。
作为企业的架构负责人,如何能让自己的服务架构能够更好地承载飞速变化的业务和服务,如何让平台更加健壮可靠而在业务洪流高峰时保障用户正常使用和优秀体验,如何规划和设计技术设施平台,如何选择满足高可用技术且性价比高的云平台等问题,是需要不断学习和优先解决的。
2018年 3月 31日下午,“高可用架构的创新与实践”技术沙龙在上海举行,活动邀请到来自前隆科技、UCloud、平安银行的几位在架构和运维层面的资深专家。深度分析他们在微服务网关设计,DevOps与容器化管理,监控与日志平台,平台的弹性支撑等方面对高可用架构的理解、实践与经验。以下根据本次活动的演讲内容整理而成。
高可用容器云在前隆科技的实践
前隆科技的业务研究范围包括人工智能、数据分析、云计算互联网、为客户提供获客、风控技术支持、IT系统的科技公司。本次前隆研发中心技术保障部经理、DevOps团队负责人朱轶坤和大家分享了前隆科技在容器云方面的实践和运用。
为什么使用容器云?
原因 1:应用服务扩容缩容效率低
应用服务器扩容缩容步骤繁多流程冗长,包括服务器申请、初始化、应用部署、测试、加入退出集群、服务器下线。当市场运营活动需要扩容服务器时,它的速度会非常慢。若业务遇到突发的流量高峰时,也无法及时进行快速扩容,导致业务出现问题。
原因 2:多套环境代码不一致,环境不稳定
代码上线发布历经多个环境,包括不同的场景、不同的测试环节、搭建环境、恢复环境等,会出现各种情况下的 bug。而在某个测试环境中修复了 bug,代码却无法及时同步到其他各环境中,提升了服务上线的风险。
原因 3:应用服务混合部署
期初企业可能只有少数几个服务应用,混合部署在同一台服务器上。各服务之间存在着相互影响的可能:如果某个应用的被访问量突然暴涨,可能将整个机器的带宽占满。同时也可能导致 CPU的使用率暴涨。这时如果修改这个应用的代码,会影响我们部署在同服务器的其他应用,造成一些迭代效应。
前隆科技容器云平台架构方案
前隆采用了 Kubernetes作为调度系统,架构主要是 Master结点和 Node结点,存储是 nfs-server。
部分核心模块的选型决策及高可用方案
如下图所示:
系统的底层架构包括基础设施层、容器层、资源管理层。基础设施层包括存储、网络、网络物理机;容器层包括 K8S、Calico、Harbor、Clair、NPS;资源管理层包括容器管理、弹性伸缩、维护降级、部署发布、权限配容。
左侧是辅系统,包括配置管理、监控告警、日志管理、编译管理、安全管理及相应的模块。
统一门户是为了用户体验更舒适、更方便、功能可视化,并赋予使用者相应的权限。
在高可用方面,前隆部署了三台 Master结点(如下图所示),每个都包含了 APISERVER、Controller-management、Scheduler 、kube-proxy、Kubelet,数据存储在 ETCD中。ETCD也是做集群,node和自动化应用系统后续调动 MASTER节点处理。
在 Node访问 Master时,前端搭建了 HA-Proxy,每个节点都会连接三台 Master。其中网络使用了 Calico,Calico网络相关数据也存于 ETCD中,保障网络的可用性。
前隆自动化运维平台
高可用架构是如何创建、部署、应用和登陆的呢?前隆自主研发了自动化应用平台,除了发布外还包括工单流程管理、代码质量管理等,平台页面如下图。
通过终端管理的容器申请项可以直接申请容器,默认配置是 4G。用户可以根据自己是内存型还是 CPU型申请不同的类型,通过审核流程就可以拿到容器了。登录平台后,选择编译相关操作就会收到反馈,可以直接看到日志信息和编译结果。选择部署版本后,也可以通过运行环境、服务器的配置变量等信息,对应用服务进行健康检查。
UCloud API 高可用部署和灰度发布实践
UCloud为企业提供云计算服务,在北上深杭等 11个地区都有线下服务站,在全球范围内建设了 23个数据中心,服务超过了 5万家企业级客户。本次的分享者是 UCloud企业事业部研发经理彭兴宇。
API服务是什么?
UCloud开放 API,提供对云计算资源灵活调度的接口。通过 API可快速便捷的创建、管理、释放云计算资源。并可将云计算资源整合入自身运维管理系统,满足上层应用的资源需求和动态调度。用户可以使用自己的程序进行云资源的创建和管理,无需登录管理控制台,就可以集中化、程序化的管理云资源,提高工作效率。
另外,用户还能对 API进行任意组合,实现其运维或运营所需要的更多功能。比如动态伸缩(AutoScaling),通过实时获取运行状态和资源使用率,一旦发现性能出现瓶颈,通过主机、数据库、网络的升降级接口,配合负载均衡模块,方便的实现纵向和横向的升级,从容应对突如其来的业务增长。同时,API也支持随时降级,合理利用资源、节省成本。
如何在多个地区部署高可用架构?
谈到高可用的部署,最主要的目标是为了保障服务的连续性,而我们的态度就是不信任任何事情,包括我们的服务、机器、网卡、交换机等都需要时刻谨慎。UCloud API服务的解决方案,就是在多个城市多个机房部署,机房内实现机房内的高可用,在城市级别或者地区级别,都有相应级别的高可用方案。这样即使遇到城市级的服务中断,其他城市也不会受影响,而且各城市都有接入层。再比如北京的服务备份到上海去,上海的备份到广州去,即使上海的服务器挂了,它的流量可以切换到其他地方的服务器中。
那么,目前我们遇到了哪些痛点亟待解决?
第一,我们需要产品特性的快速迭代。我们知道,绝大部分的故障是来自于变更,你会发现你的业务平时没什么问题,一旦发布东西报警立马就来了。对高频发布存在需求,因为产品或特性要快速上线、或者是紧急 bug 修复。
第二,预发布环境无法完全模拟生产环境。 确定一个测试周期是很难的。包括确定具体的测试时间、测试完成后是否能发布,都是是很大的挑战。即使测试过程没问题,但测试环境是无法 100%模拟现场环境的,所以在发布时仍存在隐患。
第三,发布无法控制粒度。之前的发布流程没有太关注粒度方面,所以机制上对粒度没有控制能力,要么一行代码都不发,要么就是对所有用户发布所有变更,没有细粒度的流量控制。
第四,发布无法控制影响范围。变更的粒度没有控制,同理,发布的影响范围也是没有一个统一的控制能力,我们期望有个统一的机制或者平台来整体控制发布影响的用户范围,对我们整体服务质量是一个保障。
灰度发布系统的思路
灰度系统要做的事情其实就是能够按照我们的控制规则来进行分流,进而来控制风险并对产品特性的发布有一个循序渐进的迭代过程。以下是对灰度系统的一个特性总结和通用的思路:
首先,灰度规则热更新。如果你的发布变更出了一些问题,全球所有实例去重启一遍是不可能的,这时我们希望通过工具界能够快速恢复。
其次,开放的 API。不管是对外部用户还是企业内部,在改造和重构框架方案时,如果对业务有很大的侵入性和破坏性,那这样的落地和推进肯定有很大的困难。我们既要提供一部分灰度能力又不能对内部既有业务和系统产生冲击怎么办?对外提供 API是一个解决方案,它可以被集成到既有的发布的步骤里,由使用方通过调用 API指定特定的规则来控制访问。
再次,提供一个 web操作页面。可以为非技术领域的同事,提供一个易用的操作页面。尤其是更熟悉业务领域的同事,比如产品经理,他们更了解产品特性和产品用户,甚至可以由他们来控制自己负责的产品的一个发布节奏。
最后,灰度规则是易扩展的。因为这是一套 HTTP的 API服务,所以我们期望是不是可以支持业务方按请求头和请求体里的任意字段来制定灰度规则。
灰度系统的实现
灰度系统的实现基础是 OpenResty,OpenResty 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、Web 服务和动态网关。
OpenResty 通过汇聚各种设计精良的 Nginx 模块(主要由 OpenResty 团队自主开发),从而将 Nginx 有效地变成一个强大的通用 Web 应用平台。这样,Web 开发人员和系统工程师可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块,快速构造出足以胜任 10K 乃至 1000K 以上单机并发连接的高性能 Web 应用系统。
OpenResty 的目标是让你的 Web服务直接跑在 Nginx 服务内部,充分利用 Nginx 的非阻塞 I/O 模型,不仅仅对 HTTP 客户端请求,甚至于对远程后端诸如 MySQL、PostgreSQL、Memcached 以及 Redis 等都进行一致的高性能响应。
微服务架构下的高可用网关
前隆科技框架经理、资深技术专家何雷,分享了前隆网关的背景、架构和高可用的措施。
随着前隆的业务成长,对接的客户也越来越多,产品也相应增多。web商户和公司内部的业务系统耦合越来越紧密,随之而来的一系列问题也出现了。这时候非常有必要做一个统一的网关系统,包括每个业务线都需要统一的安全权限校验、反爬虫、以及统一的限流、熔断、降级、线程隔离框架。包括一些特殊部门的动态拦截、请求的特定需求支持等,这就需要一个统一的流量和监控平台。
前隆网关的技术选型如下图所示,当前比较流行的是 Zuul、Kong和 Tyk。Zuul是基于 Java开的,是 SpringCloud集成的网关;Kong是基于 Nginx;Tyk开发的不符合前隆当前的技术体系,这里就不讲了。我们对比了 Zuul和 Kong的优缺点,最终选择了 Zuul。
物理部署图(部分业务)
上图为前隆网关的物理部署图,可以看到外部的对接商户和 app客户端,通过 CDN网络到了 WAF,再到网关 ULB,负载到网关集群,通过配置的路由规则到业务的 ULB,最终负载到业务系统。左下方是网关配置管理系统,配置了商户和路由的绑定以及路由规则,落库到 Mysql中,同时同步到 Zookeeper集群,当路由规则进行变更的时候,及时通知到网关集群。这里的 redis集群,主要针对 H5请求服务,它会有一个 Token的校验,Redis来保存 Token的,有效期为 24小时。
Spring Cloud原生态的 Zuul
前隆网关是基于 Zuul自我研发的,所以我们有必要了解一下 Spring Cloud中的原生态 Zuul。外部请求到达 Nginx,负载到 Zuul集群,Zuul从 Eureka注册中心上获取服务列表,根据自身配置的路由规则,由路由转发到后端的微服务实例。我们对 Zuul的改动主要集中在路由规则从网关后台管理系统中读取,然后路由到我们的后端业务 ULB,更改了对应的 PostFilter。
Zuul标准过滤器
Zuul大部分功能都是通过过滤器来实现的。Zuul中定义了四种标准过滤器类型,这些过滤器类型对应于请求的典型生命周期。
PRE:这种过滤器在请求被路由之前调用。我们可利用这种过滤器实现身份验证、在集群中选择请求的微服务、记录调试信息等。
ROUTING:这种过滤器将请求路由到微服务。这种过滤器用于构建发送给微服务的请求,并使用 Apache HttpClient或 Netfilx Ribbon请求微服务。
POST:这种过滤器在路由到微服务以后执行。这种过滤器可用来为响应添加标准的 HTTP Header、收集统计信息和指标、将响应从微服务发送给客户端等。
ERROR:在其他阶段发生错误时执行该过滤器。
监控告警
监控告警方面前隆自主研发了度量平台和预警平台。度量平台主要作用是指标规则注册、数据采集和聚合查询,是读取需网关日志的一个接口;预警平台是用来构建预警任务、通知预警结果、实时监控仪表盘。当错误率达到一定的阀值时,通过邮件短信内部的 RTS通知到相关的负责人。
多维度的认证授权、安全策略
支持 Http和 Https的双协议
只有授权的商户才能访问绑定过的 API
针对商户对接:IP、商户的白名单、黑名单机制
公私钥算法保护 API接口调用和数据传输安全
请求时,客户端动态生成 DES3**,对业务数据加密,公钥对 DES3**加密,服务端反之操作;返回时亦反之操作
双向 MD5加盐对业务数据验签防篡改
H5请求基于动态生成的 Token认证,有效期为 24小时
平台级和服务级限流、熔断、降级、线程隔离
平台级限流:RateLimit,每台网关服务器控制所有业务线的流量请求。实现一个 PreFilter ,filterOrder为最先顺序执行,以拦截所有请求。请求拿到令牌才能后续执行,未拿到令牌直接返回网络繁忙提示,以保证现有的服务器在请求超过最大峰值时不被冲垮。
服务级限流:Hystrix,使用命令模式 (继承 HystrixCommand类)来实现具体的服务调用逻辑 (run方法),并在命令模式中添加了服务调用失败后的降级逻辑 (getFallback)。
使用 Hystrix是帮助解决分布式系统交互时超市处理和容错的类库,它同样拥有保护系统的能力,同时使系统具有自动降级和自动恢复服务的功能。用的是舱壁模式,现在比较流行的(英),它是容器之间的一个隔离,它做了服务级的一个进程隔离,我们这个是基于线程值的隔离。
HystrixHystrix用熔 Hystrix用熔断器模式进行自我保护。熔断器模式定义了熔断器开关相互转换的逻辑,即:服务的健康状况 = 请求失败数 / 请求总数。熔断器开关由关闭到打开的状态转换是通过当前服务健康状况和设定阈值比较决定的。
实时生成公私钥影响性能的优化
在收到 H5或者 App端的请求后,会自动分配一个公私钥,实时生成 RSA**影响性能,通过任务调度中心在凌晨时预先批量生成公私钥放在缓冲中,请求来了直接取用。
反爬机制措施
现在网络上的爬虫越来越多,这些爬虫的请求如果都到达我们的业务系统,一是占用流量带宽,二是影响业务系统性能。所以我们直接在网关层做统一的反爬虫的策略,有以下几个步骤:
首先,通过校验 Headers携带的 User-Agent、Referer、Host、Cookie等信息识别爬虫;其次,统计 IP或者账号,通过判断访问时间、访问次数和阈值大小,识别是否是爬虫;再次,是关键的数据转换成图片的呈现方式;最后,是前端 JS加密混淆。
动态过滤器
部分业务部门对一些特殊请求需要做实时拦截,但在线上不可能为此重启服务或重新部署。Zuul的过滤器是由 Groovy脚本写的,这些过滤器文件被放在 Zuul Server上的特定目录下面,Zuul会定期轮询这些目录,修改过的过滤器会动态的加载到 Zuul Server中以便过滤请求使用。