欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

浅析JavaWeb项目架构之Redis分布式日志队列

程序员文章站 2023-12-05 16:07:40
摘要: 架构、分布式、日志队列,标题自己都看着唬人,其实就是一个日志收集的功能,只不过中间加了一个redis做消息队列罢了。 为什么需要消息队列? 当系统中出现“生产“和...

摘要:

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

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

浅析JavaWeb项目架构之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分布式日志队列,希望对大家有所帮助