storm源码分析--TimeCacheMap
来源:互联网 发布:opencv读取caffe 编辑:程序博客网 时间:2024/05/18 02:10
TimeCacheMap是storm里面的一个类,storm用它来保存那些最近活跃的对象,并且可以自动删除那些已经过期的对象。这个类设计的很巧妙,我们来看一下:
TimeCacheMap里面的数据是保存在内部变量_bucket里面的:
private LinkedList<HashMap<K, V>> _buckets;在这点上跟ConcurrentHashMap有点类似,ConcurrentHashMap是利用多个bucket来缩小锁的粒度,从而实现高并发的读写。而TimeCacheMap则是利用多个bucket来使得数据清理线程占用锁的时间最小。
首先来看看TimeCacheMap的构造函数,它的构造函数首先是生成numBuckets个空的HashMap:
_buckets = new LinkedList<HashMap<K,V>>;for(int i = 0; i < numBuckets; i ++){ _buckets.add(new HashMap<K, V>)();}然后就是最关键的线程清理部分,TimeCacheMap使用一个单独的线程来清理那些过期的数据:
final long expirationMillis = expirationSecs * 1000L;final long sleepTime = expirationMillis/(numBuckets-1);_cleaner = new Thread(new Runnable() { public void run() { try { while(true) { Map<K, V> dead = null; // Time.sleep(sleepTime); synchronized(_lock) { dead = _buckets.removeLast(); _buckets.addFirst(new HashMap<K, V>()); } if(_callback!=null) { for(Entry<K, V> entry: dead.entrySet()) { _callback.expire(entry.getKey(), entry.getValue()); } } } } catch (InterruptedException ex) { } }});_cleaner.setDaemon(true);_cleaner.start();这个线程每隔expirationSecs/(numBuckets - 1)秒钟的时间去把最后一个bucket里面的数据全部都删掉--这些被删掉的数据其实就是过期数据。这里值得注意的是:正式因为这种分成多个桶的机制,清理线程对于_lock的占用时间极短,只要将最后一个bucket从——buckets解下,并且向头添加一个新的bucket就好了
synchronized(_lock) { dead = _buckets.removeLast(); _buckets.addFirst(new HashMap<K, V>());}如果不是这种机制,那么我能想到最傻的办法可能就是给条数据一个过期时间字段,然后清理线程就要便利每条数据来检查数据是否过期了,这显然要hold住这个锁很长时间。
同时对于每条过期数据TimeCacheMap会执行callback函数
if(_callback!=null) { for(Entry<K, V> entry: dead.entrySet()) { _callback.expire(entry.getKey(), entry.getValue()); }}大致机制就是这样,那么我们现在回头看看前面的那个问题:为什么这个清理线程是每隔expirationSecs / (numbuckets - 1)秒的时间来检查,这样对吗?TimeCacheMap的内部有多个桶,当你向这个TimeCacheMap里面添加数据的时候,数据总是添加到第一个桶里面的。
public void put(K key, V value) { synchronized(_lock) { Iterator<HashMap<K, V>> it = _buckets.iterator(); HashMap<K, V> bucket = it.next(); bucket.put(key, value); while(it.hasNext()) { bucket = it.next(); bucket.remove(key); } }}我们看个例子就明白了,假设numBuckets = 3,expirationSecs = 2.我们先往里面填一条数据{1: 1},这条数据被加到第一个桶里面去,现在TimeCacheMap的状态是
[{1:1}, {}, {}]过了一秒钟后(expirationSecs / (numBuckets - 1) = 2/(3-1) = 1).清理线程干掉最后一个HashMap,并且在头上添加一个空的HashMap,现在的TimeCacheMap的状态是:
[{}, {1:1}, {}]再过了一秒钟,同上,TimeCacheMap的状态变成:
[{}, {}, {1:1}]再过一秒钟,现在{1:1}是最后一个TimeCacheMao了,就被干掉了。所以从{1:1}被加入到这个TimeCacheMap到被干掉一共用了3秒,其实这3秒就等于
3 = expirationSecs *(1+1/(numBuckets - 1))
storm当中0.8版本之前的TimeCacheMap这个map中的那个算法是不是有问题呢?里面记录的消息的过期时间是expirationSecs到expirationSecs * (1 + 1 / (numBuckets-1))之间,如果我设置的expirationSecs比较大,那岂不是这个时间差会很大,比如expirationSecs是100,numBuckets是3,那么这个时间就是100s到150s,这个不能容忍吧.还是说这个map只是为了存储活跃的数据,对过期数据的删除其实并没有严格的要求,个人认为是这样的,所以作者在0.8之后不再使用TimeCacheMap
有时间可以了解一下guava
0 0
- storm源码分析--TimeCacheMap
- Twitter Storm源代码分析之TimeCacheMap
- Twitter Storm源代码分析之TimeCacheMap
- Twitter Storm源代码分析之TimeCacheMap-过期清除
- Storm常见模式------TimeCacheMap
- Storm常见模式------TimeCacheMap
- storm实战--TimeCacheMap的使用
- Storm-源码分析汇总
- Storm-源码分析汇总
- Storm源码分析<转>
- Storm-源码分析汇总
- Storm源码分析汇总
- Storm-源码分析汇总
- storm 源码分析
- storm-kafka源码分析
- Storm常见模式——TimeCacheMap
- Storm常见模式——TimeCacheMap
- Storm常见模式——TimeCacheMap<转>
- 第五天CCTouch详解
- jetty之嵌入式运行jetty
- PHP中静态(static)调用非静态方法详解
- HDU1241广搜
- Linux学习笔记(八)Linux命令行快捷键
- storm源码分析--TimeCacheMap
- 堆和优先级队列
- qmake概念
- 项目6.4 "三色球" 问题
- LINUX下GDB调试
- 偏差与方差(Bias and Variance)
- 保姆照顾孩子版本1
- 寻找发帖水王
- Linux GDB调试常用命令