主题概述
在当今复杂的云环境中,运维团队面临着前所未有的挑战。随着微服务架构、容器化应用和无服务器计算的普及,系统组件之间的依赖关系变得越来越复杂,故障排查的难度也随之增加。当生产环境出现问题时,运维人员通常需要在海量的日志、指标和事件中寻找故障的根本原因,这不仅耗时耗力,还可能导致业务中断时间延长,造成严重的经济损失。
传统的运维方法已经难以应对这种复杂性。运维人员需要同时监控多个系统、分析各种指标、查看不同的日志,并尝试将这些信息关联起来以找出问题的根源。这个过程不仅繁琐,而且容易受到人为因素的影响,导致分析结果不准确或不完整。
Amazon CloudWatch AIOps 应运而生,它利用人工智能和机器学习技术,自动化根因分析过程,帮助运维团队快速定位和解决问题。本文将深入探讨 CloudWatch AIOps 的功能和优势,并通过实际案例展示其如何改变传统的运维方式,提高故障排查效率。
📢限时插播:Amazon Q Developer 来帮你做应用啦!
🌟10 分钟帮你构建智能番茄钟应用,1 小时搞定新功能拓展、测试优化、文档注程和部署
⏩快快点击进入《Agentic Al 帮你做应用 -- 从0到1打造自己的智能番茄钟》实验
免费体验企业级 AI 开发工具的真实效果吧
构建无限,探索启程!
背景
CloudWatch AIOps 的产品定位
CloudWatch AIOps 是 Amazon CloudWatch 的一项高级功能,专为解决云环境中的复杂故障排查问题而设计。它将人工智能和机器学习技术与亚马逊云科技的可观测性服务相结合,提供自动化的根因分析能力。CloudWatch AIOps 的核心目标是减少平均故障排除时间(MTTR),提高系统可靠性,并降低运维团队的工作负担。
CloudWatch AIOps 不仅仅是一个监控工具,它是一个智能分析平台,能够理解应用程序和基础设施之间的复杂关系,自动识别异常模式,并提供有针对性的解决方案建议。
主要功能
1. 智能根因分析(Root Cause Analysis, RCA):
自动分析告警和异常事件,识别潜在的根本原因
利用机器学习算法检测异常模式和关联性
提供可视化的问题影响路径,帮助理解故障传播
2. 多种入口点:
3. 广泛的服务集成:
4. 上下文感知分析:
自动收集相关的日志、指标和事件
考虑资源之间的依赖关系和最近的配置变更
分析时间序列数据,识别异常趋势和模式
5. 可操作的建议:
提供具体的修复建议和最佳实践
生成详细的调查报告,便于团队协作和知识共享
支持自定义修复工作流程
方案:可观测性与 CloudOps 的协同作用
可观测性的三大支柱
有效的故障排查需要建立在强大的可观测性基础上。可观测性通常包括三个关键支柱:
1.指标(Metrics):
2. 日志(Logs):
3. 追踪(Traces):
CloudWatch AIOps 将这三个支柱的数据整合在一起,提供全面的系统视图,使故障排查变得更加高效和准确。
CloudOps 关联产品的协同作用
CloudWatch AIOps 不是孤立运行的,它与多个 Amazon CloudOps 产品协同工作,形成完整的运维解决方案:
1.Amazon CloudTrail:
2.Amazon Config:
3.Amazon EventBridge:
4.Amazon Systems Manager:
5.Amazon DevOps Guru:
这些产品的协同作用创建了一个闭环的运维流程:监控 → 检测 → 分析 → 修复 → 验证,大大提高了运维效率和系统可靠性。
理论基础:可观测性与 CloudOps 的协同效应
从监控到可观测性的演进
传统的监控方法主要关注预定义的指标和阈值,这种方法在简单系统中可能有效,但在复杂的云环境中显得力不从心。可观测性则采取了更全面的方法,不仅关注”系统是否正常运行”,还关注”为什么系统会出现这种行为”。
可观测性的核心理念是:系统的内部状态可以通过其外部输出来推断。通过收集和分析指标、日志和追踪数据,运维团队可以构建系统行为的完整视图,即使面对未预见的问题也能快速定位根因。
CloudWatch AIOps 的工作原理
CloudWatch AIOps 基于以下理论基础运作:
1. 因果推理:
建立系统组件之间的因果关系模型
分析事件序列,识别潜在的触发因素
区分症状和根本原因
2. 异常检测:
学习系统的正常行为模式
识别偏离正常模式的异常情况
考虑时间相关性和季节性变化
3. 关联分析:
发现不同指标和事件之间的相关性
构建资源依赖关系图
追踪问题的传播路径
4. 知识图谱:
整合亚马逊云科技服务的专业知识和最佳实践
应用领域特定的故障排查逻辑
持续学习和改进分析能力
根因分析的自动化流程
当系统触发告警或用户启动调查时,CloudWatch AIOps 执行以下步骤:
1. 数据收集:
自动收集相关的指标、日志和追踪数据
获取资源配置和最近的变更记录
确定受影响资源的范围
2. 上下文构建:
分析资源之间的依赖关系
考虑时间相关性和事件顺序
构建问题的完整上下文
3. 模式识别:
应用机器学习算法识别异常模式
比较当前情况与历史案例
检测潜在的根本原因
4. 影响分析:
评估问题对系统各部分的影响
确定关键路径和瓶颈
预测问题的潜在发展
5. 解决方案生成:
提供针对根本原因的具体修复建议
推荐预防类似问题的最佳实践
生成详细的调查报告
这种自动化的根因分析流程大大减少了手动排查的时间和精力,使运维团队能够更快地解决问题,提高系统可靠性。
操作演示:使用 CloudWatch AIOps 排查 S3 权限问题
为了展示 CloudWatch AIOps 的实际应用,我们将使用一个简单的演示应用程序,该应用程序由 API Gateway、Lambda 函数和 S3 存储桶组成。我们将模拟一个常见的运维问题:S3 存储桶策略变更导致的应用程序故障,并使用 CloudWatch AIOps 进行根因分析。
演示应用架构
我们的演示应用是一个简单的图片服务,其架构如下:
API Gateway:提供 REST API 接口,接收客户端请求
Lambda 函数:处理请求,从 S3 存储桶中随机获取图片
S3 存储桶:存储图片文件
Bedrock Lambda:使用 Amazon Bedrock 生成图片并存储到 S3 存储桶
应用正常工作时,用户可以通过 API 获取随机图片。我们将通过修改 S3 存储桶策略,模拟一个权限问题,然后使用 CloudWatch AIOps 进行故障排查。
步骤 1:部署演示应用
首先,我们使用 CloudFormation 模板部署演示应用:
您需要将下面的 Cloudformation Template 存储到本地。
AWSTemplateFormatVersion: '2010-09-09'Description: 'AIOps Integration Test - Image Service'
Resources: # S3 Bucket S3BucketAIOpsIntegration: Type: 'AWS::S3::Bucket' DeletionPolicy: Delete UpdateReplacePolicy: Retain Properties: BucketName: !Join - '' - - 'aiops-image-bucket-' - !Select [0, !Split ["-", !Select [2, !Split ["/", !Ref "AWS::StackId"]]]]
CleanupLambdaRole: Type: 'AWS::IAM::Role' Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: 'sts:AssumeRole' ManagedPolicyArns: - 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole' Policies: - PolicyName: S3CleanupPolicy PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - 's3:ListBucket' - 's3:DeleteObject' - 's3:DeleteObjectVersion' Resource: - !Sub 'arn:aws:s3:::${S3BucketAIOpsIntegration}' - !Sub 'arn:aws:s3:::${S3BucketAIOpsIntegration}/*'
# Cleanup Lambda used to empty contents of S3 Bucket CleanupLambda: Type: 'AWS::Lambda::Function' DependsOn: - CleanupLambdaRole - S3BucketAIOpsIntegration Properties: FunctionName: !Sub '${AWS::StackName}-cleanup-lambda' Handler: 'index.lambda_handler' Role: !GetAtt CleanupLambdaRole.Arn Code: ZipFile: | import boto3 import cfnresponse
def lambda_handler(event, context): try: if event['RequestType'] == 'Delete': s3 = boto3.resource('s3') bucket = s3.Bucket(event['ResourceProperties']['BucketName']) bucket.objects.all().delete() print(f"Cleaned up bucket {event['ResourceProperties']['BucketName']}") cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) except Exception as e: print(f"Error: {str(e)}") cfnresponse.send(event, context, cfnresponse.FAILED, {}) Runtime: python3.13 Timeout: 300 MemorySize: 128
S3BucketCleanup: Type: 'Custom::S3BucketCleanup' DependsOn: - CleanupLambda - BedrockLambda - TriggerCustomResource Properties: ServiceToken: !GetAtt CleanupLambda.Arn BucketName: !Ref S3BucketAIOpsIntegration
# SSM Parameter for Bucket Name BucketNameParameter: Type: 'AWS::SSM::Parameter' Properties: Name: !Sub '/${AWS::StackName}/bucket-name' Type: 'String' Value: !Ref S3BucketAIOpsIntegration Description: 'S3 Bucket name for AIOps Integration Test'
# Lambda Role for Bucket Policy Update BucketPolicyLambdaRole: Type: 'AWS::IAM::Role' Properties: RoleName: !Sub '${AWS::StackName}-bucket-policy-lambda-role' AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: 'sts:AssumeRole' ManagedPolicyArns: - 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole' Policies: - PolicyName: !Sub '${AWS::StackName}-bucket-policy-lambda-policy' PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: - s3:PutBucketPolicy Resource: !GetAtt S3BucketAIOpsIntegration.Arn
# Lambda Function for Bucket Policy Update BucketPolicyLambda: Type: 'AWS::Lambda::Function' Properties: FunctionName: !Sub '${AWS::StackName}-bucket-policy-lambda' Handler: 'index.lambda_handler' Role: !GetAtt BucketPolicyLambdaRole.Arn Code: ZipFile: | import boto3 import json import os
def lambda_handler(event, context): try: s3 = boto3.client('s3') bucket_name = os.environ['BUCKET_NAME'] role_arn = os.environ['LAMBDA_ROLE_ARN'] bucket_policy = { "Version": "2012-10-17", "Id": "Policy1736953436011", "Statement": [{ "Sid": "DenyBucketAccess", "Effect": "Deny", "Principal": { "AWS": role_arn }, "Action": "s3:ListBucket", "Resource": f"arn:aws:s3:::{bucket_name}" }, { "Sid": "DenyObjectAccess", "Effect": "Deny", "Principal": { "AWS": role_arn }, "Action": "s3:GetObject", "Resource": f"arn:aws:s3:::{bucket_name}/*" }] } s3.put_bucket_policy( Bucket=bucket_name, Policy=json.dumps(bucket_policy) ) return { 'statusCode': 200, 'body': 'Bucket policy updated successfully' } except Exception as e: print(f"Error: {str(e)}") return { 'statusCode': 500, 'body': f"Error updating bucket policy: {str(e)}" } Runtime: python3.13 Timeout: 30 MemorySize: 128 Environment: Variables: BUCKET_NAME: !Ref S3BucketAIOpsIntegration LAMBDA_ROLE_ARN: !GetAtt LambdaRoleAIOpsIntegration.Arn
LambdaTriggerBucketPolicyAlarm: Type: 'AWS::CloudWatch::Alarm' Properties: AlarmName: !Sub '${AWS::StackName}-lambda-trigger-alarm' AlarmDescription: 'Alarm when Lambda is triggered 3 or more times' MetricName: 'Invocations' Namespace: 'AWS/Lambda' Dimensions: - Name: FunctionName Value: !Ref LambdaAIOpsIntegration Statistic: 'Sum' Period: 60 EvaluationPeriods: 1 Threshold: 3 ComparisonOperator: 'GreaterThanOrEqualToThreshold' TreatMissingData: 'notBreaching' AlarmActions: - !GetAtt BucketPolicyLambda.Arn
# Lambda Permission for CloudWatch Alarm BucketPolicyLambdaPermission: Type: 'AWS::Lambda::Permission' Properties: FunctionName: !Ref BucketPolicyLambda Action: 'lambda:InvokeFunction' Principal: 'lambda.alarms.cloudwatch.amazonaws.com' SourceAccount: !Ref 'AWS::AccountId' SourceArn: !Sub 'arn:aws:cloudwatch:${AWS::Region}:${AWS::AccountId}:alarm:${AWS::StackName}-lambda-trigger-alarm'
BedrockLambdaRole: Type: 'AWS::IAM::Role' Properties: RoleName: !Sub '${AWS::StackName}-bedrock-lambda-role' AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: 'sts:AssumeRole' ManagedPolicyArns: - 'arn:aws:iam::aws:policy/CloudWatchLambdaApplicationSignalsExecutionRolePolicy' Policies: - PolicyName: !Sub '${AWS::StackName}-bedrock-lambda-policy' PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: logs:CreateLogGroup Resource: !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:*' - Effect: Allow Action: - logs:CreateLogStream - logs:PutLogEvents Resource: !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${AWS::StackName}-bedrock-lambda:*' - Effect: Allow Action: - s3:PutObject Resource: !Sub '${S3BucketAIOpsIntegration.Arn}/*' - Effect: Allow Action: - bedrock:InvokeModel Resource: '*' - Effect: Allow Action: - xray:PutTraceSegments - xray:PutTelemetryRecords Resource: '*' - Effect: Allow Action: - ssm:GetParameter Resource: !Sub 'arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${AWS::StackName}/bucket-name'
# Bedrock Lambda Function BedrockLambda: Type: 'AWS::Lambda::Function' Properties: FunctionName: !Sub '${AWS::StackName}-bedrock-lambda' Handler: 'index.lambda_handler' Role: !GetAtt BedrockLambdaRole.Arn Code: ZipFile: | import boto3 import base64 import json import os
def get_bucket_name(): ssm = boto3.client('ssm') parameter_name = os.environ['BUCKET_NAME_PARAMETER'] response = ssm.get_parameter(Name=parameter_name) return response['Parameter']['Value']
def lambda_handler(event, context): try: # Initialize S3 and Bedrock clients s3 = boto3.client('s3') bedrock = boto3.client('bedrock-runtime') # Get bucket name from Parameter Store bucket_name = get_bucket_name() print(f"Using bucket: {bucket_name}") print("Generating images using Bedrock...") # Prepare request body for Bedrock request_body = { "taskType": "TEXT_IMAGE", "textToImageParams": { "text": "Provide me images of different breeds of Dogs with Sunglasses", "negativeText": "Dont include cats" }, "imageGenerationConfig": { "numberOfImages": 5, "height": 1024, "width": 1024, "cfgScale": 8.0, "seed": 0 } } # Call Bedrock to generate image response = bedrock.invoke_model( modelId="amazon.titan-image-generator-v1", contentType="application/json", accept="application/json", body=json.dumps(request_body) ) # Parse response and save image to S3 response_body = json.loads(response['body'].read()) for idx, image in enumerate(response_body['images']): # Decode base64 image image_data = base64.b64decode(image) # Upload to S3 file_name = f"generated_image_{idx}.jpg" s3.put_object( Bucket=bucket_name, Key=file_name, Body=image_data, ContentType='image/jpeg' ) print("Images generated and stored in S3") return { 'statusCode': 200, 'body': json.dumps({'message': 'Images generated successfully'}) } except Exception as e: print(f"Error: {str(e)}") return { 'statusCode': 500, 'body': json.dumps({'message': 'Internal Server Error - HTTP 500'}) } Runtime: python3.13 Timeout: 300 MemorySize: 1024 Environment: Variables: BUCKET_NAME_PARAMETER: !Sub '/${AWS::StackName}/bucket-name' TracingConfig: Mode: Active
# Custom Resource Lambda Role TriggerLambdaRole: Type: 'AWS::IAM::Role' Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: 'sts:AssumeRole' ManagedPolicyArns: - 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole' Policies: - PolicyName: InvokeBedrockLambda PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: 'lambda:InvokeFunction' Resource: !GetAtt BedrockLambda.Arn
# Custom Resource Lambda TriggerLambda: Type: 'AWS::Lambda::Function' Properties: FunctionName: !Sub '${AWS::StackName}-trigger-lambda' Handler: 'index.lambda_handler' Role: !GetAtt TriggerLambdaRole.Arn Code: ZipFile: | import boto3 import cfnresponse
def lambda_handler(event, context): try: if event['RequestType'] == 'Create': lambda_client = boto3.client('lambda') response = lambda_client.invoke( FunctionName=f"{event['ResourceProperties']['StackName']}-bedrock-lambda", InvocationType='Event' ) print("Successfully triggered Bedrock Lambda") cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) else: cfnresponse.send(event, context, cfnresponse.SUCCESS, {}) except Exception as e: print(f"Error: {str(e)}") cfnresponse.send(event, context, cfnresponse.FAILED, {}) Runtime: python3.13 Timeout: 30 MemorySize: 128
TriggerCustomResource: Type: 'Custom::TriggerBedrock' DependsOn: - S3BucketAIOpsIntegration - BedrockLambda Properties: ServiceToken: !GetAtt TriggerLambda.Arn StackName: !Ref 'AWS::StackName' # Updated Lambda Role with SSM permissions LambdaRoleAIOpsIntegration: Type: 'AWS::IAM::Role' Properties: RoleName: !Sub '${AWS::StackName}-lambda-role' AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: lambda.amazonaws.com Action: 'sts:AssumeRole' ManagedPolicyArns: - 'arn:aws:iam::aws:policy/CloudWatchLambdaApplicationSignalsExecutionRolePolicy' Policies: - PolicyName: !Sub '${AWS::StackName}-lambda-policy' PolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Action: logs:CreateLogGroup Resource: !Sub 'arn:aws:logs:${AWS::Region}:${AWS::AccountId}:*' - Effect: Allow Action: - logs:CreateLogStream - logs:PutLogEvents Resource: '*' - Effect: Allow Action: - s3:GetObject - s3:ListBucket Resource: - !GetAtt S3BucketAIOpsIntegration.Arn - !Sub '${S3BucketAIOpsIntegration.Arn}/*' - Effect: Allow Action: - xray:PutTraceSegments - xray:PutTelemetryRecords Resource: '*' - Effect: Allow Action: - ssm:GetParameter Resource: !Sub 'arn:aws:ssm:${AWS::Region}:${AWS::AccountId}:parameter/${AWS::StackName}/bucket-name'
# Updated Lambda Function with SSM parameter for S3 Bucket LambdaAIOpsIntegration: Type: 'AWS::Lambda::Function' Properties: FunctionName: !Sub '${AWS::StackName}-aiops-lambda' Handler: 'index.lambda_handler' Role: !GetAtt LambdaRoleAIOpsIntegration.Arn Code: ZipFile: | import boto3 import random import base64 import os import json
def get_bucket_name(): ssm = boto3.client('ssm') parameter_name = os.environ['BUCKET_NAME_PARAMETER'] response = ssm.get_parameter(Name=parameter_name) return response['Parameter']['Value']
def lambda_handler(event, context): try: # Initialize S3 client s3 = boto3.client('s3') # Get bucket name from Parameter Store bucket_name = get_bucket_name() print(f"Using bucket: {bucket_name}") # List all objects response = s3.list_objects_v2(Bucket=bucket_name) if 'Contents' not in response: return { 'statusCode': 404, 'headers': { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }, 'body': '{"message": "No images found"}' } # Filter for both .jpg and .jpeg files image_files = [obj for obj in response['Contents'] if obj['Key'].lower().endswith(('.jpg', '.jpeg'))] if not image_files: return { 'statusCode': 404, 'headers': { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }, 'body': '{"message": "No JPG/JPEG images found"}' } # Select random image random_image = random.choice(image_files) print(f"Selected image: {random_image['Key']}") # Get the image image = s3.get_object( Bucket=bucket_name, Key=random_image['Key'] ) # Get image data image_data = image['Body'].read() # Return binary response for API Gateway return { 'statusCode': 200, 'headers': { 'Content-Type': 'image/jpeg' }, 'body': base64.b64encode(image_data).decode('utf-8'), 'isBase64Encoded': True } except Exception as e: print(f"Error: {str(e)}") return { 'statusCode': 500, 'headers': { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' }, 'body': json.dumps({ "message": "Internal Server Error" }) } Runtime: python3.13 Timeout: 60 MemorySize: 128 Environment: Variables: BUCKET_NAME_PARAMETER: !Sub '/${AWS::StackName}/bucket-name' TracingConfig: Mode: Active
# API Gateway Role ApiGatewayRoleAIOpsIntegration: Type: 'AWS::IAM::Role' Properties: RoleName: !Sub '${AWS::StackName}-apigw-role' AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: apigateway.amazonaws.com Action: 'sts:AssumeRole' ManagedPolicyArns: - 'arn:aws:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs'
# API Gateway Account Settings ApiGatewayAccountConfig: Type: 'AWS::ApiGateway::Account' Properties: CloudWatchRoleArn: !GetAtt ApiGatewayRoleAIOpsIntegration.Arn
# REST API Gateway ApiGatewayAIOpsIntegration: Type: 'AWS::ApiGateway::RestApi' Properties: Name: !Sub '${AWS::StackName}-api' Description: 'API for random image service' EndpointConfiguration: Types: - REGIONAL BinaryMediaTypes: - 'image/jpeg' - '*/*'
# API Resource ApiResourceRandom: Type: 'AWS::ApiGateway::Resource' Properties: RestApiId: !Ref ApiGatewayAIOpsIntegration ParentId: !GetAtt ApiGatewayAIOpsIntegration.RootResourceId PathPart: 'random'
# API Method ApiMethodGet: Type: 'AWS::ApiGateway::Method' Properties: RestApiId: !Ref ApiGatewayAIOpsIntegration ResourceId: !Ref ApiResourceRandom HttpMethod: GET AuthorizationType: NONE Integration: Type: AWS_PROXY IntegrationHttpMethod: POST Uri: !Sub 'arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${LambdaAIOpsIntegration.Arn}/invocations'
# Enable CORS ApiMethodOptions: Type: 'AWS::ApiGateway::Method' Properties: RestApiId: !Ref ApiGatewayAIOpsIntegration ResourceId: !Ref ApiResourceRandom HttpMethod: OPTIONS AuthorizationType: NONE Integration: Type: MOCK IntegrationResponses: - StatusCode: 200 ResponseParameters: method.response.header.Access-Control-Allow-Headers: "'Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token'" method.response.header.Access-Control-Allow-Methods: "'GET,OPTIONS'" method.response.header.Access-Control-Allow-Origin: "'*'" ResponseTemplates: application/json: '' MethodResponses: - StatusCode: 200 ResponseParameters: method.response.header.Access-Control-Allow-Headers: true method.response.header.Access-Control-Allow-Methods: true method.response.header.Access-Control-Allow-Origin: true
# API Deployment ApiDeployment: Type: 'AWS::ApiGateway::Deployment' DependsOn: - ApiMethodGet - ApiMethodOptions Properties: RestApiId: !Ref ApiGatewayAIOpsIntegration
# API Stage ApiStage: Type: 'AWS::ApiGateway::Stage' DependsOn: ApiGatewayAccountConfig Properties: DeploymentId: !Ref ApiDeployment RestApiId: !Ref ApiGatewayAIOpsIntegration StageName: 'prod' Description: 'Production Stage' TracingEnabled: true MethodSettings: - ResourcePath: '/*' HttpMethod: '*' MetricsEnabled: true DataTraceEnabled: true LoggingLevel: INFO
# Lambda Permission LambdaPermission: Type: 'AWS::Lambda::Permission' Properties: Action: 'lambda:InvokeFunction' FunctionName: !Ref LambdaAIOpsIntegration Principal: apigateway.amazonaws.com SourceArn: !Sub 'arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${ApiGatewayAIOpsIntegration}/*' # API Gateway 5XX Error Alarm ApiGateway5XXAlarm: Type: 'AWS::CloudWatch::Alarm' Properties: AlarmName: !Sub '${AWS::StackName}-api-5xx-error-alarm' AlarmDescription: 'Alarm when API Gateway returns 5XX errors' MetricName: '5XXError' Namespace: 'AWS/ApiGateway' Dimensions: - Name: ApiName Value: !Sub '${AWS::StackName}-api' - Name: Stage Value: 'prod' Statistic: 'Sum' Period: 300 EvaluationPeriods: 1 Threshold: 1 ComparisonOperator: 'GreaterThanOrEqualToThreshold' TreatMissingData: 'notBreaching'
Outputs: S3BucketName: Description: 'Name of the created S3 bucket' Value: !Ref S3BucketAIOpsIntegration
LambdaFunctionName: Description: 'Name of the created Lambda function' Value: !Ref LambdaAIOpsIntegration
BedrockLambdaName: Description: 'Name of the Bedrock Lambda function' Value: !Ref BedrockLambda
TriggerLambdaName: Description: 'Name of the Trigger Lambda function' Value: !Ref TriggerLambda
BucketPolicyLambdaName: Description: 'Name of the Bucket Policy Lambda function' Value: !Ref BucketPolicyLambda
CloudWatchAlarmName: Description: 'Name of the CloudWatch Alarm' Value: !Ref LambdaTriggerBucketPolicyAlarm
ApiGateway5XXAlarmName: Description: 'Name of the API Gateway 5XX Error Alarm' Value: !Ref ApiGateway5XXAlarm
ApiEndpoint: Description: 'API Gateway Endpoint URL' Value: !Sub 'https://${ApiGatewayAIOpsIntegration}.execute-api.${AWS::Region}.amazonaws.com/prod/random'
复制代码
创建堆栈的时候请注意将下面命令行的 参数 --template-body 中的文件路径和文件名匹配到您当前的文件存储位置和文件名。
# 创建 CloudFormation 堆栈aws cloudformation create-stack \ --stack-name aiops-demo \ --template-body file:///【您的文件路径】/【您的文件名】.yaml \ --capabilities CAPABILITY_NAMED_IAM
复制代码
部署完成后,我们可以测试 API 是否正常工作:
# 获取 API 端点API_ENDPOINT=$(aws cloudformation describe-stacks \ --stack-name aiops-demo \ --query "Stacks[0].Outputs[?OutputKey=='ApiEndpoint'].OutputValue" \ --output text)
# 测试 APIcurl -v $API_ENDPOINT
复制代码
此时,API 应该能够正常返回一张随机图片。
我們可以透過 x-ray 查看部署的 service map
步骤 2:触发故障场景
为了模拟故障场景,我们将触发 CloudWatch 告警,该告警会自动调用 Lambda 函数修改 S3 存储桶策略,阻止 Lambda 函数访问 S3 存储桶:
# 获取 Lambda 函数名称LAMBDA_FUNCTION=$(aws cloudformation describe-stacks \ --stack-name aiops-demo \ --query "Stacks[0].Outputs[?OutputKey=='LambdaFunctionName'].OutputValue" \ --output text)
# 多次调用 Lambda 函数触发告警for i in {1..5}; do aws lambda invoke \ --function-name $LAMBDA_FUNCTION \ --payload '{}' \ /dev/null echo "Invocation $i completed" sleep 2done
复制代码
这将触发 CloudWatch 告警,进而调用修改 S3 存储桶策略的 Lambda 函数。策略修改后,主 Lambda 函数将无法访问 S3 存储桶,导致 API 返回错误。
步骤 3:验证故障
几分钟后,我们再次测试 API:
# 测试 APIcurl -v $API_ENDPOINT
复制代码
此时,API 应该返回 500 错误,表明应用程序出现了故障。
步骤 4:使用 CloudWatch AIOps 进行根因分析
现在,我们将使用 CloudWatch AIOps 来分析和解决这个问题。
方法 1:通过 CloudWatch 告警进行分析
1、登录亚马逊云科技管理控制台,导航到 CloudWatch 服务
2、在左侧导航栏中,选择”告警”
3、找到触发的 API Gateway 5XX 错误告警
4、点击”调查”按钮启动 CloudWatch AIOps 分析
输入一个 investigation title, 並且点击”开始调查”
CloudWatch AIOps 提供一个引导式的问题排查流程,在右侧会显示排查结果,我们可以通过 Accept 或 Decline 按钮,决定是否采纳该结果作为问题的根本原因分析依据。
CloudWatch AIOps 将自动收集相关数据并开始分析。分析完成后,它会显示一个调查报告,包括:
影响范围:分析受影响的资源和服务
时间线:问题发生的时间和相关事件
相关证据:CloudTrail 日志显示的 S3 策略变更事件
查看 S3 存储桶的 event record
方法 2:通过 Amazon Q 进行分析
在亚马逊云科技管理控制台中,打开 Amazon Q
输入自然语言查询,例如:”我的 API Gateway 返回 500 错误,请帮我分析原因”
Amazon Q 将启动 CloudWatch AIOps 分析,并提供类似的调查报告
步骤 5:解决问题
根据 CloudWatch AIOps 的建议,我们可以修复 S3 存储桶策略:
# 获取 S3 存储桶名称S3_BUCKET=$(aws cloudformation describe-stacks \ --stack-name aiops-demo \ --query "Stacks[0].Outputs[?OutputKey=='S3BucketName'].OutputValue" \ --output text)
# 删除错误的存储桶策略aws s3api delete-bucket-policy --bucket $S3_BUCKET
复制代码
修复后,我们再次测试 API:
# 测试 APIcurl -v $API_ENDPOINT
复制代码
此时,API 应该恢复正常,能够返回随机图片。
分析结果解读
CloudWatch AIOps 的分析报告提供了以下关键信息:
1. 问题识别:
2. 根因确定:
3. 影响路径:
4. 时间相关性:
问题开始时间与 S3 策略变更时间高度一致
没有其他相关的配置变更或系统事件
5. 修复建议:
恢复 S3 存储桶策略
实施更严格的权限控制和变更管理
添加更详细的监控和告警
这个演示展示了 CloudWatch AIOps 如何快速识别配置变更导致的问题,并提供明确的修复建议,大大减少了故障排查时间。
未来展望:全程自动化的智能运维
随着云计算和人工智能技术的不断发展,我们可以展望一个更加自动化和智能化的运维未来。CloudWatch AIOps 只是这一发展方向的开始,未来的智能运维系统将实现更高级别的自动化和预测能力。
资源的自动创建与管理
未来的智能运维系统将能够:
1. 自动化基础设施部署:
基于应用需求自动设计和部署最佳架构
持续优化资源配置,平衡性能和成本
自动扩展和收缩资源,适应负载变化
2. 智能配置管理:
自动生成符合最佳实践的配置
预测配置变更的潜在影响
防止有风险的配置变更
3. 自我修复能力:
检测到问题后自动启动修复流程
学习和改进修复策略
在问题影响用户之前解决潜在问题
告警的自动生成与优化
传统的告警配置通常是静态的,需要人工设置和维护。未来的智能运维系统将实现:
1. 自适应告警阈值:
基于历史数据和季节性模式自动调整阈值
考虑业务上下文和重要性
减少误报和漏报
2. 异常检测告警:
自动识别异常模式,无需预定义阈值
学习系统的正常行为
检测复杂的多维异常
3. 预测性告警:
预测潜在问题,在问题发生前发出警告
估计问题的严重性和影响范围
提供预防措施建议
自动化问题解决流程
未来的智能运维系统将不仅能够发现问题,还能自动解决问题:
1. 自动化修复工作流:
根据根因分析结果自动执行修复操作
验证修复效果,必要时回滚
记录和学习修复经验
2. 智能事件管理:
自动分类和优先级排序
智能路由到合适的团队或系统
协调复杂问题的解决流程
3. 持续学习和改进:
从每次事件中学习
改进分析和修复策略
预防类似问题再次发生
运维角色的转变
随着智能运维系统的发展,运维人员的角色将发生重大转变:
1. 从执行者到设计者:
设计自动化策略和工作流
定义运维最佳实践和策略
创建和优化自动化模板
2. 从被动响应到主动预防:
分析趋势和模式,预测潜在问题
实施预防措施,提高系统弹性
持续优化系统架构和配置
3. 从技术专家到业务伙伴:
将技术洞察转化为业务价值
参与战略决策和规划
推动技术创新和业务转型
总结
CloudWatch AIOps 代表了运维领域的一次重大变革,它将人工智能和机器学习技术应用于复杂系统的故障排查,大大提高了运维效率和系统可靠性。通过自动化根因分析,CloudWatch AIOps 帮助运维团队快速定位和解决问题,减少平均故障排除时间,提高用户满意度。
本文探讨了 CloudWatch AIOps 的核心功能和工作原理,并通过一个实际案例展示了它如何帮助排查 S3 权限问题。我们还展望了智能运维的未来发展方向,包括资源的自动创建与管理、告警的自动生成与优化,以及自动化问题解决流程。
随着云计算和人工智能技术的不断发展,智能运维将成为企业数字化转型的关键推动力。CloudWatch AIOps 只是这一发展方向的开始,未来的智能运维系统将实现更高级别的自动化和预测能力,彻底改变传统的运维方式。
对于企业来说,现在是时候开始探索和采用这些智能运维技术,为未来的数字化转型做好准备。通过结合 CloudWatch AIOps 和其他 AWS CloudOps 产品,企业可以构建一个全面的智能运维平台,提高系统可靠性,降低运维成本,加速业务创新。
参考资源
*前述特定亚马逊云科技生成式人工智能相关的服务目前在亚马逊云科技海外区域可用。亚马逊云科技中国区域相关云服务由西云数据和光环新网运营,具体信息以中国区域官网为准。
本篇作者
本期最新实验为《Agentic AI 帮你做应用 —— 从0到1打造自己的智能番茄钟》
✨ 自然语言玩转命令行,10 分钟帮你构建应用,1 小时搞定新功能拓展、测试优化、文档注释和部署
💪 免费体验企业级 AI 开发工具,质量+安全全掌控
⏩️[点击进入实验] 即刻开启 AI 开发之旅
构建无限, 探索启程!
评论