Apache Curator简单使用(二)
来源:互联网 发布:北京的设计公司知乎 编辑:程序博客网 时间:2024/05/28 19:25
转载自:http://www.chengxuyuans.com/Java+/72042.html
内部机制如下:
如果是消费者(QueueConsumer),会创建一个类似于PathChildrenCache的实例用于监听queuePath下的子节点变更事件(单独的线程中).同时consumer处于阻塞状态,当有子节点变更事件时会被唤醒(包括创建子节点/删除子节点等);此时consumer获取子节点列表,并将每个节点信息封装成Runnable任务单元,提交到线程池中,Runnable中执行QueueConsumer.consumer()方法.
如果是生产者,则发布一个message时recipes将会在queuePath下创建一个PERSISTENT_SEQUENTIAL节点,同时保存message数据。消费时,也将按照节点的顺序进行。发布消息并没有太多的问题仅仅是创建一个"有序"节点即可。但是对于消费者,那么需要考虑的因数就很多,比如:多个消费者同时消费时,需要确保消息不能重复且有序;消息消费时,如果网络异常,怎么办?
对于QistributedQueue中,对上述问题的解决办法也非常粗糙,内部机制如下:
如果使用了消费担保(即指定了lockPath),在调用consumer方法之前,首先创建一个临时节点(lockPath + 子节点),如果创建此临时节点失败也就意味着此消息被其他消费者,则忽略此消息。然后从子节点中获取数据,如果获取失败,意味着此节点已经被其他消费者删除,则忽略此消息。然后调用consumer()方法,如果此方法抛出异常,消息将会再次添加到队列中(删除旧的子节点,创建一个新的子节点)。如果消费正常,则删除节点。无论成败,则删除临时节点(lockPath + 子节点)。
如果没有使用消费担保,则首先获取子节点的数据(getData),然后立即删除此子节点,调用consumer()方法。
需要明确使用zookeeper作为分布式队列的场景: 1)队列深度较小;2)生产者和消费者的速度都非常的低且消费者消费速度更快,即单位时间内产生的消息很少;3)建议只有一个消费者。
DistributedQueue是最普通的一种队列。 它设计以下四个类:QueueBuilder、QueueConsumer、QueueSerializer、DistributedQueue。
1.DistributedIdQueue: 内部基于DistributedQueue的所有机制,只是除了指定queue中消息的内容之外,还可以指定一个ID,这个ID作为消息的标记,最终此ID值将作为znode的path后缀.此后可以通过ID去消费(dequeue)一个消息.队列的排序方式是根据ID的字典顺序--正序;
2.DistributedProrityQueue: 有权重的队列,对队列中的元素按照优先级进行排序,在发布消息时,需要指定此消息的权重数字; priority越小,元素越靠前,越先被消费掉。
3. DistributedDelayQueue:JDK中也有DelayQueue,DistributedDelayQueue也提供了类似的功能,元素有个delay值, 消费者隔一段时间才能收到元素。
在DistributedQueue的开发中,必须在QueueConsumer中关注"链接失效"的事件.
SharedCount使用int类型来计数。 主要涉及三个类。SharedCount、SharedCountReader、SharedCountListener。计数器改变时此Listener可以监听到改变的事件,而SharedCountReader可以读取到最新的值,包括字面值和带版本信息的值VersionedValue。
http://ifeve.com/zookeeper-sharedcount/
分布式队列Queue
分布式队列的基本特性,就是"生产者"或"消费者"跨越多个进程,且在此种环境中需要确保队列的push/poll的有序性。zookeeper本身并没有提供分布式队列的实现,只是recipse根据zookeeper的watcher和具有version标记的node,来间接的实现分布式queue。内部机制如下:
如果是消费者(QueueConsumer),会创建一个类似于PathChildrenCache的实例用于监听queuePath下的子节点变更事件(单独的线程中).同时consumer处于阻塞状态,当有子节点变更事件时会被唤醒(包括创建子节点/删除子节点等);此时consumer获取子节点列表,并将每个节点信息封装成Runnable任务单元,提交到线程池中,Runnable中执行QueueConsumer.consumer()方法.
如果是生产者,则发布一个message时recipes将会在queuePath下创建一个PERSISTENT_SEQUENTIAL节点,同时保存message数据。消费时,也将按照节点的顺序进行。发布消息并没有太多的问题仅仅是创建一个"有序"节点即可。但是对于消费者,那么需要考虑的因数就很多,比如:多个消费者同时消费时,需要确保消息不能重复且有序;消息消费时,如果网络异常,怎么办?
对于QistributedQueue中,对上述问题的解决办法也非常粗糙,内部机制如下:
如果使用了消费担保(即指定了lockPath),在调用consumer方法之前,首先创建一个临时节点(lockPath + 子节点),如果创建此临时节点失败也就意味着此消息被其他消费者,则忽略此消息。然后从子节点中获取数据,如果获取失败,意味着此节点已经被其他消费者删除,则忽略此消息。然后调用consumer()方法,如果此方法抛出异常,消息将会再次添加到队列中(删除旧的子节点,创建一个新的子节点)。如果消费正常,则删除节点。无论成败,则删除临时节点(lockPath + 子节点)。
如果没有使用消费担保,则首先获取子节点的数据(getData),然后立即删除此子节点,调用consumer()方法。
需要明确使用zookeeper作为分布式队列的场景: 1)队列深度较小;2)生产者和消费者的速度都非常的低且消费者消费速度更快,即单位时间内产生的消息很少;3)建议只有一个消费者。
DistributedQueue是最普通的一种队列。 它设计以下四个类:QueueBuilder、QueueConsumer、QueueSerializer、DistributedQueue。
import org.apache.curator.framework.recipes.queue.QueueSerializer;import java.nio.charset.Charset;public class StringQueueSerializer implements QueueSerializer<String> { private static final Charset charset = Charset.forName("utf-8"); //as producer @Override public byte[] serialize(String item) { return item.getBytes(charset); } //as consumer @Override public String deserialize(byte[] bytes) { return new String(bytes, charset); }}
import org.apache.curator.framework.CuratorFramework;import org.apache.curator.framework.recipes.queue.QueueConsumer;import org.apache.curator.framework.state.ConnectionState;import static org.apache.curator.framework.state.ConnectionState.RECONNECTED;public class DistributedQueueConsumer implements QueueConsumer<String> { @Override public void consumeMessage(String message) throws Exception { System.out.println("Consumer:" + message); } @Override public void stateChanged(CuratorFramework client, ConnectionState newState) { switch (newState) { case RECONNECTED: //当链接重建之后 try { System.out.println(RECONNECTED); } catch (Exception e) { } break; default: System.out.println(newState.toString()); } }}
import org.apache.curator.framework.CuratorFramework;import org.apache.curator.framework.recipes.queue.DistributedQueue;import org.apache.curator.framework.recipes.queue.QueueBuilder;import org.apache.curator.framework.recipes.queue.QueueConsumer;import org.apache.curator.utils.CloseableUtils;public class DistributedQueueProducer { private static CuratorFramework client; private static String queuePath; public static void main(String[] args) { QueueConsumer<String> consumer = new DistributedQueueConsumer(); DistributedQueue<String> queue = QueueBuilder.builder(client, consumer, new StringQueueSerializer(), queuePath) .lockPath("queue-lock")//消费担保 //.maxItems(1024);// 有界队列,最大队列深度,如果深度达到此值,将阻塞"生产者"创建新的节点. .buildQueue(); try { queue.start(); queue.put("test"); Thread.sleep((long) (3 * Math.random())); } catch (Exception e) { } finally { CloseableUtils.closeQuietly(queue); CloseableUtils.closeQuietly(client); } }}Recipse还提供了其他API(http://ifeve.com/zookeeper%EF%BC%8Dcurator/):
1.DistributedIdQueue: 内部基于DistributedQueue的所有机制,只是除了指定queue中消息的内容之外,还可以指定一个ID,这个ID作为消息的标记,最终此ID值将作为znode的path后缀.此后可以通过ID去消费(dequeue)一个消息.队列的排序方式是根据ID的字典顺序--正序;
2.DistributedProrityQueue: 有权重的队列,对队列中的元素按照优先级进行排序,在发布消息时,需要指定此消息的权重数字; priority越小,元素越靠前,越先被消费掉。
3. DistributedDelayQueue:JDK中也有DelayQueue,DistributedDelayQueue也提供了类似的功能,元素有个delay值, 消费者隔一段时间才能收到元素。
在DistributedQueue的开发中,必须在QueueConsumer中关注"链接失效"的事件.
计数器Counter
利用ZooKeeper可以实现一个集群共享的计数器。 只要使用相同的path就可以得到最新的计数器值, 这是由ZooKeeper的一致性保证的。Curator有两个计数器,一个是用int来计数,一个用long来计数。SharedCount使用int类型来计数。 主要涉及三个类。SharedCount、SharedCountReader、SharedCountListener。计数器改变时此Listener可以监听到改变的事件,而SharedCountReader可以读取到最新的值,包括字面值和带版本信息的值VersionedValue。
import org.apache.curator.framework.CuratorFramework;import org.apache.curator.framework.recipes.shared.SharedCount;import org.apache.curator.framework.recipes.shared.SharedCountListener;import org.apache.curator.framework.recipes.shared.SharedCountReader;import org.apache.curator.framework.state.ConnectionState;public class SharedCountTest { private static CuratorFramework client; private static String countPath; public static void main(String[] args) throws Exception { final SharedCount baseCount = new SharedCount(client, countPath, 0); baseCount.addListener(new SharedCountListener() { @Override public void countHasChanged(SharedCountReader sharedCount, int newCount) throws Exception { System.out.println("count changed:" + newCount); } @Override public void stateChanged(CuratorFramework client, ConnectionState newState) { switch (newState) { case RECONNECTED: //当链接重建之后,需要手动fresh try { Integer current = baseCount.getCount(); //reflush,无论更新成败,都会获取最新的值 baseCount.trySetCount(baseCount.getVersionedValue(), current); } catch (Exception e) { } break; default: System.out.println(newState.toString()); } } }); //test,任意的SharedCount,只要使用相同的path,都可以得到计数值 final SharedCount count = new SharedCount(client, countPath, 0); count.start(); count.trySetCount(count.getVersionedValue(), count.getCount() + 5); //trySetCount尝试设置计数器,setCount是强制更新计数器的值 count.close(); baseCount.start(); //counter.close();//取消watcher }}在"计数器"中,还提供了DistributedAtomicInteger,DistributedAtomicLong两个分布式自增计数器。
0 0
- Apache Curator简单使用(二)
- Apache Curator简单使用(一)
- Apache Curator简单使用(三)
- Apache Curator Lock 简单示例
- 学习Curator(二)
- zookeeper Curator框架简单使用
- Apache Curator Leader选举 简单示例
- [curator] Netflix Curator 使用
- [curator] Netflix Curator 使用
- Zookeeper之Curator框架简单使用-yellowcong
- 使用Apache Curator实现服务的注册和发现
- Apache Curator Leader Election
- Apache Curator入门实战
- Apache Curator入门实战
- Apache Curator快速入门
- Apache Curator入门实战
- Apache Curator入门实战
- Apache Curator入门实战
- linux根据uid反查用户名
- 随笔之java面试
- 郝斌的C语言基础 170 补码 下
- jsp实现分页显示信息(数据库、EL表达式、连接池)
- 对javascript的Array中转换方法、栈和队列的理解
- Apache Curator简单使用(二)
- JavaScript 声明全局变量的三种方式详解
- 自定义一个注解 annotation
- D. zb的生日
- activiti pom
- 采用EM算法求解高斯混合模型参数
- maven打包war,报servlet.jsp不存在解答
- Ubuntu Install Adobe Flash Player
- Vultr 服务器搭建及锐速破解教程,亲测1080随意拖动