zoukankan      html  css  js  c++  java
  • JavaWeb项目架构之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>
    

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

    /**
     * 系统日志,切面处理类
     * 创建者 张志朋
     * 创建时间	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代理 <aop:aspectj-autoproxy proxy-target-class="true" />。

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

  • 相关阅读:
    Android NDK 环境搭建(Native Development Kit )
    No enclosing instance of type Test is accessible. Must qualify the allocation with an enclosing in
    ASP.NET 未被授权访问所请求的资源。请考虑授予 ASP.NET 请求标识访问此资源的?
    解决FileUpload控件上传文件大小限制
    学习图表控件MsChart
    Delphi PChar与String互转
    Ext.data.Store的基本用法
    My97 DatePicker 日期格式
    ASP.net流的方式输出图片或文件
    C# 二进制、十进制、十六进制互转
  • 原文地址:https://www.cnblogs.com/smallSevens/p/8403420.html
Copyright © 2011-2022 走看看