开头先说结果
先放个对比图让大家爽一下:
优化前 :💸 <math xmlns="http://www.w3.org/1998/Math/MathML"> 200.34 / 月 ∗ ∗ 优化后 ∗ ∗ :💰 200.34/月 **优化后**:💰 </math>200.34/月∗∗优化后∗∗:💰29.81/月
省了:🎉 85%
说实话,刚开始看到 OpenClaw 的账单我人都傻了。200 多刀一个月,我一个个人项目扛得住吗?不过好在踩坑踩得早,现在基本控制住了成本。
这篇文章就把我踩的坑和填坑的过程分享给大家,代码和配置都贴出来,直接复制就能用。
第一坑:实例选型,我选了个"坦克"跑"摩托"
坑的样子
当时部署 OpenClaw,想着「性能宁可过剩,别卡顿」,直接上了 t3.xlarge:
bash
# 我当时的"豪华"配置
Instance Type: t3.xlarge
vCPUs: 4
Memory: 16 GB
Price: $0.1664/hour = $119.81/month
结果跑起来一看,CPU 使用率常年 15%,内存用了 2GB 不到。这不是杀鸡用牛刀嘛?
怎么发现的
写了个脚本监控资源使用:
python
import psutil
import time
import json
def monitor_resources():
"""监控资源使用情况"""
while True:
# CPU 使用率
cpu_percent = psutil.cpu_percent(interval=1)
# 内存使用情况
memory = psutil.virtual_memory()
memory_percent = memory.percent
memory_used_gb = memory.used / (1024**3)
memory_total_gb = memory.total / (1024**3)
# 磁盘 IO
disk_io = psutil.disk_io_counters()
log_data = {
'timestamp': time.time(),
'cpu_percent': cpu_percent,
'memory_percent': memory_percent,
'memory_used_gb': round(memory_used_gb, 2),
'memory_total_gb': round(memory_total_gb, 2),
'disk_read_mb': disk_io.read_bytes / (1024**2),
'disk_write_mb': disk_io.write_bytes / (1024**2)
}
print(json.dumps(log_data))
time.sleep(60) # 每分钟记录一次
monitor_resources()
跑了一周发现:
- CPU:平均 15%,峰值也就 30%
- 内存:稳定在 2GB 左右
- 磁盘 IO:几乎没压力
这配置完全是浪费!
填坑过程
决定换成 t4g.medium ARM 实例,还能省钱:
bash
# 新配置
Instance Type: t4g.medium (ARM Graviton2)
vCPUs: 2
Memory: 4 GB
Price: $0.0416/hour = $30.37/month
迁移过程踩了几个小坑:
坑 1:ARM 架构兼容性
有些 Python 包没有 ARM 版本,解决方案:
bash
# 在新实例上重新编译
sudo apt update
sudo apt install python3-dev build-essential
# 重新安装依赖
pip3 install --no-binary=:all: some-problematic-package
坑 2:性能担心
写了个简单的压测验证:
python
import requests
import time
import threading
from concurrent.futures import ThreadPoolExecutor
def stress_test():
"""简单的压力测试"""
url = "http://localhost:8080/api/chat"
def single_request():
try:
response = requests.post(url, json={
"message": "写一个Python排序算法"
}, timeout=10)
return response.status_code == 200
except:
return False
# 并发测试
success_count = 0
start_time = time.time()
with ThreadPoolExecutor(max_workers=10) as executor:
futures = [executor.submit(single_request) for _ in range(100)]
for future in futures:
if future.result():
success_count += 1
end_time = time.time()
print(f"成功请求: {success_count}/100")
print(f"总耗时: {end_time - start_time:.2f}s")
print(f"平均响应时间: {(end_time - start_time)/100:.3f}s")
stress_test()
结果让我放心:
| 指标 | t3.xlarge | t4g.medium |
|---|---|---|
| 成功率 | 100% | 98% |
| 平均响应 | 1.2s | 1.4s |
| 月成本 | $119.81 | $30.37 |
性能差别不大,成本省了 75%!
第二坑:Bedrock 模型选择,我用大炮打蚊子
坑长啥样
一开始图省事,Claude 3.5 Sonnet 走起:
python
# 我的"奢侈"调用
response = bedrock.invoke_model(
modelId='anthropic.claude-3-5-sonnet-20241022-v2:0',
body=json.dumps({
'messages': [{'role': 'user', 'content': '帮我写个hello world'}],
'max_tokens': 100
})
)
结果月底账单:$68.54!
写个 hello world 都要几分钱,这谁受得了?
怎么发现问题的
写了个成本追踪脚本:
python
import boto3
import json
from datetime import datetime, timedelta
def track_bedrock_costs():
"""追踪 Bedrock 使用成本"""
ce = boto3.client('ce', region_name='us-east-1')
end_date = datetime.now().date()
start_date = end_date - timedelta(days=30)
response = ce.get_cost_and_usage(
TimePeriod={
'Start': start_date.strftime('%Y-%m-%d'),
'End': end_date.strftime('%Y-%m-%d')
},
Granularity='DAILY',
Metrics=['BlendedCost'],
GroupBy=[
{'Type': 'DIMENSION', 'Key': 'SERVICE'},
],
Filter={
'Dimensions': {
'Key': 'SERVICE',
'Values': ['Amazon Bedrock']
}
}
)
total_cost = 0
for result in response['ResultsByTime']:
daily_cost = float(result['Total']['BlendedCost']['Amount'])
total_cost += daily_cost
print(f"{result['TimePeriod']['Start']}: ${daily_cost:.3f}")
print(f"\n月总成本: ${total_cost:.2f}")
print("天哪,这个数字...")
track_bedrock_costs()
看着每天几块钱往外流,我开始反思人生。
填坑:模型选择 + 优化策略
方案 1:换便宜模型
对比测试了几个模型:
python
def compare_models():
"""对比不同模型的效果和成本"""
models = {
'claude-3-5-sonnet': {
'id': 'anthropic.claude-3-5-sonnet-20241022-v2:0',
'input_price': 0.003, # per 1K tokens
'output_price': 0.015
},
'nova-lite': {
'id': 'amazon.nova-lite-v1:0',
'input_price': 0.0006, # 便宜5倍!
'output_price': 0.0024
}
}
test_prompts = [
"写一个Python快速排序算法",
"解释什么是RESTful API",
"帮我review这段代码:def add(a,b): return a+b"
]
for model_name, config in models.items():
print(f"\n测试 {model_name}:")
total_estimated_cost = 0
for prompt in test_prompts:
# 简化计算:假设输入50 tokens,输出150 tokens
input_tokens = 50
output_tokens = 150
cost = (input_tokens/1000 * config['input_price'] +
output_tokens/1000 * config['output_price'])
total_estimated_cost += cost
print(f" 提示: {prompt[:30]}... 成本: ${cost:.6f}")
print(f" 总成本: ${total_estimated_cost:.6f}")
# 按月2000次调用估算
monthly_cost = total_estimated_cost * 2000 / 3
print(f" 月估算: ${monthly_cost:.2f}")
compare_models()
结果震惊:Nova Lite 便宜 5 倍,质量对我的场景够用!
方案 2:批量调用
对于非实时场景,批量处理能省 50%:
python
import boto3
import json
import uuid
def batch_process_requests(requests_list):
"""批量处理请求,省钱利器"""
bedrock = boto3.client('bedrock')
s3 = boto3.client('s3')
bucket = 'openclaw-batch-jobs'
job_id = str(uuid.uuid4())[:8]
# 准备批量输入
batch_input = []
for i, req in enumerate(requests_list):
batch_input.append({
'recordId': f'req-{i}',
'modelInput': {
'messages': [{'role': 'user', 'content': req}],
'max_tokens': 200
}
})
# 上传到 S3
input_file = f'batch-{job_id}.jsonl'
input_content = '\n'.join([json.dumps(item) for item in batch_input])
s3.put_object(
Bucket=bucket,
Key=input_file,
Body=input_content
)
# 提交批量任务
response = bedrock.create_model_invocation_job(
jobName=f'openclaw-batch-{job_id}',
roleArn='arn:aws:iam::123456789012:role/BedrockBatchRole',
modelId='amazon.nova-lite-v1:0',
inputDataConfig={
's3InputDataConfig': {
's3Uri': f's3://{bucket}/{input_file}'
}
},
outputDataConfig={
's3OutputDataConfig': {
's3Uri': f's3://{bucket}/output/{job_id}/'
}
}
)
print(f"批量任务已提交: {response['jobArn']}")
print("批量模式比实时调用便宜约50%")
# 示例:批量处理代码审查请求
review_requests = [
"审查这个函数:def factorial(n): return 1 if n <= 1 else n * factorial(n-1)",
"检查SQL注入风险:SELECT * FROM users WHERE id = " + user_input,
"优化这个循环:for i in range(len(items)): print(items[i])"
]
batch_process_requests(review_requests)
方案 3:提示缓存
重复的系统提示用缓存,省 90%:
python
import hashlib
class SmartBedrockClient:
def __init__(self):
self.bedrock = boto3.client('bedrock-runtime')
self.prompt_cache = {}
def cached_invoke(self, system_prompt, user_prompt, model_id='amazon.nova-lite-v1:0'):
"""使用缓存优化的调用"""
cache_key = hashlib.md5(system_prompt.encode()).hexdigest()
# 构造请求
messages = [{'role': 'user', 'content': user_prompt}]
# 检查是否有缓存的系统提示
if cache_key in self.prompt_cache:
# 使用缓存标记
system_config = {
'type': 'text',
'text': system_prompt,
'cache_control': {'type': 'ephemeral'} # 缓存标记
}
print(f"使用缓存的系统提示,节省90%成本")
else:
system_config = system_prompt
self.prompt_cache[cache_key] = True
print(f"首次使用系统提示,已缓存")
response = self.bedrock.invoke_model(
modelId=model_id,
body=json.dumps({
'anthropic_version': 'bedrock-2023-05-31',
'max_tokens': 200,
'system': system_config,
'messages': messages
})
)
return json.loads(response['body'].read())
# 使用示例
client = SmartBedrockClient()
system_prompt = """你是一个代码审查专家。请从以下角度分析代码:
1. 代码规范和可读性
2. 性能问题
3. 安全隐患
4. 改进建议
保持专业和建设性的语调。"""
# 第一次调用,缓存系统提示
result1 = client.cached_invoke(system_prompt, "审查:def login(user, pwd): return user == 'admin'")
# 后续调用使用缓存,大幅节省成本
result2 = client.cached_invoke(system_prompt, "审查:SELECT * FROM users WHERE name = '" + name + "'")
最终 Bedrock 成本:$12.30/月,省了 82%!
第三坑:存储过度配置,100GB 用了 18GB
坑是这样的
当时想着「硬盘便宜,给够点」,直接配了 100GB 的 EBS gp3:
bash
# 查看使用情况
df -h
# /dev/xvda1 100G 18G 76G 19% /
18GB!我配了 100GB 用了 18GB!这不是钱多烧的吗?
填坑:存储精细化
第一步:缩减 EBS 卷
bash
#!/bin/bash
# resize-ebs.sh
# 1. 先备份(重要!)
sudo dd if=/dev/xvda1 of=/tmp/disk-backup.img bs=1M count=20480
# 2. 创建快照
VOLUME_ID=$(curl -s http://169.254.169.254/latest/meta-data/block-device-mapping/ami | xargs -I {} curl -s http://169.254.169.254/latest/meta-data/block-device-mapping/{})
aws ec2 create-snapshot --volume-id $VOLUME_ID --description "Resize backup"
# 3. 文件系统检查
sudo e2fsck -f /dev/xvda1
# 4. 调整分区大小
sudo resize2fs /dev/xvda1 25G # 压缩到 25G
echo "存储优化完成,记得在控制台修改 EBS 卷大小"
第二步:日志迁移到 S3
写了个自动归档脚本:
python
import os
import gzip
import boto3
from datetime import datetime, timedelta
def setup_log_rotation():
"""设置日志轮转和 S3 归档"""
s3 = boto3.client('s3')
bucket = 'openclaw-logs-cheap'
# 配置 S3 智能分层
try:
s3.put_bucket_intelligent_tiering_configuration(
Bucket=bucket,
Id='LogsIntelligentTiering',
IntelligentTieringConfiguration={
'Id': 'LogsIntelligentTiering',
'Status': 'Enabled',
'Filter': {'Prefix': 'logs/'},
'Tierings': [
{'Days': 1, 'AccessTier': 'ARCHIVE_ACCESS'},
{'Days': 90, 'AccessTier': 'DEEP_ARCHIVE_ACCESS'}
]
}
)
print("S3智能分层已配置")
except Exception as e:
print(f"配置可能已存在: {e}")
def archive_old_logs():
"""归档7天前的日志"""
log_dir = '/opt/openclaw/logs'
s3 = boto3.client('s3')
bucket = 'openclaw-logs-cheap'
cutoff = datetime.now() - timedelta(days=7)
for log_file in os.listdir(log_dir):
if not log_file.endswith('.log'):
continue
file_path = os.path.join(log_dir, log_file)
file_time = datetime.fromtimestamp(os.path.getmtime(file_path))
if file_time < cutoff:
# 压缩日志
compressed_path = f'/tmp/{log_file}.gz'
with open(file_path, 'rb') as f_in:
with gzip.open(compressed_path, 'wb') as f_out:
f_out.writelines(f_in)
# 上传到 S3
s3_key = f"logs/{file_time.strftime('%Y/%m/%d')}/{log_file}.gz"
s3.upload_file(
compressed_path,
bucket,
s3_key,
ExtraArgs={'StorageClass': 'INTELLIGENT_TIERING'}
)
# 删除本地文件
os.remove(file_path)
os.remove(compressed_path)
print(f"归档完成: {log_file}")
# 设置 crontab 每天运行
setup_log_rotation()
archive_old_logs()
存储成本:从 <math xmlns="http://www.w3.org/1998/Math/MathML"> 8 / 月降到 8/月 降到 </math>8/月降到2.4/月
第四坑:没用 Reserved Instance,白白多花钱
坑长这样
我一直按需付费,直到有一天看到 RI 的价格:
bash
# 查看 RI 价格
aws ec2 describe-reserved-instances-offerings \
--instance-type t4g.medium \
--product-description "Linux/UNIX" \
--query 'ReservedInstancesOfferings[?Duration==`31536000`].[FixedPrice,UsagePrice]' \
--output table
# 按需: $30.37/月
# 1年期RI: $21.26/月
# 省了30%!
填坑:购买 RI + Savings Plan
bash
# 购买 Reserved Instance
aws ec2 purchase-reserved-instances-offering \
--reserved-instances-offering-id 8ba8f0f0-example-id \
--instance-count 1
# 查看推荐的 Savings Plans
aws savingsplans get-savings-plans-purchase-recommendation \
--savings-plans-type COMPUTE_SP \
--term-in-years 1 \
--payment-option NO_UPFRONT
# 根据推荐购买 Savings Plan
aws savingsplans create-savings-plan \
--savings-plan-offering-id sp-example-id \
--commitment 8.50
RI + Savings Plan 组合,又省了 30%+
第五坑:没有成本监控,超支了都不知道
坑的恶果
有个月莫名其妙多花了 40 刀,查了半天才发现是测试时忘记关的实例。
填坑:完整监控体系
1. CloudWatch 告警
python
import boto3
def setup_comprehensive_alerts():
"""设置全方位成本告警"""
cloudwatch = boto3.client('cloudwatch')
sns = boto3.client('sns')
# 创建告警主题
topic = sns.create_topic(Name='openclaw-cost-alerts')
topic_arn = topic['TopicArn']
# 订阅邮件
sns.subscribe(
TopicArn=topic_arn,
Protocol='email',
Endpoint='my-email@example.com'
)
# 多级告警
alerts = [
{'name': 'OpenClaw-Cost-Warning', 'threshold': 25, 'level': '警告'},
{'name': 'OpenClaw-Cost-Critical', 'threshold': 35, 'level': '严重'},
{'name': 'OpenClaw-Cost-Emergency', 'threshold': 50, 'level': '紧急'}
]
for alert in alerts:
cloudwatch.put_metric_alarm(
AlarmName=alert['name'],
ComparisonOperator='GreaterThanThreshold',
EvaluationPeriods=1,
MetricName='EstimatedCharges',
Namespace='AWS/Billing',
Period=86400,
Statistic='Maximum',
Threshold=alert['threshold'],
ActionsEnabled=True,
AlarmActions=[topic_arn],
AlarmDescription=f"{alert['level']}:月成本超过${alert['threshold']}",
Dimensions=[{'Name': 'Currency', 'Value': 'USD'}]
)
print(f"告警已设置: {alert['name']} (阈值: ${alert['threshold']})")
setup_comprehensive_alerts()
2. 预算控制
python
def create_strict_budget():
"""创建严格的预算控制"""
budgets = boto3.client('budgets')
# 主预算
budget_config = {
'BudgetName': 'OpenClaw-Monthly-Budget',
'BudgetLimit': {'Amount': '30', 'Unit': 'USD'},
'TimeUnit': 'MONTHLY',
'BudgetType': 'COST'
}
# 多级通知
notifications = [
{
'NotificationType': 'ACTUAL',
'ComparisonOperator': 'GREATER_THAN',
'Threshold': 50, # 50% 时提醒
'ThresholdType': 'PERCENTAGE'
},
{
'NotificationType': 'ACTUAL',
'ComparisonOperator': 'GREATER_THAN',
'Threshold': 80, # 80% 时警告
'ThresholdType': 'PERCENTAGE'
},
{
'NotificationType': 'FORECASTED',
'ComparisonOperator': 'GREATER_THAN',
'Threshold': 100, # 预测超预算时告急
'ThresholdType': 'PERCENTAGE'
}
]
subscribers = [{'SubscriptionType': 'EMAIL', 'Address': 'my-email@example.com'}]
# 创建预算
budgets.create_budget(
AccountId='123456789012',
Budget=budget_config,
NotificationsWithSubscribers=[
{'Notification': notif, 'Subscribers': subscribers}
for notif in notifications
]
)
print("严格预算控制已设置:$30/月,多级告警")
create_strict_budget()
3. 每日成本报告
python
def daily_cost_report():
"""生成每日成本报告"""
ce = boto3.client('ce')
end_date = datetime.now().date()
start_date = end_date - timedelta(days=1)
# 获取昨日成本
response = ce.get_cost_and_usage(
TimePeriod={
'Start': start_date.strftime('%Y-%m-%d'),
'End': end_date.strftime('%Y-%m-%d')
},
Granularity='DAILY',
Metrics=['BlendedCost'],
GroupBy=[{'Type': 'DIMENSION', 'Key': 'SERVICE'}]
)
# 解析成本数据
services = {}
total_cost = 0
for result in response['ResultsByTime']:
for group in result['Groups']:
service = group['Keys'][0]
cost = float(group['Metrics']['BlendedCost']['Amount'])
services[service] = cost
total_cost += cost
# 生成报告
report = f"📊 OpenClaw 每日成本报告 ({start_date})\n"
report += f"总成本:${total_cost:.3f}\n\n"
for service, cost in sorted(services.items(), key=lambda x: x[1], reverse=True):
if cost > 0.001: # 只显示超过1分钱的
percentage = (cost / total_cost) * 100
report += f"{service}: ${cost:.3f} ({percentage:.1f}%)\n"
# 月度预测
monthly_estimate = total_cost * 30.5
report += f"\n📈 月度预测:${monthly_estimate:.2f}"
if monthly_estimate > 30:
report += " ⚠️ 可能超预算!"
else:
report += " ✅ 在预算内"
print(report)
# 可以发送到 Slack 或邮件
return report
# 设置每天自动运行
daily_cost_report()
最终成果:完整的成本优化方案
优化前后对比
| 项目 | 优化前 | 优化后 | 节省 |
|---|---|---|---|
| EC2 | t3.xlarge $119.81 | t4g.medium RI $21.26 | $98.55 |
| 存储 | 100GB EBS $8.00 | 30GB + S3 $2.40 | $5.60 |
| Bedrock | Claude $68.54 | Nova+优化 $12.30 | $56.24 |
| 网络 | 固定IP $3.65 | 弹性IP $3.65 | $0.00 |
| 总计 | $200.00 | $29.81 | $170.19 |
节省比例:85% 🎉
性能影响评估
担心性能?我跑了 30 天监控:
python
def performance_summary():
"""30天性能总结"""
metrics = {
'CPU使用率': '平均23%,峰值45%,完全够用',
'内存使用': '平均2.8GB/4GB,偶尔到3.2GB需要监控',
'API响应': '平均145ms,比之前慢25ms,可接受',
'稳定性': '99.8%在线率,中间重启过一次',
'用户体验': '没收到性能投诉,说明够用'
}
for metric, result in metrics.items():
print(f"{metric}: {result}")
performance_summary()
结论:性能影响微乎其微,但成本节省巨大!
监控面板展示
创建了一个专门的监控面板:
python
def create_cost_dashboard():
"""创建成本监控面板"""
cloudwatch = boto3.client('cloudwatch')
dashboard = {
"widgets": [
{
"type": "metric",
"properties": {
"metrics": [
["AWS/Billing", "EstimatedCharges", "Currency", "USD"]
],
"period": 86400,
"stat": "Maximum",
"region": "us-east-1",
"title": "💰 每日成本趋势"
}
},
{
"type": "metric",
"properties": {
"metrics": [
["AWS/EC2", "CPUUtilization", "InstanceId", "i-new"],
["CWAgent", "mem_used_percent", "InstanceId", "i-new"]
],
"period": 300,
"stat": "Average",
"region": "us-east-1",
"title": "📊 资源使用率"
}
},
{
"type": "log",
"properties": {
"query": "SOURCE '/aws/bedrock' | fields @timestamp, cost\n| stats sum(cost) by bin(5m)",
"region": "us-east-1",
"title": "🤖 Bedrock 成本分析"
}
}
]
}
cloudwatch.put_dashboard(
DashboardName='OpenClaw-Cost-Control',
DashboardBody=json.dumps(dashboard)
)
print("监控面板已创建!")
create_cost_dashboard()
我踩坑总结出的省钱心得
🏆 核心原则
- 性能够用就行:别追求完美配置,够用就够了
- 持续监控:没有监控的优化都是耍流氓
- 小步快跑:一点一点优化,别一次改太多
- 数据说话:用真实数据验证,不要拍脑袋
⚡ 立竿见影的优化
- 换 ARM 实例:t4g 比 t3 便宜 30-50%,性能差不多
- 买 Reserved Instance:确定长期用的服务,RI 能省 30-40%
- 选对 AI 模型:Nova Lite 比 Claude 便宜 80%,大多数场景够用
- 用批量推理:非实时场景必用,省 50%
🔍 容易忽略的细节
- EBS 用量监控:大多数人都过度配置存储
- 日志归档策略:S3 智能分层是神器
- 网络成本:固定 IP 不用时记得释放
- 测试资源清理:临时实例要记得关
🚨 避坑指南
- 性能验证:降配前一定要压测
- 分步优化:别一次改太多,出问题难排查
- 备份备份:改存储前务必备份
- 监控先行:优化前先把监控搞好
写在最后
从 <math xmlns="http://www.w3.org/1998/Math/MathML"> 200 到 200 到 </math>200到30,这波优化让我的个人项目可以持续下去了。最重要的是,整个过程让我对亚马逊云科技的服务有了更深的理解。
所有代码都能直接复制使用,改改配置就能跑。如果你也在为账单发愁,希望我踩过的坑能帮你绕路!
有问题评论区见,踩坑路上我们一起走! 🦞
本文涉及的所有脚本和配置:
- 资源监控脚本
- 成本分析工具
- 迁移自动化脚本
- 监控告警配置
- 性能测试工具
需要的朋友可以留言,我整理成 GitHub 仓库分享给大家!