AWS SQL Server 建置教學延伸:RDS Proxy
延續 RDS for SQL Server 的基礎建置,補充最後一哩路 RDS Proxy,包含 Secrets Manager、IAM Role、Proxy 建立、SQL Server 密碼驗證與 IAM 驗證的完整步驟,以及 Terraform 範例。
前兩篇文章分別完成了 RDS for SQL Server 的基礎建置,以及稽核設定與密碼輪替。到這裡,資料庫已經可以連線、可以備份、可以稽核,密碼也交給 Secrets Manager 管理。
但還有一個問題沒有解決:應用程式和資料庫之間的「連線」本身。
常見的情境像是:
- 應用程式重新部署或水平擴展時,瞬間建立大量新連線,把資料庫連線數打滿。
- Lambda 或容器這類生命週期短的運算資源,每次執行都重新建立連線,資料庫大部分資源花在處理連線建立與釋放。
- 微服務化以後,每個微服務水平擴展,即使應用程式有 Connection Pool 的設計,也因為連線池沒有在跨微服務間應用,導致被塞爆
這些問題的共通點是:資料庫連線被當成「應用程式自己要處理好的事」。RDS Proxy 就是把這件事搬到 AWS 這一層來管理的服務。
RDS Proxy 是什麼
RDS Proxy 是 AWS 提供的全受管資料庫連線代理。應用程式不再直接連 RDS endpoint,而是連到 Proxy endpoint,由 Proxy 維護一個到資料庫的連線池(connection pool),並在多個應用程式連線之間共用這些資料庫連線(multiplexing)。
它主要解決幾件事:
| 能力 | 說明 |
|---|---|
| 連線池化 | Proxy 維護與資料庫之間的長連線,應用程式端的大量短連線不會直接衝擊資料庫 |
| 減少 failover 中斷 | failover 時 Proxy 會保留應用程式端連線,並自動接到新的 primary,不需要等 DNS TTL |
| 憑證集中管理 | Proxy 使用 Secrets Manager 的 secret 連資料庫,密碼輪替不需要改應用程式 |
| 強化驗證 | 可以要求應用程式使用 IAM 驗證連 Proxy,讓應用程式不必保存資料庫密碼;SQL Server 情境下 Proxy 到資料庫仍使用 Secrets Manager 帳密 |
RDS Proxy 支援 RDS for SQL Server,這也是這個系列可以把它當成最後一哩路的原因。不過要注意,Proxy 是每小時依 vCPU 計費的服務,不是免費功能,導入前要評估成本是否值得。
不是每個場景都需要 RDS Proxy。如果應用程式數量少、連線穩定、已經有良好的 connection pool 管理,直接連 RDS 可能就夠了。RDS Proxy 最有價值的場景是 serverless、大量短連線、頻繁擴縮,以及希望降低 failover 中斷的系統。
建置前先確認幾件事
| 項目 | 建議先確認的內容 |
|---|---|
| VPC 與 Subnet | Proxy 必須和 RDS 在同一個 VPC,建議跨至少兩個 AZ 的 Private Subnet |
| Security Group | 應用程式 → Proxy、Proxy → RDS 兩段的 1433 規則 |
| Secrets Manager | 是否已經有存放 DB 帳密的 secret,格式是否包含 username 與 password |
| IAM Role | Proxy 需要一個可以讀取 secret 的 IAM Role |
| 驗證方式 | 應用程式要用 SQL Server 密碼驗證,還是 IAM 驗證連 Proxy |
| TLS | 應用程式端是否能啟用 TLS 連線,IAM 驗證強制要求 TLS |
| 引擎限制 | SQL Server workload 是否使用 MARS、暫存資料表、prepared statements 等容易造成 pinning 的功能 |
這裡要說聲抱歉, 前一篇帶大家建立 SQL Server 2022, 不過 SQL Server 2022 目前不在 RDS Proxy 支援列表中, 這部分我是選擇重建一台 SQL Server 2019。
網路架構會變成兩段:
1
應用程式 --( 1433 )--> RDS Proxy --( 1433 )--> RDS for SQL Server
所以 Security Group 也要拆成兩段思考:
- Proxy 的 Security Group:inbound 允許應用程式的 Security Group 連
1433。 - RDS 的 Security Group:inbound 允許 Proxy 的 Security Group 連
1433。
如果建好 Proxy 之後,應用程式仍然可以直連 RDS,連線治理就會破功。建議把 RDS 的 inbound 收斂到只剩 Proxy 的 Security Group。
方法一:使用 AWS Console GUI 建立
準備 Secrets Manager Secret
RDS Proxy 自己連資料庫時,不會使用應用程式傳進來的密碼,而是使用 Secrets Manager 中的 secret。所以第一步是確認 secret 已經存在。
如果在上一篇已經把 master user password 交給 RDS 管理,Secrets Manager 裡會有一組由 RDS 建立的 secret,可以直接拿來用。如果要讓應用程式使用非 master 的資料庫帳號,就要先在 SQL Server 中建立 login 與 user,再手動建立對應的 secret:
1
2
3
4
{
"username": "app_user",
"password": "<high-strength-password>"
}
一個 Proxy 可以掛多組 secret,每組 secret 對應一個可以透過 Proxy 連線的資料庫帳號。應用程式連 Proxy 時提供的帳號,必須能對到其中一組 secret。
Secret 內容至少要有
username和password兩個 key。如果是自己手動建立的 secret,建議直接選擇「Credentials for Amazon RDS database」類型,格式就不會出錯。
建立 IAM Policy 與 IAM Role
Proxy 需要一個 IAM Role 來讀取 secret。做法和前兩篇的 IAM Role 一樣:先建立 policy,再建立讓 rds.amazonaws.com assume 的 role。
Policy 至少需要 secretsmanager:GetSecretValue。如果 secret 使用自訂 KMS key 加密,還需要 kms:Decrypt:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "secretsmanager:GetSecretValue",
"Resource": [
"arn:aws:secretsmanager:<region>:<account-id>:secret:<secret-name>-*"
]
},
{
"Effect": "Allow",
"Action": "kms:Decrypt",
"Resource": "arn:aws:kms:<region>:<account-id>:key/<key-id>",
"Condition": {
"StringEquals": {
"kms:ViaService": "secretsmanager.<region>.amazonaws.com"
}
}
}
]
}
Trust policy 讓 rds.amazonaws.com 可以 assume 這個 role:
1
2
3
4
5
6
7
8
9
10
11
12
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "rds.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
和前兩篇一樣,正式環境建議加上 aws:SourceAccount 與 aws:SourceArn 收斂信任範圍。
在 Console 建立 Proxy 時,也可以讓精靈自動建立 IAM Role。示範環境用自動建立很方便,但正式環境建議自己管理 role 與 policy,權限邊界比較清楚,也方便放進 IaC。
建立 Proxy
進入 RDS Console,左側選單可以看到 Proxies 頁面。
按下建立後,主要設定如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
代理組態
> 引擎系列
>> Microsoft SQL Server
> 代理識別符
>> sqlserver-demo-proxy
> 閒置用戶端連線逾時
>> 30 分鐘(預設 30 分鐘,可依應用程式行為調整)
目標群組組態
> 資料庫
>> sqlserver-express-demo(前一篇建立的 DB instance)
> 連線池最大連線數
>> 100(Proxy 最多可使用資料庫 max connections 的百分比)
驗證
> Secrets Manager 秘密
>> 選擇剛剛準備好的 secret(可多選)
> IAM 角色
>> 選擇剛剛建立的 IAM Role
> 用戶端驗證類型
>> SQL Server 驗證
> IAM 身分驗證
>> 停用(稍後示範改成必要)
連線
> 子網路
>> 選擇至少兩個 AZ 的 Private Subnet
> VPC 安全群組
>> Proxy 專用的 Security Group
幾個設定值得多說明:
- 連線池最大連線數(
MaxConnectionsPercent):Proxy 可以使用資料庫最大連線數的百分比。如果同一台資料庫還有其他不走 Proxy 的連線來源,不要設 100。 - 閒置用戶端連線逾時(
IdleClientTimeout):應用程式端連線閒置多久後被 Proxy 中斷。要和應用程式的 connection pool idle 設定對齊,避免拿到已被切斷的連線。 - 連線借用逾時(
ConnectionBorrowTimeout):資料庫連線都被占用時,應用程式端請求最多等多久。
建立後等待 Proxy 狀態變成 Available,就可以在詳細頁面看到 Proxy endpoint。
建立完成後,先到 Proxy 詳細頁面的 Targets 區塊確認 target 狀態是
AVAILABLE。如果一直是unavailable,最常見的原因是 secret 的帳密和資料庫實際帳密不一致、IAM Role 讀不到 secret,或 Proxy 到 RDS 的 Security Group 沒開。
用戶端驗證方式
RDS Proxy 對「應用程式連到 Proxy」這一段提供兩種驗證方式。要注意的是,不論選哪一種,Proxy 連到資料庫那一段都是用 Secrets Manager 的 secret。
| 驗證方式 | 說明 | 適合場景 |
|---|---|---|
| SQL Server 密碼驗證 | 應用程式用資料庫帳密連 Proxy,Proxy 比對 secret 內容 | 既有應用程式無痛切換,只改連線字串的 host |
| IAM 驗證 | 應用程式用 IAM 身分產生短效 token,並透過 driver 支援的 access token 屬性連 Proxy,不需要知道資料庫密碼 | ECS、EKS、Lambda、EC2 等已有 IAM Role 的運算資源 |
這個設定對應 Proxy 的兩個欄位:
- 用戶端驗證類型(
ClientPasswordAuthType):SQL Server 引擎選擇SQL_SERVER_AUTHENTICATION。 - IAM 身分驗證(
IAMAuth):Disabled表示只用密碼驗證;Required表示強制所有連線都用 IAM token。
方式一:SQL Server 密碼驗證
這是預設也是最簡單的方式,步驟如下。
第一步,確認 Proxy 的 IAM 身分驗證設定為停用(Disabled)。
第二步,確認應用程式要使用的帳號有對應的 secret 掛在 Proxy 上。應用程式連線時使用的 username 與 password,必須和其中一組 secret 的內容一致。Proxy 收到連線後,會用這組帳密比對 secret,驗證通過後才從連線池借出資料庫連線。
第三步,把應用程式連線字串的 host 從 RDS endpoint 換成 Proxy endpoint:
1
2
3
4
Server / Host: <proxy-endpoint>
Port: 1433
User: app_user
Password: 與 secret 中相同的密碼
用 sqlcmd 測試:
1
sqlcmd -S "<proxy-endpoint>,1433" -U app_user -P '<password>' -Q "SELECT @@SERVERNAME;"
如果有正確連上,Proxy 中的 Monitoring 就會開始顯示數值。
這個方式的好處是應用程式幾乎不用改,只換 host。但密碼仍然存在應用程式設定中,密碼治理的問題只解決了一半:Proxy 到資料庫這段跟著 Secrets Manager 輪替,但應用程式到 Proxy 這段的密碼還是要自己同步。
如果 secret 有啟用自動輪替,密碼輪替後應用程式端的密碼也要跟著更新,否則會開始連線失敗。想徹底擺脫這個同步問題,就要改用 IAM 驗證。
方式二:IAM 驗證
IAM 驗證讓應用程式完全不需要知道資料庫密碼。應用程式用自己的 IAM 身分(EC2 instance profile、ECS task role、Lambda execution role 等)產生一組 15 分鐘有效的 token,再透過資料庫 driver 支援的 access token 屬性連 Proxy。
值得一提的是,RDS for SQL Server 本身不支援端到端 IAM 資料庫驗證。這裡的 IAM 驗證只發生在「應用程式到 Proxy」這一段;Proxy 到 SQL Server 仍然會使用 Secrets Manager 裡的帳密。
設定步驟如下。
第一步:修改 Proxy 的 IAM 身分驗證設定
到 Proxy 詳細頁面按下修改,把 IAM 身分驗證改成「必要」(Required)。
改成 Required 後,所有連線都必須使用 IAM token,原本的密碼驗證會失效。如果要漸進式切換,建議先在測試環境驗證完整流程。
第二步:授予應用程式 IAM 身分 rds-db:connect 權限
在應用程式使用的 IAM Role 上,加入允許連線這個 Proxy 的 policy:
1
2
3
4
5
6
7
8
9
10
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "rds-db:connect",
"Resource": "arn:aws:rds-db:<region>:<account-id>:dbuser:<proxy-resource-id>/app_user"
}
]
}
注意這裡的 ARN 格式:
- service 是
rds-db不是rds。 <proxy-resource-id>是 Proxy 的資源 ID,格式類似prx-0123456789abcdef0,可以在 Proxy 詳細頁面或用 CLI 查到,取 ARN 中 db-proxy: 後面的值:
1
2
3
aws rds describe-db-proxies \
--db-proxy-name sqlserver-demo-proxy \
--query "DBProxies[0].DBProxyArn"
- 最後的
app_user是資料庫帳號名稱。如果要允許多個帳號,可以列多個 resource;示範環境也可以先用*,但正式環境建議明確指定。
第三步:產生 IAM token 並連線
應用程式或測試機器上,使用 AWS CLI 產生 token。注意 hostname 要填 Proxy endpoint,不是 RDS endpoint:
1
2
3
4
5
aws rds generate-db-auth-token \
--hostname <proxy-endpoint> \
--port 1433 \
--username app_user \
--region <region>
輸出會是一長串 token。對 SQL Server 來說,連線時不要把 token 塞進一般 password 欄位,而是要使用 driver 提供的 token/access token 屬性;帳號仍然是 app_user。例如 JDBC 使用 accessToken,ODBC 使用 sql_copt_ss_access_token,.NET SqlClient 使用 AccessToken。
IAM 驗證強制要求 TLS,所以連線字串必須啟用加密。以 .NET 的 SqlConnection 為例,連線字串保留帳號與加密設定,token 另外放到 AccessToken:
1
2
3
4
5
6
var token = "<generate-db-auth-token 的輸出或 SDK 產生的 token>";
using var connection = new SqlConnection(
"Server=<proxy-endpoint>,1433;User ID=app_user;Encrypt=True;Database=my_app;");
connection.AccessToken = token;
await connection.OpenAsync();
也就是說,若 client 工具或 driver 沒有支援 SQL Server access token 屬性,就不能拿來測試這種 IAM 驗證模式。一般把 token 當成 -P 密碼傳入的做法,常會得到 login failed。
不同語言的產生 token 方式不一樣,但重點相同:hostname 要用 Proxy endpoint,port 要用 SQL Server 的
1433,username 要和 Proxy secret 裡的資料庫帳號一致。
第四步:處理 token 過期
token 有效期是 15 分鐘,但這是指「建立連線時」的驗證期限。已經建立的連線不會因為 token 過期而被切斷。所以應用程式要做的是:
- 每次建立新連線前產生新 token,不要把 token 當成靜態密碼快取太久。
- 如果使用 connection pool,確認 pool 建立新連線時會重新取得 token。多數 AWS SDK 或 wrapper library 都有對應的做法。
IAM 驗證的錯誤訊息常常只有 login failed,不會直接告訴你是 token 過期、
rds-db:connect權限不足,還是沒開 TLS。排查時建議依序確認:TLS 是否啟用、token 是否在 15 分鐘內產生、IAM policy 的 resource ARN 是否正確(特別是 proxy resource id 和 username)。
連不上 Proxy 時的排查順序
如果連 Proxy 失敗,建議照這個順序檢查:
- Proxy 狀態是否 Available,target 狀態是否
AVAILABLE。 - 應用程式到 Proxy 的 Security Group 是否允許
1433。 - Proxy 到 RDS 的 Security Group 是否允許
1433。 - Secret 的帳密是否和資料庫實際帳密一致(RDS 管理的 secret 輪替後要注意手動建立的副本沒跟上)。
- Proxy 的 IAM Role 是否能讀取 secret 與 KMS key。
- IAM 驗證模式下,TLS、token 有效期、
rds-db:connect權限是否正確。 - 是否從 VPC 外連線。Proxy endpoint 只能在 VPC 內解析與連線,不支援 publicly accessible。
方法二:使用 Terraform 建立
延續前一篇的 Terraform 範例,補上 RDS Proxy 相關資源。範例包含 secret、IAM role、proxy、target group 設定與 target 註冊:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
variable "db_app_username" {
type = string
default = "app_user"
}
variable "db_app_password" {
type = string
sensitive = true
}
resource "aws_secretsmanager_secret" "sqlserver_app_user" {
name = "rds/sqlserver-express-demo/app-user"
}
resource "aws_secretsmanager_secret_version" "sqlserver_app_user" {
secret_id = aws_secretsmanager_secret.sqlserver_app_user.id
secret_string = jsonencode({
username = var.db_app_username
password = var.db_app_password
})
}
resource "aws_security_group" "sqlserver_proxy" {
name = "sqlserver-proxy"
description = "Allow application access to RDS Proxy"
vpc_id = var.vpc_id
ingress {
description = "SQL Server from application"
from_port = 1433
to_port = 1433
protocol = "tcp"
security_groups = [var.app_security_group_id]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
# RDS 的 Security Group 要加上允許 Proxy 連入
resource "aws_security_group_rule" "sqlserver_from_proxy" {
type = "ingress"
from_port = 1433
to_port = 1433
protocol = "tcp"
security_group_id = aws_security_group.sqlserver.id
source_security_group_id = aws_security_group.sqlserver_proxy.id
description = "SQL Server from RDS Proxy"
}
resource "aws_iam_role" "sqlserver_proxy" {
name = "rds-proxy-sqlserver-demo"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Service = "rds.amazonaws.com"
}
Action = "sts:AssumeRole"
Condition = {
StringEquals = {
"aws:SourceAccount" = data.aws_caller_identity.current.account_id
}
}
}
]
})
}
resource "aws_iam_policy" "sqlserver_proxy_secrets" {
name = "rds-proxy-sqlserver-demo-secrets"
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = "secretsmanager:GetSecretValue"
Resource = aws_secretsmanager_secret.sqlserver_app_user.arn
}
]
})
}
resource "aws_iam_role_policy_attachment" "sqlserver_proxy_secrets" {
role = aws_iam_role.sqlserver_proxy.name
policy_arn = aws_iam_policy.sqlserver_proxy_secrets.arn
}
resource "aws_db_proxy" "sqlserver" {
name = "sqlserver-demo-proxy"
engine_family = "SQLSERVER"
role_arn = aws_iam_role.sqlserver_proxy.arn
vpc_subnet_ids = var.private_subnet_ids
vpc_security_group_ids = [aws_security_group.sqlserver_proxy.id]
idle_client_timeout = 1800
require_tls = true
auth {
auth_scheme = "SECRETS"
client_password_auth_type = "SQL_SERVER_AUTHENTICATION"
iam_auth = "DISABLED" # 改成 REQUIRED 即強制 IAM 驗證
secret_arn = aws_secretsmanager_secret.sqlserver_app_user.arn
}
tags = {
Name = "sqlserver-demo-proxy"
}
}
resource "aws_db_proxy_default_target_group" "sqlserver" {
db_proxy_name = aws_db_proxy.sqlserver.name
connection_pool_config {
max_connections_percent = 100
max_idle_connections_percent = 50
connection_borrow_timeout = 120
}
}
resource "aws_db_proxy_target" "sqlserver" {
db_proxy_name = aws_db_proxy.sqlserver.name
target_group_name = aws_db_proxy_default_target_group.sqlserver.name
db_instance_identifier = aws_db_instance.sqlserver.identifier
}
output "proxy_endpoint" {
value = aws_db_proxy.sqlserver.endpoint
}
正式環境使用時至少要再調整:
- 密碼不要透過變數明文傳入,建議由 Secrets Manager 產生或使用輪替機制。
- 如果切換到 IAM 驗證,把
iam_auth改成REQUIRED,並幫應用程式 IAM Role 加上rds-db:connect。 max_connections_percent要考慮是否還有其他不走 Proxy 的連線來源。require_tls = true建議保留。IAM 驗證強制要求 TLS,密碼驗證也建議加密傳輸。
Pinning:連線池化不是萬靈丹
RDS Proxy 的效益主要來自 multiplexing:多個應用程式連線共用少量資料庫連線。但某些操作會改變連線的 session 狀態,讓這條資料庫連線無法安全地共用。這時 Proxy 會把應用程式連線「釘」在這條資料庫連線上,直到連線結束,這個行為叫做 pinning。
被 pinning 的連線仍然可以正常使用,但會失去連線共用的效益。如果大部分連線都被 pinning,Proxy 就退化成一個單純的轉發層,錢照付但效益大打折扣。
SQL Server 引擎常見觸發 pinning 的操作包含使用 MARS、DTC、暫存資料表(temporary table)、transactions、cursors、prepared statements,以及部分 SET 陳述式。可以透過 CloudWatch 的 DatabaseConnectionsCurrentlySessionPinned 指標觀察 pinning 的比例。
導入 Proxy 後,建議實際觀察 pinning 指標一段時間。如果 pinning 比例很高,先回頭檢視應用程式是否大量使用觸發 pinning 的語法,評估能否調整,再決定 Proxy 是否值得留下。
RDS Proxy for SQL Server 的限制
導入前要知道的限制:
- Proxy 必須和 RDS 在同一個 VPC,且不支援 public access,應用程式必須在 VPC 內或透過 VPN、Peering、Transit Gateway 連入。
- 不支援 Windows Authentication,用戶端驗證只有 SQL Server 驗證與 IAM 驗證。
- 使用 MARS(Multiple Active Result Sets)會造成 session pinning,且 Proxy 不會執行 initialization queries。連線字串有啟用
MultipleActiveResultSets=True的應用程式,要先評估 Proxy 的效益是否會被 pinning 抵消。 - 每個 Proxy 只能對應一個 target 資料庫(instance 或 cluster)。
- Proxy 是計費服務,依目標資料庫的 vCPU 數計費,且有最低計費 vCPU 數。
建立完成後的檢查清單
- Proxy 與 target 狀態皆為 Available /
AVAILABLE。 - 應用程式已改連 Proxy endpoint,且能正常查詢。
- RDS 的 Security Group 已收斂到只允許 Proxy 連入。
- 選定的驗證方式已實測:密碼驗證確認 secret 同步策略,IAM 驗證確認 token 更新機制。
require_tls已啟用,應用程式連線字串已啟用加密。- CloudWatch 已觀察
DatabaseConnections、ClientConnections、DatabaseConnectionsCurrentlySessionPinned等指標。 - 做過一次 failover 演練,確認應用程式在 failover 期間的行為符合預期。
- Secrets 輪替後,Proxy 與應用程式的連線行為已驗證。
結語
到這一篇為止,這個系列把 RDS for SQL Server 從「建得起來」一路走到「可以維運」:
- 第一篇解決的是平台:網路、版本、儲存、備份與還原。
- 第二篇解決的是治理:稽核紀錄與密碼輪替。
- 這一篇解決的是連線:連線池化、failover 中斷時間,以及讓應用程式可以用 IAM 身分連資料庫。
RDS Proxy 不是必需品,它是一個用成本換取連線治理能力的選項。如果系統屬於連線行為單純的傳統架構,可能用不到;但如果是 serverless、頻繁擴縮或對 failover 中斷敏感的系統,RDS Proxy 通常能用相對少的改動,換到明顯的穩定性提升。
導入之後記得回頭看指標,尤其是 pinning 比例。Proxy 的價值要用數據驗證,而不是裝了就當作有效。




