物联网项目接收设备实时数据的一个想法

场景是:若干设备会每隔n秒,发送p数量的数据到服务端,服务端消费数据的能力为每n秒c个数据。

如果 c >= p, 则服务端正常运行。
如果 c<p,则服务端面临崩溃,越来越多的数据得不到消费,数据延迟会越来越高。

解决方法: 假设每4s 产生5个数据,服务端每4s消费4个数据
第0s到来的数据:0,1,2,3,4 (版本1)
第4s消费情况:已消费:0,1,2,3,未消费:4(版本1)
同时:设备又发来数据:0,1,2,3,4 (版本2)
后续消费方式:4(版本2),0,1,2
相当于消费能力之外的数据丢弃,下一次消费优先选择上次丢弃的数据

代码实现

public abstract class MapQueueElement<K extends Serializable> {

	private long timestamp;

	public long getTimestamp() {
		return timestamp;
	}
	
	void markTime() {
		if(timestamp==0l) {
			timestamp=System.currentTimeMillis();
		}
	}
	
	public abstract K eleKey();
	
}
public class MapQueue<K extends Serializable,E extends MapQueueElement<K>> {
	
	public ConcurrentHashMap<K, E> dataMap;
	
	private BlockingQueue<E> dataQueue;
	
	/**
	 * 默认map容量
	 * 实际应该根据可能存在的数据对象的多少来设置,减少扩容
	 */
	public static final int DEFAULT_DATAMAP_CAPACITY = 16;
	
	/**
	 * 默认队列容量
	 */
	public static final int DEFAULT_DATAQUEUE_CAPACITY = Integer.MAX_VALUE;
	
	public MapQueue(int dataMapCapacity) {
		this.dataMap=new ConcurrentHashMap<K, E>(dataMapCapacity);
		this.dataQueue=new LinkedBlockingQueue<E>();
	}
	
	public MapQueue(int dataMapCapacity,int dataQueueCapacity) {
		this.dataMap=new ConcurrentHashMap<K, E>(dataMapCapacity);
		this.dataQueue=new LinkedBlockingQueue<E>(dataQueueCapacity);
	}
	
	public MapQueue(int dataMapCapacity,BlockingQueue<E> dataQueue) {
		this.dataMap=new ConcurrentHashMap<K, E>(dataMapCapacity);
		this.dataQueue=dataQueue;
	}
	
	/**
	 * 线程安全的,得到数据直接put进来就可以
	 */
	public void put(E e) throws InterruptedException {
		E mapE=dataMap.get(e.eleKey());
		e.markTime();
		dataMap.put(e.eleKey(), e);
		if(mapE==null) {
			dataQueue.put(e);
		}
	}
	/**
	 * 程序里不停的take数据,得到数据后放到定长线程池里处理
	 */
	public E take() throws InterruptedException  {
		E queueE=dataQueue.take();
		E mapE=dataMap.get(queueE.eleKey());
		if(mapE!=null&&queueE.getTimestamp()<mapE.getTimestamp()) {//队列里的时间早于map里的时间,使用map的数据,消费能力小于生产能力时,超出部分会走这里
			dataMap.remove(queueE.eleKey());
			queueE=null;
			return mapE;
		}
		dataMap.remove(queueE.eleKey());//消费能力大于等于生产能力时,会走这里
		return queueE;
	}
}

测试方法

public class ProData extends MapQueueElement<String>{

	private String key;
	
	public String getKey() {
		return key;
	}

	public void setKey(String key) {
		this.key = key;
	}

	public ProData(String key) { 
		this.key = key;
	}

	@Override
	public String eleKey() {
		return key;
	}
	
}
public class QueueTest {
	
	public static void main(String[] args) throws InterruptedException {
		MapQueue<String,ProData> mapQueue=new MapQueue<>(1024);
		
		ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
		scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
			@Override
			public void run() {
				for(int i=0;i<5;i++) {
					try {
						mapQueue.put(new ProData(String.valueOf(i)));
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				
			}
		},0, 4, TimeUnit.SECONDS);
		
		while(true) {
			ProData proData=mapQueue.take();
			System.out.println(proData.getKey()+"当前时间:"+new Date(System.currentTimeMillis())+"---数据时间"+new Date(proData.getTimestamp()));
			Thread.sleep(1000);
		}
	}
	
	
}

得到的结果也如我当初设想:
前提:消费能力c < 生产能力p
条件:c > p/2
结果:保证 前2c-p部分 的数据被实时消费,后面2个p-c部分 的数据 以0.5的概率被消费,保证每次消费能力(2c-p + p-c)= c
条件: c = p/2
结果:每次交替消费前后p/2的数据
条件:c < p/2
结果:不知道怎么算,不过先到的消费频率还是高一些

结语:大家看看这样行不行。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值