滴滴田志伟:关于自动扩容,我们线下的时候遇到一个问题,我们最早的时候是用腾讯的公有云,它限制了 NET 的模块,导致我们最初用 Cgroup 的方案去做,绑定端口。内部使用所有应用,端口是要做分配的,要不然出现端口冲突。然后遇到问题是,在这种情况下,如果要做动态扩容的话,它每次先创建一个,再杀掉一个,导致每次起来的时候就起不来了,因为端口的问题。服务启动的时候端口是随机,会出现冲突问题,因为用的是 Host 的模式。
主持人:关于自动伸缩为什么没有考虑到请求数?因为如果内存占用率如果超过一定预支,那么请求数也可能超过一定预支了。把单个容器所处理的请求数给限定了,那么它内存自然不会超,然后也不会被干掉。
沪江黄凯:我个人认为,第一,请求数很难测,你不知道请求数到多少时要扩容,还不如根据 CPU 到 80%,或者 90% 来的直观。我们的 API 也是根据 CPU 来算的。你真正是高并发的 API 的话,我也测过,最后我们能够监测到的,其实还是 CPU 和内存。
扇贝丁彦:我们扩容是根据响应时间,跟请求数类似,请求数定指标不太好定,我们是根据响应时间,比如平时的响应时间是 50 毫秒,当响应时间是 300 毫秒的时候就要扩容了。
主持人:大家对于容器有状态无状态有没有遇到什么问题?大家一般用容器的本地磁盘还是共享磁盘呢?
沪江黄凯:关于存储,我们是有一些研究的。现在容器存储问题分为两种,Kubernetes 官方支持一种理念,任何一种存储都是一个 Volume。Volume 先于 Docker 存在的,而不是 Docker 启动之后再挂载 Volume。不管是网络存储还是本地存储,全部以卷的形式,挂载在 Pod 里面或者是宿主机上,以 Driver mapper 来驱动这个 Volume,来读到你所要的内容。
还有一种情况,就是 Docker 公司主导的存储模型,任何的存储都是一种驱动。如果你想用 NFS 或者如 Ceph 这样分布式存储的话,让 Ceph 开发 Docker 的驱动,Docker run 的时候指定存储的驱动,Docker storage driver这种方式,外部的存储在容器内部它展现形式可以是目录,也可以是挂载卷、块的形式。如果用块挂载到容器中,这个容器自己格式化它,或直接读取它都是可以的。它只不过它是相当于用了一个 Driver 的形式,把你的容器和分布式存储建立一个连接而已。对于容器,如果原本绑定块或 Volume,容器出现故障的话,直接把容器杀掉,再启动挂在同样一个 块或Volume就解决了。优点是直接读取,而不是通过再转一层,效率比较高一点。所有存储都是Volume 的形式理解度比较高一点,所以我们还是赞同于用 Volume 的形式。
有状态的容器。我知道k8s的新的计划,如果你没有用 Kubernetes 最新版本的话,一般来说我们都是容器启动在固定Host 上,下次启动还是在这台 Host 上,它的存储它的内存,包括一些 log,全部是在这台 Host 上。还有一种是用最新的版本,有个 PetSet的新kind,Kubernetes 它自己会记录 Pod 在什么 Host 上启动过,不用自己去指定一定要在某一台 Host 上启动,这种方法比较智能化,但是不是特别稳定的一种方法,因为它是刚刚开发出来的新功能。
主持人:数据多副本,假设有一个节点故障的话,是建议它直接把原来的副本重新绑定还是重新起一个新的实例,通过分布式数据的迁移呢?
沪江黄凯:我个人认为还是在同一台机器上起一个新的实例,不要让它做数据迁移,因为数据迁移会占用很多资源。而且如果你的想法是说,所有的分布式的存储只是以 Volume 的形式挂载在宿主同上,这也就没什么问题了。因为存储和 Docker 是完全分开来的。如果只有一个 Volume,存储的可靠性会得不到保障,所以在 Kubernetes 新版本当中,它会建立一个Volume的kind,也相当于建立 RC kind一样,是一个 Pod,那这样由 Kubernetes 来保障这个 Volume 的高可用。