摘要:
架構、分布式、日志隊列,標題自己都看著唬人,其實就是一個日志收集的功能,只不過中間加了一個Redis做消息隊列罷了。 為什么需要消息隊列? 當系統中出現“生產“和“消費“的速度或穩定性等因素不一致的時候,就需要消息隊列,作為抽象層,彌合雙方的差異。
架構、分布式、日志隊列,標題自己都看著唬人,其實就是一個日志收集的功能,只不過中間加了一個Redis做消息隊列罷了。
為什么需要消息隊列?
當系統中出現“生產“和“消費“的速度或穩定性等因素不一致的時候,就需要消息隊列,作為抽象層,彌合雙方的差異。
比如我們系統中常見的郵件、短信發送,把這些不需要及時響應的功能寫入隊列,異步處理請求,減少響應時間。
如何實現?
成熟的JMS消息隊列中間件產品市面上有很多,但是基于目前項目的架構以及部署情況,我們采用Redis做消息隊列。
為什么用Redis?
Redis中list數據結構,具有“雙端隊列”的特性,同時redis具有持久數據的能力,因此redis實現分布式隊列是非常安全可靠的。
它類似于JMS中的“Queue”,只不過功能和可靠性(事務性)并沒有JMS嚴格。Redis本身的高性能和"便捷的"分布式設計(replicas,sharding),可以為實現"分布式隊列"提供了良好的基礎。
提供者端
項目采用第三方redis插件spring-data-redis,不清楚如何使用的請自行谷歌或者百度。
redis.properties:
1
2
3
4
5
6
7
8
9
|
#redis 配置中心 redis.host= 192.168 . 1.180 redis.port= 6379 redis.password= 123456 redis.maxIdle= 100 redis.maxActive= 300 redis.maxWait= 1000 redis.testOnBorrow= true redis.timeout= 100000 |
redis配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
<!-- 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> |
切面日志配置(偽代碼):
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
/** * 系統日志,切面處理類 * 創建者 小柒2012 * 創建時間 2018年1月15日 */ @Component @Scope @Aspect public 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" , "日志數據,自行處理" ); return result; } } |
消費者端
Redis配置:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
<!-- 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> <!-- 監聽實現類 --> <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代表監聽的頻道,是一個正規匹配 其實就是你要訂閱的頻道--> <redis:listener ref= "listener" serializer= "stringRedisSerializer" method= "handleLog" topic= "itstyle_log" /> </redis:listener-container> |
監聽接口:
1
2
3
|
public interface MessageDelegateListener { public void handleLog(Serializable message); } |
監聽實現:
1
2
3
4
5
6
7
8
9
10
|
public class MessageDelegateListenerImpl implements MessageDelegateListener { @Override public void handleLog(Serializable message) { if (message == null ){ System.out.println( "null" ); } else { //處理日志數據 } } } |
Q&A
【問題一】為什么使用Redis?
上面其實已經有做說明,盡管市面上有許多很穩定的產品,比如可能大家會想到的Kafka、RabbitMQ以及RocketMQ。但是由于項目本身使用了Redis做分布式緩存,基于省事可行的原則就選定了Redis。
【問題二】日志數據如何存儲?
原則上是不建議存儲到關系數據庫的,比如MySql,畢竟產生的日志數量是巨大的,建議存儲到Elasticsearch等非關系型數據庫。
【問題三】切面日志收集是如何實現的?
切面日志需要引入spring-aspects相關Jar包,并且配置使Spring采用CGLIB代理 。
開源項目源碼(參考):https://gitee.com/52itstyle/spring-boot-mail
總結
以上所述是小編給大家介紹的JavaWeb項目架構之Redis分布式日志隊列,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網站的支持!
原文鏈接:https://yq.aliyun.com/articles/368401