腾讯开源分布式存储系统 Tendis
|
此时,你唯一的可行选择是收集可能涉及的每个控制循环的日志,寻找被中断的循环。如果你对所有控制循环的工作机制都有深入的了解,则定位错误的速度可以更快一些,丰富的经验可以让你从资源对象的当前状态,推断出是哪个控制循环出错,并正尝试恢复运行。 这里要注意关键一点,我们看待复杂度的视角已经从控制循环的设计者转换到到了集群运维人员。设计一个可以独立执行单一任务的控制循环很容易(并非是说其不重要)。但是,要在集群中维护数十个这样的控制循环,就需要运维人员非常熟悉这些控制循环的操作,以及它们之间的交互,并尝试理解这样一个组织松散的系统。这是必须认真考虑的问题,通常设计者编写控制循环代码验证其功能这样的工作是一次性的,但是运维人员可能要终日和它们打交道,并反复处理控制循环出现的问题。简化那些你只需要做一次的事情对运维人员来说不公平。 为了解决这个问题,我会参照systemd的做法。它解决了类似的生命周期管理问题:给定当前状态A和目标状态B,如何从A变为B?区别是,在systemd中,操作步骤及其依赖是显式的。你告诉systemd,你的服务单元是multi-user.target服务组的一部分,则它必须在挂载文件系统之后联网之前启动运行。您还可以依赖系统的其他具体组件,例如说只要sshd运行,你的服务就需要运行(听起来像边车,是吧?)。 这样做的好处是systemd可以准确地告诉用户,是系统的哪一部分发生故障,哪部分仍在运行,或是哪个前置条件没通过。它甚至还可以打印出系统启动的执行过程,以供分析定位问题,例如“哪个服务的启动耗时最长”。 我想批量的照搬这些设计到我的集群编排系统中。不过也确实需要一些微调,但大致来说:控制循环必须声明它们对其他控制循环的依赖性,必须生成结构化日志,以便用户可以轻松搜索到“有关Pod X的所有控制循环的操作日志”,并且编排系统处理生命周期事件,可以采取像systemd那样的做法,逐个排查定位到出问题的服务组单元。 这在实践起来会是怎么样的?先结合Pod的生命周期说起。可能我们将定义一个抽象的“运行”target,这是我们要达到的状态——Pod已经启动并且一切正常。容器运行时将添加一个任务到“运行”之前,以启动容器。但它可能要到存储系统完成网络设备挂载后才能运行,因此它将在“存储”target之后自行启动。同样地,对于网络,容器希望在“网络”target之后启动。 现在,你的Ceph控制循环将自己安排在“存储”target之前运行,因为它负责启动存储。其他存储控制循环也是相同的执行流程(local bind mount,NFS等)。请注意,这里的执行流程可以是并发执行,因为它们都声明要在存储准备就绪之前执行,但是并不在意在其他存储插件的控制循环之前还是之后执行。也有可能存在例外情况!比如你编写了一个很棒的存储插件,它功能出色,但是必须先进行NFS挂载,然后才能运行。好了,我们只需要在nfs-mounts步骤中添加一个依赖项,就可以完成了。这就和systemd类似,我们既规定了顺序,又规定了“还需要其他组件才能正常工作”这样的硬性要求,因此用户可以轻松定义服务的启动步骤。 (此处的讨论我稍微简化了一下,并假设各项操作步骤没有太多的循环依赖。要深入的话,这可以展开出更复杂的流程。请参阅下文进一步探讨,这里先不讨论太过于复杂的流程。)
有了这些设计,编排系统可以回答用户“为什么Pod没有启动?”用户可以dump下Pod的启动流程图,并查看哪些步骤已完成,哪些步骤失败,哪些已在运行。 NFS挂载已经进行了5分钟?会不会有可能是NFS服务器已挂掉,但控制循环没报超时?服务的各项配置和可能的状态,叠加出来的结果矩阵是非常庞大的:如果有了我们设计的这样一个辅助调试的工具,这也不算个大问题。 Systemd允许用户以任意顺序、任意约束往服务的启动过程添加内容。但是当出现问题时,我仍然可以轻松对其进行故障排查,根据约束条件,在调试工具的辅助下,我可以第一时间定位到问题的关键所在。 (编辑:伊春站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |
