重庆分公司,新征程启航
为企业提供网站建设、域名注册、服务器等服务
这篇文章将为大家详细讲解有关如何实现分布式协调Kubernet,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。
成都一家集口碑和实力的网站建设服务商,拥有专业的企业建站团队和靠谱的建站技术,十多年企业及个人网站建设经验 ,为成都超过千家客户提供网页设计制作,网站开发,企业网站制作建设等服务,包括成都营销型网站建设,品牌网站设计,同时也为不同行业的客户提供成都网站设计、成都网站建设、外贸网站建设的服务,包括成都电商型网站制作建设,装修行业网站制作建设,传统机械行业网站建设,传统农业行业网站制作建设。在成都做网站,选网站制作建设服务商就选创新互联建站。
单一的应用程序,就是之前在单个节点上运行的单个实例,包括了很多在数据库更新状态的调度jobs(现在也同样发布商务events)。单体程序创建在java中,并且大量使用Spring,所以job看起来是这个样子的:
Spring之后会确认提到过的 doSomethingEveryMinute方法每分钟执行一次。问题是,如果我们目前不在Kubernetes上主持单体程序,并且跟多个实例一起运行,这个job就每分钟会在每个实例上被执行一次,而不仅仅只是每分钟执行了一次而已。如果job有类似发送通知邮件或更新数据库这样的副作用的话,这就是一个问题了。所以我们要怎样避免这个?当然,解决方案还是很多的,显而易见的选择就是利用Kubernetes Jobs,让Kubernetes自己周期性调度jobs。问题就是这个作用只在Kubernetes1.3版本及以上版本中可用,但是1.3还没有发布。但是即使我们能够使用这样一个功能,从技术角度来说,这也是不太可行的。我们的jobs被高度耦合到已经存在的代码库,并且提取每个job到它自己的应用程序,程序可能会有错误,而且如果一次性完成的话会非常耗费时间。所以我们最初的计划是提取所有的调度jobs到一个应用程序,这个应用程序在Kubernetes中只能作为一个实例来运行。但由于现有代码的本质,和高耦合性,即使是这样也很难实现。那么,有没有一种很轻松的办法允许我们目前在单体应用中保持jobs,并且当我们从这个应用中提取功能到独立的服务的时候,逐渐替代他们呢?其实还是有的。
要解决这个,我们需要做一些分布式协调,比如,当jobs被Spring执行的时候,如果这个节点不是“leader节点”,为运行调度jobs负责,我们就只需要传回信息(而且,不要和job一起运行代码)。有一些项目能够帮助我们来处理诸如zookeeper和hazelcast之类的东西。但是仅仅只是为了决定哪个节点执行调度jobs,以此来设置、保留zookeeper集群就太劳师动众了。我们需要一些易于管理的东西,假如我们能够利用Kubernetes会怎么样呢?Kubernetes已经在cover下(使用 RAFT consensus algorithm)处理了leader选举。结果证明,这个功能通过使用gcr.io/google_containers/leader-elector Docker镜像已经被暴露给了终端用户。之前已经有一个很棒的博客帖子很细节地描述过这个是如何运行的了,点击这个网址查看:http://blog.kubernetes.io/2016/01/simple-leader-election-with-Kubernetes.html。所以在这里我就不多加赘述了,但是我会讲一讲我们是如何利用镜像来解决我们的问题的。
我们做的就是带来gcr.io/google_containers/leader-elector容器到我们的pod,这样就可以让单体应用的实例都运行一个leader选举的实例。这是证明Kubernetes pod有用的典型例子。
以下是一个在我们的配置resource中定义好的pod的摘录:
我们开启leader选举以及我们的单体应用程序。注意,我们将 --election=monolith-jobs当作第一个参数。这就意味着leader选举知道容器属于哪一个组。所以指定这个组的容器会是leader选举进程中的一部分,这个组之中只有一个容器会被选举为leader。 --http=localhost:4040的第二个参数同样是非常重要的。它在4040端口打开了一个网页服务器,在这个端口,我们可以查询到目前leader的pod名字,然后以这个格式返回:
这是我们决定要不要运行我们的job的一个小把戏。我们要做的事情就是检查即将执行调度pod的名字是否跟选举出来的leader一致,如果一致,我们就应该继续执行,并且执行job,或者其它的我们应该返回的东西。比如:
所以我们来看看ClusterLeaderService是如何被实施的。首先,我们必须从应用程序获得pod的名字。Kubernetes将pod名字存储在/etc/hostname ,Java将这个/etc/hostname暴露在HOSTNAME环境变量,这就是我们将在这个例子中引用的。另一个方法就是使用 Downward API将pod名字暴露到环境变量选择。比如:
从这里,我们可以看到 metadata.name (也就是pod的名字)会与 MY_POD_NAME环境变量联系在一起。但是现在让我们来看看 ClusterLeaderService的实施是看起来是怎么样的:
在这里例子中,我们正在从 RESTAssured 项目使用 JsonPath来查询选举者网页服务,并且从回应中提取pod的名字。然后我们简单地将本地容器的名字跟leader相比较,如果他们是相同的,那么我们就知道这个实例就是leader!就是这样!
事实证明,上述工作运行地很不错!如果leader节点要挂掉了,那么另一个就会自动选举上。但这个过程会花上一点时间,要一分钟左右。所以这个还是要权衡一下的。假如你的工作中不允许错过任意一个job执行,那么这个选择对你来说是不合适的。但在我们上述的例子中,中间有那么一分钟job没有被准确执行,对我们来说无伤大雅。所以我觉得这个方法十分简单,而且当移植一个现有的包含调度jobs的应用程序的时候很有价值,因为调度jobs总有各种各样很难提取的原因。
关于“如何实现分布式协调Kubernet”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。