網站正式上線運行時,會開始有使用者訪問瀏覽,流量就會開始出現變化,當網站推廣新活動或周年慶,就有可能出現龐大的流量訪問網站,可能導致原來在ALB後面的機器或Container負荷不了龐大的流量,而出現網站掛掉的可能性。當然可以手動臨時增加機器數量,但AWS還有提供更方便的服務,AutoScaling Group(ASG)可以根據CPU和Memory使用量,以及Request數量,進行增加、減少,可以減少手動時間,進而解決大量流量的問題。
昨天撰寫的CDK,會繼續使用,並且增加ASG這個服務
將Fargate Service加入ASG的設定,並設定最大與最小數量
scale_policy = svc.auto_scale_task_count(
max_capacity=5,
min_capacity=1
)
設定ASG觸發規則,這裡採用Request數量去增加和減少Container的數量
scale_policy.scale_on_request_count(
"asgPolicy",
requests_per_target=5,
target_group=tg,
scale_in_cooldown=core.Duration.seconds(60),
scale_out_cooldown=core.Duration.seconds(60)
)
requests_per_target: 根據CloudWatch的規則,若ALB後面的target收到超過定義的requests數量,就進行擴增
cooldown: ASG冷卻時間的設定,主要以機器在擴增時,因為大量的流量,而擴增不必要的機器,而導致不必要的花費。需要根據實務情況做設定
以上就是增加ASG的方法,接下來看實際情況
這裡主要使用ApacheBench(ab)這個指令,來去測試網站的運行效能,進而模擬大量的Requests數量
CloudWatch要觸發Scale-out時候,要先從ok變成alarm,才會觸發,在下方圖片要觸發需要3分鐘內超過5個Requests才做觸發
原先的Container數量為2,當遇到大量流量時,CloudWatch狀態變更則觸發擴增規則,就會擴增到適合的數量。但這邊有設定上限值為5
CloudWatch要觸發Scale-in減少機器數量時,需要將狀態轉為alarm時,才會觸發ASG,下方圖片規則是15分鐘內requests數量不超過4.5,數量會慢慢減少到適合當前網站的流量
數量擴增到5個Containers,但當網站流量處於低迷的情況,就會觸發縮減規則,慢慢減少機器/Container的數量,以符合當前流量。最終為減少到最低限制
ASG的擴增減少規則還有其他種類,以及步進的方式,都需要查看/設定CloudWatch的觸發方式,這邊就簡單地揭露,可以更快的操作ASG,且也懂細節的奧妙
from aws_cdk import core as cdk
from aws_cdk import (
aws_ec2 as ec2,
aws_ecs as ecs,
aws_elasticloadbalancingv2 as elbv2,
core
)
class EcsFargateItStack(cdk.Stack):
def __init__(self, scope: cdk.Construct, construct_id: str, **kwargs) -> None:
super().__init__(scope, construct_id, **kwargs)
# The code that defines your stack goes here
vpc = ec2.Vpc(self, "VPC",
cidr="10.0.0.0/16",
enable_dns_hostnames=True,
enable_dns_support=True,
max_azs=0,
nat_gateways=1)
public_subnet = ec2.Subnet(self, "public-subnet1",
availability_zone="us-east-2a",
cidr_block="10.0.10.0/24",
vpc_id=vpc.vpc_id,
map_public_ip_on_launch=True)
public_subnet2 = ec2.Subnet(
self,
"PublicSubnet2",
availability_zone="us-east-2b",
cidr_block="10.0.20.0/24",
vpc_id=vpc.vpc_id,
map_public_ip_on_launch=True
)
public_subnet.add_default_internet_route(gateway_id=vpc.internet_gateway_id, gateway_attachment=vpc)
public_subnet2.add_default_internet_route(gateway_id=vpc.internet_gateway_id, gateway_attachment=vpc)
sg = ec2.SecurityGroup(self, "CDK-SG",
vpc=vpc,
description="cdk create security group",
security_group_name="cdkSG")
sg.add_ingress_rule(peer=ec2.Peer.any_ipv4(), connection=ec2.Port.tcp(80), description="cdk allow anywhere about HTTP protocol")
alb = elbv2.ApplicationLoadBalancer(self, "CDK-ALB",
vpc=vpc,
internet_facing=True,
vpc_subnets=ec2.SubnetSelection(
subnets=[public_subnet, public_subnet2]
),
security_group=sg,
load_balancer_name="cdkALB"
)
tg = elbv2.ApplicationTargetGroup(
self,
"CDK-TG",
port= 80,
protocol=elbv2.ApplicationProtocol.HTTP,
vpc=vpc
)
listener = alb.add_listener(
"Listener",
port=80,
protocol=elbv2.ApplicationProtocol.HTTP,
default_target_groups=[tg]
)
listener.add_target_groups(
"CDK-addTG",
target_groups=[tg]
)
cluster = ecs.Cluster(self, "Fargate-Cluster",
enable_fargate_capacity_providers=True,
vpc=vpc)
task = ecs.FargateTaskDefinition(self, "fargate-task",
cpu=1024,
memory_limit_mib=2048,
)
task.add_container(id="app",
image=ecs.ContainerImage.from_registry("johnson860312/awswebdb"),
container_name="mycontainer",
port_mappings=[
ecs.PortMapping(container_port=80,
host_port=80,
protocol=ecs.Protocol.TCP)
],
cpu=128,
memory_reservation_mib=256
)
svc = ecs.FargateService(self, "fargate-svc",
task_definition=task,
cluster=cluster,
security_groups=[sg],
assign_public_ip=True,
vpc_subnets=ec2.SubnetSelection(
subnets=[public_subnet, public_subnet2]
),
desired_count=2
)
scale_policy = svc.auto_scale_task_count(
max_capacity=5,
min_capacity=1
)
scale_policy.scale_on_request_count(
"asgPolicy",
requests_per_target=5,
target_group=tg,
scale_in_cooldown=core.Duration.seconds(60),
scale_out_cooldown=core.Duration.seconds(60)
)
tg.add_target(svc)
core.CfnOutput(self, "PublicDNS", value="http://" + listener.load_balancer.load_balancer_dns_name)