DestinationRuleによる流量制限の選択肢と挙動

OpenShift Service Mesh（Istio）では、DestinationRuleで流量制限（Rate Limit）をかけることが可能です。ただし[ドキュメント]("https://istio.io/latest/docs/reference/config/networking/destination-rule/#ConnectionPoolSettings-HTTPSettings")からは設定時の挙動が不明のため、実機で確認しました。

# 概要
OpenShift v4.11(Service Mesh v2.4)上で稼働するサンプルアプリへのリクエストに対して流量制限を設定し、挙動を確認します。

サンプルアプリには[Bookinfo]("https://istio.io/latest/docs/examples/bookinfo/")を使用します。
デフォルトの状態だとレスポンスが速すぎるので、VirtualServiceで0.1sのdelayを仕込みます。
``` bookinfo.yaml
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
  name: bookinfo
  namespace: bookinfo
spec:
  gateways:
  - bookinfo-gateway
  hosts:
  - '*'
  http:
  - fault:
      delay:
        fixedDelay: 0.1s
        percentage:
          value: 100
    match:
    - uri:
        exact: /productpage
    - uri:
        prefix: /static
    - uri:
        exact: /login
    - uri:
        exact: /logout
    - uri:
        prefix: /api/v1/products
    route:
    - destination:
        host: productpage
        port:
          number: 9080

$ curl -o /dev/null -s -w "Total time: %{time_total}\n" http://istio-ingressgateway-istio-system.hogehoge-0000.jp-tok.containers.appdomain.cloud/productpage
Total time: 0.161840
```

制限値はDestinationRuleのspec.trafficPolicy.connectionPoolにて定義します。
パラメーターについては[こちら]("https://istio.io/latest/docs/reference/config/networking/destination-rule/#ConnectionPoolSettings")を参照。
以下の例ではTCPの最大接続数を10に制限しています。

``` destinationrule.yaml
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: ratelimit-test
spec:
  host: productpage
  trafficPolicy:
    connectionPool:
      tcp:
        maxConnections: 10
```

確認方法は簡易的ですが、以下の方法で実質同時にリクエストを投げます。
今回の基準値としてはレスポンス0.1~.0.2s程度となります。
```
$ for i in $(seq 1 10);do curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n" "http://istio-ingressgateway-istio-system.hogehoge-0000.jp-tok.containers.appdomain.cloud/productpage" & done; wait
Total time: 0.161840
```

# 各パラメーターの挙動
### maxConnections
最大TCP接続数。
→遅延(Pending)して200で返る。

maxConnections=1として10 Requests投げた場合
```
$ for i in $(seq 1 10);do curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n" "http://istio-ingressgateway-istio-system.hogehoge-0000.jp-tok.containers.appdomain.cloud/productpage" & done; wait
[2] 6373
[3] 6374
[4] 6375
[5] 6376
[6] 6377
[7] 6378
[8] 6379
[9] 6380
[10] 6381
[11] 6382
Http code: 200
Total time: 0.270856
[5]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.283489
[4]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.310339
[10]  - done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.320702
[2]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.346446
[7]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.365771
[11]  + done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.378823
[6]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.448821
[8]  - done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.506957
[9]  + done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.569382
[3]  + done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
```

### http1MaxPendingRequests
待機中キューに入れられるリクエスト数。
→設定値まではPendingになり、それを超えると503で返る。

