今天Solomon_肖哥弹架构,来跟大家聊聊XID如何在所有微服务中进行传递,利用了什么技术完成该任务,该问题在微服务面试中属于高频题。
分布式事务XID如何传递
Seata 框架的XID传递策略
分布式事务XID在Dubbo中的传递
XID上下文容器结构
Dubbo XID整合核心代码
"ApacheDubboTransactionPropagationFilter"
@Activate(group = {Constants.PROVIDER, Constants.CONSUMER}, order = 100)
public class TransactionPropagationFilter implements Filter {
@Override
public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
//获取本地XID
String xid = RootContext.getXID();
String xidInterceptorType = RootContext.getXIDInterceptorType();
//获取Dubbo隐式传参中的XID
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) {
//传递XID
RpcContext.getContext().setAttachment(RootContext.KEY_XID, xid);
RpcContext.getContext().setAttachment(RootContext.KEY_XID_INTERCEPTOR_TYPE, xidInterceptorType);
} else {
if (rpcXid != null) {
//绑定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) {
//进行剔除已完成事务的XID
String unbindInterceptorType = RootContext.unbindInterceptorType();
String unbindXid = RootContext.unbind();
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("unbind[{}] interceptorType[{}] from RootContext", unbindXid, unbindInterceptorType);
}
//如果发现解绑的XID并不是当前接收到的XID
if (!rpcXid.equalsIgnoreCase(unbindXid)) {
LOGGER.warn("xid in change during RPC from {} to {}, xidInterceptorType from {} to {} ", rpcXid, unbindXid, rpcXidInterceptorType, unbindInterceptorType);
if (unbindXid != null) {
//重新绑定XID
RootContext.bind(unbindXid);
RootContext.bindInterceptorType(unbindInterceptorType);
LOGGER.warn("bind [{}] interceptorType[{}] back to RootContext", unbindXid, unbindInterceptorType);
}
}
}
}
}
/**
* get rpc xid
* @return
*/
private String getRpcXid() {
String rpcXid = RpcContext.getContext().getAttachment(RootContext.KEY_XID);
if (rpcXid == null) {
rpcXid = RpcContext.getContext().getAttachment(RootContext.KEY_XID.toLowerCase());
}
return rpcXid;
}
}
SPI 整合方式
io.seata.integration.dubbo.ApacheDubboTransactionPropagationFilter
分布式事务XID在 Http中的传递
Spring Servlet拦截器整合方式
Http 服务XID整合核心代码
/**
*事务传递拦截器
**/
public class TransactionPropagationIntercepter extends HandlerInterceptorAdapter {
//前置处理
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
//上下文获取xid
String xid = RootContext.getXID();
//请求头获取远程XID
String rpcXid = request.getHeader(RootContext.KEY_XID);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("xid in RootContext[{}] xid in HttpContext[{}]", xid, rpcXid);
}
if (rpcXid != null) {
//上下文绑定
RootContext.bind(rpcXid);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("bind[{}] to RootContext", rpcXid);
}
}
return true;
}
//后置处理
public void postHandle(
HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) {
//清理XID
XidResource.cleanXid(request.getHeader(RootContext.KEY_XID));
}
}
Spring 工厂配置
SPI 整合方式
# Auto Configuration
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
io.seata.integration.http.HttpAutoConfiguration
分布式事务XID在 Motan中的传递
Motan XID 整合核心代码
@Spi(scope = Scope.SINGLETON)
@Activation(key = {MotanConstants.NODE_TYPE_SERVICE, MotanConstants.NODE_TYPE_REFERER}, sequence = 100)
public class MotanTransactionFilter implements Filter {
public MotanTransactionFilter(){}
@Override
public Response filter(final Caller<?> caller, final Request request) {
//从上下文中获取已有的XID
String currentXid = RootContext.getXID();
//获取远程传递的XID
String requestXid = getRpcXid(request);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("xid in RootContext [" + currentXid + "] xid in Request [" + requestXid + "]");
}
boolean bind = false;
if (currentXid != null) {
//从请求对象中获取XID
request.getAttachments().put(RootContext.KEY_XID, currentXid);
} else if (null != requestXid) {
//上下文绑定XID
RootContext.bind(requestXid);
bind = true;
}
try {
//远程调用
return caller.call(request);
} finally {
if (bind) {
//上下文解绑XID
String unbindXid = RootContext.unbind();
if (!requestXid.equalsIgnoreCase(unbindXid)) {
if (unbindXid != null) {
RootContext.bind(unbindXid);
LOGGER.warn("bind [" + unbindXid + "] back to RootContext");
}
}
}
}
}
/**
* 获取 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());
}
return rpcXid;
}
}
SPI 整合方式
#拦截器配置
io.seata.integration.motan.MotanTransactionFilter
分布式事务XID在 Sofa-rpc中的传递
Sofa-rpc 服务提供者XID 整合核心代码
@Extension(value = "transactionContextProvider")
@AutoActive(providerSide = true)
public class TransactionContextProviderFilter extends Filter {
@Override
public SofaResponse invoke(FilterInvoker filterInvoker, SofaRequest sofaRequest) throws SofaRpcException {
//从上下文中获取XID
String xid = RootContext.getXID();
//从请求中获取XID
String rpcXid = getRpcXid(sofaRequest);
boolean bind = false;
if (xid != null) {
//从RPC上下文中设置XID
RpcInternalContext.getContext().setAttachment(RootContext.KEY_XID, xid);
} else {
if (rpcXid != null) {
//上下文绑定XID
RootContext.bind(rpcXid);
bind = true;
}
}
try {
//远程调用
return filterInvoker.invoke(sofaRequest);
} finally {
if (bind) {
//上下文释放XID
String unbindXid = RootContext.unbind();
if (!rpcXid.equalsIgnoreCase(unbindXid)) {
if (unbindXid != null) {
RootContext.bind(unbindXid);
}
}
}
}
}
/**
* 获取 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());
}
return rpcXid;
}
}
Sofa-rpc 服务消费者XID 整合核心代码
@Extension(value = "transactionContextConsumer")
@AutoActive(consumerSide = true)
public class TransactionContextConsumerFilter extends Filter {
@Override
public SofaResponse invoke(FilterInvoker filterInvoker, SofaRequest sofaRequest) throws SofaRpcException {
//获取已有上下文中的XID
String xid = RootContext.getXID();
//从请求中获取XID
String rpcXid = getRpcXid();
boolean bind = false;
if (xid != null) {
//请求对象获取XID
sofaRequest.addRequestProp(RootContext.KEY_XID, xid);
} else {
if (rpcXid != null) {
//上下文绑定XID
RootContext.bind(rpcXid);
bind = true;
}
}
try {
//远程调用
return filterInvoker.invoke(sofaRequest);
} finally {
if (bind) {
//上下文释放XID绑定
String unbindXid = RootContext.unbind();
if (!rpcXid.equalsIgnoreCase(unbindXid)) {
if (unbindXid != null) {
RootContext.bind(unbindXid);
}
}
}
}
}
/**
* 获取 rpc xid
* @return
*/
private String getRpcXid() {
String rpcXid = (String) RpcInternalContext.getContext().getAttachment(RootContext.KEY_XID);
if (rpcXid == null) {
rpcXid = (String) RpcInternalContext.getContext().getAttachment(RootContext.KEY_XID.toLowerCase());
}
return rpcXid;
}
}
SPI 整合方式
io.seata.integration.sofa.rpc.TransactionContextProviderFilter
io.seata.integration.sofa.rpc.TransactionContextConsumerFilter
你的点赞就是对我最好的支持与动力。 关注Solomon_肖哥弹架构,后续努力推出优质的内容。