cover

雲端費用評估與優化:帳單不該是月底的驚喜

雲端最大的優勢是「用多少付多少」,但這也是最大的陷阱。沒有實體伺服器擺在機房裡提醒你成本的存在,資源的開通只要幾秒鐘,卻沒有人告訴你它每小時都在燒錢。很多團隊在上雲初期只關注功能和架構,等第一個月帳單寄來才發現金額遠超預期——NAT Gateway 的資料傳輸費比 EC2 本身還貴、忘記刪除的 EBS snapshot 累積了幾百 GB、測試環境的 RDS 24 小時跑著卻沒人在用。

成本意識不是等帳單來了才開始建立的,它應該從架構設計的第一天就融入決策。這篇文章從估算、監控、分析到優化,建立完整的雲端成本管理流程。

架構概覽

flowchart LR
    A["1. 監控 Monitor\nCost Explorer\nBudgets"] --> B["2. 分析 Analyze\nAnomaly Detection\nKubecost"]
    B --> C["3. 調整 Rightsize\nCompute Optimizer\n降級閒置資源"]
    C --> D["4. 預留 Reserve\nRI / Savings Plans\nSpot Instances"]
    D --> E["5. 檢視 Review\n清理未用資源\n驗證優化效果"]
    E --> A

    A -.->|"即時追蹤\n設定告警"| A
    B -.->|"找出異常\n定位浪費"| B
    C -.->|"CPU < 20%?\n降級規格"| C
    D -.->|"穩定負載?\n買 RI 省 30-72%"| D
    E -.->|"EBS / EIP / ALB\n未用即刪"| E

成本優化生命週期

flowchart LR
  Estimate[估算 Estimate\n預測成本基準線] --> Monitor[監控 Monitor\n即時追蹤實際花費]
  Monitor --> Analyze[分析 Analyze\n找出異常與浪費]
  Analyze --> Optimize[優化 Optimize\n採取降本措施]
  Optimize --> Estimate

  Estimate -.->|AWS Pricing Calculator\nInfracost| Estimate
  Monitor -.->|Cost Explorer\nBudgets| Monitor
  Analyze -.->|Cost Anomaly Detection\nKubecost| Analyze
  Optimize -.->|Right-sizing\nRI/SP\nSpot| Optimize

成本管理不是一次性的任務,而是持續循環的過程:估算建立基準線、監控追蹤實際花費、分析找出差異和浪費、優化採取行動降低成本、再重新估算驗證效果。每個階段都有對應的工具和方法。