http1MaxPendingRequests=10として20 Requests投げた場合
```
$ for i in $(seq 1 20);do curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n" "http://istio-ingressgateway-istio-system.hogehoge-0000.jp-tok.containers.appdomain.cloud/productpage" & done; wait
[2] 41973
[3] 41974
[4] 41975
[5] 41976
[6] 41977
[7] 41978
[8] 41979
[9] 41980
[10] 41981
[11] 41982
[12] 41983
[13] 41984
[14] 41985
[15] 41986
[16] 41987
[17] 41988
[18] 41989
[19] 41990
[20] 41991
[21] 41992
Http code: 200
Http code: 200
Total time: 0.461744
Total time: 0.464854
[12]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[6]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.477002
[2]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.481093
[5]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.489774
Http code: 200
Total time: 0.486956
Http code: 200
Total time: 0.474765
[4]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[9]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[16]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.490604
[10]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.473540
[19]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.486656
Http code: 200
Total time: 0.478652
[20]  - done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[14]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.501610
[8]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.506574
Http code: 200
Total time: 0.494267
[13]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[11]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.499243
Http code: 200
Total time: 0.522008
[18]  - done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[7]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.496920
[21]  + done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.503095
[17]  + done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.528862
[3]  - done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.511697
[15]  + done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
```
http1MaxPendingRequests=5として50 Requests投げた場合
```
$ for i in $(seq 1 50);do curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n" "http://istio-ingressgateway-istio-system.hogehoge-0000.jp-tok.containers.appdomain.cloud/productpage" & done; wait
[2] 42722
[3] 42723
[4] 42724
[5] 42725
[6] 42726
[7] 42727
[8] 42728
[9] 42729
[10] 42730
[11] 42731
[12] 42732
[13] 42733
[14] 42734
[15] 42735
[16] 42736
[17] 42737
[18] 42738
[19] 42739
[20] 42740
[21] 42741
[22] 42742
[23] 42743
[24] 42744
[25] 42745
[26] 42746
[27] 42747
[28] 42748
[29] 42749
[30] 42750
[31] 42751
[32] 42752
[33] 42753
[34] 42754
[35] 42755
[36] 42756
[37] 42757
[38] 42758
[39] 42759
[40] 42760
[41] 42761
[42] 42762
[43] 42763
[44] 42764
[45] 42765
[46] 42766
[47] 42767
[48] 42768
[49] 42769
[50] 42771
[51] 42772
Http code: 503
Total time: 0.191752
[31]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 503
Total time: 0.197707
[29]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 503
Total time: 0.298043
Http code: 503
Total time: 0.247466
Http code: 503
Total time: 0.201982
Http code: 503
Total time: 0.270401
Http code: 503
Total time: 0.283178
Http code: 503
Total time: 0.195745
Http code: 503
Total time: 0.198069
[23]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 503
Total time: 0.212651
Http code: 503
Total time: 0.212809
[48]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[26]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[10]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[14]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[42]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[19]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[46]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[39]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 503
Total time: 0.269464
[34]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 503
Total time: 0.271426
Http code: 503
Total time: 0.254064
Http code: 503
Http code: 503
Http code: 503
Total time: 0.286528
Total time: 0.277632
Total time: 0.204137
Http code: 503
Total time: 0.308243
Http code: 503
Total time: 0.205150
Http code: 503
Total time: 0.249282
Http code: 503
Total time: 0.298848
[40]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[21]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 503
Total time: 0.248523
[50]  - done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[33]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[18]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[22]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[13]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[44]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[38]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[43]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.399581
[11]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.416194
[6]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.418183
[32]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.482085
[9]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.456171
[16]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.481529
Http code: 200
Total time: 0.429431
[12]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[37]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.415324
[47]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.527018
[2]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.496417
Http code: 200
Total time: 0.530515
[20]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[3]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.536656
[8]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.539672
[7]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.482023
[24]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.437686
Http code: 200
Total time: 0.544999
Http code: 200
Total time: 0.480340
Http code: 200
Total time: 0.525193
[49]  - done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[35]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[5]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[15]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.489112
[25]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.555837
Http code: 200
Total time: 0.538254
Http code: 200
Total time: 0.452517
[4]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[17]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[28]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.449557
[51]  + done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.462055
[27]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.460945
Http code: 200
Total time: 0.532343
[36]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[30]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.505733
[41]  - done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.501190
[45]  + done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
```

### http2MaxRequests
同時リクエスト最大数。
→設定値を超えると即503で返る。

http2MaxRequests=5として50 Requests投げた場合
```
$ for i in $(seq 1 20);do curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n" "http://istio-ingressgateway-istio-system.hogehoge-0000.jp-tok.containers.appdomain.cloud/productpage" & done; wait
[2] 7312
[3] 7313
[4] 7314
[5] 7315
[6] 7316
[7] 7317
[8] 7318
[9] 7319
[10] 7320
[11] 7321
[12] 7322
[13] 7323
[14] 7324
[15] 7325
[16] 7326
[17] 7327
[18] 7328
[19] 7329
[20] 7330
[21] 7331
Http code: 200
Total time: 0.170358
[2]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 503
Total time: 0.147272
Http code: 503
Total time: 0.146497
[21]  + done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[18]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 503
Total time: 0.152906
Http code: 503
Total time: 0.147664
Http code: 503
Total time: 0.169567
[14]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[12]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[15]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 503
Total time: 0.151737
Http code: 503
Total time: 0.159501
Http code: 503
Total time: 0.153017
[16]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[11]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
[19]  - done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 503
Total time: 0.153867
[20]  + done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.206241
[3]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.195978
[6]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.204680
[10]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.216323
[5]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.226719
[8]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.244436
[4]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.217183
[13]  - done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.252870
[7]    done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.232748
[17]  + done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
Http code: 200
Total time: 0.263315
[9]  + done       curl -o /dev/null -s -w "Http code: %{http_code}\nTotal time: %{time_total}\n
```

# 補足

- 各パラメーターを組み合わせるとまた挙動が変わると思われるが未確認

- Envoy Filterを使えばより細かな制御が可能だが、こちらは現状Red Hatのサポート対象外（https://access.redhat.com/articles/6972785）