利用Docker轻松实现云原生应用 - 高可用架构设计

本文为利用Docker和容器服务轻松实现云原生应用系列的第一篇

  • 高可用架构设计(本文)
  • Spring Boot + Redis分布式会话

最近对应用迁云的讨论很多,很多用户对云环境中的应用架构和运维方式还不了解。直接利用云服务器替换自有物理机并不是使用云的正确姿势。

Cloud Native Application(云原生应用)是当下一个热门名词,简单而言就是针对云计算的特性,来设计应用架构,并优化应用的交付、运维流程。Linux基金会旗下的云原生计算基金会 CNCF(Cloud Native Computing Foundation)开宗明义地描述了云原生系统所具有的几个关键特性

  • Container packaged:容器化的交付方式,保证开发、交付和运维的一致性
  • Dynamically managed:自动化的管理,提升系统利用率、降低运维成本
  • Micro-services oriented:松耦合应用架构,提升系统的敏捷性和可维护性。

云原生应用可以满足我们的几个关键诉求:

  1. 高可用:让应用“伤得起”。 系统中没有脆弱的故障单点,另外具有良好的自我恢复能力。
  2. 弹性伸缩:能够让应用从容应对峰值流量
  3. 快速迭代:天下武功唯快不破。在互联网时代,快速迭代、最小化试错成本是核心竞争力。

下面我们将介绍,如何利用Docker和阿里云容器服务在云端实现应用的高可用。

应用架构设计

云原生应用中一个很重要的理念就是解耦

  • 架构层面:通过微服务架构方法将应用逻辑分解为一组松耦合的服务,使得每个服务可以独立开发、部署、演进和伸缩
  • 实现层面:强调应用层和数据层的分离,只有实现业务逻辑和持久化状态的解耦,才能让业务逻辑可以水平扩展,并且出现故障的时候可以快速恢复。
  • 交付层面:通过容器来解耦应用和运行时环境,使得应用可以在不同的环境中可以重复、一致地交付、部署、运维,从而更好地支持DevOps和弹性。

微服务架构设计是一个很大的话题,有兴趣的同学可以参考微服务设计12 factors应用开发方式。我们今天只是谈应用层和数据层的分离。一方面它可以使得应用逻辑变成无状态的,支持水平扩展;另一方面区分无状态和有状态服务,可以使我们针对不同工作负载实现性能优化和扩展。

以前的两篇博文中介绍了如何将一个Ghost博客应用,重构成一个符合云原生应用架构的过程。

  • 利用Docker部署Ghost博客集群
  • 当Docker遇到数据库:容器服务中使用RDS

最初Ghost应用是利用嵌入式的SQLite来存储数据,并将所有媒体文件(图像、视频)保存到本地文件上。这个应用的性能受限于单机能力,无法水平扩展,也无法保证高可用。

而简单的重构之后,我们将应用的数据层剥离出来:把关系型数据储存在RDS的MySQL实例上,并将所有媒体文件保存到OSS对象存储之中。这样配合SLB的负载均衡,可以轻松地支持Ghost博客集群的水平扩容。同时由于所有数据不再保存到本地,这样即使特点ECS实例失效,请求也可以交由其他节点应用接管。而数据的可用性是通过RDS服务、OSS存储服务来保障的。

相应的Ghost的docker-compose模板如下

ghost:
  image: registry.aliyuncs.com/acs-sample/ghost:0.7
  links:
    - db:mysql
  ports:
    - "2368"
  environment:
    - GHOST_URL=http://blog.${ACS_DEFAULT_DOMAIN}
    - OSS_BUCKET=acs-sample-ghost
    - OSS_BUCKET=acs-sample-ghost
    - OSS_ACCESS_KEY_ID=*
    - OSS_ACCESS_KEY_SECRET=*
    - OSS_PREFIX=http://acs-sample-ghost.oss-cn-beijing.aliyuncs.com
    - OSS_ENDPOINT=http://oss-cn-beijing.aliyuncs.com
  labels:
    aliyun.routing.port_2368: 'http://blog'
    aliyun.scale: '3'
  restart: always
