普通的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. ios initialize和init等方法

    在程序运行过程中,创建多个类对象,只会调用一次initialize  [ɪˈnɪʃəˌlaɪz] .而创建几个类对象就会调用几次init; 创建一个类aa,分别重写 initialize和init方法 ...

  2. C++中new和malloc的区别

    原文:http://blog.163.com/ji_wei8888/blog/static/4868044620117361747282/ 1.new 是c++中的操作符,malloc是c 中的一个函 ...

  3. linux freetds操作mssql

    1.安装freetds wget http://mirrors.ibiblio.org/freetds/stable/freetds-stable.tgz tar xvzf freetds-stabl ...

  4. java操作word,excel,pdf

    在平常应用程序中,对office和pdf文档进行读取数据是比较常见的功能,尤其在很多web应用程序中.所以今天我们就简单来看一下java对word.excel.pdf文件的读取.本篇博客只是讲解简单应 ...

  5. 如何制作u盘启动盘

    1,下载windows系统            许多人下载windows时会出现各种版本,我推荐在这里下载 你用上面的地址进行下载,一般用迅雷吧.下载结束你就有了镜像文件了. 2,下载安装碟软通 那 ...

  6. React与ES6(四)ES6如何处理React mixins

    React与ES6系列: React与ES6(一)开篇介绍 React和ES6(二)ES6的类和ES7的property initializer React与ES6(三)ES6类和方法绑定 React ...

  7. android和ubifs

    原文地址: http://opendevkit.com/?e=37 1. ubifs号称性能比yaffs2 好,同时压缩可读写,文件系统image体较小同时可写,相当不错 2. ubifs制作 (1) ...

  8. linux基本命令--学习记录

    1.mkdir -p 递归创建目录(-p参数代表递归创建): 2.touch 创建file: 3.cat 查看 5.vi 编辑器 6.echo >(直接覆盖) 或者<<(后面追加)单 ...

  9. Windows2003 架设VPN服务

    一.确保Windows防火墙关闭. 在我的电脑上右键=>管理,在左边窗口找到“服务和应用程序”,展开,单击“服务”,在右边窗口中找到“Windows Firewall/Internet Conn ...

  10. “System.Web.UI.WebControls.Literal”不允许使用子控件

    今天在写下面的代码时遭遇错误——“System.Web.UI.WebControls.Literal”不允许使用子控件('System.Web.UI.WebControls.Literal' does ...