- Introdução
- Requisitos
- Melhores práticas
- Instalação
- Atualizando
- Servidor de Identidade
- Solução de problemas de erros de inicialização
Melhores práticas de desempenho
A página a seguir descreve os requisitos recomendados para ambientes de produção de grande escala e fornece um conjunto de práticas recomendadas para melhorar seu desempenho.
Para executar 10K Robôs Assistidos ou 1K Robôs Não Assistidos, você precisa de:
- Um balanceador de carga F5
- Orchestrator - pelo menos 6 nós sendo executados em máquinas com 8 núcleos de CPU e 16 GB de RAM
- Robôs - máquinas com 4 núcleos de CPU e 16 GB de RAM
-
SQL Server - máquinas com 4 soquetes / 16 núcleos de CPU (padrão 8 soquetes / 16 núcleos de CPU) e 64 GB de RAM
Observação: para reduzir a contenção de alocação do SQL Server em um ambiente altamente simultâneo, certifique-se de empregar um número ideal de arquivos de dados tempdb que tenham tamanho igual.
UiPathOrchestrator.dll.config
do Orchestrator para melhorar o desempenho em um ambiente de produção de grande escala.
<appSettings>
<add key="LoadBalancer.UseRedis" value="true"/>
<add key="LoadBalancer.Redis.ConnectionString" value="your.redis.cache.windows.net:6379,password=***"/>
</appSettings>
<appSettings>
<add key="LoadBalancer.UseRedis" value="true"/>
<add key="LoadBalancer.Redis.ConnectionString" value="your.redis.cache.windows.net:6379,password=***"/>
</appSettings>
<connectionStrings>
<add name="Default" providerName="System.Data.SqlClient" connectionString="Data Source=<SQLServer>;Initial Catalog=<dbName>;User ID=<username>;Password=***;Max Pool Size=1000" />
</connectionStrings>
<connectionStrings>
<add name="Default" providerName="System.Data.SqlClient" connectionString="Data Source=<SQLServer>;Initial Catalog=<dbName>;User ID=<username>;Password=***;Max Pool Size=1000" />
</connectionStrings>
- Adicione ou modifique o destino de logs para o Elasticsearch usando os parâmetros a seguir.
xml <nlog> <targets> <target name="robotElasticBuffer" xsi:type="AsyncWrapper" overflowAction="Grow" queueLimit="10000" batchSize="1000" timeToSleepBetweenBatches="1"> <target xsi:type="ElasticSearch" name="robotElastic" uri="elastic.example.com:9200" requireAuth="true" username="***" password="***" index="${event-properties:item=indexName}-${date:format=yyyy.MM}" documentType="logEvent" includeAllProperties="true" layout="${message}" excludedProperties="agentSessionId,tenantId,indexName" /> </target> </targets> </nlog>
xml <nlog> <targets> <target name="robotElasticBuffer" xsi:type="AsyncWrapper" overflowAction="Grow" queueLimit="10000" batchSize="1000" timeToSleepBetweenBatches="1"> <target xsi:type="ElasticSearch" name="robotElastic" uri="elastic.example.com:9200" requireAuth="true" username="***" password="***" index="${event-properties:item=indexName}-${date:format=yyyy.MM}" documentType="logEvent" includeAllProperties="true" layout="${message}" excludedProperties="agentSessionId,tenantId,indexName" /> </target> </targets> </nlog> - Adicione ou modifique a regra de logs do robô para gravar logs apenas no destino mostrado no exemplo anterior. Isso desabilita automaticamente o destino do Banco de Dados padrão.
xml <nlog> <rules> <logger name="Robot.*" ruleName="primaryRobotLogsTarget" final="true" writeTo="robotElasticBuffer" /> </rules> </nlog>
xml <nlog> <rules> <logger name="Robot.*" ruleName="primaryRobotLogsTarget" final="true" writeTo="robotElasticBuffer" /> </rules> </nlog> - Configure o Orchestrator para ler logs a partir do ElasticSearch.
<appSettings> <add key="Logs.RobotLogs.ReadTarget" value="robotElasticBuffer" /> </appSettings>
<appSettings> <add key="Logs.RobotLogs.ReadTarget" value="robotElasticBuffer" /> </appSettings>
Você pode optar pelo Azure Blob Storage para esse fim.
<appSettings>
<add key="Storage.Type" value="Azure" />
<add key="Storage.Location" value="DefaultEndpointsProtocol=https;AccountName=yourBlob;AccountKey=yourKey;EndpointSuffix=core.windows.net" />
</appSettings>
<appSettings>
<add key="Storage.Type" value="Azure" />
<add key="Storage.Location" value="DefaultEndpointsProtocol=https;AccountName=yourBlob;AccountKey=yourKey;EndpointSuffix=core.windows.net" />
</appSettings>
Se você não for usar o recurso do Webhooks, você pode desabilitá-lo.
<appSettings>
<add key="Webhooks.Enabled" value="false" />
<add key="Ledger.Enabled" value="false"/>
<add key="Webhooks.LedgerIntegration.Enabled" value="false" />
</appSettings>
<appSettings>
<add key="Webhooks.Enabled" value="false" />
<add key="Ledger.Enabled" value="false"/>
<add key="Webhooks.LedgerIntegration.Enabled" value="false" />
</appSettings>
Se você não for usar o Modo de Manutenção, você pode desabilitá-lo.
<appSettings>
<add key="MaintenanceMode.Enabled" value="false" />
</appSettings>
<appSettings>
<add key="MaintenanceMode.Enabled" value="false" />
</appSettings>
Você pode configurar o Orchestrator para usar alguns caches em memória que reduzem o número de chamadas para o Redis. Por exemplo, configurá-los para que expirem a cada 30 minutos significa que, quando você fizer uma alteração em uma configuração de nível de aplicativo, ela pode não entrar em vigor até o intervalo de 30 minutos passar.
O tempo de expiração que você define aqui pode variar dependendo do atraso que você pode tolerar, mas mesmo um tempo de cache de 5 minutos pode melhorar muito o desempenho.
<appSettings>
<add key="Caching.MultiTier[AbpApplicationSettingsCache]" value="Memory" />
<add key="Caching.MultiTier[AbpApplicationSettingsCache].ExpiresAfter" value="0:30:00" />
<add key="Caching.MultiTier[AbpTenantSettingsCache]" value="Memory"/>
<add key="Caching.MultiTier[AbpTenantSettingsCache].ExpiresAfter" value="0:30:00"/>
<add key="Caching.MultiTier[AbpZeroTenantFeatures]" value="Memory"/>
<add key="Caching.MultiTier[AbpZeroTenantFeatures].ExpiresAfter" value="0:30:00"/>
<add key="Caching.MultiTier[AbpZeroRolePermissions]" value="Memory"/>
<add key="Caching.MultiTier[AbpZeroRolePermissions].ExpiresAfter" value="0:30:00"/>
<add key="Caching.MultiTier[LicenseKeys]" value="Memory"/>
<add key="Caching.MultiTier[LicenseKeys].ExpiresAfter" value="0:30:00"/>
<add key="Caching.MultiTier[TenantLicense]" value="Memory"/>
<add key="Caching.MultiTier[TenantLicense].ExpiresAfter" value="0:30:00"/>
</appSettings>
<appSettings>
<add key="Caching.MultiTier[AbpApplicationSettingsCache]" value="Memory" />
<add key="Caching.MultiTier[AbpApplicationSettingsCache].ExpiresAfter" value="0:30:00" />
<add key="Caching.MultiTier[AbpTenantSettingsCache]" value="Memory"/>
<add key="Caching.MultiTier[AbpTenantSettingsCache].ExpiresAfter" value="0:30:00"/>
<add key="Caching.MultiTier[AbpZeroTenantFeatures]" value="Memory"/>
<add key="Caching.MultiTier[AbpZeroTenantFeatures].ExpiresAfter" value="0:30:00"/>
<add key="Caching.MultiTier[AbpZeroRolePermissions]" value="Memory"/>
<add key="Caching.MultiTier[AbpZeroRolePermissions].ExpiresAfter" value="0:30:00"/>
<add key="Caching.MultiTier[LicenseKeys]" value="Memory"/>
<add key="Caching.MultiTier[LicenseKeys].ExpiresAfter" value="0:30:00"/>
<add key="Caching.MultiTier[TenantLicense]" value="Memory"/>
<add key="Caching.MultiTier[TenantLicense].ExpiresAfter" value="0:30:00"/>
</appSettings>
MinWorkerThreads
ajuda com cenários de crescimento.
<appSettings>
<add key="ThreadPool.MinWorkerThreads" value="50" />
</appSettings>
<appSettings>
<add key="ThreadPool.MinWorkerThreads" value="50" />
</appSettings>
Essa etapa é necessária apenas se você tiver um número muito alto de gatilhos disparando, por exemplo, na ordem de 2.000 por minuto.
<quartz>
<add key="quartz.scheduler.batchTriggerAcquisitionMaxCount" value="15" />
<add key="quartz.threadPool.threadCount" value="15" />
<add key="quartz.jobStore.misfireThreshold" value="3600000" />
<add key="quartz.jobStore.clusterCheckinInterval" value="60000" />
<add key="quartz.jobStore.clustered" value="true" />
</quartz>
<quartz>
<add key="quartz.scheduler.batchTriggerAcquisitionMaxCount" value="15" />
<add key="quartz.threadPool.threadCount" value="15" />
<add key="quartz.jobStore.misfireThreshold" value="3600000" />
<add key="quartz.jobStore.clusterCheckinInterval" value="60000" />
<add key="quartz.jobStore.clustered" value="true" />
</quartz>
Se você não estiver em uma rede corporativa ou não precisar ver os nomes de DNS dos IPs gravados no Audit, você pode desabilitar a resolução.
<appSettings>
<add key="Audit.UseDnsResolving" value="false" />
</appSettings>
<appSettings>
<add key="Audit.UseDnsResolving" value="false" />
</appSettings>
Directory.ActiveDirectory.GroupMembershipFetchStrategy
e aplicam-se Directory.ActiveDirectory.AuthorizationGroupsCacheExpirationHours
apenas ao adaptador AD legado. Você deve usar essas configurações apenas se tiver feito atualização de uma versão do Orchestrator na qual o AD estava habilitado para 2021.10 ou posterior.
Directory.ActiveDirectory.GroupMembershipFetchStrategy
como TokenGroups
na tabela [identity].[Settings]
, execute:
SELECT * FROM [identity].[Settings] WHERE [Key]='Directory.ActiveDirectory.GroupMembershipFetchStrategy' and [PartitionId]=1
IF @@ROWCOUNT>0
UPDATE [identity].[Settings] SET [Value]='TokenGroups' WHERE [Key]='Directory.ActiveDirectory.GroupMembershipFetchStrategy' and [PartitionId]=1
ELSE
INSERT INTO [identity].[Settings] ([Key], [Value], [PartitionId]) VALUES ('Directory.ActiveDirectory.GroupMembershipFetchStrategy', 'TokenGroups', 1)
SELECT * FROM [identity].[Settings] WHERE [Key]='Directory.ActiveDirectory.GroupMembershipFetchStrategy' and [PartitionId]=1
IF @@ROWCOUNT>0
UPDATE [identity].[Settings] SET [Value]='TokenGroups' WHERE [Key]='Directory.ActiveDirectory.GroupMembershipFetchStrategy' and [PartitionId]=1
ELSE
INSERT INTO [identity].[Settings] ([Key], [Value], [PartitionId]) VALUES ('Directory.ActiveDirectory.GroupMembershipFetchStrategy', 'TokenGroups', 1)
Directory.ActiveDirectory.AuthorizationGroupsCacheExpirationHours
como 4 horas na tabela [identity].[Settings]
, execute:
SELECT * FROM [identity].[Settings] WHERE [Key]='Directory.ActiveDirectory.AuthorizationGroupsCacheExpirationHours' and [PartitionId]=1
IF @@ROWCOUNT>0
UPDATE [identity].[Settings] SET [Value]='4' WHERE [Key]='Directory.ActiveDirectory.AuthorizationGroupsCacheExpirationHours' and [PartitionId]=1
ELSE
INSERT INTO [identity].[Settings] ([Key], [Value], [PartitionId]) VALUES ('Directory.ActiveDirectory.AuthorizationGroupsCacheExpirationHours', '4', 1)
SELECT * FROM [identity].[Settings] WHERE [Key]='Directory.ActiveDirectory.AuthorizationGroupsCacheExpirationHours' and [PartitionId]=1
IF @@ROWCOUNT>0
UPDATE [identity].[Settings] SET [Value]='4' WHERE [Key]='Directory.ActiveDirectory.AuthorizationGroupsCacheExpirationHours' and [PartitionId]=1
ELSE
INSERT INTO [identity].[Settings] ([Key], [Value], [PartitionId]) VALUES ('Directory.ActiveDirectory.AuthorizationGroupsCacheExpirationHours', '4', 1)
Directory.ActiveDirectory.CacheExpirationSeconds
aplica-se somente ao adaptador AD legado. Você deve usar essa configuração apenas se tiver feito atualização de uma versão do Orchestrator na qual o AD estava habilitado Para 2021.10 ou posterior.
Directory.ActiveDirectory.CacheExpirationSeconds
na tabela [identity].[Settings]
. O valor padrão desta configuração é de 43200 segundos (12 horas). Para desabilitar o cache do domínio do AD, você deve definir esta configuração para 0.
Para definir esta configuração para 7 dias, execute:
SELECT * FROM [identity].[Settings] WHERE [Key]='Directory.ActiveDirectory.CacheExpirationSeconds' and [PartitionId]=1
IF @@ROWCOUNT>0
UPDATE [identity].[Settings] SET [Value]='604800' WHERE [Key]='Directory.ActiveDirectory.CacheExpirationSeconds' and [PartitionId]=1
ELSE
INSERT INTO [identity].[Settings] ([Key], [Value], [PartitionId]) VALUES ('Directory.ActiveDirectory.CacheExpirationSeconds', '604800', 1)
SELECT * FROM [identity].[Settings] WHERE [Key]='Directory.ActiveDirectory.CacheExpirationSeconds' and [PartitionId]=1
IF @@ROWCOUNT>0
UPDATE [identity].[Settings] SET [Value]='604800' WHERE [Key]='Directory.ActiveDirectory.CacheExpirationSeconds' and [PartitionId]=1
ELSE
INSERT INTO [identity].[Settings] ([Key], [Value], [PartitionId]) VALUES ('Directory.ActiveDirectory.CacheExpirationSeconds', '604800', 1)
Para desabilitar o cache do domínio AD, execute:
SELECT * FROM [identity].[Settings] WHERE [Key]='Directory.ActiveDirectory.CacheExpirationSeconds' and [PartitionId]=1
IF @@ROWCOUNT>0
UPDATE [identity].[Settings] SET [Value]='0' WHERE [Key]='Directory.ActiveDirectory.CacheExpirationSeconds' and [PartitionId]=1
ELSE
INSERT INTO [identity].[Settings] ([Key], [Value], [PartitionId]) VALUES ('Directory.ActiveDirectory.CacheExpirationSeconds', '0', 1)
SELECT * FROM [identity].[Settings] WHERE [Key]='Directory.ActiveDirectory.CacheExpirationSeconds' and [PartitionId]=1
IF @@ROWCOUNT>0
UPDATE [identity].[Settings] SET [Value]='0' WHERE [Key]='Directory.ActiveDirectory.CacheExpirationSeconds' and [PartitionId]=1
ELSE
INSERT INTO [identity].[Settings] ([Key], [Value], [PartitionId]) VALUES ('Directory.ActiveDirectory.CacheExpirationSeconds', '0', 1)
Durante um crescimento agressivo, os eventos de aquisição de licenças colocariam uma pressão significativa no backplane do SignalR do Redis. Para mitigar isso, o evento pode ser desabilitado, o que faz com que a Interface Gráfica de licenciamento não seja mais atualizada em tempo real. No entanto, quando você tem 100k robôs, essa tela de atualização em tempo real não tem quase nenhum valor.
<appSettings>
<add key="Scalability.SignalR.Browser.RobotLicenseChangeEventEnabled" value="false" />
</appSettings>
<appSettings>
<add key="Scalability.SignalR.Browser.RobotLicenseChangeEventEnabled" value="false" />
</appSettings>
Essa alteração garante que haja o cache do lado do servidor dos conteúdos do pacote, e pode ser útil quando o compartilhamento de arquivos não puder acompanhar a taxa de transferência de download do pacote.
<<add key="NuGet.Caching.Enabled" value="true" />
<add key="NuGet.Caching.MaxCacheSize" value="104857600" /><!-- (100 MiB) -->
<add key="NuGet.Caching.MaxPackageSize" value="4194304" /><!-- (4 MiB) -->
<add key="NuGet.Caching.AbsoluteExpirationRelativeToNow" value="00:10:00" /><!-- (1 min) -->
<<add key="NuGet.Caching.Enabled" value="true" />
<add key="NuGet.Caching.MaxCacheSize" value="104857600" /><!-- (100 MiB) -->
<add key="NuGet.Caching.MaxPackageSize" value="4194304" /><!-- (4 MiB) -->
<add key="NuGet.Caching.AbsoluteExpirationRelativeToNow" value="00:10:00" /><!-- (1 min) -->
NuGet.Caching.Enabled
deve ser suficiente para habilitar o recurso. Você só precisa ajustar o resto das configurações exibidas no exemplo acima se você quiser alterar os padrões, por exemplo, aumentar o tamanho do cache ou os limites de tamanho do pacote.
Defina a seguinte configuração como slot sticky no slot de produção do Serviço de Aplicativo do Orchestrator.
WEBSITE_LOCAL_CACHE_OPTION = Always
WEBSITE_LOCAL_CACHE_SIZEINMB = 1000
WEBSITE_LOCAL_CACHE_OPTION = Always
WEBSITE_LOCAL_CACHE_SIZEINMB = 1000
Defina a seguinte configuração tanto no slot de produção quanto no slot de implantação hotswap do Serviço de Aplicativo do Orchestrator. Durante a implantação, isso irá preparar o aplicativo, minimizando a queda de desempenho causada pelo redirecionando do tráfego para um aplicativo frio.
WEBSITE_SWAP_WARMUP_PING_PATH = /api/status
WEBSITE_SWAP_WARMUP_PING_STATUSES = 200
WEBSITE_SWAP_WARMUP_PING_PATH = /api/status
WEBSITE_SWAP_WARMUP_PING_STATUSES = 200
Usar o Serviço SignalR do Azure em uma implantação do Azure pode reduzir significativamente a carga nos servidores da web. Consulte Scalability.AzureSignalR.ConnectionString para obter mais detalhes sobre a configuração.
<appSettings>
<add key="LoadBalancer.UseRedis" value="true"/>
<add key="Scalability.AzureSignalR.ConnectionString" value="**myAzureSignalRConnectionString" />
</appSettings>
<appSettings>
<add key="LoadBalancer.UseRedis" value="true"/>
<add key="Scalability.AzureSignalR.ConnectionString" value="**myAzureSignalRConnectionString" />
</appSettings>
UiPath.Orchestrator.dll.config
e configure-as de acordo com suas necessidades:
-
RobotsLogs.Flush.Interval
<add key="RobotsLogs.Flush.Interval" value="0" />
<add key="RobotsLogs.Flush.Interval" value="0" />
Para obter mais informações sobre essa configuração, consulte RobotsLogs.Flush.Interval.
-
RobotsLogs.Flush.BatchSize
<add key="RobotsLogs.Flush.BatchSize" value="100" />
<add key="RobotsLogs.Flush.BatchSize" value="100" />
Para obter mais informações sobre essa configuração, consulte RobotsLogs.Flush.BatchSize.
AppSettings.Production.json
do Identity Server devem resultar em um desempenho aprimorado em ambientes de produção de grande escala.
"ConnectionStrings": {
"DefaultConnection": "Data Source=dbServer;Initial Catalog=UiPath_is;User ID=username;Password=****;Max Pool Size=1000"
}
"ConnectionStrings": {
"DefaultConnection": "Data Source=dbServer;Initial Catalog=UiPath_is;User ID=username;Password=****;Max Pool Size=1000"
}
A Interface Gráfica do Orchestrator permite que você siga os seguintes passos para melhorar o desempenho em ambientes de produção de grande escala:
- Desabilite o espaço de trabalho pessoal;
- Desabilite Permitir login na web para usuários do robô;
- Atribua as funções Robot e Automation User para os usuários do robô.
- Requisitos Recomendados para Ambientes de Produção de Grande Escala
- Alterações do Orchestrator para um desempenho aprimorado
- Habilite o Redis
- Especifique um tamanho de pool máximo grande na String de Conexão
- Grave os logs do Robô no Elasticsearch e use o AsyncWrapper
- Use um armazenamento com alta taxa de transferência
- Desabilite o Webhooks e o Ledger
- Desabilite o Modo de Manutenção
- Aumente o tempo de cache das configurações do aplicativo
- Aumentar o valor de MinWorkerThreads
- Ajuste o Quartz para uma taxa de transferência muito alta
- Desative a resolução de IP para DNS no Audit
- Mude para uma estratégia mais rápida para obter Associações de Grupos
- Ajustar o tempo de expiração do cache do domínio do AD
- Desative o SignalR para os eventos de alteração de licença do Robô
- Habilite o Cache de Pacotes do NuGet
- Habilite o cache local nas implantações PaaS do Azure
- Configure o Slot Warm-Up nas implantações PaaS do Azure
- Use o Serviço SignalR do Azure nas implantações PaaS do Azure
- Ajuste o Intervalo de Descarga e o tamanho para o Endpoint do SubmitLogs
- Alterações no Identity Server para um desempenho aprimorado
- Especifique um tamanho de pool máximo grande na String de Conexão
- Habilite o Redis
- Alterações de configuração de Interface Gráfica para um desempenho aprimorado