Azure ManagedIdentityCredential认证失败:信号量超最大计数问题排查
我用以下C#代码从Azure获取访问令牌:
var credentialsProvider = new DefaultAzureCredential( new DefaultAzureCredentialOptions{ ManagedIdentityClientId = "XYZ" }); var accessToken = await credentialsProvider.GetTokenAsync(new TokenRequestContext(_scopes), cancellationToken);
这段代码偶尔会抛出如下异常:
ManagedIdentityCredential authentication failed: Adding the specified count to the semaphore would cause it to exceed its maximum count. See the troubleshooting guide for more information. https://aka.ms/azsdk/net/identity/managedidentitycredential/troubleshoot
Azure.Identity.AuthenticationFailedException: ManagedIdentityCredential authentication failed: Adding the specified count to the semaphore would cause it to exceed its maximum count. See the troubleshooting guide for more information. https://aka.ms/azsdk/net/identity/managedidentitycredential/troubleshoot
---> System.Threading.SemaphoreFullException: Adding the specified count to the semaphore would cause it to exceed its maximum count.
at System.Threading.SemaphoreSlim.Release(Int32 releaseCount)
at Microsoft.Identity.Client.Internal.Requests.ClientCredentialRequest.GetAccessTokenAsync(CancellationToken cancellationToken, ILoggerAdapter logger)
at Microsoft.Identity.Client.Internal.Requests.ClientCredentialRequest.ExecuteAsync(CancellationToken cancellationToken)
at Microsoft.Identity.Client.Internal.Requests.RequestBase.RunAsync(CancellationToken cancellationToken)
at Microsoft.Identity.Client.ApiConfig.Executors.ConfidentialClientExecutor.ExecuteAsync(AcquireTokenCommonParameters commonParameters, AcquireTokenForClientParameters clientParameters, CancellationToken cancellationToken)
at Azure.Identity.AbstractAcquireTokenParameterBuilderExtensions.ExecuteAsync[T](AbstractAcquireTokenParameterBuilder`1 builder, Boolean async, CancellationToken cancellationToken)
at Azure.Identity.MsalConfidentialClient.AcquireTokenForClientCoreAsync(String[] scopes, String tenantId, Boolean enableCae, Boolean async, CancellationToken cancellationToken)
at Azure.Identity.MsalConfidentialClient.AcquireTokenForClientAsync(String[] scopes, String tenantId, Boolean enableCae, Boolean async, CancellationToken cancellationToken)
at Azure.Identity.ManagedIdentityClient.AuthenticateAsync(Boolean async, TokenRequestContext context, CancellationToken cancellationToken)
at Azure.Identity.ManagedIdentityCredential.GetTokenImplAsync(Boolean async, TokenRequestContext requestContext, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at Azure.Identity.CredentialDiagnosticScope.FailWrapAndThrow(Exception ex, String additionalMessage, Boolean isCredentialUnavailable)
at Azure.Identity.ManagedIdentityCredential.GetTokenImplAsync(Boolean async, TokenRequestContext requestContext, CancellationToken cancellationToken)
at Azure.Identity.ManagedIdentityCredential.GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)
at Azure.Identity.DefaultAzureCredential.GetTokenFromSourcesAsync(TokenCredential[] sources, TokenRequestContext requestContext, Boolean async, CancellationToken cancellationToken)
at Azure.Identity.DefaultAzureCredential.GetTokenImplAsync(Boolean async, TokenRequestContext requestContext, CancellationToken cancellationToken)
at Azure.Identity.CredentialDiagnosticScope.FailWrapAndThrow(Exception ex, String additionalMessage, Boolean isCredentialUnavailable)
at Azure.Identity.DefaultAzureCredential.GetTokenImplAsync(Boolean async, TokenRequestContext requestContext, CancellationToken cancellationToken)
at Azure.Identity.DefaultAzureCredential.GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)
我怀疑问题和高负载或资源泄漏有关,但尝试单线程调用10000次、多线程并发调用都没复现异常,想知道可能的原因和解决思路。
可能原因
- MSAL库内部信号量逻辑bug:从堆栈跟踪看,异常来自MSAL的
ClientCredentialRequest.GetAccessTokenAsync方法中SemaphoreSlim.Release的调用,说明库内部存在信号量释放次数超过初始计数的逻辑错误。这类问题通常是并发场景下的边缘情况,比如请求中途取消后重复释放信号量、异步操作状态管理不当等。 - 生产环境特定触发条件:本地测试的并发模型、网络环境和生产环境存在差异,生产环境可能存在更长的请求延迟、突发的高并发请求、网络波动导致的请求重试等场景,这些更容易触发信号量异常。
- Credential实例重复创建:如果代码中每次请求都新建
DefaultAzureCredential实例,会导致内部MSAL客户端重复初始化,多个实例的资源可能相互干扰,提升异常触发概率。
解决思路
- 升级依赖库版本:这类内部逻辑bug通常会在后续版本中修复,检查并将
Azure.Identity和Microsoft.Identity.Client包升级到最新稳定版。 - 复用Credential实例:
DefaultAzureCredential是线程安全的,应全局复用单个实例,而非每次请求都创建,减少内部资源的重复初始化和冲突。 - 添加异常重试机制:针对包含
SemaphoreFullException的AuthenticationFailedException添加重试逻辑,这类偶发异常通过重试通常可以成功。 - 分析生产环境特征:收集生产环境异常发生时的并发量、请求频率、网络状态等日志,定位触发异常的具体场景,再针对性复现验证。
- 直接使用ManagedIdentityCredential:如果不需要
DefaultAzureCredential的其他认证源(如环境变量、CLI凭据),可直接使用ManagedIdentityCredential,减少不必要的认证逻辑,降低异常概率。
内容的提问来源于stack exchange,提问作者GrzegorzM

