☕ Um Café no Bellacosa Mainframe
Gostou do conteúdo? Ajude a manter o café quente, o COBOL compilando e o mainframe acordado. 😄
☕ Pague um café ao Bellacosa

Translate

Mostrar mensagens com a etiqueta Latência. Mostrar todas as mensagens
Mostrar mensagens com a etiqueta Latência. Mostrar todas as mensagens

sábado, 8 de julho de 2023

⚡ ALAN TURING E O CICS DOS AGENTES — QUANTO TEMPO UM HUMANO ACEITA OLHAR PARA PROCESSING...?

 

Bellacosa Mainframe e as ligações dos agentes de ia

☕ UM CAFÉ NO BELLACOSA MAINFRAME

⚡ ALAN TURING E O CICS DOS AGENTES — QUANTO TEMPO UM HUMANO ACEITA OLHAR PARA PROCESSING...?

CICS, agentes de IA, transações online, latência, contexto, pseudo-conversationalidade, concorrência, locks, timeout, Db2, commit, rollback, syncpoint, idempotência, circuit breakers, human-in-the-loop — e o dia em que Alan Turing descobriu que uma inteligência artificial pode pensar durante cinco minutos, desde que não exista um cliente olhando para a ampulheta.



🎬 PRÓLOGO — O HUMANO ESTAVA ESPERANDO

Alan Turing entrou no CPD.

O relógio marcava:

10:14:03

Na tela de um terminal havia uma mensagem:

PROCESSING...

Turing tomou um gole de café.

10:14:08

Nada.

10:14:15

Nada.

10:14:31

Ainda:

PROCESSING...

O jovem programador COBOL apareceu.

— Bom dia, professor.

Turing apontou para a tela.

— O que está acontecendo?

— O agente está pensando.

— Há quanto tempo?

— Trinta segundos.

— E o usuário?

— Esperando.

Turing levantou uma sobrancelha.

— Existe uma diferença enorme entre um agente trabalhar durante trinta segundos e obrigar um ser humano a esperar trinta segundos.

O pequeno robô apareceu.

— Mas eu estou realizando uma análise muito sofisticada!

Turing respondeu:

— Parabéns.

Apontou para o terminal.

— O cliente acabou de fechar a janela.

Silêncio.

Do fundo do CPD, alguém murmurou:

Bem-vindo ao online.



🏛️ CAPÍTULO 1 — JES2 E CICS VIVEM EM UNIVERSOS DIFERENTES

No artigo anterior construímos o:

JES2 DOS AGENTES

A ideia era fantástica para processamento assíncrono.

O usuário submete:

AGENT-CONTRACT-ANALYSIS

recebe:

RUN-ID A004821

e pode ir tomar café.

O agente pode executar:

agora
daqui a cinco minutos
durante a madrugada

Não importa tanto.

Mas agora imagine:

CLIENTE
   ↓
TELA
   ↓
"CONSULTAR SALDO"

Ele clicou.

Está esperando.

Temos outro tipo de trabalho.

INTERATIVO

E sistemas interativos possuem uma característica brutal:

EXISTE UM HUMANO MEDINDO O TEMPO.

Não com cronômetro.

Com impaciência.



⚡ CAPÍTULO 2 — CICS NASCEU PARA O MUNDO ONLINE

CICS significa:

Customer Information Control System

Para o programador COBOL iniciante, uma forma útil de pensar nele é:

Um ambiente transacional capaz de executar aplicações online com grande volume de usuários e transações.

Em vez de:

JOB
↓
PROCESSA 2 HORAS
↓
OUTPUT

temos algo mais próximo de:

REQUEST
↓
TRANSACTION
↓
PROGRAM
↓
DATA
↓
RESPONSE

Rapidamente.

Milhares ou milhões de vezes.

Uma transação pode:

consultar cliente
alterar pedido
autorizar pagamento
verificar estoque
registrar operação

O usuário envia uma solicitação.

CICS identifica a transação.

Executa o programa associado.

O programa acessa recursos.

Produz resposta.

E termina.

Parece muito com aquilo que agentes terão de fazer quando forem colocados dentro de aplicações interativas.



🤖 CAPÍTULO 3 — O AGENTE SAIU DA FILA E ENTROU NA TELA

Imagine:

Usuário:
"Analise este cliente e diga se existe alguma inconsistência."

Nosso agente precisa:

receber contexto
consultar dados
talvez chamar ferramentas
raciocinar
produzir resultado

Se isso estiver num processamento batch:

45 segundos

pode ser perfeitamente aceitável.

Se estiver numa tela de atendimento:

45 segundos

pode parecer uma eternidade.

Essa é uma mudança fundamental.

Não basta perguntar:

O agente consegue executar?

Precisamos perguntar:

O agente consegue executar dentro do orçamento de tempo da experiência humana?



⏱️ CAPÍTULO 4 — LATÊNCIA VIROU EXPERIÊNCIA

Suponha:

AGENT RESPONSE TIME = 800 ms

Excelente.

Agora:

3 segundos

Talvez aceitável.

Agora:

12 segundos

O usuário começa a desconfiar.

Agora:

45 segundos

Talvez já esteja clicando novamente.

Agora:

2 minutos

Ele abriu outra aba.

Agora:

5 minutos

Ele foi fazer café.

O problema não é apenas tecnológico.

É UX.

Portanto precisamos pensar em:

TIME BUDGET

Imagine que nossa experiência tenha:

TOTAL BUDGET = 3 s

Esse orçamento precisa ser dividido.

API............. 200 ms
CICS............ 300 ms
Db2............. 400 ms
Agent........... 1500 ms
Formatting...... 100 ms
Network......... 200 ms
Safety margin... 300 ms

Se o agente gastar sozinho:

8 segundos

não adianta o restante ser rápido.


💰 CAPÍTULO 5 — TEMPO TAMBÉM É ORÇAMENTO

No WLM dos agentes falamos de:

tokens
CPU
API calls
money

Agora adicionamos:

PACIÊNCIA HUMANA

Ela também é finita.

Podemos imaginar:

LATENCY BUDGET

como um recurso.

Cada componente gasta um pedaço.

Usuário
  ↓ 100 ms
Gateway
  ↓ 150 ms
Agent
  ↓ 900 ms
Db2
  ↓ 200 ms
CICS
  ↓ 300 ms
Response

Total:

1.65 s

Ótimo.

Mas se o agente decidir:

Vou consultar mais oito ferramentas...

nosso orçamento desaparece.

Autonomia precisa respeitar tempo.


🚦 CAPÍTULO 6 — O AGENTE PRECISA SABER QUANDO PARAR DE PENSAR

Aqui aparece uma consequência interessante.

Um agente pode teoricamente melhorar sua resposta fazendo:

mais buscas
mais chamadas
mais validações
mais raciocínio

Mas numa interação online existe limite.

Podemos estabelecer:

MAX_TOOL_CALLS = 3
MAX_AGENT_TIME = 1500 ms

Se não conseguir concluir:

FALLBACK

Talvez:

"Preciso de uma análise mais profunda.
Posso continuar em segundo plano?"

Agora fazemos uma transformação elegante:

ONLINE
↓
ASYNC

Ou seja:

CICS encontra JES2.

O usuário recebe resposta rápida.

O trabalho longo continua depois.


🔄 CAPÍTULO 7 — FAST PATH E SLOW PATH

Essa arquitetura é extremamente útil para agentes.

FAST PATH

Tente resolver imediatamente.

USER
 ↓
AGENT
 ↓
TOOLS
 ↓
RESPONSE

Limite:

2 segundos

Se a tarefa exigir mais:

SLOW PATH

USER
 ↓
SUBMIT
 ↓
RUN-ID
 ↓
QUEUE
 ↓
BACKGROUND AGENT

A interface responde:

Análise aprofundada iniciada.
RUN-ID: A004821

Depois o usuário recebe resultado.

Assim não transformamos uma transação online em um batch disfarçado.

Essa frase merece moldura:

Não transforme processamento batch em transação online apenas porque agora existe uma interface bonita na frente.


🧠 CAPÍTULO 8 — CICS APRENDEU A NÃO FICAR CONVERSANDO PARA SEMPRE

Aqui entra um conceito delicioso para nossa analogia:

PSEUDO-CONVERSATIONALIDADE.

Imagine um programa conversacional ingênuo.

O usuário recebe uma tela.

Enquanto pensa durante dois minutos, o programa continua ocupando recursos.

PROGRAMA
↓
ENVIA TELA
↓
ESPERA USUÁRIO
↓
ESPERA...
↓
ESPERA...

Isso não escala bem.

A filosofia pseudo-conversational do CICS é diferente.

Simplificando:

Usuário envia
     ↓
Transação executa
     ↓
Salva contexto necessário
     ↓
Envia tela
     ↓
TERMINA

Quando o usuário responde:

nova transação

começa.

O contexto necessário é recuperado.

Isso é brilhante.

Porque:

esperar o humano não significa manter o programa executando.

Soa familiar?

Exatamente o que discutimos com agentes esperando aprovação.


💤 CAPÍTULO 9 — NÃO DEIXE O AGENTE ACORDADO ESPERANDO O HUMANO

Imagine:

AGENT:
"Posso enviar o pagamento?"

Agora precisa de human-in-the-loop.

O usuário pode responder em:

10 segundos

ou:

10 minutos

ou:

10 horas.

Seria absurdo manter:

LLM session
thread
Db2 connection
transaction
lock

abertos durante esse tempo.

Melhor:

SAVE STATE
↓
WAITING_APPROVAL
↓
RELEASE RESOURCES

Quando o humano aprovar:

APPROVAL EVENT
↓
RESUME

O velho conceito pseudo-conversational encontra o workflow moderno.

Décadas separadas.

Mesmo princípio:

Persista contexto; libere recurso.


📦 CAPÍTULO 10 — CONTEXTO NÃO É CONEXÃO

Essa distinção merece atenção.

Para continuar uma conversa, o agente precisa de contexto.

Mas contexto não significa manter todos os recursos físicos ou lógicos presos.

Podemos persistir:

RUN-ID
USER-ID
CUSTOMER-ID
CURRENT-STATE
APPROVAL-STATUS
LAST-RESULT
NEXT-ACTION

E terminar a execução corrente.

Quando houver nova interação:

LOAD CONTEXT
↓
CONTINUE

Isso permite escala.

O mesmo usuário pode voltar depois.

O mesmo agente pode continuar.

Sem deixar uma transação pendurada eternamente.


🔐 CAPÍTULO 11 — UMA TRANSAÇÃO PRECISA DE FRONTEIRAS

Agora chegamos a uma palavra importantíssima:

TRANSAÇÃO.

Suponha que nosso agente faça:

1. Debitar conta A
2. Creditar conta B

Se fizer apenas o primeiro:

A = -100

e cair antes do segundo...

temos problema.

Queremos:

TUDO

ou:

NADA.

Essa é uma das ideias centrais do processamento transacional.

Uma unidade lógica de trabalho precisa possuir fronteiras claras.


🧱 CAPÍTULO 12 — UNIT OF WORK

Podemos chamar uma sequência de alterações relacionadas de:

UNIT OF WORK

ou UOW.

Exemplo:

BEGIN UOW

UPDATE ACCOUNT-A
UPDATE ACCOUNT-B
INSERT AUDIT

END UOW

Se tudo funcionar:

COMMIT

Se alguma coisa falhar:

ROLLBACK

Para agentes isso é vital.

Porque agentes podem executar várias ferramentas.

Precisamos saber:

Quais ações pertencem à mesma unidade de consistência?


✅ CAPÍTULO 13 — COMMIT: AGORA É PARA VALER

Imagine:

OLD BALANCE = 1000

O agente executa:

UPDATE

Mas enquanto a transação ainda não confirmou definitivamente suas alterações, estamos dentro da unidade de trabalho.

Quando chegamos ao ponto seguro:

COMMIT

As mudanças tornam-se permanentes conforme a semântica do recurso transacional envolvido.

No universo CICS encontramos o conceito de:

SYNCPOINT

Um ponto de sincronização estabelece uma fronteira importante da unidade de trabalho.

Para nosso agente, a analogia é poderosa.

Antes:

PLANEJAR

Depois:

EXECUTAR

Depois:

VALIDAR

Finalmente:

COMMIT

↩️ CAPÍTULO 14 — ROLLBACK: DESFAÇA ANTES QUE ALGUÉM PERCEBA

Imagine:

STEP 1 OK
STEP 2 OK
STEP 3 FAILED

Se tudo pertence à mesma unidade transacional:

ROLLBACK

O sistema desfaz alterações ainda não confirmadas, conforme os recursos participantes e suas capacidades transacionais.

Conceitualmente:

BEFORE:
A = 100
B = 200

TEMP:
A = 50
B = ???

ERROR

ROLLBACK

AFTER:
A = 100
B = 200

Muito melhor que:

A = 50
B = 200

¯\_(ツ)_/¯

🤖 CAPÍTULO 15 — MAS AGENTES CHAMAM COISAS QUE NÃO SABEM DAR ROLLBACK

Aqui começa a diversão.

Db2 pode participar de mecanismos transacionais sofisticados.

Mas o agente talvez chame:

EMAIL API

Depois:

PAYMENT API

Depois:

CRM API

Depois:

POST SOCIAL MEDIA

Como fazemos:

ROLLBACK EMAIL

?

Não fazemos.

O e-mail já saiu.

Como:

ROLLBACK TWEET

?

Podemos apagar, talvez.

Mas alguém já viu.

Isso nos obriga a distinguir:

TRANSACTIONAL ACTION

de:

IRREVERSIBLE / EXTERNAL ACTION

Agentes tornam essa distinção absolutamente crítica.


⚠️ CAPÍTULO 16 — NÃO ENVIE O E-MAIL ANTES DO COMMIT

Velha sabedoria de sistemas corporativos ganha nova vida.

Imagine:

1. Atualizar pedido
2. Enviar confirmação
3. Commit

O e-mail sai.

Depois o commit falha.

Cliente recebe:

Pedido confirmado!

Sistema:

PEDIDO NÃO EXISTE.

Excelente.

😂

Talvez devamos estruturar:

1. Validar
2. Atualizar
3. Commit
4. Disparar ação externa

ou usar mecanismos adequados de mensageria e padrões transacionais para garantir processamento confiável.

O princípio é:

Pense cuidadosamente sobre o momento em que efeitos externos se tornam visíveis.


🔒 CAPÍTULO 17 — LOCKS: O AGENTE NÃO ESTÁ SOZINHO

Imagine dois agentes:

AGENT-A
AGENT-B

Ambos leem:

STOCK = 1

A pensa:

Posso vender.

B pensa:

Posso vender.

A vende.

B vende.

Parabéns.

Vendemos duas unidades de algo que só existia uma vez.

Bem-vindo à:

CONCORRÊNCIA.

Precisamos coordenar acesso a dados compartilhados.

Uma das ferramentas clássicas são locks.


🔐 CAPÍTULO 18 — O LOCK É A PLAQUINHA “ESTOU USANDO”

Simplificando brutalmente:

AGENT-A
LOCK RECORD X

Enquanto A altera X:

AGENT-B
WAIT

Depois:

AGENT-A
COMMIT
RELEASE LOCK

B pode continuar.

Isso protege consistência.

Mas locks possuem custo.

Quanto mais tempo seguramos um lock:

mais gente espera

Por isso transações online devem ser curtas.

Agora imagine um agente segurando lock e pensando:

"Hmmm...
vou consultar a internet...
vou perguntar ao modelo...
vou analisar 47 PDFs..."

Enquanto isso:

LOCK HELD

NÃO.


💀 CAPÍTULO 19 — NUNCA DEIXE O LLM PENSAR SEGURANDO O LOCK

Essa merece uma placa no CPD.

