查看: 1911|回复: 0

[Java语言] 浅析JavaWeb项目架构之Redis分布式日志队列

发表于 2018-2-24 08:00:02

摘要:

架构、分布式、日志队列,标题自己都看着唬人,其实就是一个日志收集的功能,只不过中间加了一个Redis做消息队列罢了。 为什么需要消息队列? 当系统中出现“生产“和“消费“的速度或稳定性等因素不一致的时候,就需要消息队列,作为抽象层,弥合双方的差异。

架构、分布式、日志队列,标题自己都看着唬人,其实就是一个日志收集的功能,只不过中间加了一个Redis做消息队列罢了。

为什么需要消息队列?

当系统中出现“生产“和“消费“的速度或稳定性等因素不一致的时候,就需要消息队列,作为抽象层,弥合双方的差异。

比如我们系统中常见的邮件、短信发送,把这些不需要及时响应的功能写入队列,异步处理请求,减少响应时间。

如何实现?

成熟的JMS消息队列中间件产品市面上有很多,但是基于目前项目的架构以及部署情况,我们采用Redis做消息队列。

为什么用Redis?

Redis中list数据结构,具有“双端队列”的特性,同时redis具有持久数据的能力,因此redis实现分布式队列是非常安全可靠的。

它类似于JMS中的“Queue”,只不过功能和可靠性(事务性)并没有JMS严格。Redis本身的高性能和"便捷的"分布式设计(replicas,sharding),可以为实现"分布式队列"提供了良好的基础。

提供者端

项目采用第三方redis插件spring-data-redis,不清楚如何使用的请自行谷歌或者百度。

redis.properties:

  1. #redis 配置中心
  2. redis.host=192.168.1.180
  3. redis.port=6379
  4. redis.password=123456
  5. redis.maxIdle=100
  6. redis.maxActive=300
  7. redis.maxWait=1000
  8. redis.testOnBorrow=true
  9. redis.timeout=100000
复制代码

redis配置:

  1. <!-- redis 配置 -->
  2. <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig" />
  3. <bean id="jedisConnectionFactory"
  4. class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
  5. <property name="hostName" value="${redis.host}" />
  6. <property name="port" value="${redis.port}" />
  7. <property name="password" value="${redis.password}" />
  8. <property name="timeout" value="${redis.timeout}" />
  9. <property name="poolConfig" ref="jedisPoolConfig" />
  10. <property name="usePool" value="true" />
  11. </bean>
  12. <bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
  13. <property name="connectionFactory" ref="jedisConnectionFactory" />
  14. </bean>
复制代码

切面日志配置(伪代码):

  1. /**
  2. * 系统日志,切面处理类
  3. * 创建者 小柒2012
  4. * 创建时间 2018年1月15日
  5. */
  6. @Component
  7. @Scope
  8. @Aspect
  9. public class SysLogAspect {
  10. @Autowired
  11. private RedisTemplate<String, String> redisTemplate;
  12. //注解是基于swagger的API,也可以自行定义
  13. @Pointcut("@annotation(io.swagger.annotations.ApiOperation)")
  14. public void logPointCut() {
  15. }
  16. @Around("logPointCut()")
  17. public Object around(ProceedingJoinPoint point) throws Throwable {
  18. Object result = point.proceed();
  19. //把日志消息写入itstyle_log频道
  20. redisTemplate.convertAndSend("itstyle_log","日志数据,自行处理");
  21. return result;
  22. }
  23. }
复制代码

消费者端

Redis配置:

  1. <!-- redis 配置 -->
  2. <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig" />
  3. <bean id="jedisConnectionFactory"
  4. class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
  5. <property name="hostName" value="${redis.host}" />
  6. <property name="port" value="${redis.port}" />
  7. <property name="password" value="${redis.password}" />
  8. <property name="timeout" value="${redis.timeout}" />
  9. <property name="poolConfig" ref="jedisPoolConfig" />
  10. <property name="usePool" value="true" />
  11. </bean>
  12. <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"
  13. p:connection-factory-ref="jedisConnectionFactory">
  14. <property name="keySerializer">
  15. <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
  16. </property>
  17. <property name="hashKeySerializer">
  18. <bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
  19. </property>
  20. </bean>
  21. <!-- 监听实现类 -->
  22. <bean id="listener" class="com.itstyle.market.common.listener.MessageDelegateListenerImpl"/>
  23. <bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer" />
  24. <redis:listener-container connection-factory="jedisConnectionFactory">
  25. <!-- topic代表监听的频道,是一个正规匹配 其实就是你要订阅的频道-->
  26. <redis:listener ref="listener" serializer="stringRedisSerializer" method="handleLog" topic="itstyle_log"/>
  27. </redis:listener-container>
复制代码

监听接口:

  1. public interface MessageDelegateListener {
  2. public void handleLog(Serializable message);
  3. }
复制代码

监听实现:

  1. public class MessageDelegateListenerImpl implements MessageDelegateListener {
  2. @Override
  3. public void handleLog(Serializable message) {
  4. if(message == null){
  5. System.out.println("null");
  6. }else {
  7. //处理日志数据
  8. }
  9. }
  10. }
复制代码

Q&A

【问题一】为什么使用Redis?

上面其实已经有做说明,尽管市面上有许多很稳定的产品,比如可能大家会想到的Kafka、RabbitMQ以及RocketMQ。但是由于项目本身使用了Redis做分布式缓存,基于省事可行的原则就选定了Redis。

【问题二】日志数据如何存储?

原则上是不建议存储到关系数据库的,比如MySql,毕竟产生的日志数量是巨大的,建议存储到Elasticsearch等非关系型数据库。

【问题三】切面日志收集是如何实现的?

切面日志需要引入spring-aspects相关Jar包,并且配置使Spring采用CGLIB代理 。

开源项目源码(参考):https://gitee.com/52itstyle/spring-boot-mail

总结

以上所述是小编给大家介绍的JavaWeb项目架构之Redis分布式日志队列,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对程序员之家网站的支持!



回复

使用道具 举报