mirror of https://github.com/grpc/grpc-node.git
grpc-js: Add more outlier detection tests and tracing
This commit is contained in:
parent
aaa568fc01
commit
24c4cd7bb8
|
@ -423,9 +423,10 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer {
|
||||||
const targetRequestVolume = successRateConfig.request_volume;
|
const targetRequestVolume = successRateConfig.request_volume;
|
||||||
let addresesWithTargetVolume = 0;
|
let addresesWithTargetVolume = 0;
|
||||||
const successRates: number[] = []
|
const successRates: number[] = []
|
||||||
for (const mapEntry of this.addressMap.values()) {
|
for (const [address, mapEntry] of this.addressMap) {
|
||||||
const successes = mapEntry.counter.getLastSuccesses();
|
const successes = mapEntry.counter.getLastSuccesses();
|
||||||
const failures = mapEntry.counter.getLastFailures();
|
const failures = mapEntry.counter.getLastFailures();
|
||||||
|
trace('Stats for ' + address + ': successes=' + successes + ' failures=' + failures + ' targetRequestVolume=' + targetRequestVolume);
|
||||||
if (successes + failures >= targetRequestVolume) {
|
if (successes + failures >= targetRequestVolume) {
|
||||||
addresesWithTargetVolume += 1;
|
addresesWithTargetVolume += 1;
|
||||||
successRates.push(successes/(successes + failures));
|
successRates.push(successes/(successes + failures));
|
||||||
|
@ -545,6 +546,7 @@ export class OutlierDetectionLoadBalancer implements LoadBalancer {
|
||||||
|
|
||||||
private startTimer(delayMs: number) {
|
private startTimer(delayMs: number) {
|
||||||
this.ejectionTimer = setTimeout(() => this.runChecks(), delayMs);
|
this.ejectionTimer = setTimeout(() => this.runChecks(), delayMs);
|
||||||
|
this.ejectionTimer.unref?.();
|
||||||
}
|
}
|
||||||
|
|
||||||
private runChecks() {
|
private runChecks() {
|
||||||
|
|
|
@ -20,6 +20,7 @@ import * as path from 'path';
|
||||||
import * as grpc from '../src';
|
import * as grpc from '../src';
|
||||||
import { loadProtoFile } from './common';
|
import { loadProtoFile } from './common';
|
||||||
import { OutlierDetectionLoadBalancingConfig } from '../src/load-balancer-outlier-detection'
|
import { OutlierDetectionLoadBalancingConfig } from '../src/load-balancer-outlier-detection'
|
||||||
|
import { ServiceClient } from '../src/make-client';
|
||||||
|
|
||||||
function multiDone(done: Mocha.Done, target: number) {
|
function multiDone(done: Mocha.Done, target: number) {
|
||||||
let count = 0;
|
let count = 0;
|
||||||
|
@ -49,6 +50,54 @@ const defaultOutlierDetectionServiceConfig = {
|
||||||
|
|
||||||
const defaultOutlierDetectionServiceConfigString = JSON.stringify(defaultOutlierDetectionServiceConfig);
|
const defaultOutlierDetectionServiceConfigString = JSON.stringify(defaultOutlierDetectionServiceConfig);
|
||||||
|
|
||||||
|
const successRateOutlierDetectionServiceConfig = {
|
||||||
|
methodConfig: [],
|
||||||
|
loadBalancingConfig: [
|
||||||
|
{
|
||||||
|
outlier_detection: {
|
||||||
|
interval: {
|
||||||
|
seconds: 1,
|
||||||
|
nanos: 0
|
||||||
|
},
|
||||||
|
base_ejection_time: {
|
||||||
|
seconds: 3,
|
||||||
|
nanos: 0
|
||||||
|
},
|
||||||
|
success_rate_ejection: {
|
||||||
|
request_volume: 5
|
||||||
|
},
|
||||||
|
child_policy: [{round_robin: {}}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const successRateOutlierDetectionServiceConfigString = JSON.stringify(successRateOutlierDetectionServiceConfig);
|
||||||
|
|
||||||
|
const failurePercentageOutlierDetectionServiceConfig = {
|
||||||
|
methodConfig: [],
|
||||||
|
loadBalancingConfig: [
|
||||||
|
{
|
||||||
|
outlier_detection: {
|
||||||
|
interval: {
|
||||||
|
seconds: 1,
|
||||||
|
nanos: 0
|
||||||
|
},
|
||||||
|
base_ejection_time: {
|
||||||
|
seconds: 3,
|
||||||
|
nanos: 0
|
||||||
|
},
|
||||||
|
failure_percentage_ejection: {
|
||||||
|
request_volume: 5
|
||||||
|
},
|
||||||
|
child_policy: [{round_robin: {}}]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const falurePercentageOutlierDetectionServiceConfigString = JSON.stringify(failurePercentageOutlierDetectionServiceConfig);
|
||||||
|
|
||||||
const goodService = {
|
const goodService = {
|
||||||
echo: (call: grpc.ServerUnaryCall<any, any>, callback: grpc.sendUnaryData<any>) => {
|
echo: (call: grpc.ServerUnaryCall<any, any>, callback: grpc.sendUnaryData<any>) => {
|
||||||
callback(null, call.request)
|
callback(null, call.request)
|
||||||
|
@ -353,6 +402,20 @@ describe('Outlier detection', () => {
|
||||||
badServer.forceShutdown();
|
badServer.forceShutdown();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function makeManyRequests(makeOneRequest: (callback: (error?: Error) => void) => void, total: number, callback: (error?: Error) => void) {
|
||||||
|
if (total === 0) {
|
||||||
|
callback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
makeOneRequest(error => {
|
||||||
|
if (error) {
|
||||||
|
callback(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
makeManyRequests(makeOneRequest, total - 1, callback);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
it('Should allow normal operation with one server', done => {
|
it('Should allow normal operation with one server', done => {
|
||||||
const client = new EchoService(`localhost:${goodPorts[0]}`, grpc.credentials.createInsecure(), {'grpc.service_config': defaultOutlierDetectionServiceConfigString});
|
const client = new EchoService(`localhost:${goodPorts[0]}`, grpc.credentials.createInsecure(), {'grpc.service_config': defaultOutlierDetectionServiceConfigString});
|
||||||
client.echo(
|
client.echo(
|
||||||
|
@ -364,4 +427,110 @@ describe('Outlier detection', () => {
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
describe('Success rate', () => {
|
||||||
|
let makeCheckedRequest: (callback: () => void) => void;
|
||||||
|
let makeUncheckedRequest:(callback: (error?: Error) => void) => void;
|
||||||
|
before(() => {
|
||||||
|
const target = 'ipv4:///' + goodPorts.map(port => `127.0.0.1:${port}`).join(',') + `,127.0.0.1:${badPort}`;
|
||||||
|
const client = new EchoService(target, grpc.credentials.createInsecure(), {'grpc.service_config': successRateOutlierDetectionServiceConfigString});
|
||||||
|
makeUncheckedRequest = (callback: () => void) => {
|
||||||
|
client.echo(
|
||||||
|
{ value: 'test value', value2: 3 },
|
||||||
|
(error: grpc.ServiceError, response: any) => {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
makeCheckedRequest = (callback: (error?: Error) => void) => {
|
||||||
|
client.echo(
|
||||||
|
{ value: 'test value', value2: 3 },
|
||||||
|
(error: grpc.ServiceError, response: any) => {
|
||||||
|
callback(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
it('Should eject a server if it is failing requests', done => {
|
||||||
|
// Make a large volume of requests
|
||||||
|
makeManyRequests(makeUncheckedRequest, 50, () => {
|
||||||
|
// Give outlier detection time to run ejection checks
|
||||||
|
setTimeout(() => {
|
||||||
|
// Make enough requests to go around all servers
|
||||||
|
makeManyRequests(makeCheckedRequest, 10, done);
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('Should uneject a server after the ejection period', function(done) {
|
||||||
|
this.timeout(5000);
|
||||||
|
makeManyRequests(makeUncheckedRequest, 50, () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
makeManyRequests(makeCheckedRequest, 10, error => {
|
||||||
|
if (error) {
|
||||||
|
done(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
makeManyRequests(makeCheckedRequest, 10, error => {
|
||||||
|
assert(error);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
}, 3000);
|
||||||
|
});
|
||||||
|
}, 1000);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('Failure percentage', () => {
|
||||||
|
let makeCheckedRequest: (callback: () => void) => void;
|
||||||
|
let makeUncheckedRequest:(callback: (error?: Error) => void) => void;
|
||||||
|
before(() => {
|
||||||
|
const target = 'ipv4:///' + goodPorts.map(port => `127.0.0.1:${port}`).join(',') + `,127.0.0.1:${badPort}`;
|
||||||
|
const client = new EchoService(target, grpc.credentials.createInsecure(), {'grpc.service_config': falurePercentageOutlierDetectionServiceConfigString});
|
||||||
|
makeUncheckedRequest = (callback: () => void) => {
|
||||||
|
client.echo(
|
||||||
|
{ value: 'test value', value2: 3 },
|
||||||
|
(error: grpc.ServiceError, response: any) => {
|
||||||
|
callback();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
makeCheckedRequest = (callback: (error?: Error) => void) => {
|
||||||
|
client.echo(
|
||||||
|
{ value: 'test value', value2: 3 },
|
||||||
|
(error: grpc.ServiceError, response: any) => {
|
||||||
|
callback(error);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
it('Should eject a server if it is failing requests', done => {
|
||||||
|
// Make a large volume of requests
|
||||||
|
makeManyRequests(makeUncheckedRequest, 50, () => {
|
||||||
|
// Give outlier detection time to run ejection checks
|
||||||
|
setTimeout(() => {
|
||||||
|
// Make enough requests to go around all servers
|
||||||
|
makeManyRequests(makeCheckedRequest, 10, done);
|
||||||
|
}, 1000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('Should uneject a server after the ejection period', function(done) {
|
||||||
|
this.timeout(5000);
|
||||||
|
makeManyRequests(makeUncheckedRequest, 50, () => {
|
||||||
|
setTimeout(() => {
|
||||||
|
makeManyRequests(makeCheckedRequest, 10, error => {
|
||||||
|
if (error) {
|
||||||
|
done(error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setTimeout(() => {
|
||||||
|
makeManyRequests(makeCheckedRequest, 10, error => {
|
||||||
|
assert(error);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
}, 3000);
|
||||||
|
});
|
||||||
|
}, 1000);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
Loading…
Reference in New Issue