浅析JavaWeb项目架构之Redis分布式日志队列
摘要:
架构、分布式、日志队列,标题自己都看着唬人,其实就是一个日志收集的功能,只不过中间加了一个redis做消息队列罢了。 为什么需要消息队列? 当系统中出现“生产“和“消费“的速度或稳定性等因素不一致的时候,就需要消息队列,作为抽象层,弥合双方的差异。
架构、分布式、日志队列,标题自己都看着唬人,其实就是一个日志收集的功能,只不过中间加了一个redis做消息队列罢了。
为什么需要消息队列?
当系统中出现“生产“和“消费“的速度或稳定性等因素不一致的时候,就需要消息队列,作为抽象层,弥合双方的差异。
比如我们系统中常见的邮件、短信发送,把这些不需要及时响应的功能写入队列,异步处理请求,减少响应时间。
如何实现?
成熟的jms消息队列中间件产品市面上有很多,但是基于目前项目的架构以及部署情况,我们采用redis做消息队列。
为什么用redis?
redis中list数据结构,具有“双端队列”的特性,同时redis具有持久数据的能力,因此redis实现分布式队列是非常安全可靠的。
它类似于jms中的“queue”,只不过功能和可靠性(事务性)并没有jms严格。redis本身的高性能和"便捷的"分布式设计(replicas,sharding),可以为实现"分布式队列"提供了良好的基础。
提供者端
项目采用第三方redis插件spring-data-redis,不清楚如何使用的请自行谷歌或者百度。
redis.properties:
#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配置:
<!-- 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>
切面日志配置(伪代码):
/** * 系统日志,切面处理类 * 创建者 小柒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配置:
<!-- 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>
监听接口:
public interface messagedelegatelistener { public void handlelog(serializable message); }
监听实现:
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代理 。
开源项目源码(参考):
总结
以上所述是小编给大家介绍的javaweb项目架构之redis分布式日志队列,希望对大家有所帮助