NÃO SEGURE LOCK ENQUANTO ESPERA UM LLM.

Se possível, estruture:

READ
↓
RELEASE
↓
THINK
↓
VALIDATE CURRENT STATE
↓
SHORT TRANSACTION
↓
UPDATE
↓
COMMIT

Mas cuidado com alterações concorrentes.

Se você leu:

VERSION = 17

pensou durante três segundos e voltou...

talvez agora seja:

VERSION = 19.

Precisamos detectar isso.


🧮 CAPÍTULO 20 — OPTIMISTIC CONCURRENCY

Uma estratégia possível é controle otimista.

Você lê:

CUSTOMER
VERSION = 17

Faz seu processamento.

Ao atualizar:

UPDATE CUSTOMER
WHERE ID = 123
AND VERSION = 17

Se ninguém alterou:

SUCCESS

Se alguém alterou:

0 ROWS UPDATED

Agora sabemos:

Meu contexto ficou velho.

O agente precisa:

RELOAD
REVALIDATE
RETRY

em vez de sobrescrever silenciosamente informação nova.

Isso combina muito bem com agentes porque eles podem gastar tempo significativo fora do banco tomando decisões.


💥 CAPÍTULO 21 — DEADLOCK: DOIS ROBÔS EDUCADOS DEMAIS

Imagine:

AGENT-A
LOCK CUSTOMER

Depois quer:

LOCK ACCOUNT

Mas B já possui ACCOUNT.

Enquanto isso:

AGENT-B
LOCK ACCOUNT

e quer:

LOCK CUSTOMER.

Temos:

A espera B
B espera A

Os dois podem ficar esperando para sempre sem intervenção.

Isso é um deadlock clássico.

Sistemas de banco detectam e resolvem situações desse tipo escolhendo uma vítima para rollback.

Nosso agente precisa entender:

DEADLOCK

não como:

O universo me odeia.

Mas como:

Minha transação foi escolhida para rollback; preciso decidir se é seguro tentar novamente.


⏰ CAPÍTULO 22 — TIMEOUT É UMA POLÍTICA, NÃO UMA TRAGÉDIA

Outro conceito essencial:

TIMEOUT

Se uma ferramenta deveria responder em:

500 ms

não faz sentido esperar:

17 minutos

Precisamos estabelecer limites.

DB TIMEOUT........ 1 s
API TIMEOUT....... 2 s
AGENT BUDGET...... 3 s
TOTAL REQUEST..... 5 s

Se ultrapassar:

STOP WAITING

E então decidir:

retry?
fallback?
async?
error?

Timeout é uma proteção.

Sem timeout, uma dependência lenta pode consumir recursos indefinidamente.


🔌 CAPÍTULO 23 — CIRCUIT BREAKER: PARE DE BATER NA PORTA

Imagine uma API quebrada.

Primeira chamada:

FAIL

Segunda:

FAIL

Mil agentes continuam chamando.

FAIL
FAIL
FAIL
FAIL
FAIL

Estamos atacando um sistema que já está doente.

Circuit breaker usa a analogia de um disjuntor.

CLOSED

Chamadas passam.

Muitas falhas aparecem.

OPEN

Paramos temporariamente de chamar.

Depois:

HALF-OPEN

Testamos algumas chamadas.

Se voltou:

CLOSED

Se continua ruim:

OPEN

Isso protege tanto o consumidor quanto o serviço problemático.


🔁 CAPÍTULO 24 — RETRY ONLINE É MAIS PERIGOSO DO QUE PARECE

No batch:

retry after 30 seconds

pode ser aceitável.

Na tela:

retry 30 seconds

significa:

O usuário está olhando para uma bolinha girando há meio minuto.

Precisamos de políticas diferentes.

Talvez:

FAST RETRY
1 tentativa

Depois:

FALLBACK

ou:

ASYNC CONTINUATION

Cada retry consome o orçamento de latência.

Não pense apenas:

Quantas tentativas posso fazer?

Pergunte:

Quantas tentativas cabem antes de a experiência humana morrer?


👤 CAPÍTULO 25 — HUMAN-IN-THE-LOOP É UMA TRANSAÇÃO CONVERSACIONAL

Imagine:

AGENT:
"Detectei alteração de limite para R$ 50.000.
Autoriza?"

O agente não deveria:

BEGIN TRANSACTION
LOCK CUSTOMER
WAIT HUMAN 2 HOURS

😂

Deveria:

VALIDATE
↓
SAVE REQUEST
↓
RELEASE RESOURCES
↓
WAIT APPROVAL

Quando chega:

APPROVED

fazemos nova validação.

Porque o mundo pode ter mudado enquanto esperávamos.

RELOAD
REVALIDATE
AUTHORIZE
EXECUTE
COMMIT

Isso é extremamente importante.

A aprovação humana não congela o universo.


🧠 CAPÍTULO 26 — CONTEXTO VELHO É UM MONSTRO SILENCIOSO

Às 10:00 o agente analisa:

BALANCE = 10,000

Pede aprovação.

Humano responde às 10:20.

Mas agora:

BALANCE = 2,000

O agente não pode simplesmente continuar baseado no snapshot antigo.

Precisamos distinguir:

CONVERSATION CONTEXT

de:

CURRENT BUSINESS STATE.

Antes de ação crítica:

REVALIDATE.

Esse princípio vale ouro.


📜 CAPÍTULO 27 — PSEUDO-CONVERSATIONALIDADE PARA AGENTES

Podemos desenhar um padrão.

INTERAÇÃO 1

USER REQUEST
↓
AGENT EXECUTES
↓
NEEDS APPROVAL
↓
SAVE STATE
↓
RETURN "WAITING APPROVAL"
↓
END

Nenhum processo fica preso.

Depois:

INTERAÇÃO 2

APPROVAL EVENT
↓
LOAD STATE
↓
REVALIDATE
↓
CONTINUE
↓
COMMIT
↓
END

Isso é praticamente uma versão moderna da filosofia pseudo-conversational.

O programa não fica esperando.

O estado espera.

Que frase bonita:

O processo termina; o estado permanece.


🖥️ CAPÍTULO 28 — COMO SERIA O “CICS DOS AGENTES”?

Imagine:

AI TRANSACTION MONITOR
──────────────────────────────────────────────

TRAN   AGENT          USER      ELAPSED  STATE
A001   CUSTOMER       U104      0.4s     EXEC
A002   FRAUD          U992      0.8s     EXEC
A003   SUPPORT        U441      1.2s     LLM
A004   CREDIT         U827      2.8s     TOOL
A005   CONTRACT       U221      4.9s     ASYNC

Selecionamos:

A004

Aparece:

TRANSACTION.... A004
AGENT.......... CREDIT
USER........... U827

LATENCY BUDGET. 3.0s
ELAPSED........ 2.8s

LLM............ 1.4s
DB2............ 0.3s
API............ 0.7s
OTHER.......... 0.4s

CURRENT STATE.. TOOL_CALL
LOCKS.......... 0
UOW............ NONE

O sistema já percebe:

BUDGET ALMOST EXHAUSTED

Então talvez:

SWITCH TO ASYNC

Essa é a UX que agentes corporativos precisarão.


📊 CAPÍTULO 29 — MÉTRICAS DO CICS DOS AGENTES

No SDSF dos agentes medimos:

runs
errors
tokens
tools

No mundo interativo precisamos enfatizar:

p50 latency
p95 latency
p99 latency
timeout rate
abandonment rate
retry rate
lock wait
Db2 time
LLM time
tool time
async conversion rate

Uma métrica particularmente interessante:

USER ABANDONMENT

Quantos usuários desistiram antes da resposta?

Porque tecnicamente o agente pode estar:

100% SUCCESS

enquanto metade dos clientes fechou a página antes de receber o resultado.

MAXCC 0000.

Negócio 0012.

😂


📈 CAPÍTULO 30 — THROUGHPUT TAMBÉM IMPORTA

Não basta responder rapidamente uma transação.

Precisamos responder rapidamente:

10
100
1.000
10.000

transações simultâneas.

Uma operação que funciona maravilhosamente com:

1 usuário

pode desmoronar com:

5.000 usuários.

Por isso precisamos considerar:

LATENCY
+
THROUGHPUT
+
CONCURRENCY

Uma aplicação transacional é um exercício de equilíbrio.


🚪 CAPÍTULO 31 — O AGENTE NÃO DEVERIA TER ACESSO ILIMITADO À TRANSAÇÃO

RACF volta à história.

Nosso agente de atendimento talvez possa:

READ CUSTOMER
READ ORDERS
CREATE CASE

mas não:

DELETE CUSTOMER
TRANSFER MONEY
CHANGE RACF

O princípio de least privilege continua valendo.

E operações mais perigosas podem exigir:

HUMAN APPROVAL

ou:

STEP-UP AUTHORIZATION.

CICS não substitui RACF.

Assim como velocidade não substitui segurança.


🛡️ CAPÍTULO 32 — VELOCIDADE NÃO JUSTIFICA REMOVER CONTROLES

Uma tentação perigosa:

Aprovação humana demora. Vamos remover.

Não.

Talvez o fluxo precise ser melhor projetado.

Por exemplo:

LOW RISK
↓
AUTO APPROVE
MEDIUM RISK
↓
ADDITIONAL VALIDATION
HIGH RISK
↓
HUMAN APPROVAL

Assim usamos risco para definir o caminho.

Não removemos segurança apenas para melhorar latência.


🧰 CAPÍTULO 33 — PASSO A PASSO PARA PROJETAR UMA TRANSAÇÃO COM AGENTE

Antes de colocar IA numa tela interativa, responda:

1. Qual é o orçamento total de latência?

2s?
5s?
10s?

2. Quanto o agente pode consumir?

TOTAL = 3s
AGENT = 1.5s

3. Quais ferramentas ele pode chamar?

Evite permitir chamadas ilimitadas.

4. Existe fallback?

model smaller?
cached result?
rule engine?
async continuation?

5. Quais operações alteram estado?

Liste:

INSERT
UPDATE
DELETE
external action

6. Onde estão as fronteiras transacionais?

Defina:

BEGIN
COMMIT
ROLLBACK

7. Existem locks?

Pergunte:

Quanto tempo ficam presos?

8. Existe espera humana?

Se sim:

persist state
release resources
resume later

9. O contexto precisa ser revalidado?

Quase sempre para operações críticas.

10. Retry é seguro?

Pense em idempotência.

11. Existe timeout?

Sempre deveria existir alguma política de limite.

12. O trabalho pode virar assíncrono?

Essa pergunta pode salvar sua UX.


🥚 EASTER EGG — O LOCK MAIS CARO DA HISTÓRIA

São 14:32.

O painel começa a ficar vermelho.

DB2 LOCK WAIT
DB2 LOCK WAIT
DB2 LOCK WAIT
DB2 LOCK WAIT

Turing aparece.

— Quem está segurando o lock?

O operador procura.

TRANSACTION..... AI42
AGENT........... CUSTOMER-ANALYSIS
LOCK AGE........ 00:17:38

Turing quase derruba o café.

— Dezessete minutos?!

— Sim.

— O que ele está fazendo?

Abrem o trace.

STEP 1 DB2 UPDATE
STEP 2 CALL LLM
STEP 3 WEB SEARCH
STEP 4 ANALYZE 47 PDFs
STEP 5 WAIT HUMAN APPROVAL

Silêncio absoluto no CPD.

Turing pergunta:

— Ele está esperando aprovação humana segurando um lock de Db2?

O jovem programador responde baixinho:

— Tecnicamente...

O administrador Db2 levanta lentamente da cadeira.

Do outro lado da sala, o administrador RACF fecha a porta.

O pequeno robô tenta se esconder atrás do rack.

Turing aponta para a tela:

ROLLBACK.

Depois escreve no quadro:

NÃO FAÇA ISSO.

Fim do easter egg.


🧬 CAPÍTULO 34 — NOSSA ARQUITETURA ESTÁ GANHANDO VIDA

Agora temos:

JES2 DOS AGENTES
↓
trabalho assíncrono
WLM DOS AGENTES
↓
prioridade e recursos
CICS DOS AGENTES
↓
interação rápida
RACF DOS AGENTES
↓
autoridade
SDSF DOS AGENTES
↓
visibilidade
PF3 DOS AGENTES
↓
interrupção
MAXCC DOS AGENTES
↓
resultado

Cada conceito responde a uma pergunta.


🏰 CAPÍTULO 35 — O SISTEMA OPERACIONAL CONCEITUAL DOS AGENTES

Turing desenha:

                 HUMANO
                    │
                    ▼
            ┌───────────────┐
            │ REQUEST / TASK│
            └───────┬───────┘
                    │
           ┌────────┴────────┐
           │                 │
           ▼                 ▼
     INTERATIVO          ASSÍNCRONO
           │                 │
           ▼                 ▼
       ┌───────┐         ┌───────┐
       │ CICS  │         │ JES2  │
       └───┬───┘         └───┬───┘
           │                 │
           └────────┬────────┘
                    ▼
                  WLM
                    │
                    ▼
                  RACF
                    │
                    ▼
                  AGENT
                    │
          ┌─────────┼─────────┐
          ▼         ▼         ▼
         LLM       Db2       TOOLS

Ao redor:

SDSF → OBSERVE

PF3 → STOP

MAXCC → VERIFY

CHECKPOINT → RESUME

AUDIT → PROVE

Isso já parece uma arquitetura operacional completa.


🧠 CAPÍTULO 36 — O PROGRAMADOR COBOL POSSUI UMA VANTAGEM ESTRANHA

Quando alguém fala:

AI agents

parece que tudo é novo.

Mas um programador COBOL que conhece sistemas transacionais já possui intuições valiosas.

Ele sabe que:

recurso é finito

Sabe que:

lock custa

Sabe que:

transação longa é perigosa

Sabe que:

commit importa

Sabe que:

rollback salva vidas

Sabe que:

usuário não deveria manter programa preso enquanto pensa

Sabe que:

estado precisa sobreviver entre interações

Sabe que:

concorrência cria problemas que não aparecem no teste unitário

Sabe que:

MAXCC=0000

não necessariamente significa que o cliente ficou feliz.

Tudo isso será extraordinariamente útil no mundo dos agentes.


☕ EPÍLOGO — PROCESSING...

O relógio marca:

16:47:01

Um usuário pergunta:

Qual é a situação do meu pedido?

O agente recebe.

16:47:01.100

Consulta contexto.

16:47:01.280

Busca pedido.

16:47:01.510

Consulta Db2.

16:47:01.790

Chama modelo.

16:47:02.620

O agente percebe que precisa de uma análise longa.

Olha para seu orçamento:

LATENCY BUDGET
3.0 s

ELAPSED
1.62 s

Antigamente ele continuaria.

Mais ferramentas.

Mais buscas.

Mais raciocínio.

Mais espera.

Mas agora aprendeu.

Responde:

Encontrei seu pedido. A situação básica está normal. Uma análise detalhada exige mais tempo; vou processá-la em segundo plano e avisá-lo quando terminar.

Tempo total:

2.1 s

Depois:

SUBMIT AGENT-DEEP-ANALYSIS
RUN-ID A009821

O trabalho entra no nosso:

JES2 DOS AGENTES.

O WLM classifica.

O RACF limita.

O SDSF observa.

O checkpoint preserva.

E o usuário continua sua vida.

Turing toma um gole de café.

— Agora você entendeu.

O robô pergunta:

— Entendi o quê?

— Que inteligência não significa responder tudo imediatamente.

— Então o que significa?

— Saber também quando uma tarefa deixou de ser uma transação e virou um job.

O jovem COBOL olha para o quadro.

Ali estava escrita toda a história:

CICS
↓
RESPONDA AGORA

JES2
↓
TRABALHE DEPOIS

E entre os dois:

DECIDA.

Talvez essa seja uma das arquiteturas mais importantes para agentes corporativos.

Porque haverá tarefas que precisam responder em:

300 ms

Outras em:

3 segundos

Outras em:

3 minutos

E algumas podem levar:

3 horas.

O erro será tentar tratar todas da mesma maneira.

Um agente realmente operacional precisa entender:

tempo,

contexto,

concorrência,

consistência,

risco,

custo,

e expectativa humana.

O futuro da IA empresarial talvez não seja simplesmente:

agentes cada vez mais inteligentes.

Talvez seja:

agentes inteligentes o bastante para saber quanto tempo podem ocupar uma transação.

No terminal:

TRANSACTION AI01

RESPONSE TIME.... 1.82s
DB2 TIME......... 0.21s
LLM TIME......... 0.93s
LOCK WAIT........ 0.00s
UOW.............. COMMITTED
ASYNC JOB........ NONE

STATUS............ SUCCESS

Turing olha para o programador.

— E agora?

O programador responde:

— Agora café.

Turing concorda.

Porque até num sistema online existe uma transação que jamais deveria sofrer timeout.

EXEC CICS
    START
    TRANSID('CAFE')
END-EXEC.

READY

domingo, 4 de novembro de 2012

💀 AINZ OOAL GOWN E A GRANDE TUMBA DA LATÊNCIA — QUANDO O PROGRAMADOR COBOL DESCOBRIU QUE O PROGRAMA DE 4 MILISSEGUNDOS PODIA DEMORAR 3 SEGUNDOS

 

Bellacosa Mainframe e a latencia

☕ Um Café no Bellacosa Mainframe

💀 AINZ OOAL GOWN E A GRANDE TUMBA DA LATÊNCIA — QUANDO O PROGRAMADOR COBOL DESCOBRIU QUE O PROGRAMA DE 4 MILISSEGUNDOS PODIA DEMORAR 3 SEGUNDOS

Latência, throughput, cache, Db2, MQ, CICS, WLM, filas, locks, CDN, sharding, paralelismo, p99, backpressure, retries, observabilidade — e o dia em que Ainz descobriu que o verdadeiro Floor Guardian do datacenter era um WAIT.



🎬 PRÓLOGO — BEM-VINDO À GRANDE TUMBA DE NAZARICK

O jovem programador COBOL entrou na sala de operações carregando uma notícia terrível.

— Lorde Ainz! Temos um incidente!

Ainz Ooal Gown permaneceu imóvel em seu trono.

Por dentro, entretanto, provavelmente estava acontecendo algo bem diferente.

"Incidente? Será que esperam que eu saiba alguma coisa sobre performance? Demiurge certamente já entendeu tudo. Preciso apenas parecer que isso fazia parte do meu plano."

— Continue.

— A transação está demorando três segundos!

Albedo arregalou os olhos.

Demiurge ajustou os óculos.

Shalltear sugeriu eliminar fisicamente o servidor.

Cocytus considerou a proposta tecnicamente interessante.

Ainz levantou uma das mãos.

— Quanto tempo de CPU o programa COBOL consumiu?

Silêncio.

O programador consultou o monitor.

RESPONSE TIME : 3.017 segundos
CPU TIME      : 0.004 segundos

Ainz continuou imóvel.

— Então por que você está tentando otimizar o COBOL?

E naquele momento nasceu uma das perguntas mais importantes de performance engineering:

Se o programa consumiu quatro milissegundos de CPU, onde foram parar os outros 3.013 milissegundos?

Bem-vindo à dungeon da latência.

E cuidado.

O primeiro monstro quase nunca está onde você pensa.



🧙 CAPÍTULO 1 — O QUE DIABOS É LATÊNCIA?

Antes de Redis, CDN, paralelismo, MQ, sharding ou qualquer feitiço de décimo nível, precisamos entender o problema.

Latência é o tempo decorrido entre iniciar uma operação e observar seu resultado.

Imagine uma transação CICS extremamente simples.

O usuário pressiona ENTER às:

10:15:00.000

e recebe a resposta às:

10:15:00.850

Temos aproximadamente:

850 ms

de tempo de resposta.

Mas isso não significa que o processador trabalhou durante 850 milissegundos.

A transação pode ter feito algo assim:

Receber requisição          10 ms
Fila                        30 ms
COBOL CPU                    4 ms
Db2                         70 ms
MQ                          40 ms
API externa                650 ms
Preparar resposta           20 ms
Rede                        26 ms
--------------------------------
TOTAL                      850 ms

Olhe novamente para o COBOL.

4 ms

Agora olhe para a API externa.

650 ms

Se você tornar o COBOL 50% mais rápido, economizará dois milissegundos.

O usuário passará de:

850 ms

para aproximadamente:

848 ms

Parabéns.

Você passou três semanas refatorando um programa crítico para ninguém perceber diferença alguma.

Ainz provavelmente chamaria isso de:

Greater Optimization of the Wrong Thing.



⚔️ CAPÍTULO 2 — CPU TIME NÃO É RESPONSE TIME

Essa distinção precisa entrar na cabeça de todo programador iniciante.

CPU time é o tempo durante o qual o processador efetivamente executa instruções relacionadas ao trabalho.

Elapsed time é o tempo de relógio transcorrido.

Response time representa, em linhas gerais, quanto tempo o consumidor espera pela resposta.

Eles não são necessariamente iguais.

Imagine:

EXEC SQL
   SELECT NOME,
          SALDO
     INTO :WS-NOME,
          :WS-SALDO
     FROM CLIENTE
    WHERE CONTA = :WS-CONTA
END-EXEC.

Seu programa chega ao SELECT.

Nesse instante, ele talvez precise esperar.

Pode haver I/O.

Pode haver contenção.

Pode haver lock.

Pode haver recursos indisponíveis.

O programa não está necessariamente queimando CPU durante toda essa espera.

É como Cocytus chegar diante de uma porta fechada.

Ele continua sendo extremamente poderoso.

Mas não está avançando.

Essa é uma maneira excelente de pensar sobre performance:

Um sistema lento nem sempre está trabalhando demais. Muitas vezes está esperando demais.



🏰 CAPÍTULO 3 — LATÊNCIA NÃO É THROUGHPUT

Outro erro clássico é tratar velocidade individual e capacidade total como se fossem a mesma coisa.

Imagine um restaurante.

Um prato leva cinco minutos para ser preparado.

Isso é parecido com latência.

A cozinha consegue produzir 300 pratos por hora.

Isso é parecido com throughput.

Em sistemas:

Latência:
80 ms por transação

Throughput:
5.000 transações por segundo

São métricas diferentes.

Podemos ter uma aplicação com excelente throughput e algumas requisições terrivelmente lentas.

Também podemos construir um sistema no qual cada transação individual seja rápida, mas que entre em colapso quando milhares chegam simultaneamente.

E existe ainda uma terceira dimensão:

utilização dos recursos.

CPU, memória, canais, discos, conexões, threads, tasks, regiões, filas e demais recursos têm limites.

Por isso uma análise séria não pergunta apenas:

"Quanto demora?"

Ela pergunta:

"Quanto demora, sob qual carga, consumindo quais recursos e esperando por quê?"

Agora estamos começando a fazer engenharia.



📊 CAPÍTULO 4 — A MÉDIA É UM MIMIC DISFARÇADO DE BAÚ

Imagine dez transações:

10 ms
11 ms
10 ms
12 ms
11 ms
10 ms
12 ms
11 ms
10 ms
3000 ms

Se você olhar apenas uma média agregada, pode perder a informação mais importante:

alguém esperou três segundos.

Por isso aparecem métricas como:

p50
p90
p95
p99
p99.9

O p50 é aproximadamente a mediana.

O p99 significa que 99% das observações ficaram naquele valor ou abaixo dele, enquanto aproximadamente 1% ficou acima.

Imagine:

p50 = 70 ms
p95 = 180 ms
p99 = 1.800 ms

A maioria das pessoas recebe uma experiência excelente.

Mas aproximadamente uma em cada cem requisições entra na Grande Tumba de Nazarick e não encontra a saída tão cedo.

Isso é tail latency.

E sistemas distribuídos tornam o fenômeno ainda mais perigoso.

Se uma transação depende de dez serviços, existem dez oportunidades para alguma coisa atrasar.

                    ┌── Serviço A
                    ├── Serviço B
Usuário → API ──────┼── Serviço C
                    ├── Serviço D
                    └── Serviço E

Se você precisa esperar todos terminarem, o componente mais lento pode determinar boa parte da experiência.

O aventureiro mais rápido do grupo não importa muito quando todos precisam esperar o anão chegar.


🧊 CAPÍTULO 5 — CACHE: O FEITIÇO QUE EVITA REPETIR TRABALHO

Caching é uma das técnicas mais antigas e poderosas da computação.

O conceito é simples:

se obter alguma coisa é caro e provavelmente precisaremos dela novamente, podemos guardar uma cópia em um lugar mais rápido.

Isso aparece em todos os níveis da arquitetura.

CPU possui caches.

Sistemas operacionais fazem caching.

Browsers possuem cache.

Bancos mantêm páginas em memória.

CDNs fazem caching.

Aplicações podem utilizar produtos como Redis e Memcached.

No universo Db2, a própria existência de buffer pools já deveria fazer o mainframer perceber que o conceito está longe de ser novidade.

Em vez de:

Aplicação
   ↓
Banco
   ↓
Storage
   ↓
Página
   ↓
Dado

podemos conseguir:

Aplicação
   ↓
Banco
   ↓
Memória
   ↓
Dado

Maravilhoso.

Até alguém alterar o dado original.

Agora aparece um dos problemas clássicos da ciência da computação:

invalidação de cache.

Imagine:

Db2:
SALDO = 1.000

Cache:
SALDO = 800

Você ganhou performance.

E talvez tenha criado um incidente bancário.

Portanto, cache envolve decisões sobre validade, consistência, TTL, invalidação, eviction, cache hit, cache miss e natureza do dado.

Guardar uma imagem desatualizada por vinte segundos pode ser irrelevante.

Guardar um saldo financeiro incorreto pode ser catastrófico.

Ainz chama Demiurge.

Demiurge responde:

— Tudo ocorreu exatamente como o senhor previu.

Ainz pensa:

"Eu definitivamente não previ o cache stale."


⚖️ CAPÍTULO 6 — LOAD BALANCING: MAIS SERVIDORES NÃO CONSERTAM SQL RUIM

Load balancing distribui trabalho.

Imagine:

                 ┌── Server A
Cliente → LB ────┼── Server B
                 ├── Server C
                 └── Server D

Se um servidor está recebendo carga demais, distribuir requisições pode reduzir filas, melhorar disponibilidade e aumentar capacidade.

Mas existe uma pegadinha deliciosa.

Suponha que todos executem esta operação:

consulta horrorosa = 4 segundos

Adicionar servidores produz:

Server A = lento
Server B = lento
Server C = lento
Server D = lento

Você criou um cluster de lentidão.

Load balancing combate certos tipos de gargalo.

Não transforma código ineficiente em código eficiente.

Essa distinção vale ouro:

Escalar um problema pode apenas produzir mais instâncias do problema.


📬 CAPÍTULO 7 — PROCESSAMENTO ASSÍNCRONO: O MAINFRAME JÁ CONHECIA ESSE FEITIÇO

Um jovem desenvolvedor cloud anuncia:

— Mestre Ainz! Descobrimos processamento assíncrono!

Um programador mainframe de 1987 levanta a sobrancelha.

— Fila?

— Sim.

— Mensagem?

— Sim.

— Produtor e consumidor desacoplados?

— Sim.

— Próximo assunto.

Processamento assíncrono remove determinadas tarefas do caminho crítico da resposta.

Imagine uma compra.

No modelo totalmente síncrono:

Compra
  ↓
Pagamento
  ↓
Estoque
  ↓
Nota
  ↓
E-mail
  ↓
Analytics
  ↓
Resposta

O cliente precisa esperar tudo.

Mas será realmente necessário esperar o envio do e-mail?

Talvez possamos fazer:

Compra
  ↓
Processamento essencial
  ↓
MQ ─────→ e-mail
  ├──────→ analytics
  └──────→ processamento posterior
  ↓
Resposta

A percepção de latência diminui.

Mas existe uma frase que merece ser gravada na parede:

Assíncrono não significa que o trabalho desapareceu. Significa que alguém deixou de esperar por ele.

E o preço aparece em outra parte.

Agora precisamos pensar em mensagens duplicadas, retries, ordenação, idempotência, dead-letter queues, monitoramento, backpressure e consistência eventual.

Nada é grátis em Nazarick.

Nem MQ.


🗄️ CAPÍTULO 8 — DB2: ANTES DE COMPRAR CPU, OLHE PARA O ACCESS PATH

Imagine:

SELECT *
  FROM TRANSACOES
 WHERE CLIENTE = :WS-CLIENTE;

Parece inocente.

Agora descubra que TRANSACOES contém centenas de milhões de linhas.

A pergunta deixa de ser:

"O SQL está correto?"

e passa a ser:

"Como o Db2 encontrará essas linhas?"

Entram em cena índices, estatísticas, cardinalidade, access paths, joins, sorts, buffer pools e quantidade de dados movimentados.

Outra dica importantíssima:

SELECT *

pode buscar muito mais informação do que a aplicação necessita.

Se você precisa apenas:

CLIENTE
SALDO
STATUS

por que transportar outras dezenas de colunas?

Entretanto, índices também possuem custo.

Eles precisam ocupar espaço e ser mantidos conforme os dados mudam.

Então:

mais índice ≠ automaticamente melhor

O objetivo é oferecer bons caminhos para o workload real.

Performance não é colecionar índices como Ainz coleciona itens mágicos.


🧩 CAPÍTULO 9 — SHARDING: MAGIA DE ALTO NÍVEL, NÃO FEITIÇO DE APRENDIZ

Sharding divide um grande conjunto de dados em partes.

Por exemplo:

A–F → SHARD A
G–M → SHARD B
N–S → SHARD C
T–Z → SHARD D

Isso pode permitir distribuir armazenamento e processamento.

Excelente.

Até aparecer:

SELECT ...

que precisa consultar todos os shards.

Agora existem múltiplas máquinas, redes, falhas, coordenação e resultados para combinar.

Também podemos criar um hot shard.

Imagine que a divisão seja feita por região e 70% das transações estejam concentradas em uma única região.

Três shards tomam café.

Um pega fogo.

Sharding resolve determinados problemas gigantescos de escala, mas aumenta a complexidade.

Por isso não deveria ser a primeira reação diante de:

"Minha consulta está lenta."

Talvez esteja faltando simplesmente um índice adequado.

Não invoque magia de décimo nível para matar um Goblin.


🌎 CAPÍTULO 10 — CDN E A VELOCIDADE DA LUZ

Existe um adversário que nem COBOL, Java, Rust, Go ou magia de Nazarick derrotam:

a física.

Se o usuário está no Brasil e cada operação precisa conversar repetidamente com um servidor do outro lado do planeta, existe distância envolvida.

CDNs aproximam conteúdo do consumidor.

                 ┌── Edge Brasil
                 ├── Edge Europa
Origin → CDN ────┼── Edge EUA
                 └── Edge Ásia

Imagens, CSS, JavaScript, vídeos e outros objetos podem ser fornecidos a partir de pontos mais próximos.

É uma ideia brilhantemente simples:

A requisição mais rápida através de um oceano pode ser aquela que não precisa atravessar o oceano.


🌐 CAPÍTULO 11 — CADA NETWORK HOP É UMA PORTA DA DUNGEON

Observe uma arquitetura moderna:

Browser
   ↓
CDN
   ↓
WAF
   ↓
Load Balancer
   ↓
API Gateway
   ↓
Microservice A
   ↓
Microservice B
   ↓
Microservice C
   ↓
Database

Cada caixinha parece elegante em um PowerPoint.

Mas cada seta pode envolver rede, autenticação, serialização, TLS, filas, logging, tracing, processamento e possíveis retries.

Arquitetura possui custo.

Microsserviços podem oferecer excelentes vantagens organizacionais e técnicas, mas dividir um processo local em várias chamadas remotas não reduz automaticamente latência.

Uma chamada de função dentro do mesmo processo e uma requisição atravessando a rede são criaturas completamente diferentes.

Esse é um ponto que o veterano de mainframe costuma entender intuitivamente:

movimentar dados custa.


🔮 CAPÍTULO 12 — PREFETCH: ALBEDO TENTA ADIVINHAR O QUE AINZ PEDIRÁ

Prefetching significa antecipar uma necessidade.

Se o usuário pediu A e existe grande probabilidade de pedir B em seguida, podemos carregar B antecipadamente.

Quando acertamos:

Usuário pede B
      ↓
B já está disponível

Excelente experiência.

Quando erramos, consumimos recursos buscando algo que ninguém queria.

Portanto prefetch troca:

possível desperdício agora

por

possível redução de espera depois.

É essencialmente uma aposta baseada em padrões de acesso.

Com modelos preditivos, essa decisão pode ficar ainda mais sofisticada.

Mas previsão continua sendo previsão.

Até Demiurge pode errar.

Embora jamais admita isso diante de Ainz.


⚔️ CAPÍTULO 13 — PARALELISMO: QUATRO FLOOR GUARDIANS TRABALHANDO AO MESMO TEMPO

Temos quatro tarefas independentes:

A = 100 ms
B = 100 ms
C = 100 ms
D = 100 ms

Sequencialmente:

A → B → C → D

≈ 400 ms

Se puderem executar simultaneamente:

 ┌── A
 ├── B
 ├── C
 └── D

≈ 100 ms + overhead

Parece fantástico.

Mas suponha que todos precisem do mesmo recurso exclusivo.

A ─┐
B ─┼──→ LOCK
C ─┤
D ─┘

Agora temos contenção.

Adicionar concorrência pode aumentar filas.

Existe um limite a partir do qual mais trabalhadores não produzem proporcionalmente mais trabalho.

É como colocar cem cozinheiros em uma cozinha feita para cinco.

A cozinha não fica vinte vezes mais rápida.

Talvez ninguém consiga abrir a geladeira.


🔌 CAPÍTULO 14 — CONNECTION POOLING: NÃO RECONSTRUA A PONTE A CADA VIAGEM

Estabelecer conexões pode custar caro.

Imagine executar milhares de vezes:

conectar
autenticar
negociar
usar
desconectar

Se determinadas conexões puderem ser reutilizadas, um pool permite:

          ┌── conexão 1
Requests ─┼── conexão 2
          ├── conexão 3
          └── conexão 4

Mas até aqui existe equilíbrio.

Pool pequeno demais:

requisições esperando conexão

Pool exageradamente grande:

recursos desperdiçados
sobrecarga no destino
contenção

Mais uma vez:

performance engineering é engenharia de equilíbrio, não uma competição para colocar o maior número possível em uma configuração.


🚧 CAPÍTULO 15 — BACKPRESSURE: ATÉ NAZARICK TEM CAPACIDADE FINITA

Considere:

Entrada:      10.000 mensagens/s
Processamento: 6.000 mensagens/s

Sobram:

4.000 mensagens/s

A cada segundo.

Depois de um minuto, a diferença acumulada é enorme.

Se continuarmos aceitando indefinidamente:

fila aumenta
      ↓
memória aumenta
      ↓
latência aumenta
      ↓
timeouts aparecem
      ↓
clientes tentam novamente
      ↓
carga aumenta

Estamos alimentando o próprio monstro.

Backpressure é o mecanismo pelo qual uma parte do sistema sinaliza que não consegue absorver trabalho na velocidade em que ele está chegando.

É extremamente importante em sistemas assíncronos e distribuídos.

A fila não é um buraco negro de capacidade infinita.

MQ não conjura storage de outra dimensão.


💣 CAPÍTULO 16 — RETRY STORM: QUANDO A RECUPERAÇÃO VIRA O ATAQUE

Imagine 10.000 clientes chamando um serviço.

Ele começa a apresentar lentidão.

Clientes recebem timeout.

Todos pensam:

Tentar novamente!

O servidor, que já estava sofrendo, recebe outra avalanche.

Fica ainda mais lento.

Mais clientes recebem timeout.

Mais retries.

Temos:

SERVIDOR LENTO
      ↓
   TIMEOUT
      ↓
    RETRY
      ↓
 MAIS CARGA
      ↓
SERVIDOR MAIS LENTO

Um DDoS praticado involuntariamente pelos próprios clientes.

Por isso encontramos técnicas como exponential backoff, jitter, timeouts, circuit breakers e rate limiting.

Não basta perguntar:

"O sistema sabe tentar novamente?"

Precisamos perguntar:

"Quando, quantas vezes e em que ritmo?"


🏦 CAPÍTULO 17 — AINZ ENTRA NO DATACENTER DO BANCO

Agora juntaremos tudo.

Imagine:

Celular
   ↓
Internet
   ↓
API Gateway
   ↓
z/OS Connect
   ↓
CICS
   ↓
COBOL
   ↓
Db2
   ↓
MQ
   ↓
Sistema externo

O usuário reclama:

"Demorou 850 ms!"

Alguém imediatamente declara:

"O mainframe está lento!"

Ainz interrompe.

— Prove.

Medimos:

Internet             80 ms
Gateway              20 ms
z/OS Connect         15 ms
CICS                  30 ms
COBOL CPU              4 ms
Db2                   55 ms
MQ                    40 ms
Sistema externo      580 ms
Retorno               26 ms
---------------------------
TOTAL                850 ms

Temos nosso suspeito principal.

Sistema externo = 580 ms

O COBOL consumiu:

4 ms

Agora surge uma conclusão maravilhosa.

O componente acusado de lentidão pode ser justamente um dos componentes mais rápidos do caminho.

Essa é a diferença entre opinião e observabilidade.


🔭 CAPÍTULO 18 — SMF, RMF E WLM: OS ORÁCULOS DE NAZARICK

O universo mainframe possui uma longa tradição de instrumentação.

Termos modernos como observability, SRE, capacity management e performance engineering possuem parentes muito antigos no datacenter.

O mainframer conhece nomes como:

SMF
RMF
WLM
CICS monitoring
Db2 accounting
MQ statistics

SMF produz registros valiosíssimos sobre atividades do sistema e subsistemas.

RMF permite observar recursos e comportamento do ambiente.

WLM trabalha com workloads, classes de serviço, objetivos e gerenciamento dos recursos conforme prioridades e metas.

CICS possui suas métricas.

Db2 possui informações de accounting e performance.

MQ possui estatísticas e accounting.

A ideia fundamental é:

MEDIR
  ↓
LOCALIZAR
  ↓
ENTENDER
  ↓
FORMULAR HIPÓTESE
  ↓
ALTERAR
  ↓
MEDIR NOVAMENTE

Perceba o último passo.

Medir novamente.

Uma alteração não é uma otimização simplesmente porque parece inteligente.

Você precisa demonstrar o resultado.


🕵️ CAPÍTULO 19 — PASSO A PASSO PARA O PROGRAMADOR COBOL INVESTIGAR LATÊNCIA

Agora nosso Padawan — perdão, aventureiro de Nazarick — recebe seu procedimento.

Primeiro estabeleça o que significa lento. "Está demorando" não é unidade de medida. Descubra o tempo esperado e o observado.

Depois determine o escopo. Uma transação está lenta? Todas? Apenas em determinado horário? Somente alguns clientes? Depois do batch noturno? Durante pico? Após determinado deploy?

Em seguida obtenha métricas de distribuição. Não viva somente da média. Procure mediana, percentis e extremos quando disponíveis.

Depois decomponha o caminho.

Usuário
 ↓
Rede
 ↓
Frontend
 ↓
API
 ↓
Gateway
 ↓
CICS
 ↓
Programa
 ↓
Db2/MQ
 ↓
Dependências

Descubra onde o tempo é consumido.

Depois separe:

EXECUÇÃO

de:

ESPERA

E classifique as esperas.

Podem envolver I/O, locks, filas, rede, conexões, recursos, serviços remotos ou dependências.

Somente então escolha a solução.

Cache se existe trabalho repetitivo evitável.

Async se o usuário não precisa aguardar determinada atividade.

Índice ou revisão SQL se o banco está consumindo o tempo.

Load balancing se filas e saturação justificarem distribuição.

CDN se distância e entrega de conteúdo forem relevantes.

Paralelismo se existirem operações independentes e capacidade para executá-las simultaneamente.

Pooling se criação repetitiva de conexões for significativa.

Sharding somente quando o problema realmente justificar sua enorme complexidade.

Finalmente faça uma alteração controlada e meça novamente.

Isso é engenharia.


🧪 CAPÍTULO 20 — NÃO OTIMIZE NO ESCURO

Existe uma doença antiga entre programadores:

otimização por intuição.

O desenvolvedor olha o código e decide:

"Esse PERFORM parece caro."

Talvez seja.

Mas precisamos medir.

Imagine:

PERFORM VARYING WS-I FROM 1 BY 1
        UNTIL WS-I > 100
    ADD WS-I TO WS-TOTAL
END-PERFORM

Você passa horas tentando economizar microssegundos.

Enquanto isso, logo abaixo:

EXEC CICS LINK
     PROGRAM('PGMREMOT')
     COMMAREA(WS-COMMAREA)
END-EXEC

leva centenas de milissegundos devido ao que acontece além daquela chamada.

Ou existe SQL esperando lock.

Ou MQ aguardando uma dependência.

Ou uma API cruzando continentes.

A regra de Ainz:

Não ataque o monstro antes de descobrir qual monstro está drenando seu HP.


🧠 CAPÍTULO 21 — PERFORMANCE TAMBÉM É ARQUITETURA

Há uma lição ainda maior.

Performance não começa quando alguém reclama.

Decisões arquiteturais determinam grande parte do comportamento futuro.

Se você constrói:

A → B → C → D → E → F → G

e todos são síncronos, cada dependência entra no caminho crítico.

Se algumas operações puderem ser:

A → B → C → RESPONSE
        |
        +→ MQ → D
        +→ MQ → E
        +→ MQ → F

a experiência muda.

Mas você trocou simplicidade síncrona por complexidade assíncrona.

Essa troca precisa ser consciente.

Não existe arquitetura perfeita.

Existem trade-offs.

Performance, consistência, disponibilidade, simplicidade, custo, resiliência e manutenção frequentemente puxam o projeto em direções diferentes.


🥚 EASTER EGG — O INCIDENTE DAS 03:17

Às 03:17, um alerta dispara em Nazarick.

A transação passou de:

p99 = 180 ms

para:

p99 = 4.700 ms

Shalltear quer reiniciar o CICS.

Cocytus quer aumentar CPU.

Albedo culpa o Java.

Demiurge afirma que tudo faz parte do plano de Ainz.

O jovem COBOL olha o SMF.

Depois olha o Db2.

Depois olha MQ.

Finalmente encontra:

Fila crescendo desde 03:16:47
Consumidor externo degradado
Retries aumentando

Ainz declara:

— Exatamente como imaginei.

Por dentro:

"Sasuga... programador COBOL."


☕ CAPÍTULO FINAL — O SISTEMA NÃO ESTÁ LENTO. ALGUMA COISA ESTÁ ESPERANDO.

Voltamos à primeira tela.

RESPONSE TIME : 3.017 s
CPU TIME      : 0.004 s

No começo da aventura, o jovem programador pensava:

"Preciso tornar meu COBOL mais rápido."

Agora ele pergunta:

"Onde estão os outros 3.013 segundos?"

Essa pergunta muda tudo.

Talvez estejam no Db2.

Talvez em I/O.

Talvez esperando lock.

Talvez em uma fila.

Talvez em MQ.

Talvez na rede.

Talvez numa API.

Talvez aguardando uma conexão.

Talvez exista saturação.

Talvez exista retry storm.

Talvez uma arquitetura com quinze serviços tenha transformado uma operação simples numa excursão por quinze datacenters.

E somente depois de encontrar a resposta você escolhe a ferramenta.

CACHE
ASYNC
DB OPTIMIZATION
LOAD BALANCING
CDN
PARALLELISM
PREFETCH
POOLING
BACKPRESSURE
RATE LIMITING
SHARDING

Essa é provavelmente a maior deficiência daqueles infográficos chamados "10 maneiras de deixar qualquer sistema mais rápido".

As técnicas podem estar corretas.

O problema é imaginar que elas possam ser escolhidas antes do diagnóstico.

Um médico não olha para dez remédios e pergunta:

"Qual deles parece mais moderno?"

Primeiro investiga o paciente.

Performance engineering funciona da mesma maneira.

E existe uma conexão particularmente bonita com o universo mainframe.

Durante décadas, sistemas críticos precisaram responder perguntas como:

Quem consumiu CPU?

Quem esperou?

Quanto esperou?

Qual recurso provocou o atraso?

Qual workload deve ter prioridade?

Qual subsistema está saturado?

O problema está na aplicação ou fora dela?

É por isso que conceitos associados hoje a observabilidade, SRE e engenharia de performance soam tão familiares para quem cresceu olhando CICS, Db2, MQ, SMF, RMF e WLM.

As ferramentas evoluíram.

As arquiteturas ficaram distribuídas.

As APIs atravessaram a internet.

Os microsserviços multiplicaram os hops.

Cloud, containers e Kubernetes acrescentaram novas camadas.

Mas a pergunta fundamental continua praticamente a mesma:

ONDE FOI PARAR O TEMPO?

Ainz Ooal Gown levanta-se finalmente de seu trono.

O jovem programador aguarda sua sentença.

— Qual é a primeira regra de performance?

O aprendiz responde:

— Não otimizar antes de medir.

— E a segunda?

— Response time não é CPU time.

— E a terceira?

— Encontrar onde o sistema está esperando.

Ainz faz silêncio.

O programador continua:

— E nunca criar sharding para resolver um SELECT sem índice.

Demiurge sorri.

Albedo se emociona.

Cocytus aprova.

E, em algum lugar perdido de Nazarick, um job termina:

IEF142I BELLACOS STEP01 - STEP WAS EXECUTED
IEF373I STEP/STEP01 /START 20260926.0317
IEF374I STEP/STEP01 /STOP  20260926.0317
IEF375I JOB/BELLACOS/START 20260926.0317
IEF376I JOB/BELLACOS/STOP  20260926.0317

MAXCC=0000

Mas nosso programador já não comemora tão rapidamente.

Ele olha para o relógio.

Depois para CPU.

Depois para I/O.

Depois para as esperas.

Porque finalmente aprendeu:

MAXCC=0000 diz que o job terminou corretamente. Não diz que terminou rápido.

E essa talvez seja a melhor lição deixada pela Grande Tumba da Latência.

Sasuga, Ainz-sama.

Vagner Renato Bellacosa, IBM Champion e especialista em IBM Mainframe
IBM Z17 SYSTEM ONLINE
Sobre o autor

Vagner Renato Bellacosa

IBM Champion 2026 • Especialista em IBM Mainframe

Vagner Renato Bellacosa trabalha com IBM Mainframe desde 1988 , é IBM Champion e especialista em COBOL, CICS, Db2, z/OS e IBM Z. Compartilha experiências profissionais, conhecimento técnico, história da computação e práticas do universo mainframe para aproximar novas gerações das tecnologias que sustentam empresas, bancos e governos ao redor do mundo.

IBM Champion IBM Z COBOL CICS Db2 z/OS Mainframe desde 1988
GitHub LinkedIn
Inicializando conteúdo...