核心概念

  1. 雲端計價模型:雲端服務的計價方式主要分為四種。(1)On-Demand(隨需計費):最彈性也最貴,按小時或秒計費,隨時開隨時關,適合短期測試或流量不可預測的場景。(2)Reserved Instance(RI,預留執行個體):承諾使用 1 年或 3 年,換取 30%-72% 的折扣。適合穩定運行的生產環境。1 年期約省 30-40%,3 年期約省 60-72%,但中途不能退。(3)Spot / Preemptible Instance(競價型執行個體):使用雲端供應商的閒置容量,價格最低(省 60-90%),但隨時可能被回收(通常會有 2 分鐘的通知)。適合可中斷的工作負載,例如 batch processing、CI runner、資料分析。(4)Savings Plans(節省方案):AWS 特有的方案,承諾每小時固定消費金額(例如 $10/hr),不綁定特定執行個體類型,比 RI 更有彈性,折扣力度類似。

  2. 主要成本組成:雲端帳單的大頭通常來自四個類別。(1)Compute(運算):EC2 / GCE / Azure VM 是最大的支出項,費用取決於執行個體類型、數量和運行時間。一台 t3.medium(2 vCPU / 4GB)在 us-east-1 的 On-Demand 價格約 30。(2)Storage(儲存):S3 / GCS / Azure Blob 的儲存費用按 GB-月計算。S3 Standard 約 0.08/GB-月。(3)Network(網路):資料傳輸費是最容易被忽略的成本。從雲端傳出到網際網路(egress)收費、跨 AZ 傳輸收費、NAT Gateway 的資料處理費每 GB 50/月(Multi-AZ 翻倍)。

  3. 隱藏成本陷阱:以下是最常讓人帳單爆炸的隱藏成本。(1)NAT Gateway 資料處理費:每個 NAT Gateway 固定費用 32/月),加上每 GB 資料處理費 0.01。微服務架構下如果 service A 在 AZ-a、service B 在 AZ-b,兩者頻繁通訊的流量費會很可觀。(3)EBS Snapshots:每 GB-月 0.005(約 16/月,即使沒有流量通過。測試環境的 ALB 常常被遺忘。

  4. FinOps 原則:FinOps(Financial Operations)是一套雲端財務管理的方法論,核心原則包含:(1)Cost Visibility(成本可視化):每筆費用都必須能追溯到具體的團隊、專案或環境。透過 tagging 策略(例如 team=backendenv=prodproject=api)讓成本分攤清晰。(2)Accountability(責任歸屬):每個團隊要對自己的雲端花費負責,而不是全公司共用一張帳單、沒人在意。設定每個團隊的預算上限和告警。(3)Optimization(持續優化):定期 review 成本報表,找出浪費並採取行動。不是一次優化就結束,而是持續循環的過程。

成本估算方法論

使用 AWS Pricing Calculator

AWS Pricing Calculator(calculator.aws)可以在上雲前估算月費。操作流程:選擇 Region → 加入服務(EC2、RDS、S3 等)→ 設定規格和用量 → 檢視月費估算。估算時要注意包含所有相關成本,不要只算 EC2 就覺得夠了。

估算公式

月費估算 = Compute + Storage + Network + Database + Misc

Compute  = Σ (instance 單價 × 數量 × 運行時數)
Storage  = Σ (儲存 GB × 單價) + (請求次數 × 單價)
Network  = egress 流量 GB × 單價 + NAT 處理 GB × 單價 + 跨 AZ 流量 GB × 單價
Database = DB instance 單價 + 儲存 + 備份 + 讀取副本
Misc     = ALB + Route53 + CloudWatch + EIP + 其他

實戰估算:典型 Web 應用的月費

假設要部署一個中型 Web 應用,架構如下:2 台 EC2 (t3.medium) + 1 台 RDS (db.t3.medium, Multi-AZ) + S3 (100GB) + ALB + NAT Gateway。Region 選 us-east-1

項目規格月費估算
EC2 × 2t3.medium, On-Demand60
RDSdb.t3.medium, Multi-AZ, 100GB gp38 = $108
S3100GB Standard + 100 萬次 GET0.4 = $2.7
ALB固定費 + LCU (低流量)5 = $21
NAT Gateway固定費 + 50GB 處理2.25 = $34.25
Data Transfer100GB egress$9
EBS2 × 30GB gp3$4.8
Route 531 Hosted Zone + 100 萬次 query0.4 = $0.9
CloudWatch基本監控$0 (免費)
合計~$240/月

注意幾個重點:(1)RDS Multi-AZ 讓資料庫費用翻倍,如果 staging 環境不需要高可用可以用 Single-AZ。(2)NAT Gateway 的固定費用 32 × AZ 數量。(3)Data Transfer 的 egress 費用會隨流量線性增長,如果有大量對外回應(例如影片串流),這一項會爆增。

如果把 EC2 改成 1 年 RI(All Upfront),Compute 成本從 38,節省 37%。再加上 RDS 的 RI,整體可以從 180 左右,年省約 $720。

優化策略

  1. Right-sizing(調整規格):最簡單也最有效的優化方式。很多團隊在初期為了「安全」選了太大的執行個體,但實際 CPU 使用率長期低於 20%。AWS 的 Compute Optimizer 和 Cost Explorer 的 Right Sizing Recommendations 可以根據過去的使用量建議更合適的執行個體類型。例如把長期 CPU < 10% 的 m5.xlarge0.096/hr),直接省 50%。

  2. Reserved Instances / Savings Plans(預留或承諾):對於穩定運行 24/7 的生產環境工作負載,RI 或 Savings Plans 是最直接的降本手段。建議策略:先用 On-Demand 運行 1-2 個月,觀察實際用量和穩定性。確認工作負載穩定後,對核心 Compute 和 Database 購買 1 年期 RI。Savings Plans 比 RI 更靈活,如果團隊會頻繁調整執行個體類型,優先選擇 Savings Plans。3 年期折扣更大,但只建議對非常確定的長期負載使用。

  3. Spot Instances(競價型執行個體):適合以下場景:(1)CI/CD Pipeline runner:build job 跑完就結束,被中斷就重跑。(2)Batch processing:大量資料處理、影片轉碼,可以分批進行。(3)開發/測試環境:不需要 100% 可用性。(4)無狀態的 Web worker:搭配 Auto Scaling Group 和 On-Demand 混合使用。Spot 的價格通常是 On-Demand 的 10-30%,但要設計好中斷處理機制。

  4. Auto Scaling(自動擴縮):根據實際負載自動調整執行個體數量。白天流量高時擴展到 4 台,凌晨流量低時縮減到 1 台。如果平均流量只有尖峰的 30%,Auto Scaling 理論上可以省下 50-60% 的 Compute 成本。搭配 Scheduled Scaling(例如工作日 8:00 擴展、22:00 縮減)可以更精準控制。

  5. Storage Tiering(儲存分層):S3 提供多種儲存等級,價格差異巨大。S3 Standard 約 0.0125/GB-月(每月存取 1-2 次的資料)、S3 Glacier Instant Retrieval 約 0.00099/GB-月(歸檔資料,取回需要 12 小時)。用 Lifecycle Policy 自動將老舊資料降級到低成本等級。

  6. 清理未使用的資源:這是最容易被忽略但效果顯著的優化。常見的浪費:(1)未掛載的 EBS volumes:EC2 刪了但 EBS 沒刪。(2)過期的 EBS snapshots:備份策略沒有設定保留期限。(3)閒置的 NAT Gateway:VPC 還在但裡面沒有服務了。(4)未使用的 Elastic IP:分配了但沒掛到 EC2。(5)測試環境的 RDS / ALB:週末和晚上沒人用但 24 小時在跑。

成本監控工具

  1. AWS Cost Explorer:AWS 內建的成本分析工具,可以按服務、Region、Tag、Linked Account 等維度查看花費。支援過去 12 個月的歷史資料和未來 12 個月的預測。建議每週至少看一次,觀察趨勢變化。

  2. AWS Budgets:設定月預算上限和告警閾值。當實際花費或預測花費超過閾值時,透過 Email 或 SNS 通知。建議為每個環境(prod / staging / dev)分別設定 Budget。

  3. AWS Cost Anomaly Detection:用機器學習偵測異常花費。例如某個服務突然比過去 30 天的平均值高出 3 倍,系統會自動發出告警。適合偵測忘記關閉的資源或意外的流量暴增。

  4. Infracost(IaC 成本估算):在 Terraform plan 階段就估算基礎設施的月費變化。整合到 CI/CD pipeline,每次 PR 自動附上成本影響。例如加一台 RDS 時,PR comment 會顯示「月費增加 $108」。

  5. Kubecost(Kubernetes 成本):專門分析 Kubernetes cluster 的成本分攤。可以看到每個 namespace、deployment、pod 的實際資源消耗和對應費用。幫助找出 over-provisioned 的 deployment 和 idle 的資源。

實作範例 / 設定範例

AWS Budget 告警設定(CloudFormation)

# cloudformation-budget.yml
AWSTemplateFormatVersion: '2010-09-09'
Description: Monthly cost budget with alert notifications
 
Resources:
  MonthlyBudget:
    Type: AWS::Budgets::Budget
    Properties:
      Budget:
        BudgetName: monthly-total-cost
        BudgetType: COST
        TimeUnit: MONTHLY
        BudgetLimit:
          Amount: 500
          Unit: USD
        CostFilters: {}
        CostTypes:
          IncludeTax: true
          IncludeSubscription: true
          UseBlended: false
      NotificationsWithSubscribers:
        # 實際花費達到 80% 時通知
        - Notification:
            NotificationType: ACTUAL
            ComparisonOperator: GREATER_THAN
            Threshold: 80
            ThresholdType: PERCENTAGE
          Subscribers:
            - SubscriptionType: EMAIL
              Address: team@example.com
            - SubscriptionType: SNS
              Address: !Ref BudgetAlertTopic
        # 預測花費超過 100% 時通知
        - Notification:
            NotificationType: FORECASTED
            ComparisonOperator: GREATER_THAN
            Threshold: 100
            ThresholdType: PERCENTAGE
          Subscribers:
            - SubscriptionType: EMAIL
              Address: team@example.com
 
  BudgetAlertTopic:
    Type: AWS::SNS::Topic
    Properties:
      TopicName: budget-alerts
      DisplayName: Budget Alert Notifications
 
  # 每個環境的 Budget
  ProductionBudget:
    Type: AWS::Budgets::Budget
    Properties:
      Budget:
        BudgetName: production-env-cost
        BudgetType: COST
        TimeUnit: MONTHLY
        BudgetLimit:
          Amount: 300
          Unit: USD
        CostFilters:
          TagKeyValue:
            - 'user:env$production'
      NotificationsWithSubscribers:
        - Notification:
            NotificationType: ACTUAL
            ComparisonOperator: GREATER_THAN
            Threshold: 90
            ThresholdType: PERCENTAGE
          Subscribers:
            - SubscriptionType: EMAIL
              Address: team@example.com

也可以用 AWS CLI 快速建立 Budget:

# 用 AWS CLI 建立 Budget 告警
aws budgets create-budget \
  --account-id 123456789012 \
  --budget '{
    "BudgetName": "monthly-limit",
    "BudgetType": "COST",
    "TimeUnit": "MONTHLY",
    "BudgetLimit": {
      "Amount": "500",
      "Unit": "USD"
    }
  }' \
  --notifications-with-subscribers '[
    {
      "Notification": {
        "NotificationType": "ACTUAL",
        "ComparisonOperator": "GREATER_THAN",
        "Threshold": 80,
        "ThresholdType": "PERCENTAGE"
      },
      "Subscribers": [
        {
          "SubscriptionType": "EMAIL",
          "Address": "team@example.com"
        }
      ]
    }
  ]'

Terraform + Infracost 整合

# main.tf - 附上 Infracost 的成本註解
# Infracost 會自動解析 Terraform 並估算費用
# 執行 infracost breakdown --path . 即可看到成本明細
 
# EC2 instance
# Infracost 估算:~$30/月 (On-Demand)
resource "aws_instance" "web" {
  ami           = "ami-0abcdef1234567890"
  instance_type = "t3.medium"
 
  root_block_device {
    volume_size = 30    # Infracost 估算:~$2.4/月 (gp3)
    volume_type = "gp3"
  }
 
  tags = {
    Name    = "web-server"
    env     = "production"
    team    = "backend"
    project = "api"
  }
}
 
# RDS instance
# Infracost 估算:~$108/月 (Multi-AZ)
resource "aws_db_instance" "main" {
  identifier     = "main-db"
  engine         = "postgres"
  engine_version = "15.4"
  instance_class = "db.t3.medium"
 
  allocated_storage     = 100
  storage_type          = "gp3"
  multi_az              = true     # Multi-AZ 費用翻倍
 
  backup_retention_period = 7      # 超過免費額度的備份會收費
  skip_final_snapshot     = false
 
  tags = {
    env  = "production"
    team = "backend"
  }
}
 
# NAT Gateway — 容易被忽略的成本大戶
# Infracost 估算:~$32/月 (固定費用) + 資料處理費
resource "aws_nat_gateway" "main" {
  allocation_id = aws_eip.nat.id
  subnet_id     = aws_subnet.public.id
 
  tags = {
    Name = "main-nat"
    env  = "production"
  }
}
 
# 在 CI/CD pipeline 中整合 Infracost
# .github/workflows/infracost.yml 可以在 PR 自動附上成本影響:
#
#   - name: Infracost breakdown
#     run: |
#       infracost diff \
#         --path . \
#         --format json \
#         --out-file /tmp/infracost.json
#
#   - name: Post PR comment
#     run: |
#       infracost comment github \
#         --path /tmp/infracost.json \
#         --repo $GITHUB_REPOSITORY \
#         --pull-request $PR_NUMBER \
#         --github-token $GITHUB_TOKEN

S3 Lifecycle Policy 自動降級儲存等級

{
  "Rules": [
    {
      "ID": "archive-old-logs",
      "Status": "Enabled",
      "Filter": {
        "Prefix": "logs/"
      },
      "Transitions": [
        {
          "Days": 30,
          "StorageClass": "STANDARD_IA"
        },
        {
          "Days": 90,
          "StorageClass": "GLACIER_IR"
        },
        {
          "Days": 365,
          "StorageClass": "DEEP_ARCHIVE"
        }
      ],
      "Expiration": {
        "Days": 730
      }
    },
    {
      "ID": "cleanup-incomplete-uploads",
      "Status": "Enabled",
      "Filter": {
        "Prefix": ""
      },
      "AbortIncompleteMultipartUpload": {
        "DaysAfterInitiation": 7
      }
    },
    {
      "ID": "archive-old-backups",
      "Status": "Enabled",
      "Filter": {
        "Prefix": "backups/"
      },
      "Transitions": [
        {
          "Days": 7,
          "StorageClass": "STANDARD_IA"
        },
        {
          "Days": 30,
          "StorageClass": "GLACIER_IR"
        }
      ],
      "Expiration": {
        "Days": 180
      }
    }
  ]
}

用 AWS CLI 套用這個 Lifecycle Policy:

aws s3api put-bucket-lifecycle-configuration \
  --bucket my-app-bucket \
  --lifecycle-configuration file://lifecycle-policy.json

自動清理未使用資源的腳本

#!/bin/bash
# cleanup-unused-resources.sh
# 定期執行(cron: 每週一 9:00)尋找並列出未使用的 AWS 資源
# 0 9 * * 1 /opt/scripts/cleanup-unused-resources.sh
 
set -euo pipefail
 
REPORT_FILE="/tmp/unused-resources-$(date +%Y%m%d).txt"
echo "=== 未使用資源報告 $(date) ===" > "$REPORT_FILE"
 
# 1. 找出未掛載的 EBS Volumes
echo -e "\n--- 未掛載的 EBS Volumes ---" >> "$REPORT_FILE"
aws ec2 describe-volumes \
  --filters Name=status,Values=available \
  --query 'Volumes[*].{ID:VolumeId,Size:Size,Created:CreateTime,AZ:AvailabilityZone}' \
  --output table >> "$REPORT_FILE"
 
UNATTACHED_EBS=$(aws ec2 describe-volumes \
  --filters Name=status,Values=available \
  --query 'length(Volumes)')
echo "未掛載 EBS 數量: $UNATTACHED_EBS" >> "$REPORT_FILE"
 
# 2. 找出未使用的 Elastic IPs
echo -e "\n--- 未使用的 Elastic IPs ---" >> "$REPORT_FILE"
aws ec2 describe-addresses \
  --query 'Addresses[?AssociationId==`null`].{IP:PublicIp,AllocationId:AllocationId}' \
  --output table >> "$REPORT_FILE"
 
# 3. 找出超過 30 天的 EBS Snapshots
echo -e "\n--- 超過 30 天的 EBS Snapshots ---" >> "$REPORT_FILE"
THIRTY_DAYS_AGO=$(date -d '30 days ago' +%Y-%m-%dT%H:%M:%S 2>/dev/null \
  || date -v-30d +%Y-%m-%dT%H:%M:%S)
aws ec2 describe-snapshots \
  --owner-ids self \
  --query "Snapshots[?StartTime<='${THIRTY_DAYS_AGO}'].{ID:SnapshotId,Size:VolumeSize,Date:StartTime}" \
  --output table >> "$REPORT_FILE"
 
# 4. 找出閒置的 Load Balancers(過去 7 天無流量)
echo -e "\n--- 可能閒置的 ALB ---" >> "$REPORT_FILE"
for ALB_ARN in $(aws elbv2 describe-load-balancers --query 'LoadBalancers[*].LoadBalancerArn' --output text); do
  REQUEST_COUNT=$(aws cloudwatch get-metric-statistics \
    --namespace AWS/ApplicationELB \
    --metric-name RequestCount \
    --dimensions Name=LoadBalancer,Value="$(echo "$ALB_ARN" | cut -d'/' -f2-)" \
    --start-time "$(date -d '7 days ago' +%Y-%m-%dT%H:%M:%S 2>/dev/null || date -v-7d +%Y-%m-%dT%H:%M:%S)" \
    --end-time "$(date +%Y-%m-%dT%H:%M:%S)" \
    --period 604800 \
    --statistics Sum \
    --query 'Datapoints[0].Sum // `0`' \
    --output text 2>/dev/null || echo "0")
 
  if [ "$REQUEST_COUNT" = "0" ] || [ "$REQUEST_COUNT" = "None" ]; then
    ALB_NAME=$(aws elbv2 describe-load-balancers \
      --load-balancer-arns "$ALB_ARN" \
      --query 'LoadBalancers[0].LoadBalancerName' --output text)
    echo "閒置 ALB: $ALB_NAME ($ALB_ARN)" >> "$REPORT_FILE"
  fi
done
 
# 5. 找出 stopped 超過 7 天的 EC2 instances
echo -e "\n--- 長期 Stopped 的 EC2 ---" >> "$REPORT_FILE"
aws ec2 describe-instances \
  --filters Name=instance-state-name,Values=stopped \
  --query 'Reservations[*].Instances[*].{ID:InstanceId,Type:InstanceType,Name:Tags[?Key==`Name`]|[0].Value,StopTime:StateTransitionReason}' \
  --output table >> "$REPORT_FILE"
 
# 發送報告
echo -e "\n=== 報告結束 ===" >> "$REPORT_FILE"
echo "報告已產生: $REPORT_FILE"
 
# 可以透過 SNS 發送通知
# aws sns publish \
#   --topic-arn arn:aws:sns:us-east-1:123456789012:cost-alerts \
#   --subject "Weekly Unused Resources Report" \
#   --message file://"$REPORT_FILE"

常見問題與風險

  • 帳單爆炸才發現問題:上雲第一個月帳單 500。原因通常是:(1)忘記 NAT Gateway 和 Data Transfer 的費用。(2)測試環境的資源沒有關閉。(3)Multi-AZ 和備份費用沒算進去。避免方式:上雲前用 Pricing Calculator 完整估算所有項目(不要漏掉 Network 和 Misc),第一天就設定 Budget Alert。

  • Reserved Instance 買錯規格:花了 $5000 買 3 年 RI,結果半年後發現需要換執行個體類型或搬到其他 Region。RI 不能跨 Region 使用、部分類型不能換。避免方式:先用 1 年期試水溫,不要一開始就買 3 年期。優先考慮 Savings Plans(不綁定執行個體類型)。只對非常確定的核心負載購買長期承諾。

  • Spot Instance 被回收導致服務中斷:Spot Instance 被 AWS 回收(2 分鐘通知),如果沒有設計好 graceful shutdown 和 failover,使用者會看到服務中斷。避免方式:Spot 只用在可中斷的工作負載。Production 的 Web 服務用 On-Demand + Spot 混合(例如 ASG 中 70% On-Demand + 30% Spot)。設計好中斷處理(checkpoint、job retry)。

  • Tag 策略沒有落實:沒有統一的 tagging 標準,Cost Explorer 看到的都是 untagged 的資源,無法分辨哪些費用屬於哪個團隊或專案。避免方式:用 AWS Organizations 的 SCP(Service Control Policy)或 Config Rules 強制要求 tag。在 Terraform 的 provider 層級設定 default tags。定期稽核 untagged 資源。

  • 忽略非生產環境的成本:Staging 和 Dev 環境照搬 Production 的規格,加起來的費用甚至超過 Production。避免方式:非生產環境用更小的執行個體、Single-AZ 的 RDS、關閉不必要的 NAT Gateway。設定排程(weekday 8:00 開機、22:00 關機)。詳見 Environment Separation

  • Data Transfer 費用失控:大量資料從 S3 透過 CloudFront 對外服務、跨 Region 複製資料、微服務之間跨 AZ 呼叫,這些都會產生顯著的網路傳輸費。避免方式:使用 CloudFront 可以降低 S3 egress 費用(CloudFront 的 data transfer 費率比直接從 S3 傳出便宜)。盡量讓相關服務部署在同一個 AZ。用 VPC Endpoint 取代 NAT Gateway 存取 AWS 服務。

優點

  • 雲端的彈性計費讓小團隊可以從低成本開始,隨業務增長擴展
  • RI / Savings Plans / Spot 提供多種降本選擇,適合不同場景
  • 完善的成本監控工具(Cost Explorer、Budgets)讓花費透明可追蹤

缺點 / 限制

  • 計價模型複雜,不同服務的計費方式差異大,容易漏算隱藏成本
  • RI 和 Savings Plans 需要提前承諾,預測不準會造成浪費
  • 跨團隊的成本分攤需要嚴格的 tagging 策略,執行成本不低
  • 優化是持續性的工作,需要投入人力定期 review 和調整

延伸閱讀