Skip to content

Commit e6512e2

Browse files
authored
Issue 116 - Add k6 profile and docs (#117)
1 parent 33f8a82 commit e6512e2

17 files changed

+730
-12
lines changed

PERFORMANCE.md

+33
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ All of the tests are run from a CloudWatch Shell within the same region as the l
66

77
# Table of Contents <!-- omit in toc -->
88
- [Overview](#overview)
9+
- [Testing with `k6`](#testing-with-k6)
10+
- [CloudWatch Agent Config](#cloudwatch-agent-config)
911
- [Test Cases](#test-cases)
1012
- [GET: Text/Plain Ping](#get-textplain-ping)
1113
- [Commands](#commands)
@@ -37,6 +39,37 @@ All of the tests are run from a CloudWatch Shell within the same region as the l
3739
- [Results](#results-4)
3840
- [Lambda Dispatcher](#lambda-dispatcher-3)
3941

42+
# Testing with `k6`
43+
44+
- `brew install k6`
45+
- `k6 run k6/backend.js`
46+
47+
## CloudWatch Agent Config
48+
49+
- Status: This fails to start the agent
50+
- Install AWS CloudWatch Agent: https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/download-cloudwatch-agent-commandline.html
51+
- Save config file below to `/opt/aws/amazon-cloudwatch-agent/etc/statsd.json`
52+
- Login with AWS SSO CLI
53+
- Source the CW role change script: `. ./assume_cw_role.sh`
54+
- Start the CloudWatch Agent: `sudo /opt/aws/amazon-cloudwatch-agent/bin/amazon-cloudwatch-agent-ctl -a fetch-config -m onPremise -s -c file:/opt/aws/amazon-cloudwatch-agent/etc/statsd.json`
55+
56+
`/opt/aws/amazon-cloudwatch-agent/etc/statsd.json`
57+
58+
```json
59+
{
60+
"metrics": {
61+
"namespace": "k6",
62+
"metrics_collected": {
63+
"statsd": {
64+
"service_address": ":8125",
65+
"metrics_collection_interval": 5,
66+
"metrics_aggregation_interval": 0
67+
}
68+
}
69+
}
70+
}
71+
```
72+
4073
# Test Cases
4174

4275
| Test Case | Concurrent | Total<br>Reqs | Direct<br>Instances | Direct<br>RPS | Direct<br>Avg (ms) | Direct<br>Max (ms) | Dispatch<br>Instances | Dispatch<br>RPS | Dispatch<br>Avg (ms) | Dispatch<br>Max (ms) |

artillery/read-dynamodb-steady.yaml

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
config:
2+
target: "https://lambdadispatch.ghpublic.pwrdrvr.com"
3+
phases:
4+
- duration: 20
5+
arrivalRate: 1
6+
- duration: 20
7+
arrivalRate: 10
8+
- duration: 300
9+
arrivalRate: 1000
10+
- duration: 300
11+
arrivalRate: 2000
12+
- duration: 300
13+
arrivalRate: 3000
14+
defaults:
15+
headers:
16+
discardResponseBodies: "true"
17+
18+
scenarios:
19+
- name: "Dispatch Scenario"
20+
flow:
21+
- get:
22+
url: "/read"
23+
24+
- name: "Direct Scenario"
25+
flow:
26+
- get:
27+
url: "https://directlambda.ghpublic.pwrdrvr.com/read"

fargate.template.yaml

+62-8
Original file line numberDiff line numberDiff line change
@@ -56,17 +56,18 @@ Resources:
5656
OperatingSystemFamily: 'LINUX'
5757
ContainerDefinitions:
5858
- Name: lambda-dispatch-router
59-
# When using the public ECR published by the github builds, use this line:
60-
Image: public.ecr.aws/pwrdrvr/lambda-dispatch-router:main
59+
# When using the public ECR published by the github builds, use this line,
60+
# but not that it requires a NAT Gateway or other connectivity to the internet
61+
# Image: public.ecr.aws/pwrdrvr/lambda-dispatch-router:main
6162
# When testing local builds published to the Private ECR, use this line:
62-
# Image: !Sub '${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/lambda-dispatch-router:latest'
63+
Image: !Sub '${AWS::AccountId}.dkr.ecr.${AWS::Region}.amazonaws.com/lambda-dispatch-router:latest'
6364
Essential: true
6465
Environment:
66+
# Setting to 1 seems to hang on Fargate, so set to no less than 2
6567
- Name: LAMBDA_DISPATCH_MaxWorkerThreads
66-
Value: "1"
67-
# Limiting the spins is no longer needed when limiting to 1 thread
68-
# - Name: DOTNET_ThreadPool_UnfairSemaphoreSpinLimit
69-
# Value: "6"
68+
Value: "2"
69+
- Name: DOTNET_ThreadPool_UnfairSemaphoreSpinLimit
70+
Value: "0"
7071
- Name: LAMBDA_DISPATCH_FunctionName
7172
Value: !GetAtt LambdaDemoApp.Arn
7273
- Name: LAMBDA_DISPATCH_MaxConcurrentCount
@@ -141,6 +142,10 @@ Resources:
141142
PredefinedMetricSpecification:
142143
PredefinedMetricType: ECSServiceAverageCPUUtilization
143144
TargetValue: 50
145+
# These default to 300 seconds for ECS Services
146+
# https://docs.aws.amazon.com/autoscaling/application/userguide/target-tracking-scaling-policy-overview.html#target-tracking-cooldown
147+
ScaleInCooldown: 60
148+
ScaleOutCooldown: 60
144149

145150
# Security Group used by the tasks
146151
ECSFargateSG:
@@ -390,17 +395,30 @@ Resources:
390395
DNSName: !GetAtt ECSFargateLoadBalancer.DNSName
391396
HostedZoneId: !GetAtt ECSFargateLoadBalancer.CanonicalHostedZoneID
392397

398+
DirectLambdaALBAliasRecordSet:
399+
Type: AWS::Route53::RecordSet
400+
Properties:
401+
HostedZoneId: Z005084420J9MD9JNBCUK
402+
Name: directlambdaalias.ghpublic.pwrdrvr.com.
403+
Type: A
404+
AliasTarget:
405+
DNSName: !GetAtt ECSFargateLoadBalancer.DNSName
406+
HostedZoneId: !GetAtt ECSFargateLoadBalancer.CanonicalHostedZoneID
407+
393408
Certificate:
394409
Type: AWS::CertificateManager::Certificate
395410
Properties:
396411
DomainName: lambdadispatch.ghpublic.pwrdrvr.com
397412
SubjectAlternativeNames:
398413
- directlambda.ghpublic.pwrdrvr.com
414+
- directlambdaalias.ghpublic.pwrdrvr.com
399415
DomainValidationOptions:
400416
- DomainName: lambdadispatch.ghpublic.pwrdrvr.com
401417
HostedZoneId: Z005084420J9MD9JNBCUK
402418
- DomainName: directlambda.ghpublic.pwrdrvr.com
403419
HostedZoneId: Z005084420J9MD9JNBCUK
420+
- DomainName: directlambdaalias.ghpublic.pwrdrvr.com
421+
HostedZoneId: Z005084420J9MD9JNBCUK
404422
ValidationMethod: DNS
405423

406424
FargateListener:
@@ -567,6 +585,13 @@ Resources:
567585
SecurityGroupIds: [!Ref LambdaLBSG]
568586
SubnetIds: [!Ref PrivateSubnet1, !Ref PrivateSubnet2]
569587

588+
DirectLambdaALBAlias:
589+
Type: AWS::Lambda::Alias
590+
Properties:
591+
FunctionName: !Ref DirectLambda
592+
FunctionVersion: $LATEST
593+
Name: ALBAlias
594+
570595
DirectLambdaInvokePermission:
571596
Type: AWS::Lambda::Permission
572597
Properties:
@@ -597,8 +622,37 @@ Resources:
597622
ListenerArn: !Ref FargateHttpsListener
598623
Priority: 1
599624

625+
DirectLambdaALBAliasInvokePermission:
626+
Type: AWS::Lambda::Permission
627+
Properties:
628+
Action: lambda:InvokeFunction
629+
FunctionName: !Ref DirectLambdaALBAlias
630+
Principal: elasticloadbalancing.amazonaws.com
631+
632+
DirectLambdaALBAliasTargetGroup:
633+
DependsOn:
634+
- DirectLambdaALBAliasInvokePermission
635+
Type: AWS::ElasticLoadBalancingV2::TargetGroup
636+
Properties:
637+
TargetType: lambda
638+
Targets:
639+
- Id: !Ref DirectLambdaALBAlias
640+
641+
DirectLambdaALBAliasListenerRule:
642+
Type: AWS::ElasticLoadBalancingV2::ListenerRule
643+
Properties:
644+
Actions:
645+
- Type: forward
646+
TargetGroupArn: !Ref DirectLambdaALBAliasTargetGroup
647+
Conditions:
648+
- Field: host-header
649+
HostHeaderConfig:
650+
Values:
651+
- directlambdaalias.ghpublic.pwrdrvr.com
652+
ListenerArn: !Ref FargateHttpsListener
653+
Priority: 2
654+
600655
Outputs:
601656
LoadBalancerDNS:
602657
Description: DNS Name of the Load Balancer
603658
Value: !GetAtt ECSFargateLoadBalancer.DNSName
604-
+25
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import http from "k6/http";
2+
3+
export const options = {
4+
discardResponseBodies: true,
5+
scenarios: {
6+
direct: {
7+
executor: "constant-arrival-rate",
8+
preAllocatedVUs: 300,
9+
maxVUs: 1000,
10+
11+
timeUnit: "1s",
12+
13+
// We want to act like web users clicking to the site (not already on the site)
14+
// They don't stop clicking on Google links just because we're slow at the moment, they don't know that
15+
// So they keep arriving at the same rate even if we're hitting a cold start
16+
rate: 200,
17+
duration: "5m",
18+
exec: "direct",
19+
},
20+
},
21+
};
22+
23+
export function direct() {
24+
http.get("https://directlambda.ghpublic.pwrdrvr.com/ping");
25+
}
+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import http from "k6/http";
2+
3+
export const options = {
4+
discardResponseBodies: true,
5+
scenarios: {
6+
direct: {
7+
executor: "ramping-vus",
8+
startVUs: 500,
9+
stages: [
10+
{ target: 1, duration: "0" },
11+
{ target: 1, duration: "10s" },
12+
{ target: 500, duration: "0" },
13+
{ target: 500, duration: "5m" },
14+
{ target: 0, duration: "0" },
15+
],
16+
exec: "direct",
17+
},
18+
},
19+
};
20+
21+
//
22+
// Respond immediately with `pong`
23+
// This allows cleanly testing the cold starts that happen when concurrent
24+
// requests suddenly increase
25+
//
26+
export function direct() {
27+
http.get("https://directlambda.ghpublic.pwrdrvr.com/ping");
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import http from "k6/http";
2+
3+
export const options = {
4+
discardResponseBodies: true,
5+
scenarios: {
6+
directalias: {
7+
executor: "constant-arrival-rate",
8+
preAllocatedVUs: 300,
9+
maxVUs: 1000,
10+
11+
timeUnit: "1s",
12+
13+
// We want to act like web users clicking to the site (not already on the site)
14+
// They don't stop clicking on Google links just because we're slow at the moment, they don't know that
15+
// So they keep arriving at the same rate even if we're hitting a cold start
16+
rate: 200,
17+
duration: "5m",
18+
exec: "directalias",
19+
},
20+
},
21+
};
22+
23+
export function directalias() {
24+
http.get("https://directlambdaalias.ghpublic.pwrdrvr.com/ping");
25+
}
+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
import http from "k6/http";
2+
3+
export const options = {
4+
discardResponseBodies: true,
5+
scenarios: {
6+
dispatch: {
7+
executor: "ramping-vus",
8+
startVUs: 1,
9+
stages: [
10+
{ target: 1, duration: "0" },
11+
{ target: 1, duration: "10s" },
12+
// https://k6.io/docs/examples/instant-load-increase/
13+
{ target: 10, duration: "0" },
14+
{ target: 10, duration: "20s" },
15+
{ target: 20, duration: "0" },
16+
{ target: 20, duration: "20s" },
17+
{ target: 50, duration: "0" },
18+
{ target: 50, duration: "20s" },
19+
{ target: 100, duration: "0" },
20+
{ target: 100, duration: "20s" },
21+
{ target: 200, duration: "0" },
22+
{ target: 200, duration: "20s" },
23+
{ target: 300, duration: "0" },
24+
{ target: 300, duration: "20s" },
25+
{ target: 400, duration: "0" },
26+
{ target: 400, duration: "20s" },
27+
{ target: 500, duration: "0" },
28+
{ target: 500, duration: "20s" },
29+
{ target: 600, duration: "0" },
30+
{ target: 600, duration: "20s" },
31+
{ target: 0, duration: "0" },
32+
],
33+
exec: "dispatch",
34+
},
35+
direct: {
36+
executor: "ramping-vus",
37+
startVUs: 1,
38+
stages: [
39+
{ target: 1, duration: "0" },
40+
{ target: 1, duration: "10s" },
41+
// https://k6.io/docs/examples/instant-load-increase/
42+
{ target: 10, duration: "0" },
43+
{ target: 10, duration: "20s" },
44+
{ target: 20, duration: "0" },
45+
{ target: 20, duration: "20s" },
46+
{ target: 50, duration: "0" },
47+
{ target: 50, duration: "20s" },
48+
{ target: 100, duration: "0" },
49+
{ target: 100, duration: "20s" },
50+
{ target: 200, duration: "0" },
51+
{ target: 200, duration: "20s" },
52+
{ target: 300, duration: "0" },
53+
{ target: 300, duration: "20s" },
54+
{ target: 400, duration: "0" },
55+
{ target: 400, duration: "20s" },
56+
{ target: 500, duration: "0" },
57+
{ target: 500, duration: "20s" },
58+
{ target: 600, duration: "0" },
59+
{ target: 600, duration: "20s" },
60+
{ target: 0, duration: "0" },
61+
],
62+
exec: "direct",
63+
},
64+
},
65+
};
66+
67+
//
68+
// Respond immediately with `pong`
69+
// This allows cleanly testing the cold starts that happen when concurrent
70+
// requests suddenly increase
71+
//
72+
export function dispatch() {
73+
http.get("https://lambdadispatch.ghpublic.pwrdrvr.com/ping");
74+
}
75+
export function direct() {
76+
http.get("https://directlambda.ghpublic.pwrdrvr.com/ping");
77+
}

0 commit comments

Comments
 (0)