查看原文
其他

数据库不适合上容器云?| 技术头条

CSDN云计算 CSDN云计算 2019-05-25

戳蓝字“CSDN云计算”关注我们哦!

技术头条:干货、简洁、多维全面。更多云计算精华知识尽在眼前,get要点、solve难题,统统不在话下!


Docker 在企业环境的应用端具有很大的潜力,在这一点上我想大家是有目共睹的,无状态的服务采用容器化已经是一种大趋势,那么问题来了,作为系统核心的数据库是否需要容器化?

 

针对数据库是否适合容器化这个问题,不同的人可能会给出不同的答案,在回答此问题之前我们先看下容器化部署数据库和常规数据库部署上的一些比较。

 

 

 

容器VS非容器化

 

  数据库不适合容器化,笔者相信持这种观点的技术人员不在少数,为此笔者专门梳理了此种观点常见的一些依据,我们一起看一下:

 

1. 数据安全性

 

数据安全这个话题较大,可以细分很多的小方向,在此我们只从数据丢失这个角度分下数据库容器化后引入的问题。

 

和数据库打过交道的同学应该都知道,公司线上的数据库一般都需要进行定期的数据备份,区别的话无非就是根据业务的轻重缓急设置不同的数据备份方式、备份频率和备份数量。常见的数据库的数据备份方式有全量备份和增量备份。

 

顾名思义,全量备份即每次都进行一次完整的数据备份,即便是相较前一次的全量备份数据没有丝毫的增加也要再进行一次完整的数据备份,此种方式的特点是可靠性较好,每一个数据备份都是备份所在时间点的完整数据,当然此种方式的缺点也是显而易见的,即备份周期较长(相比增量备份的数据量大),且备份数据占用的磁盘存储也较大;增量备份即在第一次备份时进行一次全量的备份,后续在进行备份时只备份相较前一次备份时变化的数据,增量备份的优点是备份周期短,且备份数据占用的磁盘空间较少。

 

 

 

备份周期并非越小越好,需要结合业务的属性进行选择,如公司OA系统使用的数据库可以一周备份一次,毕竟OA 这种系统并会经常进行大量数据的写入。再一种情况,比如公司的重要的线上业务一般需要较高的备份频率,一般以天或者小时作为备份周期的时间单位,比如一天备份一次、或者1小时备份一次。有些更重要的业务系统,出现数据丢失时会带来比较大的损失,此种情况一般会采用更高的数据备份频率,比如银行的数据库备份多以分钟或者秒作为数据库的备份周期单位。

 

和备份周期的设置类似,备份数据保留的数量也并非越多越好,也需要根据具体的业务场景来设置备份数据的保留数量。比如一般的线上业务可以每天备份一次,最多保留7份备份数据。

 

以上我们说的是我们在将数据库容器化之前为防止数据库数据丢失通常进行的配置,从现实角度来看即使我们设置了上面提到的各种配置也仍然不能保证不丢失数据。

 

从上面的经验来看,容器化后即使我们通过容器的volume 将数据存储在容器所在宿主机上也不能保证数据不丢失。况且Docker 的volume 是围绕联合文件系统的镜像层来进行的持久化存储设计,这种设计目前在数据库存储方面仍缺乏保证。

 

除了上面的问题,还有一种情况也会为数据库的数据安全性带来问题,众所周知在容器的世界里某个容器的崩溃、重建是常态,这种情况对于业务实例来说也许不会有多大的影响,但同样的场景换为数据库可能会出现问题,比如运行着数据库的容器崩溃可能会导致容器内的数据库不能正确关闭,从而可能造成数据的损坏。

 

2. 环境需求

 

在非容器化的场景中,为了避免避免和其他组件的资源竞争,数据库这种核心组件我们一般都是单独部署的,要么单独部署到一台或者几台的虚拟机上,要么单独部署到一台或者几台的物理机上,一般需要和其它的线上组件分开部署,比如后端的一些业务实例等,防止其它异常组件拖垮数据库,毕竟数据库挂了线上业务一般也就歇菜了,这种情况下企业一般也是宁愿多花点钱来保证线上业务的正常运行。

 

数据库的单独部署只是第一步,实际环境中一般还需要给数据库组件配置好一些的硬件资源,具体需要在哪些方面进行升配也需要结合具体额业务场景和数据库的类型来看。比如关系型数据库,一般对I/O要求较高,这个时候一般需要为数据库配置较好的存储设备,比如磁盘选用优质的全固态盘。在一种比如缓存数据库,为提高查询效率缓存数据库一般会将数据存储在内存中,如果存在较多的高频访问数据,此时一般需要为数据库配置较高的内存。

 

考虑到上面的两种情况,我们在进行数据库的容器化过程中为了避免数据库实例和其他的业务实例产生资源竞争,我们需要为数据库容器配置大量额外的资源,一般可能需要设置超过实际用量一倍的资源,比如我们实际需要8GB内存,可能需要为实例分配16GB内存,多出的这8GB的内存资源一般并不会被完全使用。

 

3. 网络需求

 

  Docker 的引入一定程度上增加了网络的复杂性,想要理解Docker 的网络需要对网络虚拟化有比较深入的了解。另外,虽然Docker 的使用已经逐步落地,但Docker 本身的技术仍在发展之中,Docker 本身还存在或多或少的bug,这些bug可能会为我们带来一些意外的情况。为应对这些意外,我们可能需要花费较多的时间排查和修复Docker 的bug,从笔者实际体验来看这种情况一般会花费企业较多的人力。

 

 

 

  上文中我们提到数据库一般会有较高的吞吐量,因此通常情况下我们需要为数据库配置较好的配置,以此来应对更高的负载。除了磁盘、内存、CPU会较大的影响数据库的性能之外,网络对数据库的性能也是非常只要的一环,尤其是在涉及到数据复制的场景,网络性能差的情况下可能会影响到数据库的数据复制效率,在异步复制的场景下网络性能差可能会导致业务实例读不到最新的数据。我们知道容器是虚拟机管理程序和主机虚拟机背后的一个隔离层,Docker 容器引入的额外的网络逻辑一定程度上会降低网络的传输效率,进而可能会影响到数据库容器之间的数据复制,进而导致业务实例从数据库读取到错误的数据。

 

  数据库本身就是一个比较复杂的系统,数据库的容器化会导致数据库更加难以管理,相比引入Docker复杂的网络环境,将数据库实例放在专用的环境中,节省下时间专注于业务的改进对项目、对企业来说可能会是更好的选择。

 

4. 状态抉择

 

  Docker 容器出现之初主要是用来运行无状态的应用实例,对于数据库这种情况并未专门的支持。数据库的特性决定了它是有状态的,和无状态的应用实例混布在一起,会加大系统的故障范围,业务系统中的应用程序实例异常可能会直接影响到运行在有状态容器中的数据库实例。

 

5. Docker支持

 

简单说来就是Docker并未对容器中运行数据库这种场景做专门的优化。我们先看下Docker 官方对Docker的定义:

 

Docker Containerization Unlocks the Potential for Dev and Ops,Freedom of choice, agile operations and integrated container security for legacy and cloud-native applications。

 

 

具体说来就是:

 

(1) Docker 是为程序开发者和系统运维人员提供的一个开放平台,这个平台提供了包含应用构建、应用分发和运行分布式应用在内的一些功能。


