Da mesma forma que um suco de pomelo com mel e gengibre nos dá energia suficiente para seguir com as tarefas do dia-a-dia, por aqui preparamos nossos serviços e infraestrutura aplicando testes de carga, escalabilidade e resiliência para garantir que eles tenham a melhor performance possível.
Neste artigo, compartilhamos nossa experiência com o Identity, nosso produto para validação de identidade do usuário. Trata-se do sistema de segurança biométrica, desenvolvido pela Pomelo, que registra clientes e usuários durante a abertura e a ativação de produtos financeiros.
👉 Um spoiler: trazemos um exemplo prático dado por um super techie que detalha tooodo o nosso processo. Mas, se você é mais do tipo que não tem paciência para ler textos longos, não se preocupe — temos um resumo ao final do blog post! 👈
Pontapé inicial
A tecnologia biométrica em questão fará com que o cliente/usuário do banco passe por uma série de filtros de validação de biometria facial, cuja mágica interna se baseia em algoritmos que comprovam se a pessoa está viva. Além disso, verifica se o mapa do seu rosto corresponde às fotos que o sistema solicita durante a sessão de onboarding, como, por exemplo, uma foto em close, uma foto de longe, uma foto da sua carteira de identidade.
A API do SDK expõe alguns endpoints que devem gerar o token de segurança da sessão de onboarding. Também decodifica as fotos capturadas no processo de biometria, que utiliza a codificação base64.
O SDK tem dois algoritmos que medem indicadores FAR/FRR (False Accept Rate de Spoofing e False Rejection Rate):
- session-token: gera um token uuid, um identificador único universal, para cada sessão de onboarding;
- liveness-3d: o componente Liveness 2D-3D mede a eficácia da biometria na identificação e verificação de um ser humano vivo usando FAR/FRR, isto é, quando você tira uma foto/selfie do seu rosto.
- enrollment-3d: é o mesmo processo do liveness-3d, que comprova se a pessoa está viva. Além disso, ele salva em um banco de dados um registro de provas de vida que servirão como base de comparação para futuras verificações de liveness. Aqui também é registrado um parâmetro adicional, o externalDatabaseRefID , para indexar a biometria no banco de dados.
Validações de segurança
As validações de segurança têm margens de erro e de sensibilidade. Por isso, cada implementador deve configurar o limite de tolerância para a inconsistência de um determinado padrão.
Match-3d-2d: Componente biométrico que analisa se os Facemaps 3D atingem pelo menos 1/125.000.000 FAR, e, portanto, são provenientes de seres humanos vivos. Exemplo: sua selfie e a foto da sua carteira de identidade.
Por que testar o desempenho do SDK?
Geralmente, ao emitir um cartão ou um produto usando mala direta para os clientes, todos eles desejarão se registrar ao mesmo tempo assim que o receberem. É por isso que o processo de conversão, criptografia, descriptografia, comparação e registro de provas de vida bem-sucedidas e mal-sucedidas exigem um alto desempenho em termos de infraestrutura, a fim de oferecer alta disponibilidade.
Para criar um planejamento de capacidade e um plano de mitigação de riscos em ambientes de produção, você realmente necessita de métricas de desempenho no nível da API, do Serviço, do Cluster e da Instância.
Elementos-chave do nosso sistema de biometria com uso simultâneo e elevado:
- O Servidor HTTP é um elemento importante. Por exemplo, um servidor baseado em Java precisa ter uma JVM otimizada.
- O componente de calibração de imagens da selfie e da foto da carteira de identidade.
Desafio
Em resumo, fazer testes de carga sem ser banido pelo servidor SDK e, além disso, atingir o coração do SDK.
O primeiro desafio é simular testes de carga para uma tecnologia que, por natureza, rejeita solicitações de agentes do tipo bots, crawlers, wrappers, DDoS e ferramentas de teste de desempenho. Portanto, é preciso fazer com que o sistema acredite que somos pessoas vivas.
O segundo desafio é enviar solicitações ao SDK simultaneamente e sem estressar a máquina de teste de carga, o que geraria gargalos sem causar maiores impactos ao sistema em teste.
E, bem, qual é o nosso objetivo final?
Atingir o SDK com cargas de solicitações por segundo e ver como reage o balanceamento do servidor http dedicado do SDK, o componente biométrico e a infraestrutura que dá suporte a ele.
Recursos disponíveis
Como em uma receita culinária, sempre são necessários vários elementos para começar:
- Um ambiente de teste que seja homologado para produção na medida do possível: neste caso temos um AWS ECS. No nosso caso, usamos instâncias do tipo c6i.2xlarge
- Uma ferramenta versátil de teste de carga com o menor consumo de recursos possível em sua máquina de geração de usuários virtuais. No nosso caso, usamos o K6. Para obter mais informações sobre o k6 e suas funcionalidades, visite http://www.k6.io
- Postman
- New Relic como ferramenta de Logs, Métricas e Rastreamento.
Proposta
Existem duas formas de medir o desempenho do SDK da tecnologia de biometria:
- Simular chamadas para o front-end, que se encarrega de atingir o back-end;
- Ignorando o front-end e atingindo diretamente os endpoints do SDK.
A forma proposta e mais simples de alcançar nosso objetivo é a número 2. Os endpoints que me proponho a testar neste artigo são os seguintes, uma vez que permitiram que eu alcançasse o objetivo apresentado:
- /session-token
- /liveness-3d
- /enrollment-3d
Está na hora de nos tornarmos techies
O SDK recebe solicitações de dispositivos Android, iOS, Mac, WIndows e Linux. Focarei apenas na simulação de solicitações a partir de um Mac, como se quisesse me registrar a partir do PC.
Observação: A maioria das tecnologias de biometria facial utiliza o mesmo esquema cliente-servidor que exibimos aqui.
- No navegador você deve ativar as “Ferramentas para Desenvolvedores” para analisar o tráfego na guia “Rede”. Depois de ativá-las, abra a URL da ID da sessão, por exemplo: “https://identity-stage.yoursite.com/iss-29hc40KvFEGFw8VkSBwmvbMywot”
- Depois de iniciar sua sessão de onboarding, aceite os termos e condições e o processo de captura de fotos/selfies.
- Abra a solicitação /session-token na guia “Rede” das “ferramentas para desenvolvedores” e extraia os seguintes parâmetros da Solicitação de Cabeçalho:
- User-Agent
- X-Device-Key
- X-User-Agent
Estamos interessados em obter os valores X-Device-Key e X-User-Agent que vamos inserir em nosso script com o k6 mais tarde.
Exemplo:
X-Device-Key': 'duw7grMW0E0aQXhm2xWaknFpXLJZn1E3',
'X-User-Agent':'faceTechnology|sdk|web|identity-stage.yoursite.com|duw7grMW0E0aQXhm2xWaknFpXLJZn1E3|adeb284a-72a8-4da0-bb9d-23dd8874b0f1|MacIntel10_15_7|9.4.7|en-US|en|528bc9bc-7f93-4bf3-9726-7524a38e1229'
4. Na solicitação /liveness, vamos à seção Solicitação e extraímos a carga útil debiometric_data, a biometria da sua selfie com codificação base64:
Como podemos observar, a carga útil no nível frontal tem a forma:
{
"biometric_provider": "biometricTec",
"biometric_data": {
"metadata": {
"face_scan": "yyyyyyy",
"low_quality_audit_trail_image": "xxxxxxyyyyy/",
"session_id": "23nb123-"
"selfie": "xxxxxx",
}
}
}
5. Com base na coleta do Teste Postman fornecida por nosso provedor do SDK de biometria, descobrimos que a solicitação POST/liveness3d tem uma carga útil do corpo com menos campos, que são os que vamos utilizar em nosso script.
6. Cruzando a carga útil da solicitação capturada pelas “ferramentas para desenvolvedores” com a carga útil da solicitação do TestSuite Postman do provedor SDK, criaremos nossa solicitação/liveness da seguinte forma:
{
"faceScan": "acá va el valor de face_scan",
"auditTrailImage": "acá va el valor de selfie",
"lowQualityAuditTrailImage": "acá va el lowQualityAuditTrailImage"
}
7. Acontece que /liveness e /enrollment constituem uma mesma solicitação e respondem com a mesma API, então em /enrollment precisaremos adicionar mais um campo na Carga Útil chamado externalDatabaseRefID cujo valor é uma string única por sessão. No meu caso, uso o mesmo valor de session_id.
8. “session_id” pode ser extraído do Json Response ligando para o {{SERVER_BASE_URL}}/session-tokendo endpoint
Um lembrete: O parâmetro X-Device-Key é obtido por meio das Ferramentas para Desenvolvedores na solicitação /session-token quando você aceita os termos e condições.
O session_id corresponde ao “tid” que nos dá como resultado o elemento “$callData.tid” equivalente ab14c3737-5cce-499a-a7db-5a65123b18d5
9. Agora que temos o session_id, devemos construir nosso header X-User-Agent:
facetechnolgy|sdk|web|identity-stage.yoursite.com||adeb284a-72a8-4da0-bb9d-23dd8874b0f1|MacIntel 10_15_7|9.4.7|en-US|en|b14c3737-5cce-499a-a7db-5a65123b18d5
Caso queira testar simulando através de um Android ou iOS, basta alterar o valor. Por exemplo: facetechnolgy|sdk| {{Android}} | identity-stage.yoursite….|…
10. Uma vez que você tenha entendido como são construídos o X-Device-Key e o X-User-Agent, você deverá colocá-los na solicitação de cabeçalho para /liveness-3d e /enrollment
Colocando tudo no k6
No k6 podemos facilmente construir scripts separadamentepara depois importá-los a partir de um main.js. No nosso caso, decidi fazê-lo assim:
1. Criei uma função para cada endpoint a ser executado, isto é, /session-token, /liveness, /enrollment
2. Preparei um cenário de cargas com foco na ramping-arrival-rate, em que o K6 permite definir a quantidade de RPS necessária de acordo com suas necessidades. Neste exemplo, o k6 fará 2 iterações por segundo, (target :2 / timeUnit 1s) durante 120 segundos, com pausas de 60 segundos.
Cada iteração consiste em 3 solicitações ao SDK:
1. /session-token => 2. /liveness => 3./enrollment
Portanto, a taxa de acertos será de 2*(3 acertos)/s, permitindo que alcancemos uma taxa de transferência no SDK entre 3 e 6 acertos/s, já que teremos think times intermediários que alteram ligeiramente a taxa de simultaneidade.
3. Em seguida, construímos nossa função padrão principal, que faz parte dos módulos importados.
Ao externadlDabaseRefID eu atribuo um valor qualquer. Nesse caso, utilizei novamente o session_id, que também é nosso token de autenticação para cada solicitação.
Função liveness3D.js
Vocês podem ver que, antes de iniciar a função, carregamos o arquivo que contém a carga útil, no qual devemos inserir o ExternalDatabaseRFID e a session_id.
Função enrollment.js
É basicamente a mesma funcionalidade do Liveness-3d, mas adicionamos a ela o externadlDabaseRefID.
Observem que em cada script é carregado um arquivo .json que tem a carga útil de cada endpoint e cujo tamanho é superior a 300 Mb devido à criptografia das imagens da captura biométrica.
Esta função é a primeira solicitação feita pela iteração, em que obteremos a session_id do elemento“callData”:
{
"tid": "b14c3737-5cce-499a-a7db-5a65123b18d5",
…..
Resultados
Lembrem-se de que o objetivo final era, por um lado, evitar rejeições do agente de segurança do lado do SDK como consequência de enviarmos solicitações simultâneas e com parâmetros biométricos repetidos. E, por outro lado, estimular o serviço que exige infraestrutura.
Ambos os objetivos foram alcançados. Temos métricas de desempenho coletadas pelo K6 no nível do cliente, nesse caso um Mac Intel M1, e também temos métricas do Cloudwatch, coletadas pelo New Relic:
No nível dos logs, filtrando por “solicitação iniciada” podemos observar o número de solicitações por segundo que conseguimos impactar nos endpoints. Vejam o carimbo de data/hora:
Chegamos ao fim!
Nós prometemos que, no final do blog post, traríamos um resumo deste estudo de caso – bem, aqui está!
Nós comprovamos que sim, é possível realizar testes de carga para a infraestrutura que dá suporte ao SDK de biometria e conhecer seu comportamento com o tráfego virtual.
Isso mesmo que não estivéssemos simulando um cenário real, já que não envolvemos o Match-3d devido a restrições primitivas na segurança do SDK de biometria. Mas, ao gerar tráfego no liveness3d e no enrollment, obtém-se as “quatro métricas de ouro”, que certamente darão a você insights sobre o que nossa implementação do SDK é capaz de suportar. Ou então, dirão se você deve considerar criar sua própria implantação do servidor http que faça o balanceamento das cargas para o SDK. Mas isso depende principalmente do seu negócio e da sua estimativa de clientes simultâneos.
Também vimos que com a ajuda do K6 é fácil desenvolver scripts que automatizam as solicitações simultâneas para o sistema de destino. E, ao mesmo tempo, permitir que qualquer desenvolvedor entenda a lógica dos scripts.
… e, claro, mais um serviço da nossa pilha, que passa pelos respectivos testes de carga para proporcionar o melhor desempenho aos nossos clientes.
Espero que este artigo te traga insights e seja útil para seu produto e negócio. Por aqui, estamos sempre realizando testes de tecnologia na velocidade Pomelo — e claro que não deixamos de compartilhá-los com vocês aqui no blog!