ZooKeeper,策展人以及微服务负载平衡的工作方式

Zookeeper如何确保每位工人都能愉快地从工作委托经理那里得到一些工作。

Apache ZooKeeper是注册,管理和发现在不同计算机上运行的服务的工具。 当我们必须处理具有许多节点的分布式系统时,它是技术堆栈中必不可少的成员,这些节点需要知道其依赖关系从何处启动。


zookeeper_logo

但是ZooKeeper的级别很低,即使标准用例也需要很多行代码。 这就是Apache Curator诞生的原因–一个比ZooKeeper更友好,更易于使用的包装器库。 使用Curator,我们可以用更少的代码和更简洁的方式交付更多内容。

curator_logo

“ Guava对于Java来说就像Curator对ZooKeeper一样” – ZooKeeper提交者Patrick Hunt

使用ZooKeeper负载均衡微服务

我们习惯于在应用程序前面部署负载均衡器的情况。 它的作用是确保每个单个节点获得或多或少相同的流量。

在微服务世界中,情况是相同的,但是与单片方法相比,我们具有显着的优势:当我们需要扩展应用程序时,我们不必复制整个系统并将其部署在功能强大的服务器上即可平稳运行。 我们只能将精力集中在需要扩展的小模块上,因此扩展成本要低得多(无论是在服务器成本还是在很多情况下为部署模块做准备所需的开发方面)。

但是随着我们系统的发展,我们最终会得到许多可扩展的模块,每个模块都需要单独的负载平衡器。 这似乎很麻烦,因为即使没有基础架构,我们的基础架构也非常复杂。 幸运的是,如果我们将ZooKeeper用作服务编排和发现工具,则可以使用内置的负载平衡功能,而不会在我们的微服务架构中引入任何其他复杂性。

为了展示ZooKeeper中开箱即用的负载平衡工作方式,我们需要两项服务:将多次部署的工作人员,以及将任务委派给已注册工作人员的经理。

简单工人

让我们从创建一个简单的工作程序开始,该工作程序将侦听给定的端口并在要求执行其工作时返回一些结果。 为了实现这个微小的微服务,我们将使用Groovy, Undertow轻量级servlet容器,当然还要使用ZooKeeper和Curator。

我们的工作人员将由一个小类组成,该小类的主要方法可以完成三件事:

class Main {static final void main(String[] args) {// Step 1: Extract name and port number to launch worker// Step 2: Configure and start Rest server on given port// Step 3: Register worker in ZooKeeper}
}

为简便起见,我将在此处省略步骤1和2,您可以在GitHub project上查看完整的源代码。 我们的工作人员只有一个端点GET / work,它会返回一个响应,并带有被叫工作人员的名字:

@Path("/")
class Main {@GET@Path("/work")public String work() {String response = "Work done by $workerName"println responsereturn response}}

步骤3: ZooKeeper中的注册工作人员是最有趣的地方,因此我将对其进行详细说明:

private static void registerInZookeeper(int port) {CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient("localhost:2181", new RetryNTimes(5, 1000))curatorFramework.start()ServiceInstance<Void> serviceInstance = ServiceInstance.builder().uriSpec(new UriSpec("{scheme}://{address}:{port}")).address('localhost').port(port).name("worker").build()ServiceDiscoveryBuilder.builder(Void).basePath("load-balancing-example").client(curatorFramework).thisInstance(serviceInstance).build().start()
}
  • 第2-3行:我们创建并启动CuratorFramework客户端,该客户端包装了我们要在ZooKeeper实例上执行的所有操作。 为简单起见,我们将localhost与默认端口一起使用(通常,它应该是ZooKeeper的运行实例的URL)
  • 第4-9行创建了代表我们的工作人员的ServiceInstance。 我们传递了从其他微服务呼叫此工作人员所需的所有“联系方式”
  • 第11-16行在由CuratorFramework客户端表示的ZooKeeper中注册我们的实例。

出发工人

现在,Worker已经准备就绪,因此我们可以创建胖子罐(使用Gradle fatJar任务),然后使用以下命令启动它:

java -jar simple-worker/build/libs/simple-worker-1.0-shadow.jar Worker_1 18005

在启动worker之前,请记住您需要在默认2181端口上运行的ZooKeeper实例!

要检查worker是否正在运行,您应该在http:// localhost:18005 / work上打开浏览器,并在其中看到“ Worker_1完成的工作”文本。 要验证工作人员是否已在ZooKeeper中正确注册了自己,请启动命令行客户端:

cd/bin
./zkCli.sh

然后执行ls命令,查看在/ load-balancing-example / worker路径下注册的一个节点:

[zk: localhost:2181(CONNECTED) 1] ls /load-balancing-example/worker <enter>
[f69545e8-8466-40c0-93e9-f493eb7496b4]

简单的经理

现在,由于我们有工作人员在监听/ work的请求,因此我们可以创建简单的经理服务委托任务给其下属。 主要方法看上去与简单工作人员项目中的方法非常相似,主要区别在于我们没有在ZooKeeper中注册,我们仅创建角色(给惊喜)为我们提供工作人员实例的ServiceProvider 。 所以基本的工作流程是:

  1. 等待/ delegate上的请求
  2. 从ZooKeeper的ServiceProvider获取工作程序服务的实例
  3. 调用工作人员的/工作并返回其执行结果

要创建ServiceProvider,我们必须创建CuratorFramework客户端,连接到ZooKeeper,然后获取具有给定名称的服务的ServiceProvider,在本例中为worker

CuratorFramework curatorFramework = CuratorFrameworkFactory.newClient("localhost:2181", new RetryNTimes(5, 1000))
curatorFramework.start()ServiceDiscovery<Void> serviceDiscovery = ServiceDiscoveryBuilder.builder(Void).basePath("load-balancing-example").client(curatorFramework).build()
serviceDiscovery.start()serviceProvider = serviceDiscovery.serviceProviderBuilder().serviceName("worker").build()
serviceProvider.start()
  • 第1-2行,创建ZooKeeper客户端,方法与简单工作者相同
  • 第4-8行,创建ServiceDiscovery,它将能够为我们提供服务提供商。
  • 第10-11行。 创建并启动ServiceProvider,将用于获取工作程序节点的工作实例。

最后,我们需要一个Rest端点,管理器在其上等待任务委派:

@GET
@Path("/delegate")
public String delegate() {def instance = serviceProvider.getInstance()String address = instance.buildUriSpec()String response = (address + "/work").toURL().getText()println responsereturn response
}

起始经理

Manager已准备就绪,执行fatJar任务后,我们可以使用以下命令启动它:

java -jar simple-manager/build/libs/simple-manager-1.0-shadow.jar 18000

为了验证它是否正常工作,我们可以在浏览器中打开( http:// localhost:18000 / delegate )以查看消息“ Worker_1完成的工作”。

经理对其员工一无所知。 他唯一知道的是服务已在ZooKeeper中的特定路径下注册。 这很简单,无论我们是在本地启动多个工作人员还是在不同国家/地区的不同服务器上分布。

使用ZooKeeper开箱即用的负载平衡

想象一下这样的情况:经理从首席执行官那里获得了太多任务,以至于他需要多个工人来委派工作。 在标准情况下,我们将被迫扩大规模并在他们前面放置负载平衡器。 但是ZooKeeper无需任何其他工作即可为我们提供此功能。

让我们添加更多在不同端口上侦听的工作者:

java -jar simple-worker/build/libs/simple-worker-1.0-shadow.jar Worker_1 18005 &java -jar simple-worker/build/libs/simple-worker-1.0-shadow.jar Worker_2 18006 &java -jar simple-worker/build/libs/simple-worker-1.0-shadow.jar Worker_3 18007 &java -jar simple-worker/build/libs/simple-worker-1.0-shadow.jar Worker_4 18008 &

诀窍是所有工作程序都在ZooKeeper中的同一路径下注册,因此当我们在/ load-balancing-example / worker下列出节点时,将看到四个实例:

[zk: localhost:2181(CONNECTED) 0] ls /load-balancing-example/worker  <enter>
[d5bc4eb9-8ebb-4b7c-813e-966a25fdd843, 13de9196-bfeb-4c1a-b632-b8b9969b9c0b, 85cd1387-2be8-4c08-977a-0798017379b1, 9e07bd1d-c615-430c-8dcb-bf228e9b56fc]

这里最重要的是,要利用这四个新工作人员,经理不需要对代码进行任何更改。 我们可以在流量增加时启动新的工作程序实例,或者在无事可做时将其关闭。 Manager与这些操作脱钩,它仍然调用ServiceProvider来获取worker的实例并将工作传递给他。

所以现在当我们打开http:// localhost:18000 / delegate并按几次刷新时,我们将看到:

Work done by Worker_1
Work done by Worker_2
Work done by Worker_3
Work done by Worker_4
Work done by Worker_1
Work done by Worker_2
Work done by Worker_3

它是如何实现的? 默认情况下,ServiceProvider使用Rounded-robin ProviderStrategy实现,该实现旋转给定路径下可用的实例,从而使每个实例都有一些工作要做。 如果默认机制不符合我们的需求,我们当然可以实施自定义策略。

摘要

今天就这些。 如您所见,通过使用Apache ZooKeeper和Curator,我们可以在无需部署,监视和管理单独负载均衡器的情况下生存。 即使没有微服务架构,基础架构也非常复杂。

翻译自: https://www.javacodegeeks.com/2014/07/zookeeper-curator-and-how-microservices-load-balancing-works.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/362699.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

elementUI清空弹框中的表单数据

点击此处直达应用场景示例 官网&#xff1a;https://element.eleme.cn/#/zh-CN/component/form 补充&#xff1a;改变表头颜色&#xff1a; <el-table :data"tableData" border style"width: 100%" :header-cell-style"{background:#d3dce6,col…

(一)PHP基础知识考察点

1&#xff0c;PHP引用变量的考察点&#xff1a; 概念&#xff1a;引用就是用不同的名字访问同一个变量内容。 定义方式&#xff1a; 使用&符号。 PHP引用变量的工作原理 这里有个COW copy on write 用zval&#xff08;&#xff09;去查看空间占用情况以及引用情况。 unse…

.Net4.0 Parallel编程(三)Data Parallelism下

在上篇文章中介绍了如何Break、Stop循环&#xff0c;以及如何定义线程局部变量。在本文中介绍如何在外部去取消循环、以及异常的处理。 Cancel 在并行的循环中支持通过传递ParallelOptions参数中的CancellationToken进行取消循环的控制&#xff0c;我们可以CancellationTokenSo…

节点的运用和方法

JQUERY的父&#xff0c;子&#xff0c;兄弟节点查找方法 jQuery.parent(expr) 找父亲节点&#xff0c;可以传入expr进行过滤&#xff0c;比如$("span").parent()或者$("span").parent(".class") jQuery.parents(expr),类似于jQuery.parents(ex…

Java:使用终止信号确定数据导入的状态

几周前&#xff0c;我正在尝试将约6000万位数据最初导入Neo4j&#xff0c;但我们一直遇到一个问题&#xff0c;即导入过程似乎停滞了&#xff0c;什么也没导入。 很难分辨该过程中发生了什么—采取线程转储只是告诉我们它正在尝试处理CSV行中的一行&#xff0c;并且以某种方式…

根据可视窗口判断面板向上还是向下展开

本demo以element-ui框架为视图模板~ HTML代码 JS代码 CSS代码 转载于:https://www.cnblogs.com/dreamsqin/p/10885502.html

关于几本模拟IC设计书

1.P.R.Gray的书  这本书被业界誉为模拟IC的Bible&#xff0c;盛名之下&#xff0c;必无虚士。现在已经出到第四版&#xff0c;作者无一例外是业界大牛&#xff0c;该书论述严谨&#xff0c;思路清晰&#xff0c;对电路分析透彻&#xff0c;定义严格明确&#xff0c;无愧Bible…

编写JUnit测试的另一种方法(Jasmine方法)

最近&#xff0c;我为一个小型个人项目编写了很多Jasmine测试。 我花了一些时间才终于感到正确地完成了测试。 此后&#xff0c;当我切换回JUnit测试时&#xff0c;我总是很难过。 出于某种原因&#xff0c;JUnit测试不再那么好&#xff0c;我想知道是否有可能以类似于Jasmine的…

H5 input输入限制最大位数,和调用小键盘需求发生冲突的解决办法

首先&#xff0c;限制输入最大位数时&#xff0c;input有自带的属性maxlength。 <input type"text" name"email" maxlength"55" /> 使用方法&#xff1a;maxlength"位数" 但是&#xff0c;对于这个属性他是有自己的限制条件的 …

解决vue项目在ie浏览器中不显示的问题

安装 “babel-polyfill” npm install babel-polyfill --save-dev 或者 cnpm install babel-polyfill --save-dev在入口 main.js 文件引入&#xff1a;import babel-polyfill在 build 文件下的 webpack.base.conf.js 文件中修改代码&#xff1a; entry: {app: ["babel-p…

Spark-Luanch Driver

1.SparkSubmit.scala主要调用M-prepareSubmitEnvironment&#xff0c;该方法更根据用户定义的参数&#xff0c;匹配不同client&#xff0c;去调用不同clientApp。(ps&#xff1a;本次讲ClientApp 也就是standalone)在M-runMain通过 调用M-Utils.classForName 反射的方式调用 …

大风大浪大鱼

一群年轻人常在一泓深潭边钓鱼&#xff0c;而有一个渔夫总是在潭上边水流湍急的河里捕鱼。 年轻人觉得这渔夫可笑&#xff0c;在大风大浪的河里怎么会捕到鱼呢?有一天&#xff0c;年轻人忍不住去问渔夫&#xff1a;“鱼能在这么湍急的地方停留吗?”渔夫说&#xff0c;当然不能…

清空表单时出现问题

打开页面时报警告&#xff1a; 解决办法&#xff1a; &#xff08;1&#xff09;npm i default-passive-events -S &#xff08;2&#xff09;main.js中加入&#xff1a;import ‘default-passive-events’ 参考&#xff1a;https://www.jianshu.com/p/23850d4cade8 出现原…

JQuery Ajax 使用FormData上传文件对象

FormData部分: 先new FormData对象 :let somedata new FormData(),然后将数据添加进去&#xff0c;这里我们使用append()进行添加。 这里举一个上传头像的例子&#xff1a; let token localStorage.token; let img $(".file")..get(0).files[0]; let somedat…

[探索][管理]《现在,发现你的优势》

此书是我迄今为止看过最棒的一本书&#xff01;&#xff01;&#xff01; 为什么这么说&#xff0c;因为就像前言彼得德鲁克所说的一样 -- 大部分的人都不知道他们的优势何在。此书的宗旨就是测试你的优势是什么&#xff0c;并且发展你的优势。为何要去改变你不擅长的东西呢&am…

box2d——1.tiles瓦片积木

【调试渲染】 将TestCpp里Box2DTestBed的GLES-Render.h/cpp加入到项目中。声明绘制变量&#xff1a;GLESDebugDrawmDebugDraw。 【创建世界】 // 依据重力创建世界b2Vec2 gravity;gravity.Set(0.0f, -10.0f);mWorld new b2World(gravity);// 设置调试渲染和碰撞侦听mWorld-&…

如何在JSF中实现自定义密码强度指示器

使用JavaScript验证密码强度是一项常见任务。 在本文中&#xff0c;我将展示如何向基于JSF的Web应用程序添加密码强度指示器。 的 PrimeFaces中的密码组件已经具有密码强度的反馈指示符&#xff0c;但是它有两个主要缺点&#xff1a; 反馈指示器没有响应&#xff08;固定宽度…

CSS 学习路线(二)选择器

选择器 规则结构: 分两个基本部分 选择器(selector)和声明块(declaration block) 组成 声明块:由一个或多个声明组成,每一个声明都是属性-值对 选择器分为:元素选择器,类选择器,后代选择器,通配选择器,ID选择器,属性选择器,伪类选择器.子元素选择器,相邻兄弟选择器. 元素选…

关于vue打包的问题

一、vue-cli2 二、vue-cli3 一、vue-cli2 错误提示&#xff1a; npm ERR! code ELIFECYCLE npm ERR! errno 1 npm ERR! hewelry1.0.0 build: node build/build.js npm ERR! Exit status 1 npm ERR! npm ERR! Failed at the hewelry1.0.0 build script. npm ERR! This is prob…