Spring源码阅读:Spring事务执行流程

news/2024/11/24 6:30:44/

一、概述

Spring事务执行的流程如下图,我们将按照下面的执行顺序,介绍Spring的事务。

 

二、代码分析

(一)核心流程

TransactionAspectSupport#invokeWithinTransaction 事务处理核心伪代码

// 通过事务调用
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,final InvocationCallback invocation) throws Throwable {// 获取事务属性源对象TransactionAttributeSource tas = getTransactionAttributeSource();// 通过事务属性源对象获取到当前方法的事务属性信息final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);// 获取配置的事务管理器对象DataSourceTransactionManagerfinal TransactionManager tm = determineTransactionManager(txAttr);// TransactionManager 转换为  PlatformTransactionManagerPlatformTransactionManager ptm = asPlatformTransactionManager(tm);// 获取连接点的唯一标识  类名+方法名final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);// 创建事务信息TransactionInfoTransactionInfo txInfo = createTransactionIfNecessary(ptm, txAttr, joinpointIdentification);Object retVal;try {// 执行被增强方法,调用具体的处理逻辑retVal = invocation.proceedWithInvocation();}catch (Throwable ex) {// 异常回滚completeTransactionAfterThrowing(txInfo, ex);throw ex;}finally {//清除事务信息,恢复线程私有的老的事务信息cleanupTransactionInfo(txInfo);}// 成功后提交,会进行资源储量,连接释放,恢复挂起事务等操作commitTransactionAfterReturning(txInfo);return retVal;}

  1、 getTransactionAttributeSource() 获取事务属性源对象,获取的是在IOC容器启动过程中,创建的NameMatchTransactionAttributeSource对象,内含属性nameMap,可通过方法名称获取方法对应的事务属性。

// key: 方法名称;value:方法的事务属性
2 private Map<String, TransactionAttribute> nameMap = new HashMap<>();

 2、determineTransactionManager(txAttr) 获取事务管理器,返回在IOC容器启动过程中,创建的DataSourceTransactionManager事务管理器对象。

  3、asPlatformTransactionManager(txAttr) 将DataSourceTransactionManager转换为PlatformTransactionManager。

  4、methodIdentification(method, targetClass, txAttr) 获取被增强方法的类名 + 方法名

  5、获取连接、开启事务 (包含事务传播特性的处理,执行insert、update、delete等被增强方法前的处理)

  6、执行被增强方法,数据库新增、删除、更新操作

  7、是否异常

   被增强方法执行异常,completeTransactionAfterThrowing(txInfo, ex) 事务回滚操作

   被增强方法执行无异常, commitTransactionAfterReturning(txInfo) 事务提交操作

(二)创建事务信息

protected TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm,@Nullable TransactionAttribute txAttr, final String joinpointIdentification) {// If no name specified, apply method identification as transaction name.// 如果没有名称指定则使用方法唯一标识,并使用DelegatingTransactionAttribute封装txAttrif (txAttr != null && txAttr.getName() == null) {txAttr = new DelegatingTransactionAttribute(txAttr) {@Overridepublic String getName() {return joinpointIdentification;}};}// 获取TransactionStatus事务状态信息,开启事务、获取jdbc连接TransactionStatus status = tm.getTransaction(txAttr);// 根据指定的属性与status准备TransactionInfo,return prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
}

1、封装事务属性对象

  用DelegatingTransactionAttribute对象封装事务属性对象TransactionAttribute,若事务属性对象的name属性为空,重写DelegatingTransactionAttribute的getName方法,将被增强方法的类名+方法名返回;

2、事务状态 - TransactionStatus

AbstractPlatformTransactionManager#getTransaction 获取事务状态信息核心伪代码

public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition)throws TransactionException {// 若不指定事务定义,则使用默认的事务定义StaticTransactionDefinitionTransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults());// 获取数据源对象 DataSourceTransactionObjectObject transaction = doGetTransaction();// 若已存在事务,按已存在事务流程执行if (isExistingTransaction(transaction)) {return handleExistingTransaction(def, transaction, debugEnabled);}// Mandatory支持当前事务,如果不存在就抛异常if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {throw new IllegalTransactionStateException("No existing transaction found for transaction marked with propagation 'mandatory'");}// 事务不存在,创建新事务else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {SuspendedResourcesHolder suspendedResources = suspend(null);try {// 开启事务(获取连接、开启事务)return startTransaction(def, transaction, debugEnabled, suspendedResources);}catch (RuntimeException | Error ex) {resume(null, suspendedResources);throw ex;}}else {// 创建一个空事务信息,用作事务同步boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);return prepareTransactionStatus(def, null, true, newSynchronization, debugEnabled, null);}
}

1、获取数据源事务对象DataSourceTransactionObject,含是否允许当前事务设置保存点、jdbc连接持有对象,此处有一个复用JDBC连接逻辑。

  TransactionSynchronizationManager.getResource(obtainDataSource()) 获取数据源对应的jdbc连接 核心伪代码

private static Object doGetResource(Object actualKey) {// 获取线程私有事务资源Map<Object, Object> map = resources.get();// 第一次创建事务,线程私有事务资源为空,后续创建,返回nullif (map == null) {return null;}// 获取线程私有事务资源中数据源对应的jdbc连接Object value = map.get(actualKey);// 如果value是ResourceHolder类型,并且已经解绑if (value instanceof ResourceHolder && ((ResourceHolder) value).isVoid()) {// 将该数据源从线程私有事务资源中的元素map里移除map.remove(actualKey);// 线程私有事务资源的map为空,清空线程私有事务资源if (map.isEmpty()) {resources.remove();}// 返回nullvalue = null;}// 返回数据源对应的jdbc连接return value;
}

2、isExistingTransaction(transaction) 若已存在事务,根据被增强方法的传播特性,判断是抛异常、新建事务、还是支持原有事务。

3、根据被增强方法的传播特性判断是抛异常、创建事务、按非事务方式执行。

  当然我们最关心的还是按照事务的方式来执行被增强方法,下面来看看被增强方法的事务是如何处理的。

(三)开启事务

  AbstractPlatformTransactionManager#startTransaction 开启事务核心伪代码

// 开启事务
private TransactionStatus startTransaction(TransactionDefinition definition, Object transaction,boolean debugEnabled, @Nullable SuspendedResourcesHolder suspendedResources) {// 是否需要新同步boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);// 创建新事务状态对象DefaultTransactionStatus status = newTransactionStatus(definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);// 获取连接、开启事务doBegin(transaction, definition);// 新同步事务的设置,针对于当前线程的设置prepareSynchronization(status, definition);return status;
}

1、获取事务是否需要同步标识

  用作后续prepareSynchronization对线程私有变量做初始化操作的判断;

2、创建事务状态对象

  AbstractPlatformTransactionManager#newTransactionStatus 创建事务状态对象

// 创建事务状态对象
protected DefaultTransactionStatus newTransactionStatus(TransactionDefinition definition, @Nullable Object transaction, boolean newTransaction,boolean newSynchronization, boolean debug, @Nullable Object suspendedResources) {// 重置同步标识,只有当前事务需要同步,并且未被激活,同步标识为trueboolean actualNewSynchronization = newSynchronization && !TransactionSynchronizationManager.isSynchronizationActive();// 创建DefaultTransactionStatus事务状态对象return new DefaultTransactionStatus(transaction, newTransaction, actualNewSynchronization, definition.isReadOnly(), debug, suspendedResources);
}

3、获取连接、开启事务

  DataSourceTransactionManager#doBegin 获取连接、开启事务核心伪代码:

// 获取连接、开启事务
protected void doBegin(Object transaction, TransactionDefinition definition) {// 强制转化事务对象DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;Connection con = null;try {// 判断事务对象没有数据库连接持有器if (!txObject.hasConnectionHolder() ||txObject.getConnectionHolder().isSynchronizedWithTransaction()) {// 通过数据源获取一个数据库连接对象Connection newCon = obtainDataSource().getConnection();// 把数据库连接包装成一个ConnectionHolder对象 然后设置到txObject对象中去txObject.setConnectionHolder(new ConnectionHolder(newCon), true);}// 标记当前的连接是一个同步事务txObject.getConnectionHolder().setSynchronizedWithTransaction(true);// 获取JDBC连接con = txObject.getConnectionHolder().getConnection();// 为当前的事务设置隔离级别Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);// 设置先前隔离级别txObject.setPreviousIsolationLevel(previousIsolationLevel);// 设置是否只读txObject.setReadOnly(definition.isReadOnly());// 关闭自动提交if (con.getAutoCommit()) {//设置需要恢复自动提交txObject.setMustRestoreAutoCommit(true);// 关闭自动提交con.setAutoCommit(false);}// 判断是否设置为只读事务prepareTransactionalConnection(con, definition);// 标记激活事务txObject.getConnectionHolder().setTransactionActive(true);// 设置事务超时时间int timeout = determineTimeout(definition);if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {txObject.getConnectionHolder().setTimeoutInSeconds(timeout);}// 绑定数据源和连接到同步管理器上,把数据源作为key,数据库连接作为value 设置到线程变量中if (txObject.isNewConnectionHolder()) {// 将当前获取到的连接绑定到当前线程TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());}}catch (Throwable ex) {if (txObject.isNewConnectionHolder()) {// 释放数据库连接DataSourceUtils.releaseConnection(con, obtainDataSource());txObject.setConnectionHolder(null, false);}throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);}
}

3.1、获取jdbc连接

  第一次创建事务,数据源属性对象中的数据库jdbc连接为空,通过数据源获取jdbc数据源连接。

3.2、填充数据源属性对象属性

  1、设置连接持有器中的事务为同步事务,设置数据源属性对象之前的隔离级别、设置只读属性;

  2、关闭jdbc连接的自动提交,开启事务;

  3、标记当前事务为激活状态,可用作后续prepareSynchronization对线程私有变量做初始化操作的判断;

3.3、绑定新的jdbc连接至当前线程的事务资源中

  若当前连接是一个新的jdbc连接,需要将当前jdbc连接绑定到线程当前线程私有的事务资源属性中TransactionSynchronizationManager#bindResource 核心伪代码如下:

// 绑定jdbc连接至当前线程的事务资源中
public static void bindResource(Object key, Object value) throws IllegalStateException {// 获取数据源Object actualKey = TransactionSynchronizationUtils.unwrapResourceIfNecessary(key);Assert.notNull(value, "Value must not be null");// 获取线程私有事务资源中jdbc连接Map<Object, Object> map = resources.get();// 第一次创建事务,事务资源未创建,初始化线程私有事务资源if (map == null) {map = new HashMap<>();resources.set(map);}// 将数据源作为key,jdbc连接作为value,绑定到线程私有的事务资源中Object oldValue = map.put(actualKey, value);// 若当前线程的事务资源中原有的value为ResourceHolder类型,并且已经解绑,将原有的事务资源value置空if (oldValue instanceof ResourceHolder && ((ResourceHolder) oldValue).isVoid()) {oldValue = null;}// 若当前线程的事务资源已经被绑定,抛异常if (oldValue != null) {throw new IllegalStateException("Already value [" + oldValue + "] for key [" +actualKey + "] bound to thread [" + Thread.currentThread().getName() + "]");}}

  当外层事务的传播特性为REQUIRED,内层的传播特性也为REQUIRED时,内层可复用外层创建的jdbc连接。通过数据源获取的jdbc连接是同一个。

(四)事务信息

  事务信息准备核心伪代码:

// 准备事务信息
protected TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm,@Nullable TransactionAttribute txAttr, String joinpointIdentification,@Nullable TransactionStatus status) {// 创建事务信息TransactionInfo txInfo = new TransactionInfo(tm, txAttr, joinpointIdentification);// 设置新事务状态txInfo.newTransactionStatus(status);// 事务信息绑定到当前线程txInfo.bindToThread();// 返回事务信息return txInfo;
}

