Tengo un servidor NodeJS que se ejecuta con NestJS y se implementa en AKS.
Creé un interceptor para que si envío un 'perfil' de encabezado HTTP, ejecutará el código habitual, pero en lugar de enviar la respuesta, reemplazará el cuerpo con la salida del perfil.
Aquí está el código:
import { CallHandler, ExecutionContext, Injectable, NestInterceptor, } from '@nestjs/common'; import { Observable } from 'rxjs'; import { map } from 'rxjs/operators'; import { Session } from 'inspector'; /** * This interceptor will replace the body of the response with the result of the profiling * if the request as a header 'profile' * * To use on a controller or a method, simply decorate it with @UseInterceptors(Profiler) */ @Injectable() export class Profiler implements NestInterceptor { intercept(context: ExecutionContext, next: CallHandler): Observable<any> | Promise<Observable<any>> { const profile = context.switchToHttp().getRequest().get('profile'); // if the request doesn't have a 'profile' header, we deal with the request as usual if (!profile) return next.handle(); // start a profiling session const session = new Session(); session.connect(); return new Promise((resolve) => { session.post('Profiler.enable', () => { session.post('Profiler.start', () => { resolve(next.handle().pipe(map(() => new Promise((resolve) => { session.post('Profiler.stop', (_, { profile }) => { resolve(profile); }); })))); }); }); }); } }Al hacerlo, puedo obtener un JSON que luego puedo abrir con la herramienta de desarrollo de Chrome:
Puede ver que todas las funciones individuales solo tardan unos pocos ms en ejecutarse, pero en el medio, hay muuuuchos descansos.
Aquí hay un extracto de mi archivo deployment.yaml que muestra que mi pod debe tener 2 GB de memoria, lo que creo que debería ser suficiente.
spec: serviceAccount: {{ include "api.fullname" . }}-service-account containers: - name: {{ .Chart.Name }} image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" imagePullPolicy: {{ .Values.image.pullPolicy }} resources: limits: memory: "2000Mi" requests: memory: "2000Mi" ports: - name: http containerPort: {{ .Values.port }} protocol: TCPEntonces, ¿cómo podemos explicar estos largos descansos y cómo prevenirlos?
Al agregar más registros en torno a las solicitudes de la base de datos, nos dimos cuenta de que las primeras solicitudes demoraban alrededor de 2 a 3 segundos, mientras que las siguientes solo demoraban ~ 10 ms o menos.
La solución fue usar PgBouncer para mantener un grupo de conexiones con la base de datos.
Más información aquí: https://techcommunity.microsoft.com/t5/azure-database-for-postgresql/steps-to-install-and-setup-pgbouncer-connection-pooling-proxy/ba-p/730555