写点什么

eBay Kubernetes 集群的存储实践

  • 2019-10-01
  • 本文字数:4911 字

    阅读完需:约 16 分钟

eBay Kubernetes集群的存储实践

如今,eBay 已在内部广泛使用 Kubernetes 作为容器管理的平台,并自研了 AZ 和联邦级别的控制平面,用以负责 50 多个集群的创建、部署、监控、修复等工作,并且规模在不断扩大。


我们的生产集群上,针对各种应用场景,大量使用了本地存储网络存储,并通过原生的 PV/PVC 来使用。其中本地存储分为静态分区类型基于 lvm 的动态类型,支持 ssd, hdd, nvme 等介质。网络块存储使用 ceph RBD 和 ISCSI,共享文件存储使用 cephfs 和 nfs。

一、本地存储

01 静态分区

我们最早于 2016 年开始做 localvolume(本地卷),当时社区还没有本地的永久存储方案,为了支持内部的 NoSQL 应用使用 PV(Persistent Volume),开发了第一版的 localvolume 方案:


首先,在节点创建的时候,provision 系统根据节点池 flavor 定义对数据盘做分区和格式化,并将盘的信息写入系统配置文件。


同时,我们在集群内部署了 daemonset localvolume-provisioner,当节点加入集群后,provisioner 会从配置文件中读取配置信息并生成相应的 PV,其中包含相应的 path,type 等信息。这样,每个 PV 对象也就对应着节点上的一个分区。


除此之外,我们改进了 scheduler,将本地 PV/PVC 的绑定(binding)延迟到 scheduler 里进行。这也对应现在社区的 volumeScheduling feature。


现在 cgroup v1 不能很好地支持 buffer io 的限流和隔离,对于一些 io 敏感的应用来说,需要尽可能防止这些“noisy neighbors”干扰。同时对于 disk io load 很高的应用,应尽可能平均每块盘的负担,延长磁盘寿命。


因此,我们增加了 PVC 的反亲和性(anti affinity)调度特性,在满足节点调度的同时,会尽可能调度到符合反亲和性规则的盘上。


具体做法是,在 PV 中打上标签表明属于哪个节点的哪块盘,在 PVC 中指定反亲和性规则,如下图一所示。scheduler 里增加相应的预选功能,保证声明了同类型的反亲和性的 PVC,不会绑定到处在同一块盘的 PV 上,并在最终调度成功后,完成选定 PV/PVC 的绑定。



图 1(点击可查看大图)

02 LVM 动态存储

对于上述静态存储的方案,PV 大小是固定的,我们同时希望 volume 空间能够更灵活地按需申请,即动态分配存储。


类似地,我们在节点 flavor 里定义一个 vg 作为存储池,节点创建的时候,provision 系统会根据 flavor 做好分区和 vg 的创建。同时集群内部署了 daemonset local-volume-dynamic-provisioner,实现 CSI 的相应功能。


在 CSI 0.4 版本中,该 daemonset 由 CSI 的四个基本组件组成,即:csi-attacher, csi-provisioner, csi-registrar 以及 csi-driver。其中 csi-attacher, csi-provisioner 和 csi-registrar 为社区的 sidecar controller。csi-driver 是根据存储后端自己实现 CSI 接口, 目前支持 xfs 和 ext4 两种主流文件系统,也支持直接挂载裸盘供用户使用。


为了支持 scheduler 能够感知到集群的存储拓扑,我们在 csi-registrar 中把从 csi-driver 拿到的拓扑信息同步到 Kubernetes 节点中存储,供 scheduler 预选时提取,避免了在 kubelet 中改动代码。


如图 2 所示,pod 创建后,scheduler 将根据 vg 剩余空间选择节点、local-volume-dynamic-provisioner 来申请相应大小的 lvm logical volume,并创建对应的 PV,挂载给 pod 使用。



图 2(点击可查看大图)

二、网络存储

01 块存储

对于网络块存储,我们使用 ceph RBD 和 ISCSI 作为存储后端,其中 ISCSI 为远端 SSD,RBD 为远端 HDD,通过 openstack 的 cinder 组件统一管理。


网络存储卷的管理主要包括 provision/deletion/attach/detach 等,在 provision/deletion 的时候,相比于 localvolume(本地卷)需要以 daemonset 的方式部署,网络存储只需要一个中心化的 provisioner


我们利用了社区的 cinder provisioner 方案(详情可见:https://github.com/kubernetes/cloud-provider-openstack),并加以相应的定制,比如支持利用已有快照卷(snapshot volume)来创建 PV,secret 统一管理等。


Provisioner 的基本思路是


watch PVC 创建请求


→ 调用 cinder api 创建相应类型和大小的卷,获得卷 id


→ 调用 cinder 的 initialize_connection api,获取后端存储卷的具体连接信息和认证信息,映射为对应类型的 PV 对象


→ 往 apiserver 发请求创建 PV


→ PV controller 负责完成 PVC 和 PV 的绑定。


Delete 为逆过程。


Attach 由 volume plugin 或 csi 来实现,直接建立每个节点到后端的连接,如 RBD map, ISCSI 会话连接,并在本地映射为块设备。这个过程是分立到每个节点上的操作,无法在 controller manager 里实现中心化的 attach/detach。因此放到 kubelet 或 csi daemonset 来做,而 controller manager 主要实现逻辑上的 accessmode 的检查和 volume 接口的伪操作,通过节点的状态与 kubelet 实现协同管理。


Detach 为逆过程。


在使用 RBD 的过程中,我们也遇到过一些问题


1)RBD map hang:

RBD map 进程 hang,然而设备已经 map 到本地并显示为/dev/rbdX。经分析,发现是 RBD client 端的代码在执行完 attach 操作后,会进入顺序等待 udevd event 的 loop,分别为"subsystem=rbd" add event 和"subsystem=block" add event。而 udevd 并不保证遵循 kernel uevent 的顺序,因此如果"subsystem=block" event 先于 “subsystem=rbd” event, RBD client 将一直等待下去。通过人为触发 add event(udevadm trigger --type=devices --action=add),就可能顺利退出。

这个问题后来在社区得到解决,我们反向移植(backport)到所有的生产集群上。

(详情可见:https://tracker.ceph.com/issues/39089

2)kernel RBD 支持的 RBD feature 非常有限,很多后端存储的特性无法使用。

3)当节点 map 了 RBD device 并被 container 使用,节点重启会一直 hang 住,原因是 network shutdown 先于 RBD umount,导致 kernel 在 cleanup_mnt()的时候 kRBD 连接 ceph 集群失败,进程处于 D 状态。我们改变 systemd 的配置 ShutdownWatchdogSec 为 1 分钟,来避免这个问题。


除了 kernel RBD 模块,Ceph 也支持块存储的用户态 librbd 实现:rbd-nbd。Kubernetes 也支持使用 rbd-nbd。


如图 3 所示,我们对 kRBD 和 rbd-nbd 做了对比:



图 3(点击可查看大图)


如上,rbd-nbd 在使用上有 16 个 device 的限制,同时会耗费更多的 cpu 资源,综合考虑我们的使用需求,决定继续使用 kRBD。


图 4 为三类块存储的性能比较:



图 4(点击可查看大图)

02 文件存储

我们主要使用 cephfs 作为存储后端,cephfs 可以使用 kernel mount,也可以使用 cephfs-fuse mount,类似于前述 kRBD 和 librbd 的区别。前者工作在内核态,后者工作在用户态


经过实际对比,发现性能上 fuse mount 远不如 kernel mount,而另一方面,fuse 能更好地支持后端的 feature,便于管理。目前社区 cephfs plugin 里默认使用 ceph fuse,为了满足部分应用的读写性能要求,我们提供了 pod annotation(注解)选项,应用可自行选择使用哪类 mount 方式,默认为 fuse mount。


下面介绍一下在使用 ceph fuse 的过程中遇到的一些问题(ceph mimic version 13.2.5, kernel 4.15.0-43)


1)ceph fuse internal type overflow 导致 mount 目录不可访问


ceph fuse 设置挂载目录 dentry 的 attr_timeout 为 0,应用每次访问时 kernel 都会重新验证该 dentry cache 是否可用,而每次 lookup 会对其对应 inode 的 reference count + 1。

经过分析,发现在 kernel fuse driver 里 count 是 uint_64 类型,而 ceph-fuse 里是 int32 类型。当反复访问同一路径时,ref count 一直增加,如果节点内存足够大,kernel 没能及时触发释放 dentry 缓存,会导致 ceph-fuse 里 ref count 值溢出。

