如何使用zookeeper .net实现实现负载均衡器

关于一个简单的负载均衡实现的问题(多线程相关) - ITeye问答
最近做一个Demo,里面涉及到一个客户端负载均衡的问题。基本问题如下:
1. A 服务依赖 B,C等服务(均为Rest风格服务,JSON作为数据协议)。
2. B,C等服务分别有N个节点,忽略权重(所有节点权重一样)。
3. A可以通过Zookeeper拿到每个依赖服务的节点列表。比如,A - [10.10.10.10, 10.10.10.11, 10.10.10.12], B - [10.10.10.20, 10.10.10.21, 10.10.10.22]
4. 现在我要做的是通过简单的统一包装类,封装请求的执行过程。负载均衡使用简单Polling模式。
问题:
Endpoints的next 方法是否需要加锁?为什么
目前的实现有什么问题?
下面是我的实现代码(基于JDK1.8):
import mon.collect.L
import mons.logging.L
import mons.logging.LogF
import org.springframework.beans.factory.annotation.A
import org.springframework.core.ParameterizedTypeR
import org.springframework.http.HttpM
import org.springframework.http.ResponseE
import org.springframework.web.client.RestT
import java.util.L
import java.util.M
import java.util.concurrent.ConcurrentHashM
import java.util.concurrent.TimeU
import java.util.concurrent.locks.ReentrantL
* @author: nealmi
* Date: 4/9/14
* Time: 10:24 PM
public class PollingEndpointManagerImpl implements EndpointManager {
private static final Log logger = LogFactory.getLog(PollingEndpointManagerImpl.class);
private final Map&String, Endpoints& endpointsMapping = new ConcurrentHashMap&&(3, .75f, 16);
private final RestTemplate restT
@Autowired(required = false)
private int maxRetries = 3;
public PollingEndpointManagerImpl() {
this.restTemplate = new RestTemplate();
public PollingEndpointManagerImpl(RestTemplate restTemplate) {
this.restTemplate = restT
public PollingEndpointManagerImpl(RestTemplate restTemplate, int maxRetries) {
this.restTemplate = restT
this.maxRetries = maxR
public int getMaxRetries() {
return maxR
public void setMaxRetries(int maxRetries) {
this.maxRetries = maxR
public void refresh(String key, List&String& endpoints) {
endpointsMapping.put(key, Endpoints.create(key, endpoints));
private String next(Endpoints endpoints) {
return endpoints.next();
public String next(String key) {
if (!endpointsMapping.containsKey(key)) {
throw new RuntimeException("No endpoints for key:" + key);
return next(endpointsMapping.get(key));
public &T& T get(String key, String uri, Class&T& t) {
return doIt(() -& {
String url = getFullUrl(key, uri);
if (logger.isInfoEnabled()) {
("Retrieving data from " + url);
ResponseEntity&T& responseEntity = restTemplate.getForEntity(url, t);
return responseEntity.getBody();
public &T& T get(String key, String uri, ParameterizedTypeReference&T& t) {
return doIt(() -& {
String url = getFullUrl(key, uri);
if (logger.isInfoEnabled()) {
("Retrieving data from " + url);
ResponseEntity&T& responseEntity = restTemplate.exchange(url, HttpMethod.GET, null, t);
return responseEntity.getBody();
private &T& T doIt(RequestExecutor&T& requestExecutor) {
int counter = 0;
while (true) {
return requestExecutor.execute();
} catch (Exception e) {
if (counter & maxRetries) {
counter++;
if (logger.isInfoEnabled()) {
("Request failure, retrying... counter= " + counter + ", error:" + e.getMessage());
throw new RuntimeException(e);
private static interface RequestExecutor&T& {
T execute();
private String getFullUrl(String key, String uri) {
return "http://" + next(key) +
private static class Endpoints {
private int counter = 0;
private List&String& endpoints = Lists.newArrayList();
private ReentrantLock lock = new ReentrantLock();
private Endpoints() {
private Endpoints(String key, List&String& endpoints) {
this.key =
this.endpoints =
private static Endpoints create(String key, List&String& endpoints) {
return new Endpoints(key, endpoints);
public String getKey() {
public List&String& getEndpoints() {
public String next() {
lock.tryLock(10, TimeUnit.SECONDS);
if (counter &= endpoints.size()) {
counter = (0);
String endpoint = endpoints.get(counter);
counter++;
} catch (Exception e) {
logger.error("Error when getting next endpoint. counter=" + counter + "
endpoints.size=" + endpoints.size(), e);
} finally {
lock.unlock();
Endpoints的next需要加锁,它负责轮训,如果多个线程同一时间执行到
if (counter &= endpoints.size()) {&
&&& counter = (0);&
有可能连续二次都是从endpoints.get(0)的服务执行,也就没法保证轮询的正确性,或者count++也是多线程同时读的0,有个可能线程1, 0++,现场 0++。
你用到了最新的语法,还没具体看新的语法,不会。不过看程序大致是一个前端的一个
负载均衡,
已解决问题
未解决问题使用zookeeper和curator实现微服务的负载平衡 -解道Jdon
& & & &&& & &
  是一个可以注册 管理和服务发现工具,能够在不同服务器上发现可用的服务,
能够是对ZooKeeper封装,更加容易使用,只需要更少的代码。
We are accustomed to situation when there is a load balancer deployed in front of our application. Its role is to make sure that every single node gets more or less same amount of traffic.
微服务架构能让我们关注更小的模块,随着系统的复杂增加,将会拥有很多微服务,它们的调用需要负载平衡,现在我们使用ZooKeeper作为服务的指挥家和发现工具。
让我们从一个简单案例开始,监听一个端口然后返回一些结果,这里我们使用 Groovy,
和 ZooKeeper 以及 Curator.本案例的。
假设已经有一个Restful微服务代码如下:
@Path(&/&)
class Main
@Path(&/work&)
public String work() {
String response = &Work done by $workerName&
println response
return response
这是一个简单的worker,直接响应一些字符串给客户端。下面我们将这个worker注册到ooKeeper中:
private static void
registerInZookeeper(int port) {
CuratorFramework curatorFramework =
CuratorFrameworkFactory.newClient(&localhost:2181&,
RetryNTimes(5, 1000))
curatorFramework.start()
ServiceInstance&Void& serviceInstance
= ServiceInstance.builder()
.uriSpec(new
UriSpec(&{scheme}://{address}:{port}&))
.address('localhost')
.port(port)
.name(&worker&)
ServiceDiscoveryBuilder.builder(Void)
.basePath(&load-balancing-example&)
.client(curatorFramework)
.thisInstance(serviceInstance)
首先我们创建和启动 CuratorFramework 客户端包装我们所有想在Zookeeper上的操作,这里使用localhost作为缺省,通常应该是运行ZooKeeper的实例服务器的URL。
然后创建ServiceInstance代表我们的worker. 我们传递所有从其他微服务调用这个worker的合约细节。
最后将我们的实例注册到ZooKeeper,这是通过CuratorFramework client.
现在Worker已经准备完成,我们创建fat jar (使用 Gradle fatJar task),然后使用下面命令加载:
java -jar simple-worker/build/libs/simple-worker-1.0-shadow.jar Worker_1 18005
在启动worker之前,你必须有ZKr运行在2181上。
为了验证运行正常,在浏览器键入,应该看到响应:&Work done by Worker_1&. 通过下面命令可以验证worker已经注册到ZK中:
cd &zk_root&/bin
./zkCli.sh&/zk_root&
然后在 /load-balancing-example/worker 运行ls:
[zk: localhost:2181(CONNECTED) 1] ls /load-balancing-example/worker &enter&
[f6-40c0-93e9-f493eb7496b4]
通过下面命令可以加入更多worker:
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 &
通过ls可以查看:
[zk: localhost:2181(CONNECTED) 0] ls /load-balancing-example/worker
[d5bc4eb9-8ebb-4b7c-813e-966a25fdd843, 13de9196-bfeb-4c1a-b632-b8bb, 85cd-4c08-977a-b1, 9e07bd1d-c615-430c-8dcb-bf228e9b56fc]
| 网站地图 | 设为首页主题信息(必填)
主题描述(最多限制在50个字符)
申请人信息(必填)
申请信息已提交审核,请注意查收邮件,我们会尽快给您反馈。
如有疑问,请联系
CSDN &《程序员》编辑/记者,投稿&纠错等事宜请致邮
如今的编程是一场程序员和上帝的竞赛,程序员要开发出更大更好、傻瓜都会用到软件。而上帝在努力创造出更大更傻的傻瓜。目前为止,上帝是赢的。个人网站:。个人QQ群:、
个人大数据技术博客:
人生得意须尽欢,莫使金樽空对月。
详细动态负载平衡和Nginx和Zookeeper部署,并告诉大家为什么你应该投资于你的流量控制器。2729人阅读
分布式(11)
原理解析& & & &&架构图& & & &&& & & & 每台WorkServer启动的时候都会到Server创建临时节点。& & & & 每台ClientServer启动的时候,都会到Server节点下面取得所有WorksServer节点,并通过一定算法取得一台并与之连接。& & & &&服务端主体流程& & & &&& & & & 有ClientServer与之建立连接,这台WorksServer的负载计数器加一,断开连接负载计数器减一。负载计数器作为客户端负载均衡算法的依据,客户端会选择负载最轻的WorksServer建立连接。& & & &&客户端流程& & & &&& & & &&服务端核心类& & & &&& & & &&ServerRunner 调度类&& & & & RegistProvider 服务端启动时的注册过程& & & & ServerHander 处理与客户端之间的连接& & & & DefaultBalanceUpdateProvider 连接建立与断开,修改负载信息& & & &&& & & &客户端核心类& & & &&& & & & ClientRunner 调度类& & & & ClientHander 处理与服务器之间的通信& & & & BanceProvider 负载的算法& & & & ServerData 服务器和客户端公用的类,计算负载等使用& &&& & & & 代码:
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:337856次
积分:5703
积分:5703
排名:第4545名
原创:200篇
转载:95篇
评论:61条
阅读:9822
阅读:5005
阅读:15634
(1)(3)(4)(28)(4)(2)(12)(12)(11)(9)(1)(4)(1)(1)(1)(5)(5)(12)(13)(31)(13)(13)(18)(8)(2)(2)(11)(12)(21)(35)

我要回帖

更多关于 zookeeper实现原理 的文章

 

随机推荐