Today Solomon_ Xiao Ge plays the architecture, to talk to you about how XID is delivered in all micro-services, what technology is used to accomplish this task, this question is a frequent question in micro-services interview.

How is distributed transaction XID passed

XID delivery strategy for the Seata framework

Delivery of distributed transaction XIDS in Dubbo

XID context container structure

Dubbo XID integrates core code

“ApacheDubboTransactionPropagationFilter”

@Activate(group = {Constants.PROVIDER, Constants.CONSUMER}, order = 100)
public class TransactionPropagationFilter implements Filter {

    @Override
    public Result invoke(Invoker
        invoker, Invocation invocation) throws RpcException {
        // Get the local XID
        String xid = RootContext.getXID();
        String xidInterceptorType = RootContext.getXIDInterceptorType();
        // Get the XID of the implicit Dubbo parameter
        String rpcXid = getRpcXid();
        String rpcXidInterceptorType = RpcContext.getContext().getAttachment(RootContext.KEY_XID_INTERCEPTOR_TYPE);
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("xid in RootContext[{}] xid in RpcContext[{}]", xid, rpcXid);
        }
        boolean bind = false;
        if(xid ! =null) {
            / / pass XID
            RpcContext.getContext().setAttachment(RootContext.KEY_XID, xid);
            RpcContext.getContext().setAttachment(RootContext.KEY_XID_INTERCEPTOR_TYPE, xidInterceptorType);
        } else {
            if(rpcXid ! =null) {
                / / bind XID
                RootContext.bind(rpcXid);
                RootContext.bindInterceptorType(rpcXidInterceptorType);
                bind = true;
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("bind[{}] interceptorType[{}] to RootContext", rpcXid, rpcXidInterceptorType); }}}try {
            return invoker.invoke(invocation);
        } finally {
            if (bind) {
                // Perform the XID to exclude completed transactions
                String unbindInterceptorType = RootContext.unbindInterceptorType();
                String unbindXid = RootContext.unbind();
                if (LOGGER.isDebugEnabled()) {
                    LOGGER.debug("unbind[{}] interceptorType[{}] from RootContext", unbindXid, unbindInterceptorType);
                }
                // If it is found that the unbound XID is not the currently received XID
                if(! rpcXid.equalsIgnoreCase(unbindXid)) { LOGGER.warn("xid in change during RPC from {} to {}, xidInterceptorType from {} to {} ", rpcXid, unbindXid, rpcXidInterceptorType, unbindInterceptorType);
                    if(unbindXid ! =null) {
                        // rebind XID
                        RootContext.bind(unbindXid);
                        RootContext.bindInterceptorType(unbindInterceptorType);
                        LOGGER.warn("bind [{}] interceptorType[{}] back to RootContext", unbindXid, unbindInterceptorType);
                    }
                }
            }
        }
    }

    /**
     * get rpc xid
     * @return* /
    private String getRpcXid(a) {
        String rpcXid = RpcContext.getContext().getAttachment(RootContext.KEY_XID);
        if (rpcXid == null) {
            rpcXid = RpcContext.getContext().getAttachment(RootContext.KEY_XID.toLowerCase());
        }
        returnrpcXid; }}Copy the code

SPI integration mode

io.seata.integration.dubbo.ApacheDubboTransactionPropagationFilter

Delivery of distributed transaction Xids in Http

Spring Servlet interceptor integration

Http service XID integration core code

/** * transaction delivery interceptor **/
public class TransactionPropagationIntercepter extends HandlerInterceptorAdapter {

    // preprocessing
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        // Context fetch xID
        String xid = RootContext.getXID();
        // The request header gets the remote XID
        String rpcXid = request.getHeader(RootContext.KEY_XID);

        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("xid in RootContext[{}] xid in HttpContext[{}]", xid, rpcXid);
        }
        if(rpcXid ! =null) {
            // Context binding
            RootContext.bind(rpcXid);
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("bind[{}] to RootContext", rpcXid); }}return true;
    }

    // post-processing
    public void postHandle( HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {      
        / / clean up XIDXidResource.cleanXid(request.getHeader(RootContext.KEY_XID)); }}Copy the code

Spring Factory Configuration

SPI integration mode

# Auto Configuration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
io.seata.integration.http.HttpAutoConfiguration
Copy the code

Delivery of distributed transaction XIDS in Motan

Motan XID integrates core code

@Spi(scope = Scope.SINGLETON)
@Activation(key = {MotanConstants.NODE_TYPE_SERVICE, MotanConstants.NODE_TYPE_REFERER}, sequence = 100)
public class MotanTransactionFilter implements Filter {