针对该问题,临时的解决办法是周期性释放缓存(drop cache),这样每次会生成新的 dentry,重新开始计数。同时我们存储的同事也往 ceph 社区提交补丁,将 ceph-fuse 中该值改为 uint_64 类型,同 kernel 匹配起来。(详情可见:https://tracker.ceph.com/issues/40775


2)kubelet du hang


kubelet 会周期性通过 du 来统计 emptydir volume 使用情况,我们发现在部分节点上存在大量 du 进程 hang,并且随着时间推移数量越来越多,一方面使系统 load 增高,另一方面耗尽 pid 资源,最终导致节点不响应。

经分析,du 会读取到 cephfs 路径,而 cephfs 不可达是导致 du hang 的根本原因,主要由以下两类问题导致

a. 网络问题导致 mds 连接断开。如图 5 所示,通过 ceph admin socket,可以看到存在失效链接(stale connection),原因是 client 端没有主动去重连,导致所有访问 mount 路径的操作 hang 在等待 fuse answer 上,在节点启用了 client_reconnect_stale 选项后,得到解决。

b. mds 连接卡在 opening 状态,同样导致 du hang。原因是服务端打开了 mds_session_blacklist_on_evict,导致连接出现问题时客户端无法重连。



图 5(点击可查看大图)


3)性能


kernel mount 性能远高于 fuse 性能,经过调试,发现启用了 fuse_big_write 后,在大块读写的场景下,fuse 性能几乎和 kernel 差不多。

三、应用场景

01 本地数据备份还原

本地存储相比网络存储,具有成本低,性能高的优点,但是如果节点失效,将会导致数据丢失,可靠性比网络存储低。


为了保证数据可靠性,应用实现了自己的备份还原机制。使用本地 PV 存储数据,同时挂载 RBD 类型的 PV,增量传输数据至远端备份集群。同时远端会根据事先定义规则,周期性地在这些 RBD 盘上打 snapshot(快照),在还原的时候,选定特定 snapshot,provision 出对应 PV,并挂载到节点上,恢复到本地 PV。

02 盘加密

对于安全要求级别高的应用,如支付业务,我们使用了 kata 安全容器方案,同时对 kata container 的存储进行加密。如图 6 所示,我们使用了 kernel dm-crypt 对盘进行加密,并将生成的 key 对称加密存入 eBay 的密钥管理服务中,最后给 container 使用的是解密后的盘,在 pod 生命周期结束后,会关闭加密盘,防止数据泄漏。



图 6(点击可查看大图)

四、磁盘监控

对于本地存储来说,节点坏盘,丢盘等错误,都会影响到线上应用,需要实时有效的监控手段。我们基于社区的 node-problem-detector 项目,往其中增加了硬盘监控(disk monitor)的功能。


(详情可见:https://github.com/Kubernetes/node-problem-detector)


主要监控手段有三类:


1)smart 工具检测每块盘的健康状况。

2)系统日志中是否有坏盘信息。根据已有的模式(pattern)对日志进行匹配,如图 7 所示。

3)丢盘检测,对比实际检测到的盘符和节点 flavor 定义的盘符。



图 7(点击可查看大图)


以上检测结果以 metrics(指标) 的形式被 prometheus 收集,同时也更新到自定义 crd computenode 的状态中,由专门的 remediation controller(修复控制器)接管,如满足预定义的节点失效策略,将会进入后续修复流程。


对于有问题的盘,monitor 会对相应 PV 标记 taint,scheduler 里会防止绑定到该类 PV,同时对于已绑定的 PV,会给绑定到的 PVC 发 event,通知应用。

五、管理部署

以上提到了几类组件,local-volume-provisioner,local-volume-dynamic-provisioner,cinder-provisioner,node-problem-detector 等,我们开发了 gitops + salt 的方案对其进行统一管理


首先把每个组件作为一个 salt state,定义对应的 salt state 文件和 pillar,写入 git repo,对于 key 等敏感信息则存放在 secret 中。这些 manifest 文件通过 AZ 控制面同步到各个集群并执行。我们将所有的组件视为 addon,salt 会生成最终的 yaml 定义文件,交由 kube addon manager 进行 apply。在需要更新的时候,只需更新相应的 salt 文件和 pillar 值即可。

六、后续工作

1)对于网络存储,将后端控制面由 cinder 切换到 SDS,届时将会对接新的 SDS api,实现新的 dynamic provision controller 和 csi 插件;

2)实现 Kubernetes 平台上的 volume snapshot(卷快照)功能;

3)将 in-tree 的 volume 插件全部迁移到 CSI,并将 CSI 升级到最新版本,方便部署和升级;

4)引入 cgroup v2, 以实现 blkio qos 控制;

5)实现本地存储的自动扩容能力。


本文转载自公众号 eBay 技术荟(ID:eBayTechRecruiting)


原文链接


https://mp.weixin.qq.com/s/VeyR4dSkH_bOH7YmbwSE2w


2019-10-01 08:002732

评论

发布
暂无评论
发现更多内容

超级app+轻应用=未来?

發財KK

移动应用 轻应用 快应用 App生态

大数据培训Flink中常见问题定位

@零度

大数据 flink

DevSecOps: 让大家都 Happy 的安全软件构建模式

火线安全

云原生 软件架构 DevSecOps 云安全

谷歌云对象存储攻防

火线安全

云原生 云安全 云存储

负载均衡,你想了解的全在这里!

博文视点Broadview

阿里云云原生应用平台总经理丁宇:“连接、合作、赋能”,携手加速器伙伴助力企业云上创新

阿里巴巴云原生

DevSecOps邂逅云原生:云原生时代下的持续安全

火线安全

DevOps 云原生 云安全 云原生安全

4种典型限流实践保障应用高可用|云效工程师指北

阿里云云效

云计算 阿里云 云原生 系统安全 研发

产品经理必看的高效产品文档撰写指南

小炮

产品文档

浅谈SaaS多租户数据隔离和共享

数商云

SASS

云原生安全实践

火线安全

云原生 安全 云安全

Flink 在米哈游的落地实践

Apache Flink

大数据 flink 编程 流计算 实时计算

性能指标、响应时间、并发量…聊聊性能优化的衡量指标

华为云开发者联盟

性能优化 高并发 响应时间 性能指标 并发量

java培训SpringBoot性能优化

@零度

Java springboot

云计算时代,好用的IT运维软件我给推荐行云管家!

行云管家

云计算 运维 网络运维 IT运维

平衡树:为什么Redis内部实现用跳跃表

华为云开发者联盟

redis 数据结构 集合 跳跃表 平衡树

数盾科技加入,携手龙蜥社区提升网络安全整体防护能力

OpenAnolis小助手

开源 网络安全 数盾科技 密码算法

尚硅谷监控告警系统(Zabbix)视频教程发布

@零度

大数据 zabbix

OpenHarmony 标准系统 HDF 框架之 I2C 驱动开发

Anna

开源 后端 直播 OpenHarmony I2C

TypeScript里string和String,真不是仅仅是大小写的区别

华为云开发者联盟

JavaScript typescript string ts

有奖互动|中国信通院联合 OceanBase 邀您参加《数据库发展研究报告(2022)》调研问卷

OceanBase 数据库

关于 Nvm

隔壁的猫

node.js 前端 NVM 3月月更

数字经济“双碳”目标下,“东数西算”数据中心为何依靠液冷散热技术节能减排?

GPU算力

东数西算 GPU服务器

Android技术分享|【自定义View】实现Material Design的Loading效果

anyRTC开发者

android 音视频 移动开发 自定义view loading

碰到运维难题怎么快速解决?有工具推荐吗?

行云管家

运维 网络运维 IT运维 服务器运维

EventBridge 事件总线及 EDA 架构解析

阿里巴巴云原生

阿里云 VPC 内网性能测试最佳实践

阿里巴巴云原生

web前端培训JS解构赋值知识点分享

@零度

JavaScript web前端

关于React项目本地开发设置Https的过程

隔壁的猫

前端 React 3月月更

华为云企业级Redis揭秘第17期:集群搭载多DB,多租隔离更降本

华为云开发者联盟

数据库 redis 集群 GaussDB(for Redis) 多DB

eBay Kubernetes集群的存储实践_数据库_eBay技术荟_InfoQ精选文章