1、创建事务信息

  创建TransactionInfo对象,封装事务管理器,事务注解属性,被增强方法类名+方法名,事务状态对象

2、事务信息绑定到当前线程

// 持有当前被增强方法的事务状态,支持多个被增强方法间的事务处理
private static final ThreadLocal<TransactionInfo> transactionInfoHolder =new NamedThreadLocal<>("Current aspect-driven transaction");// 将事务信息绑定到当前线程
private void bindToThread() {// 获取事务信息持有器原来的事务信息,并设置到oldTransactionInfo属性this.oldTransactionInfo = transactionInfoHolder.get();// 将当前线程的事务属性设置进事务持有器中transactionInfoHolder.set(this);
}

(五)事务信息

  TransactionAspectSupport#commitTransactionAfterReturning 调用事务管理器提交事务概览伪代码

// 提交事务
protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {// 事务信息不为空,并且事务信息对象持有事务状态不为空if (txInfo != null && txInfo.getTransactionStatus() != null) {// 调用事务信息对象中事务管理器的事务提交方法txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());}
}

1、提交处理

  AbstractPlatformTransactionManager#commit 事务提交伪代码

public final void commit(TransactionStatus status) throws TransactionException {// 获取事务状态对象DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;// 处理事务提交processCommit(defStatus);
}

  AbstractPlatformTransactionManager#processCommit 处理事务提交伪代码