(2) Docker 为程序开发者和系统管理人员提供了Docker 引擎和众多的配套组件,如Docker Hub,Docker 引擎是一个C/S架构的应用程序,开发者可以借助Docker 引擎对Docker 对象进行管理,常见的Docker 对象包括:Dcoker镜像、Docker容器、Docker网络、Docker 数据库卷等。Docker Hub 为开发者提供镜像的托管服务。开发者借助Docker 可以将应用程序以组件的形式进行快速的部署,同时借助Docker 可以消除各种环境的差异性,比如开发环境、测试环境、生产环境。因此借助Docker 开发者可以更快的对应用进行分发,可以实现一份应用在个人电脑、数据中心的虚拟机和任何云上运行上快速运行。

   

  从上面的介绍我们可以明显的看出Docker的一些特性,比如易于构建新环境、适合持续集成、灵活的水平伸缩和不同环境的易维护性等。那么问题来了,这些特性会为数据库带来什么?

 

  为了回答这个问题我们先看下数据库的容器化和本地化运行数据库,二者是否有较大的差异,我们以mongodb数据库为例来具体看下:

 

  本地化的批量部署软件大家一般都会借助一些现成的批量部署工具,比如我们最常使用的Ansible,借助Ansible 我们可以很轻松的部署并设置几十个mongodb实例,比对下容器化部署几十个mongodb实例,可能容器化的方式并未为我们节省多少时间。

 

  有些同学可能会问如果批量重新部署多个mongodb实例的话容器化的部署方案应该会更加高效一些,但问题来了,实际工作中数据库实例需要批量升级的频率有多高,这种情况可能大部分人在自己目前的职业生涯中都还没有遇到过一次。且数据库实例的升级一般不是可用性问题,而是一个比较系统的工程问题,需要考虑到数据库实例在升级后在整个系统中的可用性。比如更新数据库的版本之后已有的应用中的逻辑可以无缝的对接吗,这个可能不见得,从实际情况来看,数据库实例更换了引擎版本之后可能会引入很多的新特性,这些特性中一般也会有一些不兼容的情况,为解决更新数据库版本带来的不兼容的问题,我们需要花费很多额外的人力来对应用进行对应的版本升级,整个过程耗时、耗力,因此实际生产环境中一般不会对数据库实例进行频繁的升级,所以在此点上数据库的容器化并不能带来明显的效率提升。

 

  再一个方面,比如动态伸缩。容器化的实例在动态伸缩方面确实存在优势,尤其是一般的后端应用上,但放在数据库的容器化实例上却不能这么乐观。比如我们在容器云中运行了一个db server的多个实例,那么我们需要考虑下多个实例之间的数据一致性问题,如何解决这个数据一致性?有些同学可能会说多个容器实例共享数据目录或者加入复制的从节点不就可以解决吗,这些方式当然是合适的,但是都会引入额外的问题,比如数据并发问题和可能出现的数据损坏问题改如何应对,这些都是问题。反观非容器化部署数据库实例,将多个数据库实例部署到专用的环境中相对来说更简单,更容易维护,数据更安全,且不会引入额外的问题,另外对于技术人员来说学习成本也相对较低。

 

  通过上面几个特性的对比,相比专用环境部署数据库数据库的容器化似乎并未为我们带来明显的改进。

 

6. 隔离问题

 

了解Docker 的同学应该都知道,Docker 通过namespace(命名空间)对各种资源进行了隔离,这些隔离包括:主机和域名隔离、进程编号隔离、用户和用户组隔离、文件系统隔离、网络设备隔离、网络栈隔离、端口号隔离、信号量消息队列和共享内存的隔离等。

 

默认情况下只有同一个namespace下的进程之间是可以相互联系的,无法感受到外部进程的存在,Docker通过这种方式营造出一种独立的系统环境,从而实现隔离。

 

这种隔离性虽然保证了不同容器中进程的冲突等问题,但是这些额外引入的隔离级别也会增加资源的开销。并且这种隔离性只是为业务的应用量身打造的,并未专门针对数据库做做额外的优化。

 

7. 云平台问题

 

当前环境下借助云平台已经成为常态,我们知道云计算简化了虚拟机管理、替换上的复杂性,因此在需要添加新的虚拟机计算节点时直接登录上云平台,控制台界面上鼠标操作几个步骤即可准备完毕几台新的计算节点,为我们节省了很多的购买已经设备和测试硬件设备的时间和精力,可谓方便至极。当然这个也是我们需要向云厂商付费的原因之一。

 

我们再说回容器云,用过云厂商容器云产品的同学应该会知道,云厂商提供的容器产品相比原生的容器往往会有一些限制,这个时候如果我们不想直接使用云厂商提供的容器云产品,转而使用云厂商提供的其他的计算产品自己部署容器环境,比如使用虚拟机或者使用物理机,这种情况下上文中我们讲到的云厂商为我们提供的便利性就不存在了,当然我们可以在容器所在宿主上对数据库容器实例的资源使用进行限制,这种方式的确可以,但相比直接使用虚拟机或者物理机部署数据库实例这种容器化部署的方式更加复杂。

 

以上我们在7个方面列举了下数据库不适合进行容器化的原因,很多方面仅仅只是进行了粗略的描述,尤其是在关键的有状态部署和无状态部署方面,由于此部分涉及对比的方面较多,在此下面我们专门单独拿出来看下。

 

 

