摘要:
架構(gòu)、分布式、日志隊(duì)列,標(biāo)題自己都看著唬人,其實(shí)就是一個日志收集的功能,只不過中間加了一個Redis做消息隊(duì)列罷了。 為什么需要消息隊(duì)列? 當(dāng)系統(tǒng)中出現(xiàn)“生產(chǎn)“和“消費(fèi)“的速度或穩(wěn)定性等因素不一致的時(shí)候,就需要消息隊(duì)列,作為抽象層,彌合雙方的差異。
架構(gòu)、分布式、日志隊(duì)列,標(biāo)題自己都看著唬人,其實(shí)就是一個日志收集的功能,只不過中間加了一個Redis做消息隊(duì)列罷了。
為什么需要消息隊(duì)列?
當(dāng)系統(tǒng)中出現(xiàn)“生產(chǎn)“和“消費(fèi)“的速度或穩(wěn)定性等因素不一致的時(shí)候,就需要消息隊(duì)列,作為抽象層,彌合雙方的差異。
比如我們系統(tǒng)中常見的郵件、短信發(fā)送,把這些不需要及時(shí)響應(yīng)的功能寫入隊(duì)列,異步處理請求,減少響應(yīng)時(shí)間。
如何實(shí)現(xiàn)?
成熟的JMS消息隊(duì)列中間件產(chǎn)品市面上有很多,但是基于目前項(xiàng)目的架構(gòu)以及部署情況,我們采用Redis做消息隊(duì)列。
為什么用Redis?
Redis中l(wèi)ist數(shù)據(jù)結(jié)構(gòu),具有“雙端隊(duì)列”的特性,同時(shí)redis/277434.html">redis具有持久數(shù)據(jù)的能力,因此redis實(shí)現(xiàn)分布式隊(duì)列是非常安全可靠的。
它類似于JMS中的“Queue”,只不過功能和可靠性(事務(wù)性)并沒有JMS嚴(yán)格。Redis本身的高性能和"便捷的"分布式設(shè)計(jì)(replicas,sharding),可以為實(shí)現(xiàn)"分布式隊(duì)列"提供了良好的基礎(chǔ)。
提供者端
項(xiàng)目采用第三方redis插件spring-data-redis,不清楚如何使用的請自行谷歌或者百度。
redis.properties:
#redis 配置中心 redis.host=192.168.1.180redis.port=6379redis.password=123456redis.maxIdle=100 redis.maxActive=300 redis.maxWait=1000 redis.testOnBorrow=true redis.timeout=100000
redis配置:
<!-- redis 配置 --> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig" /> <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <property name="hostName" value="${redis.host}" /> <property name="port" value="${redis.port}" /> <property name="password" value="${redis.password}" /> <property name="timeout" value="${redis.timeout}" /> <property name="poolConfig" ref="jedisPoolConfig" /> <property name="usePool" value="true" /> </bean> <bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate"> <property name="connectionFactory" ref="jedisConnectionFactory" /> </bean>
切面日志配置(偽代碼):
/** * 系統(tǒng)日志,切面處理類 * 創(chuàng)建者 小柒2012 * 創(chuàng)建時(shí)間 2018年1月15日 */@Component@Scope@Aspectpublic class SysLogAspect { @Autowired private RedisTemplate<String, String> redisTemplate; //注解是基于swagger的API,也可以自行定義 @Pointcut("@annotation(io.swagger.annotations.ApiOperation)") public void logPointCut() { } @Around("logPointCut()") public Object around(ProceedingJoinPoint point) throws Throwable { Object result = point.proceed(); //把日志消息寫入itstyle_log頻道 redisTemplate.convertAndSend("itstyle_log","日志數(shù)據(jù),自行處理"); return result; }}
消費(fèi)者端
Redis配置:
<!-- redis 配置 --> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig" /> <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <property name="hostName" value="${redis.host}" /> <property name="port" value="${redis.port}" /> <property name="password" value="${redis.password}" /> <property name="timeout" value="${redis.timeout}" /> <property name="poolConfig" ref="jedisPoolConfig" /> <property name="usePool" value="true" /> </bean> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" p:connection-factory-ref="jedisConnectionFactory"> <property name="keySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" /> </property> <property name="hashKeySerializer"> <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" /> </property> </bean> <!-- 監(jiān)聽實(shí)現(xiàn)類 --> <bean id="listener" class="com.itstyle.market.common.listener.MessageDelegateListenerImpl"/> <bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer" /> <redis:listener-container connection-factory="jedisConnectionFactory"> <!-- topic代表監(jiān)聽的頻道,是一個正規(guī)匹配 其實(shí)就是你要訂閱的頻道--> <redis:listener ref="listener" serializer="stringRedisSerializer" method="handleLog" topic="itstyle_log"/> </redis:listener-container>
監(jiān)聽接口:
public interface MessageDelegateListener { public void handleLog(Serializable message);}
監(jiān)聽實(shí)現(xiàn):
public class MessageDelegateListenerImpl implements MessageDelegateListener { @Override public void handleLog(Serializable message) { if(message == null){ System.out.println("null"); }else { //處理日志數(shù)據(jù) } }}
Q&A
【問題一】為什么使用Redis?
上面其實(shí)已經(jīng)有做說明,盡管市面上有許多很穩(wěn)定的產(chǎn)品,比如可能大家會想到的Kafka、RabbitMQ以及RocketMQ。但是由于項(xiàng)目本身使用了Redis做分布式緩存,基于省事可行的原則就選定了Redis。
【問題二】日志數(shù)據(jù)如何存儲?
原則上是不建議存儲到關(guān)系數(shù)據(jù)庫的,比如MySql,畢竟產(chǎn)生的日志數(shù)量是巨大的,建議存儲到Elasticsearch等非關(guān)系型數(shù)據(jù)庫。
【問題三】切面日志收集是如何實(shí)現(xiàn)的?
切面日志需要引入spring-aspects相關(guān)Jar包,并且配置使Spring采用CGLIB代理 。
開源項(xiàng)目源碼(參考):https://gitee.com/52itstyle/spring-boot-mail
總結(jié)
以上所述是小編給大家介紹的JavaWeb項(xiàng)目架構(gòu)之Redis分布式日志隊(duì)列,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時(shí)回復(fù)大家的。在此也非常感謝大家對VeVb武林網(wǎng)網(wǎng)站的支持!
新聞熱點(diǎn)
疑難解答
圖片精選