private void processCommit(DefaultTransactionStatus status) throws TransactionException {try {//当前状态是新事务if (status.isNewTransaction()) {// 若当前事务为新事务,事务提交doCommit(status);}} finally {//根据条件,完成后数据清除,和线程的私有资源解绑,重置连接自动提交,隔离级别,是否只读,释放连接,恢复挂起事务等cleanupAfterCompletion(status);}
}

  DataSourceTransactionManager#doCommit 事务提交核心伪代码

protected void doCommit(DefaultTransactionStatus status) {// 获取事务状态中的数据源事务对象DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();// 获取数据源事务对象中连接持有器的jdbc连接Connection con = txObject.getConnectionHolder().getConnection();try {// jdbc连接事务提交con.commit();}
catch (SQLException ex) {throw new TransactionSystemException("Could not commit JDBC transaction", ex);}
}

  AbstractPlatformTransactionManager#cleanupAfterCompletion 提交完成时的清理核心伪代码

private void cleanupAfterCompletion(DefaultTransactionStatus status) {// 将当前事务设置为完成状态status.setCompleted();// 新事务完成事务提交,清理线程私有事务属性资源if (status.isNewSynchronization()) {TransactionSynchronizationManager.clear();}// 恢复jdbc连接相关操作if (status.isNewTransaction()) {doCleanupAfterCompletion(status.getTransaction());}// 恢复挂起事务if (status.getSuspendedResources() != null) {Object transaction = (status.hasTransaction() ? status.getTransaction() : null);resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources());}
}

  TransactionSynchronizationManager#clear() 清除当前线程私有的事务同步信息核心代码

// 事务同步
private static final ThreadLocal<Set<TransactionSynchronization>> synchronizations = new NamedThreadLocal<>("Transaction synchronizations");// 当前事务的名称
private static final ThreadLocal<String> currentTransactionName = new NamedThreadLocal<>("Current transaction name");// 当前事务是否只读
private static final ThreadLocal<Boolean> currentTransactionReadOnly = new NamedThreadLocal<>("Current transaction read-only status");// 当前事务的隔离级别
private static final ThreadLocal<Integer> currentTransactionIsolationLevel = new NamedThreadLocal<>("Current transaction isolation level");// 实际事务是否激活
private static final ThreadLocal<Boolean> actualTransactionActive = new NamedThreadLocal<>("Actual transaction active");public static void clear() {synchronizations.remove();currentTransactionName.remove();currentTransactionReadOnly.remove();currentTransactionIsolationLevel.remove();actualTransactionActive.remove();}

  DataSourceTransactionManager#doCleanupAfterCompletion jdbc连接相关操作核心伪代码。  jdbc连接解绑、属性恢复、连接释放、连接关闭及数据源事务对象持有jdbc连接释放操作。

// 事务提交后jdbc连接相关处理
protected void doCleanupAfterCompletion(Object transaction) {// 获取数据源事务对象DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;// 新事务,将数据库连接从当前线程中解除绑定if (txObject.isNewConnectionHolder()) {TransactionSynchronizationManager.unbindResource(obtainDataSource());}// 获取连接Connection con = txObject.getConnectionHolder().getConnection();// 关闭事务,恢复数据库连接的自动提交属性if (txObject.isMustRestoreAutoCommit()) {con.setAutoCommit(true);}// 重置数据库jdbc连接, 恢复原有隔离级别、是否只读属性DataSourceUtils.resetConnectionAfterTransaction(con, txObject.getPreviousIsolationLevel(), txObject.isReadOnly());// 当前事务是独立的新创建的事务,在事务完成时释放数据库连接并关闭连接if (txObject.isNewConnectionHolder()) {DataSourceUtils.releaseConnection(con, this.dataSource);}// 清除数据源事务对象中的连接持有器txObject.getConnectionHolder().clear();
}

  AbstractPlatformTransactionManager#resume 恢复外层原挂起事务核心代码

// 恢复外层挂起事务
protected final void resume(@Nullable Object transaction, @Nullable SuspendedResourcesHolder resourcesHolder)throws TransactionException {// 若存在挂起事务,恢复挂起事务if (resourcesHolder != null) {// 获取挂起事务的资源属性Object suspendedResources = resourcesHolder.suspendedResources;// 挂起事务的资源属性不为空,将事务属性资源绑定到线程私有的事务属性资源中if (suspendedResources != null) {doResume(transaction, suspendedResources);}}
}

2、回滚处理

  TransactionAspectSupport#completeTransactionAfterThrowing 事务回滚概览伪代码:

// 异常时事务处理
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {if (txInfo != null && txInfo.getTransactionStatus() != null) {// 事务信息中事务属性不为空,并且事务属性中回滚if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {// 进行回滚txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());}else {// 回滚标识rollBackOnly为 false,执行提交txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());}}
}

  DefaultTransactionAttribute#rollbackOn 是否回滚判断标识

// 未捕获异常的回滚操作
public boolean rollbackOn(Throwable ex) {return (ex instanceof RuntimeException || ex instanceof Error);
}

  AbstractPlatformTransactionManager#processRollback 回滚核心伪代码

// 处理回滚
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {try {// 当前事务是一个新事务if (status.isNewTransaction()) {// 进行回滚doRollback(status);}}finally {// 回滚完成时的处理cleanupAfterCompletion(status);}
}

  DataSourceTransactionManager#doRollback 事务回滚核心伪代码

@Override
protected void doRollback(DefaultTransactionStatus status) {// 获取事务状态中的数据源事务对象DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();// 获取数据源事务对象中连接持有器的jdbc连接Connection con = txObject.getConnectionHolder().getConnection();try {// jdbc的回滚con.rollback();}catch (SQLException ex) {throw new TransactionSystemException("Could not roll back JDBC transaction", ex);}
}

参考文章:

Spring 事务源码分析_spring事务源码分析_J3code的博客-CSDN博客

Spring事务源码分析_spring事务源码深度解析_程序员小潘的博客-CSDN博客

https://www.cnblogs.com/wt20/p/10957371.html

https://www.cnblogs.com/RunningSnails/p/17015808.html

Spring事务流程源码剖析+传播行为运用案例+心得 - 知乎

十八、spring 事务之事务执行流程 - 简书

https://www.cnblogs.com/RunningSnails/p/17015808.html

https://www.cnblogs.com/RunningSnails/p/17017176.html

https://www.cnblogs.com/RunningSnails/p/17020456.html

https://www.cnblogs.com/RunningSnails/p/17023323.html

https://www.cnblogs.com/RunningSnails/p/17025931.html


http://www.ppmy.cn/news/76862.html

相关文章

linux系统打包压缩与搜索命令

1、tar命令 在linux系统中&#xff0c;常见的文件格式比较多&#xff0c;其中主要使用使用的tar和zip来压缩文件&#xff0c;tar命令的参数比较多&#xff0c;这里呢我一般只会记得几个比较常用的。 -c创建压缩文件-x解开压缩文件-z用Gzip压缩或解压-v显示压缩或者解压的过程-…

一台电脑同时安装多个tomcat服务器教程,window同时安装tomcat7、tomcat8、tomcat9三个服务器教程

一台电脑同时安装多个tomcat服务器 . 介绍 A. 解释为什么有时需要同时安装多个Tomcat服务器 应用程序隔离&#xff1a;当你需要在同一台设备上运行多个独立的应用程序时&#xff0c;每个应用程序可能需要使用不同的Tomcat配置和环境。通过同时安装多个Tomcat服务器&#xff0…

C语言入门级小游戏——三子棋

文章目录 游戏文件的创建游戏菜单重头戏&#xff0c;游戏正式开始棋盘的创建数据清空打印棋盘 玩家下棋电脑下棋输赢的判断1.赢2.平局&#xff0c;游戏继续 代码展示 今天我们写一个小游戏——三子棋来增加我们对编程的兴趣&#xff0c; 希望这篇文章对友友们有帮助! 游戏文件的…

聚焦金融行业网络安全|安全狗亮相知虎科技生态大会

5月18日&#xff0c;知虎科技生态大会在上海顺利举办。作为国内云原生安全领导厂商&#xff0c;安全狗也受邀出席此次活动。 据悉&#xff0c;此次大会邀请了来自国内顶级安全厂商的安全专家介绍从网络安全、应用安全、业务安全、数据安全、资金安全、通信安全等六个方面全方位…

C++继承技术

方法覆盖 virtual关键字 只有在基类中声明为 virtual 的方法才能被派生类正确覆盖。关键字位于方法声明的开头&#xff0c;如下面的 Base 的修改版本所示&#xff1a; class Base {public:virtual void someMethod() {}protected:int m_protectedInt { 0 };private:int m_pr…

BigDecimal加减乘除计算

1、BigDecimal概述 Java在java.math包中提供的API类BigDecimal&#xff0c;用来对超过16位有效位的数进行精确的运算。双精度浮点型变量double可以处理16位有效数&#xff0c;但在实际应用中&#xff0c;可能需要对更大或者更小的数进行运算和处理。一般情况下&#xff0c;对于…

[Tool]ansible与playbook简介

文章目录 ansible安装配置ansible.cfg 命令与模块相关模块setup模块 playbookFacts基本语法变量变量作用域逻辑控制语句重用标签lookup访问数据过滤器filter条件测试 lineinfile模块role ansible是基于Python开发的自动化运维工具&#xff0c;集合了众多运维工具&#xff08;pu…

Linkerd部署模式

per-host linkerd作为独立进程运行在每台机器(物理机/虚拟机)上,服务所有运行在该机器的服务实例。 各个服务产生的流量都需要经过Linkerd,然后转发到目标服务 sidecar linkerd和服务部署在一起,每个服务配套自己的linkerd 一台机器上可能同时存在多个linkerd进程 per…