db:
  external:
    host: rds.mysql.rds.aliyuncs.com
    ports:
      - 3306
  environment:
    - MYSQL_DATABASE=blog
    - MYSQL_USER=ghost
    - MYSQL_PASSWORD=*

阿里云扩展的注释:

  • 标签 aliyun.routing.port_xxxx : 定义的虚拟域名访问方式
  • 标签 aliyun.scale: 定义了容器复本数量
  • external: 描述了容器对外部云服务的引用,可以方便地将容器和云服务组合在一起。

需要注意的是Docker不是银弹,仅依赖容器技术无法解决所有问题。用户需要认真思考和判断什么样的应用可以运行在容器中。容器非常适合部署无状态的应用,因为这类应用可以方便地水平扩展和动态调度。然而对于有状态应用,比如数据库、消息队列,我的建议是可以在开发测试环境和非关键应用的生产环境中使用容器;然而对于核心应用,建议采用云服务提供的高可用中间件能力来实现。

部署架构设计

解决了架构层面的水平伸缩能力和高可用,我们下面讨论一下应用部署中需要关注的可用性因素。

进程监控

进程监控是最常用的可用性保证机制,传统上是利用Supervisor, Monit等工具来监控应用进程,并自动拉起失效进程。

Docker内置了进程监控能力,可以利用 docker run --restart=always ... 命令参数,或者在Compose模板中通过 restart: always 指明进程重启策略。

以上文为例,当Ghost容器运行之后,Docker Daemon会监控容器中PID1的NodeJS进程,如果进程退出会自动重启容器。可以参考restart policy了解更多信息。

然而仅仅根据进程状态判断应用的健康状态是不够的:因为有时候由于应用逻辑问题导致应用死锁或挂起,虽然进程还处于运行状态,但是已经无法接受新的请求。为此容器服务引入了服务的健康检查机制,可以通过

目前支持的健康性设置包括:

  • 标签 aliyun.probe.url: 支持通过HTTP/TCP协议的URL请求对容器进行健康检查
  • 标签 aliyun.probe.cmd: 通过 shell 脚本检查对容器进行健康检查

通过上面的方式,容器服务可以更加细粒度地判断应用健康状态,并会根据健康信息实现应用可用性的优化控制,比如:

  1. 应用路由:如果服务容器状态不健康,该容器会被从负载均衡上摘除,保障后续请求可以路由到健康的容器中。
  2. 容器依赖:Docker Compose一个缺陷是只能描述容器之间的启动顺序,但是不能保证所依赖的容器已经正常运行,很多同学都为此吃过苦头。而当容器服务部署应用模板时,如果指明了aliyun.depends标签或者使用Compose V2中的depends_on指令,只有当所依赖的容器进入健康状态,容器才会被启动。这样可以非常优雅地保证应用中容器的启动顺序。
  3. 平滑升级:在升级过程中,为了保证应用访问不被中断,系统需要当一个容器更新完毕并健康运行之后再更新下一个容器。这个行为可以通过aliyun.rolling_updates标签来非常简单的配置。

可以通过容器服务帮助文档了解更多详细信息

在Docker 1.12之后,Docker Engine将内置容器的健康检查,可以通过命令方式支持容器的健康状态检测,并自动重启失效容器。容器服务已经实现对Docker 1.12的支持和兼容。

高可用部署架构

一个常见误区是:用户认为应用的高可用性可以完全由云服务商的基础设施保证,自己无需关注。而真实情况是:虽然云服务提供了高可靠的基础设施,还要合理配置组合才能保障应用的可用性。

在云端和在自有物理机上部署应用有很多不同。在自有数据中心中,有经验的运维人员会根据应用负载特性选择合适的物理机。比如,根据应用的可用性要求,把应用部署到不同的物理服务器或不同机架的物理服务器上。然而在公共云和专有云中,由于虚拟化层支持虚拟机的迁移甚至热迁移,我们不应也不能再试图将应用和其部署位置简单绑定。

正确的姿势是:在理解云供应商提供的隔离性、可用性保证机制上,根据应用负载特征设计部署架构,并让系统来实现动态管理。

对可用性而言,在阿里云上可以有多种部署方式:跨多个ECS实例部署应用,防止单实例失效导致的应用无法访问;跨多个可用区(Availability Zone)的方式可以防止机房整体失效导致的应用中断;而跨多个地域(Region)的部署方式可以保证,即使一个地域的服务无法访问时,应用也可正常运行。此外阿里云上的RDS,SLB等云服务都提供了跨多个可用区的服务能力。关于云端高可用架构可以参见 双11技术攻略:企业云架构的正确姿势

随着微服务架构的引入,应用的部署更加富有挑战性。首先微服务和传统应用相比,部署组件的数量可能有10倍以上的区别;而且由于每个服务都支持快速的演进和动态地伸缩,除了需要更好地服务治理能力,也需要系统提供自动化的部署和管理能力保障应用SLA。

阿里云容器服务为Docker应用提供了内置的高可用支持,可以更好地支持微服务应用部署。

对于容器服务中的集群,用户可以选择新建ECS实例或者手动添加已有ECS实例,并支持手动和弹性扩容。如果用户应用关注网络性能,则可以选择自于同一个可用区的ECS实例,这样例之间的网络延迟会最小化。如果用户应用关注于高可用性。我们可以为集群添加来自多个可用区的ECS实例,配合SLB,RDS等多可用区支持能力,我们就会有一个高可用的容器基础架构。

下面是一个典型的高可用的容器集群的配置。其中ECS实例和RDS数据库实例部署在不同可用区之上。哪怕一个机房掉电也不会影响到集群中应用的可用性。

然而这还不够,因为在一个集群上的ECS实例上,通常会运行成百上千个应用。在调度容器高效地利用ECS节点资源的同时,如何避免由ECS节点/可用区失效导致的应用访问失败?

阿里云容器服务完全兼容Docker Swarm的集群管理和资源调度能力。Swarm允许在容器部署时,通过声明约束条件来指定容器和容器,容器和节点之间的亲和性和反亲和性。详细信息可以参考文档

比如,下面的命令可以让两个redis容器部署在不同的节点上

docker run -d --name redis_1 -e 'affinity:container!=redis_*' redis
docker run -d --name redis_2 -e 'affinity:container!=redis_*' redis

阿里云容器服务在此基础之上提供了更加丰富而简便的的服务级别的亲和性约束。在compose模板中,服务定义了一组容器的集合,它们拥有一致的镜像和配置。

如果指明了 aliyun.scale标签,相同服务的不同容器复本会尽量分布到不同节点之上,防止因为ECS实例失效导致该服务所有容器全部无法访问。

服务之间可以通过 affinity:service标签来描述服务直接容器的亲和性。比如下面的模板,描述了一个MySQL主从结构中,MySQL master和slave容器不会调度到一个ECS实例上

master:
  image: tutum/mysql:5.6
  environment:
    - MYSQL_USER=user
    - MYSQL_PASS=test
    - REPLICATION_MASTER=true
    - REPLICATION_USER=repl
    - REPLICATION_PASS=repl
    - affinity:service!=slave
slave:
  image: tutum/mysql:5.6
  environment:
    - MYSQL_USER=user
    - MYSQL_PASS=test
    - REPLICATION_SLAVE=true
    - affinity:service!=master
  links:
    - master:mysql

还有一个方式通过容器和节点的亲和性,可以细粒度的指定如果将容器部署到指定节点之上。可以参见分布式Zookeeper集群了解其中示例。

为了保证服务有更高的可用性,我们可以将服务中的容器调度在不同的可用区(availability zone)里。

比如,通过 availability:az标签,我们可以非常简单地把如下web服务的Nginx容器部署到2个可用区之中。

web:
  image: 'nginx:latest'
  environment:
    - availability:az==2
  labels:
    aliyun.scale: '8'
    aliyun.routing.port_80: 'web'
  restart: always

一个容器集群可以保证容器应用在节点或可用区级别的可用性。如果用户需要达到更高级别的可用性,可以在不同地域创建容器集群,并分别部署应用。阿里云容器服务也提供混合云能力,支持用户在自有数据中心和云端分别创建容器集群,并用统一的方式进行应用部署和管理。其简单部署架构如下:

自动恢复能力

在分布式架构中,节点失效是不可避免的。高可用部署让应用可以容忍一定的失效;另一方面我们需要能够让应用从故障状态中自动恢复回来。就像X战警中的金刚狼,虽然战斗力可能不是最强,但是超强恢复力让他成为决定战斗命运的角色。

阿里云容器服务支持容器自动重新调度策略。也就是当容器所属宿主机节点失效时,系统可以将该容器自动迁移到其他健康节点上继续运行,从而保证应用的SLA。

容器服务提供兼容 Docker Swarm 的容器重调度策略。 在下面一个示例中,Redis服务开启了重调度策略

redis:
  image: redis
  labels:
    - com.docker.swarm.reschedule-policies=["on-node-failure"]

什么样的容器支持重调度?我们需要分析容器中应用对持久化状态的依赖。无状态应用可以简单地被调度到任何节点上正确执行的;而如果容器应用依赖于宿主机的本地存储,则是无法被重调度的。对于后者,需要进一步分离应用层和数据层逻辑才能支持迁移。比如在阿里云容器服务中,容器可以利用文件卷插件(volume plugin)提供的网络存储能力(NAS/NFS和OSSFS)来共享和保存数据。一旦节点失效,容器被调度到其他节点,容器服务会保证其相应文件卷的正确挂载。这样应用可以从网络中获得已保存的数据并继续运行。

总结

云原生应用在架构、开发、运维等方面和传统软件应用有很多不同。利用Docker和阿里云容器服务可以轻松解决高可用部署和故障恢复的复杂性。

阿里云容器服务在兼容Docker原生编排技术的同时,提供了针对阿里云能力的优化和集成。开发者可以利用声明式的方式来描述容器应用的部署约束,以及集成阿里云服务,从而满足对可用性SLA的要求。

想了解更多容器服务内容,请访问 https://www.aliyun.com/product/containerservice

时间: 2025-01-26 20:53:43

利用Docker轻松实现云原生应用 - 高可用架构设计的相关文章

利用Docker轻松实现云原生应用: Spring Boot + Redis分布式会话

本文为利用Docker和容器服务轻松实现云原生应用系列的第二篇 高可用架构设计 Spring Boot + Redis分布式会话 (本文) 前文谈到了云原生应用在部署架构中需要考虑的重要问题.文本将介绍一个常见的应用架构模式来提升应用的可用性和可伸缩性 - 分布式会话管理. 随着业务增长,Web应用也从单节点部署演变为集群部署.这时候除了需要为应用服务器增加负载均衡之外,也要解决会话(session)管理的问题.Session在应用中常被用于存储用户相关的数据.在高可用系统中,如果一台应用服务

基于AWS云平台的高可用应用设计

基于AWS云平台的高可用应用设计 方国伟 云计算在给架构师带来了许多新的设计挑战的时候,也给带来了许多新的设计理念和可用的服务.如何在设计应用的时候充分利用云平台的各种特点是基于云平台设计的一个重要因素.在这个演讲中,我们将以亚马逊AWS云平台为例,讨论如何设计一个高可用应用.我们先会对AWS的服务进行高可用性的分类,并从高可用角度对典型服务进行介绍,然后依次讨论高可用设计的5大常见设计原则,并结合AWS的相关服务依次进行架构设计分析. 基于AWS云平台的高可用应用设计

面向业务的立体化高可用架构设计

原文链接:http://www.csdn.net/article/2015-10-27/2826042 ======================================================== 面向业务的立体化高可用架构设计 发表于2015-10-27 10:47| 2924次阅读| 来源<程序员>杂志| 8 条评论| 作者李运华 <程序员>杂志2015年10月B架构李运华面向对象 摘要:为了实现阿里九游游戏接入系统的业务高可用,技术人员跳出传统的面向系统的

可用性高达五个9!支付系统高可用架构设计实战

