Dubbo分布式日志追踪,多线程不能获取窜ID和IP问题

接着上一篇日志,当用MDC或者ThreadContext来put或者get数据的时候,不同线程是获取不到的,他们都是ThreadLocal维护,所以线程独立。

如果需要子线程获取则将参数传入,在Thread的run方法执行的时候将传入的ID和IP都put到MDC或者ThreadContext中。

  • 这里使用ThreadContext:
<context:component-scan base-package="spring04"/>

    <bean id="threadPool"
          class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
        <!-- 核心线程数 -->
        <property name="corePoolSize" value="3"/>
        <!-- 最大线程数 -->
        <property name="maxPoolSize" value="10"/>
        <!-- 队列最大长度 >=mainExecutor.maxSize -->
        <property name="queueCapacity" value="25"/>
        <!-- 线程池维护线程所允许的空闲时间 -->
        <property name="keepAliveSeconds" value="300"/>
        <!-- 线程池对拒绝任务(无线程可用)的处理策略 ThreadPoolExecutor.CallerRunsPolicy策略 ,调用者的线程会执行该任务,如果执行器已关闭,则丢弃.  -->
        <property name="rejectedExecutionHandler">
            <bean class="java.util.concurrent.ThreadPoolExecutor$CallerRunsPolicy"/>
        </property>
    </bean>
  • 创建一个AbstractRunnable实现Runnable,以后创建线程都用AbstractRunnable创建
package spring04;

import org.slf4j.MDC;

public abstract class AbstractRunnable implements Runnable {
    private String traceid;
    private String ip;

    public AbstractRunnable(String traceid, String ip) {
        this.traceid = traceid;
        this.ip = ip;
    }

    private void log() {
        MDC.put(Constant.TRANC_ID, traceid);
        MDC.put(Constant.LOCAL_IP, ip);
    }

    protected abstract void thread();

    public void run() {
        log();
        thread();
    }

    public String getTraceid() {
        return traceid;
    }

    public void setTraceid(String traceid) {
        this.traceid = traceid;
    }

    public String getIp() {
        return ip;
    }

    public void setIp(String ip) {
        this.ip = ip;
    }
}
  • 创建一个线程池context
package spring04;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.ArrayList;
import java.util.List;

@Component
public class TreadContext {

    @Autowired
    private ThreadPoolTaskExecutor executor;

    private static TreadContext context;

    private List<AbstractRunnable> threads = new ArrayList<AbstractRunnable>();

    @PostConstruct
    private void init() {
        context = this;
    }

    /**
     * 关闭线程池
     */
    public void close() {
        executor.shutdown();
    }

    /**
     * 执行所有线程池
     */
    public void open() {
        for (Runnable thread : this.threads) {
            executor.execute(thread);
        }
    }

    /**
     * 添加多个线程任务
     *
     * @param threads
     * @return
     */
    public TreadContext source(List<AbstractRunnable> threads) {
        this.threads.addAll(threads);
        return context;
    }

    /**
     * 添加单个线程任务
     *
     * @param thread
     */
    public void source(AbstractRunnable thread) {
        this.threads.add(thread);
    }

    /**
     * 获取线程池管理对象
     *
     * @return
     */
    public static TreadContext getContext() {
        return context;
    }
}
  • 常量
package spring04;

public class Constant {
    public static final String TRANC_ID = "TRANC_ID";
    public static final String LOCAL_IP = "LOCAL_IP";
}
  • 线程类
package spring04;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;

public class MyThread extends AbstractRunnable {

    private static Logger logger = LoggerFactory.getLogger(MyThread.class);

    public MyThread(String traceid, String ip) {
        super(traceid, ip);
    }

    /**
     * 用来替代run方法
     */
    protected void thread() {
        logger.info("thread name:{}  ,trace_id:{}  ,local_ip:{}", Thread.currentThread().getName(), MDC.get(Constant.TRANC_ID), MDC.get(Constant.TRANC_ID));
    }

}
  • 执行的main方法
package spring04;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.ArrayList;
import java.util.List;

public class Main {

    private static Logger logger = LoggerFactory.getLogger(Main.class);

    private static String ID = "10000000000001";
    private static String IP = "192.168.80.123";

    public static void main(String[] args) {
        AbstractApplicationContext appContext = new ClassPathXmlApplicationContext("application04.xml");
        TreadContext context = appContext.getBean(TreadContext.class);
        MDC.put(Constant.TRANC_ID, ID);
        MDC.put(Constant.LOCAL_IP, "192.168.80.123");
        AbstractRunnable thread1 = new MyThread(ID, IP);
        AbstractRunnable thread2 = new MyThread(ID, IP);
        List<AbstractRunnable> threads = new ArrayList<AbstractRunnable>();
        threads.add(thread1);
        threads.add(thread2);
        context.source(threads).open();
        logger.info("thread name:{}  ,trace_id:{}  ,local_ip:{}", Thread.currentThread().getName(), MDC.get(Constant.TRANC_ID), MDC.get(Constant.LOCAL_IP));
        appContext.registerShutdownHook();
    }
}
  • 执行结果:

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
dubbo微服务分布式事务是指在使用dubbo框架进行微服务架构设计时,处理跨多个服务节点间的事务一致性问题的方法。 在分布式系统中,每个服务节点都可以独立运行并处理自己的业务逻辑,因此可能存在多个服务节点相互协作完成一个完整的事务。而分布式事务要求所有参与节点在提交或回滚时保持一致性,即要么都提交,要么都回滚,不能出现部分节点提交,部分节点回滚的情况。 为了解决这个问题dubbo提供了分布式事务解决方案。首先,可以通过编写一致的接口来规范事务操作的方法。通过在接口上添加@Transactional注解,可以标识该方法为事务处理方法。在方法执行时,dubbo会根据配置的事务管理器对事务进行管理,保证所有事务操作的一致性。 其次,dubbo可以与各种消息中间件集成,如RocketMQ、Kafka等,通过消息队列的方式实现分布式事务的异步提交。使用这种方式,可以先将事务操作记录到消息队列中,然后由消息队列负责保证所有操作的一致性。 另外,dubbo还提供了基于TCC(Try-Confirm-Cancel)模式的分布式事务解决方案。TCC模式通过在事务的预备阶段、确认阶段和取消阶段执行相应的操作,来确保所有参与节点在最终提交或回滚时保持一致性。在dubbo中,可以通过实现Transaction接口来自定义TCC模式的事务管理器,以满足各种业务场景的需求。 总的来说,dubbo微服务框架提供了多种解决方案来处理分布式事务,开发者可以根据具体的业务需求选择合适的方法来保证分布式系统的事务一致性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值