생산 시험
got
에서 undici
로 전환함으로써 시간을 절약할 수 있다는 것이지만, 결정을 내리기 전에 깊이 있는 실험을 하기로 결정했다.때가 됐어.그러나 실험을 시작하기 전에 먼저 New Relic 계기판이 추적 기능을 사용한 상태에서 며칠 동안 생산 환경에서 실행된 후의 모습을 살펴보겠습니다.
깔끔해요.첫 번째 도표는 평균 응답 시간(추적의 지속 시간)을 나타냈고, 두 번째 도표는 내가 초당 몇 개의 추적을 나타냈는지(내가 항상 요청한 샘플임을 기억하세요), 세 번째 도표는 오류가 발생했음을 나타냈다(비록 오보가 많았지만).
이런 관찰 도구와 보고에 익숙해지는 것은 좋은 생각이다.this article에서 지적한 바와 같이 서비스의'정상'을 느낄 수 있도록 도와주면 언제 문제가 생겼는지 쉽게 알 수 있다.
그것들은 또한 귀하가 서비스나 사용자의 행위를 이해하는 데 도움을 줄 수 있는 견해를 제공합니다.예를 들어 저희가 받은 요청 수량과 응답 시간 사이에 관련성이 있음을 발견할 수 있습니다.그러나 이것은 관찰일 뿐 결론이 아니다.가능한 원인은 더 높은 부하, 특정 유형의 요청 입력, 맞춤형 공격 등일 수 있다. 그리고 우리는 당시 추적된 데이터를 보고 조사를 하고 필요에 따라 더 많은 도구를 추가할 수 있다.
자, 이제 실험을 시작합시다.
구현
우선, 새로운 요청이 들어왔을 때, 우리는 사용할 클라이언트를 무작위로 선택할 것입니다.요청을 시작할 때 이렇게 하고, 선택을 요청 상하문에 저장합니다. 그러면 코드의 어느 곳에서든 접근할 수 있습니다. 이것은 매우 중요합니다.
function chooseHttpClient() {
// There may be more sophisticated ways, but we'll do a simple Math.random()
return Math.random() > 0.5 ? 'got' : 'undici';
}
// ...
const openTelemetry = require("@opentelemetry/sdk-node");
// Request handler: Pick a client and save it to the context
app.post('/fetch', async (req, res, next) => {
const client = chooseHttpClient();
// Save thechosen client as a span attribute so we can filter or group traces by it
// for easy comparisons (in Zipkin or New Relic)
span.setAttribute('external.client', client);
// And save it to the context so we can access it in nested spans
const context = openTelemetry.api.context.active().setValue(Symbol.for('external.client'), client);
return openTelemetry.api.context.with(context, async () => {
// Handle request...
res.send(result);
});
});
그리고 다음 코드에서 외부 호출이 필요할 때 선택한 클라이언트를 검색하고 해당하는 라이브러리를 사용합니다.이것은 약간 까다로워 보이지만, 우리가 하는 일은 단지 다른 함수를 호출한 다음에 임의의 라이브러리에서 온 응답을 같은 모양으로 규범화하는 것이다.function getChosenHttpClient() {
return openTelemetry.api.context.active().getValue(Symbol.for('external.client'))
};
const got = require("got");
const undici = require('undici');
const makeRequest = (url) => {
return wrapExternalCallInSpan('first external call', url, (span) => {
let requestPromise;
switch (getChosenHttpClient()) {
case 'got':
requestPromise = got(url, gotOptions).then(response => {
return [response.statusCode, response.body];
});
break;
case 'undici':
requestPromise = undici.request(url, undiciOptions).then(response => {
return Promise.all([response.statusCode, response.body.text()]);
});
}
return requestPromise.then(([statusCode, body]) => {
span.setAttribute('external.status_code', statusCode);
// Do stuff with body
}).catch(handleError)
.finally(() => {
span.end();
});
};
쿨하다실험을 진행하다
우리 현지 기계에 대한 영향을 봅시다.나는
autocannon
concurrency series에서 온 친구)로 40개의 요청을 신속하게 보낼 것이다.이것은 우리에게 대량의got/undici 요청을 제공할 것이다.autocannon --connections 5 --amount 40 \
--body "The request body" --method POST \
http://localhost:3000/fetch
그리고 우리는 두 개의 창에서 Zipkin을 열었다.그중 하나는 여과external.client=got
;또 하나external.client=undici
.나는 모든 요청을 표시할 수 없지만, 여기는 모든 요청이 가장 느리고 빠르다.우선:그런 다음 undici:
(겸사겸사 한마디 하자면, 각 유형마다 딱 20개의 결과가 있는데, 이거 좋잖아?
Math.random()
통과했어!😅)좋아요.보아하니
undici
많이 이긴 것 같다.여기서 가장 빠른 요청got
은 1.8초, 가장 느린 요청은 2.9초였다.아울러 undici
에는 2초 이하 요청이 13개 있었고, 가장 빠른 요청은 1.355초였다.생산 모니터링
이 점에서, 당신은 "쿨, 우리를undici로 전환합시다."라고 말할 수 있습니다.그러나 만약에 방대한 사용자군과 더 복잡한 절차가 있다면 여러 가지 이유로 먼저 생산 과정에서 이 실험을 실행하는 것이 좋다.
우선, 생산 환경에서 실험을 진행하면 더욱 현실적인 기준인 더 큰 견본량과 실제 세계의 사용 모델과 서버 조건을 제공할 것이다.New Relic의 차트를 통해 많은 요청을 보다 쉽게 비교할 수 있습니다.
생산에서 실험을 하는 것은 reliability에 있어서 큰 복음이다.우리는 전체 응용 프로그램을 파괴하지 않는 상황에서 undici를 사용하는 다른 방면(예를 들어 외부 오류나 전환할 때 누락된 내용)을 감시할 수 있다.우리는 일부 사용자를 위해 new kid (undici) 를 사용하고, 대부분의 사용자를 위해 테스트를 거친 신뢰할 수 있는 (got) 하나를 보존할 것입니다.이렇게 하면 undici에 문제가 생기면 최대 소수의 사용자만 영향을 받는다.
여기 있는 코드에서, 우리는 두 클라이언트 사이에서 평균 분배 ((
Math.random() > 0.5
를 하지만, 더 큰 사용자 그룹에 대해서는, 당신은 일부분 (0.3일 수도 있음) 에서undici를 시도하기를 원할 수도 있습니다.시간의 흐름에 따라 undici에 대한 자신감이 높아지면 이 파벌을 1로 늘릴 수 있다.코드 변경 없이 클라이언트를 분할하거나 전환할 수 있도록 환경 변수를 사용해서 점수를 지정하는 것도 권장합니다.QA의 목적을 위해 귀하는 특수한 쿠키나 조회 파라미터를 사용하여 특정한 클라이언트를 강제할 수 있습니다.그래서 우리는 그것을 생산 환경에 배치하고 일정 시간 동안 감시하여 요청의 결과가 어떠한지 봅시다.
오류와 오류 결과에 대해 며칠 동안 모니터링을 한 후에 다음은 클라이언트별로 그룹을 나누어 추적하는 것이다.
그래프가 좀 드문드문합니다. 왜냐하면 저는 New Relic에서 며칠 동안 보존할 수 있기 때문입니다. 그러나 예상한 바와 같이 undici의 평균 응답 시간은 보통 비교적 낮습니다.그러나 우리는 평균치만 보아서는 안 된다.백분위수why?를 살펴보자. 다음은 통계 세분화. 먼저 got, 그 다음에 undici.
너는 got의 평균 소모 시간이 더 높을 뿐만 아니라, 그것의 p95도 undici의 (약 10초) 보다 훨씬 높다는 것을 알 수 있다.
그러므로 이 점에서 우리는 결론을 얻을 수 있다. 이것은 고칠 만한 것이다.남은 일은 최종적으로 우리의 코드를 업데이트하는 것이다.예!
Reference
이 문제에 관하여(생산 시험), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/shalvah/experimenting-in-production-acn텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)