普通的zk用法,如下写法:

zk.Exists("/aaa", true);
zk.Create(...);

但是由于这些API会抛Zookeeper的Exception,比如ConnectionLossException, NoNodeException等,所以必须配合一堆try/catch的机制来catch错误,catch后再处理...

写起来很麻烦

因此写了个RetryHelper来封装上面这个try/catch行为,用起来也比较方便,如下:

RetryHelper helper=RetryHelper.Make();

helper.CreateNodeStructure = () => { Console.WriteLine("CreateNodeStructure"); };
helper.FixConnectionLossAction = () => { Console.WriteLine("FixConnectionLossAction");};
helper.IfErrorThen = () => { Console.WriteLine("IfErrorThen"); };
helper.Execute(() =>
{
this.zk.GetChildren(...);
});

上面的意思是如果在Execute中,如果报错了,则会看报错的是哪种类型,如果是ConnectionLoss则执行FixConnectionLossAction委托,如果是NoNode则执行建立节点的委托

也就是将最常见的2个zookeeper动作给结构化了:建立节点目录结构以及连接丢失时的重新连接动作

RetryHelper代码:

public class RetryHelper
{
private int retryDelay = ;
private long signal = ;
public Action IfErrorThen;
public Action CreateNodeStructure;
public Action FixConnectionLossAction; public static RetryHelper Make()
{
return new RetryHelper();
} public void Execute(Action action)
{
while (true)
{
try
{
action();
break;
}
catch (ZooKeeperNet.KeeperException.NoNodeException ex)
{
//create node structure Console.WriteLine("retry helper NoNodeException: " + ex.Message); if (CreateNodeStructure != null)
RetryHelper.Make().Execute(CreateNodeStructure);
continue;
}
catch (ZooKeeperNet.KeeperException.ConnectionLossException ex)
{
Console.WriteLine("retry helper ConnectionLossException: " + ex.Message); long attempSignal = Interlocked.Read(ref signal); while (Interlocked.Read(ref signal) > )
Thread.Sleep(retryDelay); if (attempSignal == )
{
Interlocked.Increment(ref signal); if (FixConnectionLossAction != null)
RetryHelper.Make().Execute(FixConnectionLossAction); Interlocked.Decrement(ref signal);
} continue;
}
catch (Exception ex)
{
Console.WriteLine("retry helper catch: " + ex.Message);
Thread.Sleep(retryDelay); if (IfErrorThen != null)
IfErrorThen();
continue;
}
}
}
}

仔细看上面代码的朋友肯定也注意到里面catch connectionloss exception的代码块中使用了Interlocked,这是因为:在多线程系统侠,如果zk连接丢失了,由于多个地方都在尝试zk操作,所以会导致并发性的进入catch loss connection exception代码处理块,如果此时不加判断的处理所有并发请求,则会出现连接多次到zk,严重影响性能;因此,这里的代码实际上意图是将多次连接请求合并为一次连接。此处特别感谢我同事的code review,哈哈。

下面是个测试并发消除的demo,为了让结果清晰,我把RetryHelper的catch中的Console.WriteLine注释了

static void Main(string[] args)
{
RetryHelper helper=RetryHelper.Make(); helper.CreateNodeStructure = () => { Console.WriteLine("CreateNodeStructure"); };
helper.FixConnectionLossAction = () =>
{
Console.WriteLine(Thread.CurrentThread.ManagedThreadId+" FixConnectionLossAction BEGIN "+DateTime.Now.ToString());
Thread.Sleep();
Console.WriteLine(Thread.CurrentThread.ManagedThreadId + " FixConnectionLossAction END " + DateTime.Now.ToString());
};
helper.IfErrorThen = () => { Console.WriteLine("IfErrorThen"); }; var tasks=new List<Task>();
for (int i = ; i < ; i++)
{
var task = new Task(() => {
helper.Execute(() =>
{
throw new ZooKeeperNet.KeeperException.ConnectionLossException();
});
});
tasks.Add(task);
} tasks.ForEach(t=>t.Start()); Task.WaitAll(tasks.ToArray()); Console.ReadKey();
}

运行:

code download