对于互联网应用和企业大型应用而言,多数都尽可能地要求做到7*24小时不间断运行,而要做到完全的不间断运行可以说"难于上青天". 为此,对应用的可用性程度一般衡量标准有三个9到五个9. 对于一个功能和数据量不断增加的应用,要保持比较高的可用性并非易事.为了实现高可用,付钱拉从避免单点故障.保证应用自身的高可用.解决交易量增长等方面做了许多探索和实践. 在不考虑外部依赖系统突发故障,如网络问题.三方支付和银行的大面积不可用等情况下,付钱拉的服务能力可达99.999%. 本文重点讨论如何提高

利用Docker和阿里云容器服务轻松搭建TensorFlow Serving集群

本系列将利用Docker和阿里云容器服务,帮助您上手TensorFlow的机器学习方案 第一篇:打造TensorFlow的实验环境 第二篇:轻松搭建TensorFlow Serving集群 - 本文 第三篇 打通TensorFlow持续训练链路 第四篇 利用Neural Style的TensorFlow实现,像梵高一样作画 第五篇 轻松搭建分布式TensorFlow训练集群(上) 本文是系列中的第二篇文章,将带您快速了解Tensorflow Serving的原理和使用,并利用阿里云容器服务轻松在

【干货】阿里资深技术专家丁宇谈双11高可用架构演进之路

近日Velocity China 2016在京举行,会上阿里中间件技术部资深技术专家丁宇(花名叔同)发表了题为<零点之战–阿里双11高可用架构演进之路>的演讲.丁宇从2009年开始,参加了每年的阿里双11技术保障工作, 最近两年他分别以共享平台事业部双11项目负责人,和集团双11项目稳定性总负责人的身份参与其中. 阿里巴巴平台的业务规模在过去的8年呈指数级增长,给双11所带来的技术挑战是世界性的,特别是如何在零点峰值到来时确保系统的稳定性.零点技术挑战的本质是用有限的成本去实现最大化的集群整体

2017QCon分享:从淘宝到云端的高可用架构演进

大家好,我今天分享的题目是<高可用实践:从淘宝到上云的差异>,取这个标题是因为会涉及到两个方面内容,一方面以淘宝为例子,传统的IDC的时候,我们稳定性是怎么做的,另外在云计算背景下,有很多创业公司是基于阿里云这样的公有云基础设施做研发,在公有云的环境下怎么做好我们系统的高可用. 长期做稳定性的人会有一些职业病,记得去年冬天有个周末,我要寄快递,穿着睡衣在门口填快递单,那时候我家里养了一只猫,因为怕猫跑出去,就把门关上了.寄完快递口袋一掏发现自己没带钥匙,冷静了3秒钟,打车到公司刚巧碰到同事,看

《企业迁云实战》——3.2 云上运维管理架构设计

3.2 云上运维管理架构设计 为保证云上运维管理操作的安全性和便捷性,客户需要根据业务对云上网络环境进行规划和隔离并对内部用户访问进行管理和权限规划.下面将会从这两方面介绍如何利用阿里云产品实现云上运维管理架构设计.3.2.1 基于RAM实现账号权限管理方案 本节将介绍基于阿里云RAM账号体系在内部用户访问资源时如何进行管理和权限规划. 1 . RAM简介 RAM(Resource Access Management)是阿里云为客户提供的用户身份管理与访问控制服务.使用RAM,可以创建.管理用户

八年来我们到底经历了什么?——中间件专家带你“重走”双11高可用架构演进之路

双11的技术挑战 双11技术挑战的本质使用用有限的成本去是实现最大化的用户体验和集群整体吞吐能力,用最合理的代价解决零点峰值,支撑好业务的狂欢.阿里做双11已经有八年之久了,八年来双11的交易额增长200倍,交易峰值增长400多倍,系统复杂度和大促支撑难度以指数级攀升:并且经过多年的发展,双11技术实现链条中的变量不断增加,如峰值的增量和系统架构的变化.交易峰值的组成.拆单比.每个业务入口的访问量等,这些变量也给系统带来了不确定性.回顾这八年的双11零点之战,它推动了阿里的技术进步.推动了架构优