redis stream數據類型

redis5新加了stream流類型,可以代替之前基於list的發佈訂閱,採用類似kafka的設計方式,而且支持持久化,常規場景mq代替品,是廣大碼農的福音,如果不是具有巨大流量,則可以完全棄用其他單獨

(因爲是key設計模式,所以基本是單節點承受壓力,所以單個topic流量不能過於巨大,不過萬級不是問題)

以下是基本命令:

增加一條數據: xadd mzvd:vedio * data aaa

創建一個消費組: XGROUP create mzvd:vedio g1 $

通過組讀取數據: XREADGROUP group g1 cons1 count 1 block 0

處理完消息進行回執:XACK  mzvd:vedio group 1000001

如果採用spring-data-redis,springboot版本到2.2.7,redisTemaplet已經有了封裝,我這提供了3個類,分別爲消費者、提供者、屬性配置類



import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.apache.commons.collections.map.HashedMap;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.connection.stream.Consumer;
import org.springframework.data.redis.connection.stream.MapRecord;
import org.springframework.data.redis.connection.stream.ReadOffset;
import org.springframework.data.redis.connection.stream.Record;
import org.springframework.data.redis.connection.stream.RecordId;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;

import com.alibaba.fastjson.JSONObject;

import cn.stylefeng.guns.base.utils.SpringUtil;
import io.lettuce.core.XReadArgs.StreamOffset;
import lombok.extern.slf4j.Slf4j;

/**
 * @author yy
 * @date 2020年5月12日
 * @description redis隊列
 *
 */
@Slf4j
public abstract class RedisMQConsumer implements InitializingBean{
	
	private RedisTemplate<String, String> redisTemplate;
	private RedisMQProperty mqProperty;
	private static String key="";
	
	public void setMqProperty(RedisMQProperty mqProperty) {
		this.mqProperty = mqProperty;
	}

	/**
	 * @author yy
	 * @date 2020年5月12日
	 * @description 初始化信息
	 */
	public void initConsumer(RedisTemplate<String, String> redisTemplate,RedisMQProperty mqProperty) {
		
		this.redisTemplate=redisTemplate;
		this.mqProperty=mqProperty;
		
		synchronized(key) {
			
			log.info("MQ初始化信息開始");
			//初始化隊列
			key = RedisMQProperty.prex+mqProperty.topic;
			RecordId recordId = redisTemplate.boundStreamOps(key).add(new HashedMap() {{put("-1", "-1");}});
			this.redisTemplate.boundStreamOps(key).delete(recordId.getValue());
			//初始化組
			this.redisTemplate.boundStreamOps(key).destroyGroup(mqProperty.group);
			redisTemplate.boundStreamOps(key).createGroup(ReadOffset.latest(), mqProperty.group);
			log.info("MQ初始化信息完畢");
			
			try {
				TimeUnit.SECONDS.sleep(1L);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			//觸發
			new Thread(new Runnable() {
				@Override
				public void run() {
					// TODO Auto-generated method stub
					while(true) {
						event();
					}
				}
			}).start();
			
		}
		
	}
	
	private void event() {
		List<MapRecord<String, Object, Object>>  list=
				this.redisTemplate.boundStreamOps(RedisMQConsumer.key).read(Consumer.from(mqProperty.group, mqProperty.consname),ReadOffset.lastConsumed());
		
		if(list==null || list.isEmpty())
			return;
		
		try {
			message(list.get(0).getValue().get("data").toString());
		} catch (Exception e) {
			handlerException(list.get(0).getValue(), e);
		}
		
		this.redisTemplate.boundStreamOps(key).acknowledge(mqProperty.group, list.get(0).getId().getValue());
	}
	/**
	 * @author yy
	 * @date 2020年5月12日
	 * @description 處理消息
	 * @param o
	 */
	public abstract void message(String json) ;
	
	/**
	 * @author yy
	 * @date 2020年5月12日
	 * @description 處理異常
	 * @param map
	 * @param exception
	 */
	protected void handlerException(Map<Object, Object> map,Exception exception) {
		log.info("mq消費異常:"+JSONObject.toJSONString(map),exception);
	}
	
}

import java.util.Map;

import javax.annotation.Resource;

import org.apache.commons.collections.map.HashedMap;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSONObject;

import lombok.extern.slf4j.Slf4j;

/**
 * @author yy
 * @date 2020年5月12日
 * @description redis隊列
 *
 */
@Component
public class RedisMQProvier {
	@Resource
	private RedisTemplate<String, String> redisTemplate;

	private String prex=RedisMQProperty.prex;
	

	
	/**
	 * @author yy
	 * @date 2020年5月12日
	 * @description 發佈隊列
	 * @param <T>
	 * @param topic
	 * @param obj
	 */
	public <T> void pub(String topic,T obj) {
		
		Map<Object,Object> data = new HashedMap();
		data.put("data", JSONObject.toJSONString(obj));
		redisTemplate.boundStreamOps(prex+topic).add(data);
		redisTemplate.boundStreamOps(prex+topic).trim(20000);
	}
	
	
	
	int i=0;
//	@Scheduled(fixedDelay = 10)
	private void pubSomething() {
	
		pub("vedio", i);
		i++;
		System.out.println(i);
//		pub("vedio", System.currentTimeMillis()+"====>");
	}
}

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.repository.NoRepositoryBean;
import org.springframework.stereotype.Component;

import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;
/**
 * @author yy
 * @date 2020年5月12日
 * @description redismq配置
 *
 */
@Component
@NoArgsConstructor
@AllArgsConstructor
public class RedisMQProperty {


	public static final String prex="mq:";
	public String topic;
	public String group;
	public String consname;
	
	public void setRedisMQProperty(String topic, String group, String consname) {
		this.topic = topic;
		this.group = group;
		this.consname = consname;
	}
	
	
}

配置文件

#redismq
redis.mq.vedio.topic=vedio
redis.mq.vedio.group=g1
redis.mq.vedio.consname=c1

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章