ZookeeperNet太难用,写了个RetryHelper来进行配套使用的更多相关文章

  1. 曹工说Spring Boot源码(26)-- 学习字节码也太难了,实在不能忍受了,写了个小小的字节码执行引擎

    曹工说Spring Boot源码(26)-- 学习字节码也太难了,实在不能忍受了,写了个小小的字节码执行引擎 写在前面的话 相关背景及资源: 曹工说Spring Boot源码(1)-- Bean De ...

  2. 朱晔的互联网架构实践心得S2E1:业务代码究竟难不难写?

    注意,这是我的架构实践心得的第二季的系列文章,第一季有10篇你也可以回顾. 见https://www.cnblogs.com/lovecindywang/category/1296779.html 最 ...

  3. 浏览器主页锁定之战——IE:我太难了

    精彩回顾: 我是一个explorer的线程 我是一个杀毒软件线程 我是一个IE浏览器线程 比特宇宙-TCP/IP的诞生 产品vs程序员:你知道www是怎么来的吗? Hello, World! 我是一个 ...

  4. arithmetic-slices-ii-subsequence(太难了)

    https://leetcode.com/problems/arithmetic-slices-ii-subsequence/ 太难了... package com.company; import j ...

  5. 前阿里CEO卫哲谈阿里创业经验:如何找人、找钱、找方向?(不同的阶段分别有:时间优先、金额优先、比例优先,不要做平台,太难)

    新浪科技李根 整理报道 卫哲现在是御嘉基金的创始合伙人,他另一个更加知名的身份是阿里巴巴(B2B)前CEO,在2006年到2011年的时间里,卫哲见证了阿里巴巴如何利用人才.资本和方向选择一路壮大. ...

  6. 对不起,给pandas配表情包太难了,pandas你该这么学,No.6

    如果图片无法观看,请移步 https://blog.csdn.net/hihell 标题起的长,才能引起你的注意呢 昨天,有个家伙,留言给我说 嫌我不好好写博客 就知道给文章配表情包 在这里,郑重的回 ...

  7. ORACLE 监听日志文件太大停止写监听日志引起数据库连接不上问题

    生产库监听日志文件太大(达到4G多),发现oracle停止写监听日志,检查参数log_file,log_directory,log_status 均正常,数据库运行也正常. 经确认确实为监听日志过大引 ...

  8. ACM数论之旅11---浅谈指数与对数(长篇)(今天休息,不学太难的数论> 3<)

    c/c++语言中,关于指数,对数的函数我也就知道那么多 exp(),pow(),sqrt(),log(),log10(), exp(x)就是计算e的x次方,sqrt(x)就是对x开根号 pow()函数 ...

  9. 电商项目面试题 及mysql面试题 太难没啥用

    需要按照功能点把系统拆分,拆分成独立的功能.单独为某一个节点添加服务器.需要系统之间配合才能完成整个业务逻辑.叫做分布式.集群:同一个工程部署到多台服务器上.优点:1.把模块拆分,使用接口通信,降低模 ...

随机推荐

  1. 组合(composition)与继承(inheritance)

    c++中一个重要的特点就是代码的重用,为了代码重用,有两个非常重要的手段,一个是继承,一个是组合 上面两种类的关系就分别是继承和组合.下面我们看一下代码示例: #ifndef USEFUL_H #de ...

  2. 基于OpenCv的人脸检测、识别系统学习制作笔记之一

    基于OpenCv从视频文件到摄像头的人脸检测 在OpenCv中读取视频文件和读取摄像头的的视频流然后在放在一个窗口中显示结果其实是类似的一个实现过程. 先创建一个指向CvCapture结构的指针 Cv ...

  3. 取td里面的内容

    var rowLength = document.getElementById("table名字").rows.length;   for(var i=0;i<rowLeng ...

  4. 第38讲:List伴生对象操作方法代码实战

    今天来看一下List伴生对像的操作方法 让我们来看下代码  println(List.apply(1,2,3))//等同于List(1,2,3)     println(List.range(1, 4 ...

  5. Linux内核--网络栈实现分析(一)--网络栈初始化

    本文分析基于内核Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7488828 更多请看专栏, ...

  6. 【基础知识】.Net基础加强09天

    委托: 1. 委托是一种数据类型,像类一样{可以声明委托变量类型} 2. deleate关键字定义委托 : public delegate void MethodDelegate();//这就是定义了 ...

  7. Dynamic CRM 2013学习笔记(三十七)自定义审批流7 - 初始化(整套审批流下载、安装)

    前面介绍了自定义审批流的配置.使用,这篇介绍下如何进行初始化. 一. 下载 从下面的地址下载整个审批流: http://yunpan.cn/cZ5Rdx5HCt3VF 下载完后,一共有三块内容: 二. ...

  8. Oracle数据创建表空间

    一.直接在服务器端通过sqlplus命令行创建: 如果您用的是Linux系统,那么Oracle用户名为oracle.同时,您是在oracle服务器上操作. 如果是在Windows系统下, 请先点击“开 ...

  9. 设计模式之美:Command(命令)

    索引 别名 意图 结构 参与者 适用性 效果 相关模式 实现 实现方式(一):直接注入 Receiver 对象,Command 决定调用哪个方法. 实现方式(二):注入 Receiver 的指定方法, ...

  10. 曲演杂坛--EXISTS语句

    通常在我写EXISTS语句时,我会写成IF EXISTS(SELECT TOP(1) 1 FROM XXX),也没细细考究过为什么要这么写,只是隐约认为这样写没有啥问题,那今天就深究下吧! 首先准备测 ...