状态 VS 无状态

 

  Docker 及其编排技术的兴起和逐步成熟让大家由最初的要不要上容器转为什么不用容器,但在业务容器化的过程中大家一般都会遇到这样一个问题:我们应该将自己的数据库实例跑在容器中吗?                     

                        

  要想回答这个问题,我们不妨先回顾下容器技术出现的背景,即这门技术的出现是为了解决什么问题。接触容器比较早的话大家应该记得容器技术主要是用在有临时数据的无状态服务上,也就是说可以随时起、随时用、随时销毁(销毁的组件包括容器中的缓存和数据),容器基本就是用来处理请求,可能还会保存一部分的临时数据,且这部分数据是允许丢失的。由于这种特性的存在,用户不能将不允许丢失的数据存放在容器中,这类数据比如用户上传的文件、应用的关键日志信息等,也是由于此特性的存在为数据库的容器化带来了障碍。



      

  有些同学可能会问,通过给容器挂载volume不能解决吗? 的确,容器是有挂载volume的机制,volume 可将docker 容器所在的宿主机上的某个路径挂载到容器中,这样容器中的应用可以将需要持久化的数据写入到volume挂载的路径中,写入到volume 挂载路径的数据实际会被写入到Docker 容器所在的宿主机上,这样docker 容器销毁之后我们需要的数据仍然存于容器所在的宿主机之上,不会丢失。这种方案看似比较合理,但是也存在一个很大的漏洞。使用容器的时我们一般通过保存镜像的方式将容器中新增的数据保存到镜像中,但是docker 容器的镜像保存机制不能将容器中挂载的volume里的数据保存到镜像中,如果容器中运行的为我们的数据库,数据库的data路径为docker容器的volume挂载路径,当我们保存容器镜像时,由于刚刚讲到的docker的特性,容器运行后数据库中新增的数据并不能被保存到镜像中,不是很方便。由于数据库有状态特性的存在一定程度上限制了我们对数据库实例的容器化。

 

  上面我们谈到的volume 可以解决数据库实例数据库持久化的问题只是在为引入容器编排的情况下的情况。实际使用中项目在使用容器部署应用时一般都会引入容器的编排功能,最常见的容器编排工具,比如kubernetes。加入容器编排之后,假设我们将数据库容器实例以有状态服务的方式进行运行,那么问题来了,如果数据库容器实例漂移到了另一台的宿主机上怎么办,毕竟数据库的数据还在漂移前的宿主机上。这个时候我们可能就需要将计算和存储进行分离,最常见的比如加入分布式存储来解决这个问题,如Ceph分布式存储,这种方式的确是可以的,很多实用容器云的企业也是这样操作的,但是引入Ceph会引入很多的复杂性,且企业内的运维人员不一定对Ceph存储了如指掌,这种情况下我们为了实现数据库容器化而额外引入的问题可能比数据库容器化带来的便利性还要多。

                           

总结

 

  上文中关于数据库是否适合容器化的描述中我们更多的对比的是数据需要持久化的数据库,以及需要特殊硬件环境才能运行的数据库。但大家都知道数据库中众多,并不是每一种都需要进行数据的持久化,比如当做缓存使用的数据库,拿redis来说,如果我们使用redis作为缓存或者用来存储用户会话这一类的数据,这种场景下数据库的容器化不会涉及前文中提到的7个方面的限制,因此数据库实例作为缓存这种场景时,数据库实例的容器化也是合适的。

 

  从实际的使用来看,数据库要不要容器化这个问题并不是绝对的,需要结合具体的业务场景才能得出结论。比如,微服务的场景,如果我们的系统已经实现了微服务化,数据库实例的规模可以根据业务负载的实际情况进行动态的调整,这种场景下数据库实例的微服务化是比较有意义的,一般也是比较推荐的,且很多业务做了微服务化改造的企业确实也是这样做的。当然微服务化的过程中数据库的容器化也不是绝对的,笔者自己接触的一些业务已经微服务化落地的企业中就存在一些未对数据库做微服务化改造的情况。

 

  笔者个人认为数据库的容器化像一般应用的容器化那样普及只是时间问题,随着Docker 及其周边的配套技术的逐步成熟,相信在不久的将来大家会像使用Docker 容器部署应用一样来部署自己的各种数据库实例,会像使用kubernetes 编排应用的实例一样来自由的编排自己的数据库实例。




福利

扫描添加小编微信,备注“姓名+公司职位”,加入【云计算学习交流群】,和志同道合的朋友们共同打卡学习!



推荐阅读:


真香,朕在看了!

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存