mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
Revert "[8.8] [APM] Circuit breaker and perf improvements for service… (#160132)
This commit is contained in:
parent
258f83fd90
commit
f190fd1da9
9 changed files with 162 additions and 204 deletions
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License
|
||||
* 2.0 and the Server Side Public License, v 1; you may not use this file except
|
||||
* in compliance with, at your election, the Elastic License 2.0 or the Server
|
||||
* Side Public License, v 1.
|
||||
*/
|
||||
|
||||
import { ApmFields, httpExitSpan } from '@kbn/apm-synthtrace-client';
|
||||
import { service } from '@kbn/apm-synthtrace-client/src/lib/apm/service';
|
||||
import { Transaction } from '@kbn/apm-synthtrace-client/src/lib/apm/transaction';
|
||||
import { Scenario } from '../cli/scenario';
|
||||
import { RunOptions } from '../cli/utils/parse_run_cli_flags';
|
||||
import { getSynthtraceEnvironment } from '../lib/utils/get_synthtrace_environment';
|
||||
|
||||
const environment = getSynthtraceEnvironment(__filename);
|
||||
|
||||
const scenario: Scenario<ApmFields> = async (runOptions: RunOptions) => {
|
||||
const numServices = 500;
|
||||
|
||||
const tracesPerMinute = 10;
|
||||
|
||||
return {
|
||||
generate: ({ range }) => {
|
||||
const services = new Array(numServices)
|
||||
.fill(undefined)
|
||||
.map((_, idx) => {
|
||||
return service(`service-${idx}`, 'prod', environment).instance('service-instance');
|
||||
})
|
||||
.reverse();
|
||||
|
||||
return range.ratePerMinute(tracesPerMinute).generator((timestamp) => {
|
||||
const rootTransaction = services.reduce((prev, currentService) => {
|
||||
const tx = currentService
|
||||
.transaction(`GET /my/function`, 'request')
|
||||
.timestamp(timestamp)
|
||||
.duration(1000)
|
||||
.children(
|
||||
...(prev
|
||||
? [
|
||||
currentService
|
||||
.span(
|
||||
httpExitSpan({
|
||||
spanName: `exit-span-${currentService.fields['service.name']}`,
|
||||
destinationUrl: `http://address-to-exit-span-${currentService.fields['service.name']}`,
|
||||
})
|
||||
)
|
||||
.timestamp(timestamp)
|
||||
.duration(1000)
|
||||
.children(prev),
|
||||
]
|
||||
: [])
|
||||
);
|
||||
|
||||
return tx;
|
||||
}, undefined as Transaction | undefined);
|
||||
|
||||
return rootTransaction!;
|
||||
});
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
export default scenario;
|
|
@ -26,8 +26,6 @@ const configSchema = schema.object({
|
|||
serviceMapTraceIdBucketSize: schema.number({ defaultValue: 65 }),
|
||||
serviceMapTraceIdGlobalBucketSize: schema.number({ defaultValue: 6 }),
|
||||
serviceMapMaxTracesPerRequest: schema.number({ defaultValue: 50 }),
|
||||
serviceMapTerminateAfter: schema.number({ defaultValue: 100_000 }),
|
||||
serviceMapMaxTraces: schema.number({ defaultValue: 1000 }),
|
||||
ui: schema.object({
|
||||
enabled: schema.boolean({ defaultValue: true }),
|
||||
maxTraceItems: schema.number({ defaultValue: 5000 }),
|
||||
|
|
|
@ -15,19 +15,12 @@ import {
|
|||
} from '../../../common/service_map';
|
||||
import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client';
|
||||
|
||||
export async function fetchServicePathsFromTraceIds({
|
||||
apmEventClient,
|
||||
traceIds,
|
||||
start,
|
||||
end,
|
||||
terminateAfter,
|
||||
}: {
|
||||
apmEventClient: APMEventClient;
|
||||
traceIds: string[];
|
||||
start: number;
|
||||
end: number;
|
||||
terminateAfter: number;
|
||||
}) {
|
||||
export async function fetchServicePathsFromTraceIds(
|
||||
apmEventClient: APMEventClient,
|
||||
traceIds: string[],
|
||||
start: number,
|
||||
end: number
|
||||
) {
|
||||
// make sure there's a range so ES can skip shards
|
||||
const dayInMs = 24 * 60 * 60 * 1000;
|
||||
const startRange = start - dayInMs;
|
||||
|
@ -37,7 +30,6 @@ export async function fetchServicePathsFromTraceIds({
|
|||
apm: {
|
||||
events: [ProcessorEvent.span, ProcessorEvent.transaction],
|
||||
},
|
||||
terminate_after: terminateAfter,
|
||||
body: {
|
||||
track_total_hits: false,
|
||||
size: 0,
|
||||
|
|
|
@ -46,10 +46,8 @@ async function getConnectionData({
|
|||
end,
|
||||
serviceGroupKuery,
|
||||
kuery,
|
||||
logger,
|
||||
}: IEnvOptions) {
|
||||
return withApmSpan('get_service_map_connections', async () => {
|
||||
logger.debug('Getting trace sample IDs');
|
||||
const { traceIds } = await getTraceSampleIds({
|
||||
config,
|
||||
apmEventClient,
|
||||
|
@ -61,8 +59,6 @@ async function getConnectionData({
|
|||
kuery,
|
||||
});
|
||||
|
||||
logger.debug(`Found ${traceIds.length} traces to inspect`);
|
||||
|
||||
const chunks = chunk(traceIds, config.serviceMapMaxTracesPerRequest);
|
||||
|
||||
const init = {
|
||||
|
@ -74,8 +70,6 @@ async function getConnectionData({
|
|||
return init;
|
||||
}
|
||||
|
||||
logger.debug(`Executing scripted metric agg (${chunks.length} chunks)`);
|
||||
|
||||
const chunkedResponses = await withApmSpan(
|
||||
'get_service_paths_from_all_trace_ids',
|
||||
() =>
|
||||
|
@ -86,16 +80,12 @@ async function getConnectionData({
|
|||
traceIds: traceIdsChunk,
|
||||
start,
|
||||
end,
|
||||
terminateAfter: config.serviceMapTerminateAfter,
|
||||
logger,
|
||||
})
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
logger.debug('Received chunk responses');
|
||||
|
||||
const mergedResponses = chunkedResponses.reduce((prev, current) => {
|
||||
return chunkedResponses.reduce((prev, current) => {
|
||||
return {
|
||||
connections: prev.connections.concat(current.connections),
|
||||
discoveredServices: prev.discoveredServices.concat(
|
||||
|
@ -103,10 +93,6 @@ async function getConnectionData({
|
|||
),
|
||||
};
|
||||
});
|
||||
|
||||
logger.debug('Merged responses');
|
||||
|
||||
return mergedResponses;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -133,19 +119,12 @@ export function getServiceMap(
|
|||
getServiceStats(options),
|
||||
anomaliesPromise,
|
||||
]);
|
||||
|
||||
logger.debug('Received and parsed all responses');
|
||||
|
||||
const transformedResponse = transformServiceMapResponses({
|
||||
return transformServiceMapResponses({
|
||||
response: {
|
||||
...connectionData,
|
||||
services: servicesData,
|
||||
anomalies,
|
||||
},
|
||||
});
|
||||
|
||||
logger.debug('Transformed service map response');
|
||||
|
||||
return transformedResponse;
|
||||
});
|
||||
}
|
||||
|
|
|
@ -11,9 +11,9 @@ import { Connection, ConnectionNode } from '../../../common/service_map';
|
|||
function getConnectionsPairs(connections: Connection[]) {
|
||||
return connections
|
||||
.map((conn) => {
|
||||
const source = conn.source['service.name'];
|
||||
const source = `${conn.source['service.name']}:${conn.source['service.environment']}`;
|
||||
const destination = conn.destination['service.name']
|
||||
? conn.destination['service.name']
|
||||
? `${conn.destination['service.name']}:${conn.destination['service.environment']}`
|
||||
: conn.destination['span.type'];
|
||||
return `${source} -> ${destination}`;
|
||||
})
|
||||
|
@ -21,71 +21,139 @@ function getConnectionsPairs(connections: Connection[]) {
|
|||
}
|
||||
|
||||
describe('getConnections', () => {
|
||||
const paths = [
|
||||
[
|
||||
{
|
||||
'service.name': 'opbeans-ruby',
|
||||
'agent.name': 'ruby',
|
||||
},
|
||||
{
|
||||
'service.name': 'opbeans-node',
|
||||
'agent.name': 'nodejs',
|
||||
},
|
||||
{
|
||||
'service.name': 'opbeans-go',
|
||||
'agent.name': 'go',
|
||||
},
|
||||
{
|
||||
'service.name': 'opbeans-java',
|
||||
'agent.name': 'java',
|
||||
},
|
||||
{
|
||||
'span.subtype': 'http',
|
||||
'span.destination.service.resource': '172.18.0.6:3000',
|
||||
'span.type': 'external',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
'service.name': 'opbeans-ruby',
|
||||
'agent.name': 'ruby',
|
||||
},
|
||||
{
|
||||
'service.name': 'opbeans-python',
|
||||
'agent.name': 'python',
|
||||
},
|
||||
{
|
||||
'span.subtype': 'http',
|
||||
'span.destination.service.resource': '172.18.0.6:3000',
|
||||
'span.type': 'external',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
'service.name': 'opbeans-go',
|
||||
'agent.name': 'go',
|
||||
},
|
||||
{
|
||||
'service.name': 'opbeans-node',
|
||||
'agent.name': 'nodejs',
|
||||
},
|
||||
],
|
||||
] as ConnectionNode[][];
|
||||
describe('with environments defined', () => {
|
||||
const paths = [
|
||||
[
|
||||
{
|
||||
'service.environment': 'testing',
|
||||
'service.name': 'opbeans-ruby',
|
||||
'agent.name': 'ruby',
|
||||
},
|
||||
{
|
||||
'service.environment': null,
|
||||
'service.name': 'opbeans-node',
|
||||
'agent.name': 'nodejs',
|
||||
},
|
||||
{
|
||||
'service.environment': 'production',
|
||||
'service.name': 'opbeans-go',
|
||||
'agent.name': 'go',
|
||||
},
|
||||
{
|
||||
'service.environment': 'production',
|
||||
'service.name': 'opbeans-java',
|
||||
'agent.name': 'java',
|
||||
},
|
||||
{
|
||||
'span.subtype': 'http',
|
||||
'span.destination.service.resource': '172.18.0.6:3000',
|
||||
'span.type': 'external',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
'service.environment': 'testing',
|
||||
'service.name': 'opbeans-ruby',
|
||||
'agent.name': 'ruby',
|
||||
},
|
||||
{
|
||||
'service.environment': 'testing',
|
||||
'service.name': 'opbeans-python',
|
||||
'agent.name': 'python',
|
||||
},
|
||||
{
|
||||
'span.subtype': 'http',
|
||||
'span.destination.service.resource': '172.18.0.6:3000',
|
||||
'span.type': 'external',
|
||||
},
|
||||
],
|
||||
] as ConnectionNode[][];
|
||||
|
||||
it('includes all connections', () => {
|
||||
const connections = getConnections({
|
||||
paths,
|
||||
it('includes all connections', () => {
|
||||
const connections = getConnections({
|
||||
paths,
|
||||
});
|
||||
|
||||
const connectionsPairs = getConnectionsPairs(connections);
|
||||
expect(connectionsPairs).toEqual([
|
||||
'opbeans-ruby:testing -> opbeans-node:null',
|
||||
'opbeans-node:null -> opbeans-go:production',
|
||||
'opbeans-go:production -> opbeans-java:production',
|
||||
'opbeans-java:production -> external',
|
||||
'opbeans-ruby:testing -> opbeans-python:testing',
|
||||
'opbeans-python:testing -> external',
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
const connectionsPairs = getConnectionsPairs(connections);
|
||||
expect(connectionsPairs).toEqual([
|
||||
'opbeans-ruby -> opbeans-node',
|
||||
'opbeans-node -> opbeans-go',
|
||||
'opbeans-go -> opbeans-java',
|
||||
'opbeans-java -> external',
|
||||
'opbeans-ruby -> opbeans-python',
|
||||
'opbeans-python -> external',
|
||||
'opbeans-go -> opbeans-node',
|
||||
]);
|
||||
describe('environment is "not defined"', () => {
|
||||
it('includes all connections', () => {
|
||||
const environmentNotDefinedPaths = [
|
||||
[
|
||||
{
|
||||
'service.environment': 'production',
|
||||
'service.name': 'opbeans-go',
|
||||
'agent.name': 'go',
|
||||
},
|
||||
{
|
||||
'service.environment': 'production',
|
||||
'service.name': 'opbeans-java',
|
||||
'agent.name': 'java',
|
||||
},
|
||||
{
|
||||
'span.subtype': 'http',
|
||||
'span.destination.service.resource': '172.18.0.6:3000',
|
||||
'span.type': 'external',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
'service.environment': null,
|
||||
'service.name': 'opbeans-go',
|
||||
'agent.name': 'go',
|
||||
},
|
||||
{
|
||||
'service.environment': null,
|
||||
'service.name': 'opbeans-java',
|
||||
'agent.name': 'java',
|
||||
},
|
||||
{
|
||||
'span.subtype': 'http',
|
||||
'span.destination.service.resource': '172.18.0.6:3000',
|
||||
'span.type': 'external',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
'service.environment': null,
|
||||
'service.name': 'opbeans-python',
|
||||
'agent.name': 'python',
|
||||
},
|
||||
{
|
||||
'service.environment': null,
|
||||
'service.name': 'opbeans-node',
|
||||
'agent.name': 'nodejs',
|
||||
},
|
||||
{
|
||||
'span.subtype': 'http',
|
||||
'span.destination.service.resource': '172.18.0.6:3000',
|
||||
'span.type': 'external',
|
||||
},
|
||||
],
|
||||
] as ConnectionNode[][];
|
||||
const connections = getConnections({
|
||||
paths: environmentNotDefinedPaths,
|
||||
});
|
||||
|
||||
const connectionsPairs = getConnectionsPairs(connections);
|
||||
expect(connectionsPairs).toEqual([
|
||||
'opbeans-go:production -> opbeans-java:production',
|
||||
'opbeans-java:production -> external',
|
||||
'opbeans-go:null -> opbeans-java:null',
|
||||
'opbeans-java:null -> external',
|
||||
'opbeans-python:null -> opbeans-node:null',
|
||||
'opbeans-node:null -> external',
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -5,43 +5,38 @@
|
|||
* 2.0.
|
||||
*/
|
||||
|
||||
import { Logger } from '@kbn/logging';
|
||||
import { find, uniqBy } from 'lodash';
|
||||
import { Connection, ConnectionNode } from '../../../common/service_map';
|
||||
import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client';
|
||||
import { fetchServicePathsFromTraceIds } from './fetch_service_paths_from_trace_ids';
|
||||
import { getConnectionId } from './transform_service_map_responses';
|
||||
|
||||
export function getConnections({
|
||||
paths,
|
||||
}: {
|
||||
paths: ConnectionNode[][] | undefined;
|
||||
}): Connection[] {
|
||||
}) {
|
||||
if (!paths) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const connectionsById: Map<string, Connection> = new Map();
|
||||
|
||||
paths.forEach((path) => {
|
||||
path.forEach((location, i) => {
|
||||
const prev = path[i - 1];
|
||||
|
||||
const connectionsArr = paths.flatMap((path) => {
|
||||
return path.reduce((conns, location, index) => {
|
||||
const prev = path[index - 1];
|
||||
if (prev) {
|
||||
const connection = {
|
||||
return conns.concat({
|
||||
source: prev,
|
||||
destination: location,
|
||||
};
|
||||
|
||||
const id = getConnectionId(connection);
|
||||
|
||||
if (!connectionsById.has(id)) {
|
||||
connectionsById.set(id, connection);
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
return conns;
|
||||
}, [] as Connection[]);
|
||||
}, [] as Connection[]);
|
||||
|
||||
return Array.from(connectionsById.values());
|
||||
const connections = uniqBy(connectionsArr, (value) =>
|
||||
find(connectionsArr, value)
|
||||
);
|
||||
|
||||
return connections;
|
||||
}
|
||||
|
||||
export async function getServiceMapFromTraceIds({
|
||||
|
@ -49,26 +44,14 @@ export async function getServiceMapFromTraceIds({
|
|||
traceIds,
|
||||
start,
|
||||
end,
|
||||
terminateAfter,
|
||||
logger,
|
||||
}: {
|
||||
apmEventClient: APMEventClient;
|
||||
traceIds: string[];
|
||||
start: number;
|
||||
end: number;
|
||||
terminateAfter: number;
|
||||
logger: Logger;
|
||||
}) {
|
||||
const serviceMapFromTraceIdsScriptResponse =
|
||||
await fetchServicePathsFromTraceIds({
|
||||
apmEventClient,
|
||||
traceIds,
|
||||
start,
|
||||
end,
|
||||
terminateAfter,
|
||||
});
|
||||
|
||||
logger.debug('Received scripted metric agg response');
|
||||
await fetchServicePathsFromTraceIds(apmEventClient, traceIds, start, end);
|
||||
|
||||
const serviceMapScriptedAggValue =
|
||||
serviceMapFromTraceIdsScriptResponse.aggregations?.service_map.value;
|
||||
|
|
|
@ -26,6 +26,8 @@ import { environmentQuery } from '../../../common/utils/environment_query';
|
|||
import { APMEventClient } from '../../lib/helpers/create_es_client/create_apm_event_client';
|
||||
import { APMConfig } from '../..';
|
||||
|
||||
const MAX_TRACES_TO_INSPECT = 1000;
|
||||
|
||||
export async function getTraceSampleIds({
|
||||
serviceName,
|
||||
environment,
|
||||
|
@ -161,7 +163,7 @@ export async function getTraceSampleIds({
|
|||
uniq(
|
||||
sortBy(traceIdsWithPriority, 'priority').map(({ traceId }) => traceId)
|
||||
),
|
||||
config.serviceMapMaxTraces
|
||||
MAX_TRACES_TO_INSPECT
|
||||
);
|
||||
|
||||
return { traceIds };
|
||||
|
|
|
@ -101,7 +101,7 @@ const serviceMapRoute = createApmServerRoute({
|
|||
serviceName,
|
||||
environment,
|
||||
searchAggregatedTransactions,
|
||||
logger: logger.get('serviceMap'),
|
||||
logger,
|
||||
start,
|
||||
end,
|
||||
maxNumberOfServices,
|
||||
|
|
|
@ -35,7 +35,7 @@ function getConnectionNodeId(node: ConnectionNode): string {
|
|||
return node[SERVICE_NAME];
|
||||
}
|
||||
|
||||
export function getConnectionId(connection: Connection) {
|
||||
function getConnectionId(connection: Connection) {
|
||||
return `${getConnectionNodeId(connection.source)}~${getConnectionNodeId(
|
||||
connection.destination
|
||||
)}`;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue