基于redis队列的日志系统实现

思路

1、log的保存不应该被当前线程的session影响,和log4j一样,运行到哪一步就记录哪一步,输出到数据库,不能出现错误回滚或则保存失败。
2、log的保存和插入不能影响当前线程,不能因为日志保存过多而影响当前进程响应速度,或则占用数据库资源影响进程的读写。

解决方法

先将日志产生后放入缓存队列中,不影响当前进程,另起一个进程去消费队列中的日志信息,保存至数据库。
本次使用了redis 的生产消费模式,生产日志,另起线程消费日志
优点: 不影响当前进程,也不受当前进程影响,用redis队列的话,读写速度极快,每秒百万级别基本不会出现堵塞现象。
缺点:需要另起进程消费,虽然读写很快,但是还是做不到实时保存。
步骤:
1、新建日志实体,数据库日志表,可以根据自己的需求创建多个日志实体保存。

public class SystemLoginfo extends BaseEntity<String> implements Serializable {

    /** 日志级别 */
    @Column(name = "log_level", length = 10)
    private String logLevel;
    /** 日志打印时间 */
    @JsonSerialize(using = JsonDateSerializer.class)
    @JsonDeserialize(using = JsonDateDeSerializer.class)
    @Column(name = "log_time", length = 30)
    private Date logTime;
    /** 端口号 */
    @Column(name = "port", length = 30)
    private String port=AllConstant.getInstance().getLocalPort();
    /** 日志信息 */
    @Column(name = "message", length = 2000)
    private String message;
    /** ip地址 */
    @Column(name = "ip_address", length = 50)
    private String ipAddress= AllConstant.getInstance().getLocalAddr();

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public String getIpAddress() {
        return ipAddress;
    }

    public void setIpAddress(String ipAddress) {
        this.ipAddress = ipAddress;
    }

    public String getPort() {
        return port;
    }

    public void setPort(String port) {
        this.port = port;
    }

    public Date getLogTime() {
        return logTime;
    }

    public void setLogTime(Date logTime) {
        this.logTime = logTime;
    }

    public String getLogLevel() {
        return logLevel;
    }

    public void setLogLevel(String logLevel) {
        this.logLevel = logLevel;
    }
}

2集成jedis;(这里我用到了集群,所以创建了jedisCluster的bean对象)

<bean id="jedisCluster" class="redis.clients.jedis.JedisCluster">
		<constructor-arg>
			<set>
				<bean class="redis.clients.jedis.HostAndPort">
					<constructor-arg name="host" value="${redis.cluster.node-1.host}"></constructor-arg>
					<constructor-arg name="port" value="${redis.cluster.node-1.port}"></constructor-arg>
				</bean>
				<bean class="redis.clients.jedis.HostAndPort">
					<constructor-arg name="host" value="${redis.cluster.node-2.host}"></constructor-arg>
					<constructor-arg name="port" value="${redis.cluster.node-2.port}"></constructor-arg>
				</bean>
				<bean class="redis.clients.jedis.HostAndPort">
					<constructor-arg name="host" value="${redis.cluster.node-3.host}"></constructor-arg>
					<constructor-arg name="port" value="${redis.cluster.node-3.port}"></constructor-arg>
				</bean>
				<bean class="redis.clients.jedis.HostAndPort">
					<constructor-arg name="host" value="${redis.cluster.node-4.host}"></constructor-arg>
					<constructor-arg name="port" value="${redis.cluster.node-4.port}"></constructor-arg>
				</bean>
				<bean class="redis.clients.jedis.HostAndPort">
					<constructor-arg name="host" value="${redis.cluster.node-5.host}"></constructor-arg>
					<constructor-arg name="port" value="${redis.cluster.node-5.port}"></constructor-arg>
				</bean>
				<bean class="redis.clients.jedis.HostAndPort">
					<constructor-arg name="host" value="${redis.cluster.node-6.host}"></constructor-arg>
					<constructor-arg name="port" value="${redis.cluster.node-6.port}"></constructor-arg>
				</bean>
			</set>
		</constructor-arg>
		<constructor-arg index="1" value="${redis.timeOut}"></constructor-arg>
		<constructor-arg index="2" value="${redis.socketTimeout}"></constructor-arg>
		<constructor-arg index="3" value="${redis.maxAttempts}"></constructor-arg>
		<constructor-arg index="4" value="${redis.cluster.password}"></constructor-arg>
		<constructor-arg index="5" ref="poolConfig"></constructor-arg>
	</bean>

3调用 jedisCluster.lpush()左边插入数据(即生产数据)

jedisCluster.lpush(RedisSerializerUtil.serialize(MESSAGE_KEY),RedisSerializerUtil.serialize(message));

4调用jedisCluster.brpop(),从右侧取数据(即消费数据)

wateTime即为等待时间,如果没有数据会等待直至队列中有数据,为0 时会一直等待(
因为redis队列是单线程,所以这个等待会堵塞队列的获取。所以消费线程只需要一个就可以,无需多个)

List<byte[]> message =jedisCluster.brpop(wateTime, RedisSerializerUtil.serialize(Logging.MESSAGE_KEY));
if (null != message && (!message.isEmpty())){
            Object object = RedisSerializerUtil.unserialize(message.get(1));
            SystemLoginfo entity = (SystemLoginfo)object;
            //插入数据库
            systemLoginfoDao.save(entity);
        }

5总结,redis的特性有很多,本次用到了redis的生产消费模式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Redis消息队列是一种基于内存的队列,用于在应用程序之间或不同服务之间传输消息。Redis作为一个高性能的内存数据库,可以快速地将消息存储在内存中,并提供了一系列的指令来操作这些消息。在Redis中,消息队列通常使用List数据结构来实现。 以下是Redis消息队列的详细讲解: 1. Redis List数据结构 Redis的List是一个双向链表,可以在列表的两端进行插入和删除操作。在Redis中,List可以用于实现队列、栈等数据结构。List中的每个元素都是一个字符串。 2. Redis消息队列实现 Redis消息队列实现通常使用List数据结构,其中List的头部作为队列的入口,尾部作为队列的出口。当有新的消息进入队列时,使用LPUSH指令将消息插入到List的头部,当有消费者需要消费消息时,使用RPOP指令从List的尾部弹出一条消息。 3. 消息队列的生产者和消费Redis消息队列有生产者和消费者两个角色。生产者负责向队列中添加消息,消费者则负责从队列中取出消息进行处理。由于Redis是一个高性能的内存数据库,可以快速地将消息存储在内存中,并提供了一系列的指令来操作这些消息,因此Redis消息队列可以高效地实现生产者和消费者之间的消息传递。 4. 消息队列的应用场景 Redis消息队列可以应用于很多场景,比如异步任务处理、实时消息推送、日志处理等。在异步任务处理中,可以将需要异步处理的任务放入队列中,由消费者从队列中取出任务进行处理,从而提高任务处理的效率。在实时消息推送中,可以使用Redis消息队列实现消息的分发,从而提高消息的实时性和可靠性。在日志处理中,可以将日志信息放入队列中,由消费者从队列中取出日志信息进行处理,从而实现日志实时处理和分析。 总之,Redis消息队列是一种高效、可靠的消息传递机制,可以应用于各种场景中,是构建分布式系统的重要组件之一。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值