    public MotanTransactionFilter(a){}
    @Override
    public Response filter(finalCaller<? > caller,final Request request) {
        // Get the existing XID from the context
        String currentXid = RootContext.getXID();
        // Get the XID passed remotely
        String requestXid = getRpcXid(request);
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("xid in RootContext [" + currentXid + "] xid in Request [" + requestXid + "]");
        }
        boolean bind = false;
        if(currentXid ! =null) {
            // Get the XID from the request object
            request.getAttachments().put(RootContext.KEY_XID, currentXid);
        } else if (null! = requestXid) {// Context binding XID
            RootContext.bind(requestXid);
            bind = true;

        }
        try {
            // Remote call
            return caller.call(request);
        } finally {
            if (bind) {
                // Context unbind XID
                String unbindXid = RootContext.unbind();
                if(! requestXid.equalsIgnoreCase(unbindXid)) {if(unbindXid ! =null) {
                        RootContext.bind(unbindXid);
                        LOGGER.warn("bind [" + unbindXid + "] back to RootContext");
                    }
                }
            }
        }
    }

    /** * get RPC xid *@param request
     * @return* /
    private String getRpcXid(Request request) {
        String rpcXid = request.getAttachments().get(RootContext.KEY_XID);
        if (rpcXid == null) {
            rpcXid = request.getAttachments().get(RootContext.KEY_XID.toLowerCase());
        }
        returnrpcXid; }}Copy the code

SPI integration mode

Interceptor configuration

io.seata.integration.motan.MotanTransactionFilter

Transfer of distributed transaction XID in Sofa- RPC

Sofa- RPC service provider XID integrates core code

@Extension(value = "transactionContextProvider")
@AutoActive(providerSide = true)
public class TransactionContextProviderFilter extends Filter {
    @Override
    public SofaResponse invoke(FilterInvoker filterInvoker, SofaRequest sofaRequest) throws SofaRpcException {
        // Get XID from context
        String xid = RootContext.getXID();
        // Get the XID from the request
        String rpcXid = getRpcXid(sofaRequest);
        boolean bind = false;
        if(xid ! =null) {
            // Set XID from RPC context
            RpcInternalContext.getContext().setAttachment(RootContext.KEY_XID, xid);
        } else {
            if(rpcXid ! =null) {
                // Context binding XID
                RootContext.bind(rpcXid);
                bind = true; }}try {
            // Remote call
            return filterInvoker.invoke(sofaRequest);
        } finally {
            if (bind) {
                // Context releases XID
                String unbindXid = RootContext.unbind();
                if(! rpcXid.equalsIgnoreCase(unbindXid)) {if(unbindXid ! =null) {
                        RootContext.bind(unbindXid);
                    }
                }
            }
        }
    }

    /** * get RPC xid *@return* /
    private String getRpcXid(SofaRequest sofaRequest) {
        String rpcXid = (String) sofaRequest.getRequestProp(RootContext.KEY_XID);
        if (rpcXid == null) {
            rpcXid = (String) sofaRequest.getRequestProp(RootContext.KEY_XID.toLowerCase());
        }
        returnrpcXid; }}Copy the code

Sofa- RPC service consumer XID integration core code

@Extension(value = "transactionContextConsumer")
@AutoActive(consumerSide = true)
public class TransactionContextConsumerFilter extends Filter {
 
    @Override
    public SofaResponse invoke(FilterInvoker filterInvoker, SofaRequest sofaRequest) throws SofaRpcException {
        // Get the XID in the existing context
        String xid = RootContext.getXID();
        // Get the XID from the request
        String rpcXid = getRpcXid();
 
        boolean bind = false;
        if(xid ! =null) {
            // Request the object to get the XID
            sofaRequest.addRequestProp(RootContext.KEY_XID, xid);
        } else {
            if(rpcXid ! =null) {
                // Context binding XID
                RootContext.bind(rpcXid);
                bind = true; }}try {
            // Remote call
            return filterInvoker.invoke(sofaRequest);
        } finally {
            if (bind) {
                // Context releases the XID binding
                String unbindXid = RootContext.unbind();
                if(! rpcXid.equalsIgnoreCase(unbindXid)) {if(unbindXid ! =null) {
                        RootContext.bind(unbindXid);
                    }
                }
            }
        }
    }

    /** * get RPC xid *@return* /
    private String getRpcXid(a) {
        String rpcXid = (String) RpcInternalContext.getContext().getAttachment(RootContext.KEY_XID);
        if (rpcXid == null) {
            rpcXid = (String) RpcInternalContext.getContext().getAttachment(RootContext.KEY_XID.toLowerCase());
        }
        returnrpcXid; }}Copy the code

SPI integration mode

io.seata.integration.sofa.rpc.TransactionContextProviderFilter
io.seata.integration.sofa.rpc.TransactionContextConsumerFilter
Copy the code

Your “like” is the best support and motivation for me. Pay attention to Solomon_ Xiao Ge shell structure, follow-up efforts to launch high-quality content.

Chat 🏆 technology project stage v | distributed those things…