继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

容器的六个误区

青春有我
关注TA
已关注
手记 1206
粉丝 205
获赞 1008

误区一:容器启动速度快,秒级启动

这是很多人布道容器的时候经常说的一句话,往往人们会启动一个Nginx之类的应用,的确很快就能够启动起来了。

容器为啥启动快,一是没有内核,二是镜像比较小。

然而容器是有主进程的,也即Entrypoint,只有主进程完全启动起来了,容器才算真正的启动起来。

用一个比喻:容器更像人的衣服,人站起来了,衣服才站起来,人躺下了,衣服也躺下了。衣服有一定的隔离性,但是隔离性没那么好。衣服没有根(内核),但是衣服可以随着人到处走。

所以按照一个Nginx来评判一个容器的启动速度有意义么?对于Java应用,里面安装的是 Tomcat,而 Tomcat 的启动,加载 War,并且真正的应用启动起来。

如果你盯着Tomcat的日志看的话,还是需要一些时间的,根本不是秒级;如果应用启动起来要一两分钟,仅仅谈容器的秒级启动是没有意义的。

现在OpenStack中 VM 的启动速度也优化的越来越快了,启动一个 VM 的时候,原来需要从 Glance 下载虚拟机镜像。

后来有了一个技术,是在Glance和系统盘共享 Ceph 存储的情况下,虚拟机镜像无需下载,启动速度就快很多。

而且容器之所以启动速度快,往往建议使用一个非常小的镜像,例如alpine,里面很多东西都裁剪掉了,启动的速度就更快了。

OpenStack的虚拟机镜像也可以经过大量的裁剪,实现快速的启动。

我们可以精细的衡量虚拟机启动的每一个步骤,裁剪掉相应的模块和启动的过程,大大降低虚拟机的启动时间。

例如在UnitedStack的一篇博客里面 https://www.ustack.com/blog/build-block-storage-service,我们可以看到这样的实现和描述:

使用原生的OpenStack创建虚拟机需要 1~3 分钟,而使用改造后的 OpenStack 仅需要不到 10 秒钟时间。

这是因为nova-compute不再需要通过 HTTP 下载整个镜像,虚拟机可以通过直接读取 Ceph 中的镜像数据进行启动。

所以对于虚拟机的整体启动时间,现在优化的不错的情况下,一般能够做到十几秒到半分钟以内。

这个时间和Tomcat的启动时间相比较,其实不算是负担,和容器的启动速度相比,没有质的差别,可能有人会说启动速度快一点也是快。

尤其是对于在线环境的挂掉自修复来讲,不是分秒必争么?关于自修复的问题,我们下面另外说。

然而虚拟机有一个好处,就是隔离性好,如果容器是衣服,虚拟机就是房子,房子立在那里,里面的人无论站着还是躺着,房子总是站着的,房子也不会跟着人走。

使用虚拟机就像人们住在公寓里面一样,每人一间,互不干扰,使用容器像大家穿着衣服挤在公交车里面,看似隔离,谁把公交弄坏了,谁都走不了。

综上所述,容器的启动速度不足以构成对OpenStack虚拟机的明显优势,然而虚拟机的隔离性,则秒杀容器。

误区二:容器轻量级,每个主机会运行成百上千个容器

很多人会做实验,甚至会跟客户说,容器平台多么多么牛,你看我们一台机器上可以运行成百上千个容器,虚拟机根本做不到这一点。

但是一个机器运行成百上千个容器,有这种真实的应用场景么?对于容器来讲,重要的是里面的应用,应用的核心在于稳定性和高并发支撑,而不在于密度。

我在很多演讲的会议上遇到了很多知名的处理双十一和618的讲师,普遍反馈当前的 Java 应用基本上 4 核 8G 是标配,如果遇见容量不足的情况,少部分通过纵向扩容的方式进行,大部分采用横向扩容的方式进行。

如果4核 8G 是标配,不到 20 个服务就可以占满一台物理服务器,一台机器跑成百上千个 Nginx 有意思么? 这不是一个严肃的使用场景。

当然现在有一个很火的Serverless无服务架构,在无服务器架构中,所有自定义代码作为孤立的、独立的、常常细粒度的函数来编写和执行,这些函数在例如 AWS Lambda 之类的无状态计算服务中运行。

这些计算服务可以是虚拟机,也可以是容器。对于无状态的函数来讲,需要快速的创建可删除,而且很可能执行一个函数的时间本身就非常短,在这种情况下容器相比于虚拟机还是有一定优势的。

目前无服务架构比较适用于运行一些任务型批量操作,利用进程级别的横向弹性能力来抵消进程创建和销毁带来的较大的代价。

在Spark和 Mesos 的集成中,有一个 Fine-Grained 模式,在大数据的执行时候,任务的执行进程早就申请好了资源,与等在那里分配资源不同,这种模式是当任务分配到的时候才分配资源。

好处就是对于资源的弹性申请和释放的能力,坏处是进程的创建和销毁还是粒度太大,所以这种模式下Spark运行的性能会差一些。

Spark的这种做法思想类似无服务架构,你会发现我们原来学操作系统的时候,说进程粒度太大,每次都创建和销毁进程会速度太慢。

为了高并发,后来有了线程,线程的创建和销毁轻量级的多,当然还是觉得慢,于是有了线程池,事先创建在了那里,用的时候不用现创建,不用的时候交回去就行。

后来还是觉得慢,因为线程的创建也需要在内核中完成,所以后来有了协程,全部在用户态进行线程切换。

例如AKKA,Go 都使用了协程,你会发现趋势是为了高并发,粒度是越来越细的,现在很多情况又需要进程级别的,有种风水轮流转的感觉。

误区三:容器有镜像,可以保持版本号,可以升级和回滚

容器有两个特性,一个是封装,一个是标准。有了容器镜像,就可以将应用的各种配置,文件路径,权限封装起来,然后像孙悟空说“定”,就定在了封装好的那一刻。

镜像是标准的,无论在哪个容器运行环境,将同样的镜像运行起来,都能还原当时的那一刻。

容器的镜像还有版本号,我们可以根据容器的版本号进行升级,一旦升级有错,可以根据版本号进行回滚,回滚完毕则能够保证容器内部还是原来的状态。

但是OpenStack虚拟机也是有镜像的,虚拟机镜像也是可以打 snapshot 的,打 snapshot 的时候,也会保存当时的那一刻所有的状态,而且 snapshot 也可以有版本号,也可以升级和回滚。

似乎容器有的这些特性OpenStack虚拟机都有,二者有什么不同呢?

虚拟机镜像大,而容器镜像小。虚拟机镜像动不动就几十个G甚至上百 G,而容器镜像多几百 M。

虚拟机镜像不适合跨环境迁移。例如开发环境在本地,测试环境在一个OpenStack上,开发环境在另一个 OpenStack 上,虚拟机的镜像的迁移非常困难,需要拷贝非常大的文件。

而容器就好的多,因为镜像小,可以很快的从不同的环境之间迁移。

虚拟机镜像不适合跨云迁移。当前没有一个公有云平台支持虚拟机镜像的下载和上传(安全的原因,盗版的原因),因而一个镜像在不同的云之间,或者同一个云不同的 Region 之间,无法进行迁移,只能重新做一个镜像,这样环境的一致性就得不到保障。

而容器的镜像中心是独立于云之外的,只要能够连上镜像中心,到哪个云上都可以下载,并且因为镜像小,下载速度快,镜像是分层的,每次只需要下载差异的部分。

OpenStack对于镜像方面的优化,基本上还是在一个云里面起作用,一旦跨多个环境,镜像方便的多。

误区四:容器可以使用容器平台管理自动重启实现自修复

容器的自修复功能是经常被吹嘘的。因为容器是衣服,人躺下了,衣服也躺下了,容器平台能够马上发现人躺下了,于是可以迅速将人重新唤醒工作。

而虚拟机是房子,人躺下了,房子还站着。因而虚拟机管理平台不知道里面的人能不能工作,所以容器挂了会被自动重启,而虚拟机里面的应用挂了,只要虚拟机不挂,很可能没人知道。

这些说法都没错,但是人们慢慢发现了另外的场景,就是容器里面的应用没有挂,所以容器看起来还启动着,但是应用已经不工作没有反应了。

当启动容器的时候,虽然容器的状态起来了,但是里面的应用还需要一段时间才能提供服务。

所以针对这种场景,容器平台会提供对于容器里面应用的health check,不光看容器在不在,还要看里面的应用能不能用,如果不能,可自动重启。

一旦引入了health check,和虚拟机的差别也不大了,因为有了 health check,虚拟机也能看里面的应用是否工作了,不工作也可以重启应用。

还有就是容器的启动速度快,秒级启动,如果能够自动重启修复,那就是秒级修复,所以应用更加高可用。

这个观点当然不正确,应用的高可用性和重启的速度没有直接关系。高可用性一定要通过多个副本来实现,在任何一个挂掉之后,不能通过这一个应用快速重启来解决,而是应该靠挂掉的期间,其他的副本马上把任务接过来进行解决。

虚拟机和容器都可以有多副本,在有多个副本的情况下,重启是1秒还是 20 秒,就没那么重要了,重要的是挂掉的这段时间内,程序做了什么。

如果程序做的是无关紧要的操作,那么挂了20秒,也没啥关系;如果程序正在进行一个交易和支付,那挂掉 1 秒也不行,也必须能够修复回来。

所以应用的高可用性要靠应用层的重试,幂等去解决,而不应该靠基础设施层重启的快不快来解决。

对于无状态服务,在做好重试的机制的情况下,通过自动重启修复是没有问题的,因为无状态的服务不会保存非常重要的操作。

对于有状态服务,容器的重启不但不是推荐的,而且可能是灾难的开始。

一个服务有状态,例如数据库,在高并发场景下,一旦挂了,哪怕只有1秒,我们必须要弄清楚这 1 秒都发生了什么,哪些数据保存了,哪些数据丢了,而不能盲目的重启,否则很可能会造成数据的不一致性,后期修都没法修。

例如高频交易下的数据库挂了,按说DBA应该严格审核丢了哪些数据,而不是在 DBA 不知情的情况下,盲目的重启了,DBA 还觉得没什么事情发生,最终很久才能发现问题。

所以容器是比较适合部署无状态服务的,随便重启都可以。

而容器部署有状态容器不是不能,而是要非常小心,甚至都是不推荐的。



作者:程序员的那点事
链接:https://www.jianshu.com/p/304a92c46e81


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP