anycable 0.5.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.rubocop.yml +6 -0
- data/.travis.yml +4 -4
- data/CHANGELOG.md +7 -1
- data/Gemfile +0 -2
- data/README.md +25 -2
- data/anycable.gemspec +1 -1
- data/benchmarks/2017-02-12.md +54 -57
- data/benchmarks/2018-03-04.md +192 -0
- data/benchmarks/2018-05-27-rpc-bench.md +57 -0
- data/benchmarks/HowTo.md +1 -1
- data/benchmarks/benchmark.yml +35 -8
- data/benchmarks/hosts +2 -2
- data/benchmarks/servers.yml +11 -4
- data/etc/bug_report_template.rb +76 -0
- data/lib/anycable.rb +2 -1
- data/lib/anycable/rpc_handler.rb +4 -4
- data/lib/anycable/server.rb +1 -0
- data/lib/anycable/version.rb +1 -1
- metadata +10 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 190929557d66d3cb49e7dee5e8a87f841f8e6a248df55673faab9b09d4027d81
|
|
4
|
+
data.tar.gz: 0b703c1626163f1175664aeae26110214fdd3d819633291f390ec2401e985dee
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 17f2e03a750e60a1bc3f9022212cc7009c3ecf825bacf37552ceadbf1e195421281d5d9509495c8dfd1805948061c6f29406299e8cc51f9a1b4924549173bf30
|
|
7
|
+
data.tar.gz: 10032b73f09581d3bb9d9ebf844765d28fb5de1d80e970ea1ead176c67cf1c35fa93d9cd9f1d8f4f7d251ba92c03a9226b7ade4e6c9c83ed990364b3023153db
|
data/.rubocop.yml
CHANGED
|
@@ -22,6 +22,9 @@ AllCops:
|
|
|
22
22
|
Naming/AccessorMethodName:
|
|
23
23
|
Enabled: false
|
|
24
24
|
|
|
25
|
+
Naming/UncommunicativeMethodParamName:
|
|
26
|
+
Enabled: false
|
|
27
|
+
|
|
25
28
|
Style/PercentLiteralDelimiters:
|
|
26
29
|
Enabled: false
|
|
27
30
|
|
|
@@ -45,6 +48,9 @@ Style/BlockDelimiters:
|
|
|
45
48
|
Lint/AmbiguousRegexpLiteral:
|
|
46
49
|
Enabled: false
|
|
47
50
|
|
|
51
|
+
Lint/MissingCopEnableDirective:
|
|
52
|
+
Enabled: false
|
|
53
|
+
|
|
48
54
|
Metrics/MethodLength:
|
|
49
55
|
Exclude:
|
|
50
56
|
- 'spec/**/*.rb'
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
# Change log
|
|
2
2
|
|
|
3
|
-
##
|
|
3
|
+
## master
|
|
4
|
+
|
|
5
|
+
## 0.5.1 (2018-06-13)
|
|
6
|
+
|
|
7
|
+
Minor fixes.
|
|
8
|
+
|
|
9
|
+
## 0.5.0 (2017-10-21)
|
|
4
10
|
|
|
5
11
|
- [#2](https://github.com/anycable/anycable/issues/2) Add support for [Redis Sentinel](https://redis.io/topics/sentinel). ([@accessd](https://github.com/accessd))
|
|
6
12
|
|
data/Gemfile
CHANGED
data/README.md
CHANGED
|
@@ -16,9 +16,21 @@ Rails plug-n-play integration has been extracted to [anycable-rails](https://git
|
|
|
16
16
|
|
|
17
17
|
## Requirements
|
|
18
18
|
|
|
19
|
-
- Ruby
|
|
19
|
+
- Ruby >= 2.3, <= 2.5
|
|
20
20
|
- Redis (for brodcasting, [discuss other options](https://github.com/anycable/anycable/issues/2) with us!)
|
|
21
21
|
|
|
22
|
+
Or you can try to [build it from source](https://github.com/grpc/grpc/blob/master/INSTALL.md#build-from-source).
|
|
23
|
+
|
|
24
|
+
For MacOS there is also [the same problem](https://github.com/google/protobuf/issues/4098) with `google-protobuf` that can be solved
|
|
25
|
+
the following way:
|
|
26
|
+
|
|
27
|
+
```ruby
|
|
28
|
+
# Gemfile
|
|
29
|
+
git 'https://github.com/google/protobuf' do
|
|
30
|
+
gem 'google-protobuf'
|
|
31
|
+
end
|
|
32
|
+
```
|
|
33
|
+
|
|
22
34
|
## How It Works?
|
|
23
35
|
|
|
24
36
|

|
|
@@ -29,7 +41,15 @@ Read our [Wiki](https://github.com/anycable/anycable/wiki) for more.
|
|
|
29
41
|
|
|
30
42
|
- [AnyCable: Action Cable on steroids!](https://evilmartians.com/chronicles/anycable-actioncable-on-steroids)
|
|
31
43
|
|
|
32
|
-
- [Connecting LiteCable to Hanami](http://gabrielmalakias.com.br/ruby/hanami/iot/2017/05/26/websockets-connecting-litecable-to-hanami.html)
|
|
44
|
+
- [Connecting LiteCable to Hanami](http://gabrielmalakias.com.br/ruby/hanami/iot/2017/05/26/websockets-connecting-litecable-to-hanami.html) by [@GabrielMalakias](https://github.com/GabrielMalakias)
|
|
45
|
+
|
|
46
|
+
- [From Action to Any](https://medium.com/@leshchuk/from-action-to-any-1e8d863dd4cf) by [@alekseyl](https://github.com/alekseyl)
|
|
47
|
+
|
|
48
|
+
## Talks
|
|
49
|
+
|
|
50
|
+
- Wroc_Love.rb 2018 [slides](https://speakerdeck.com/palkan/wroc-love-dot-rb-2018-cables-cables-cables) and [video](https://www.youtube.com/watch?v=AUxFFOehiy0) (EN)
|
|
51
|
+
|
|
52
|
+
- RubyConfMY 2017 [slides](https://speakerdeck.com/palkan/rubyconf-malaysia-2017-anycable) and [video](https://www.youtube.com/watch?v=j5oFx525zNw) (EN)
|
|
33
53
|
|
|
34
54
|
- RailsClub Moscow 2016 [slides](https://speakerdeck.com/palkan/railsclub-moscow-2016-anycable) and [video](https://www.youtube.com/watch?v=-k7GQKuBevY&list=PLiWUIs1hSNeOXZhotgDX7Y7qBsr24cu7o&index=4) (RU)
|
|
35
55
|
|
|
@@ -71,6 +91,7 @@ Performing Channel Actions | +
|
|
|
71
91
|
Streaming | +
|
|
72
92
|
[Custom stream callbacks](http://edgeapi.rubyonrails.org/classes/ActionCable/Channel/Streams.html) | -
|
|
73
93
|
Broadcasting | +
|
|
94
|
+
Custom pubsub adapter | Only redis
|
|
74
95
|
|
|
75
96
|
## Build
|
|
76
97
|
|
|
@@ -91,5 +112,7 @@ make
|
|
|
91
112
|
|
|
92
113
|
Bug reports and pull requests are welcome on GitHub at https://github.com/anycable/anycable.
|
|
93
114
|
|
|
115
|
+
Please, provide reproduction script (using [this template](https://github.com/anycable/anycable/blob/master/etc/bug_report_template.rb)) when submitting bugs if possible.
|
|
116
|
+
|
|
94
117
|
## License
|
|
95
118
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
data/anycable.gemspec
CHANGED
|
@@ -26,7 +26,7 @@ Gem::Specification.new do |spec|
|
|
|
26
26
|
spec.add_development_dependency "rake", ">= 10.0"
|
|
27
27
|
spec.add_development_dependency "rack", "~> 2.0"
|
|
28
28
|
spec.add_development_dependency "rspec", ">= 3.5"
|
|
29
|
-
spec.add_development_dependency "rubocop", "
|
|
29
|
+
spec.add_development_dependency "rubocop", "~> 0.57.1"
|
|
30
30
|
spec.add_development_dependency "simplecov", ">= 0.3.8"
|
|
31
31
|
spec.add_development_dependency "pry-byebug"
|
|
32
32
|
end
|
data/benchmarks/2017-02-12.md
CHANGED
|
@@ -3,17 +3,18 @@
|
|
|
3
3
|
Code: https://github.com/palkan/websocket-shootout
|
|
4
4
|
Client/Server instances: c3.4xlarge (16 vCPU, 30 GiB RAM).
|
|
5
5
|
|
|
6
|
+
Ruby: 2.3.4
|
|
7
|
+
Rails: 5.1.0
|
|
8
|
+
|
|
6
9
|
The benchmark measures broadcasting RTT for 10k clients.
|
|
7
10
|
|
|
8
|
-
**NOTE**: memory
|
|
11
|
+
**NOTE**: memory and CPU usage was measured by looking at `htop` output.
|
|
9
12
|
|
|
10
13
|
## Action Cable (8 workers)
|
|
11
14
|
|
|
12
15
|
```
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
00 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:333
|
|
16
|
-
4/cable --server-type=actioncable
|
|
16
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/cable --server-type=actioncable
|
|
17
|
+
|
|
17
18
|
clients: 1000 95per-rtt: 700ms min-rtt: 2ms median-rtt: 264ms max-rtt: 854ms
|
|
18
19
|
clients: 2000 95per-rtt: 1155ms min-rtt: 1ms median-rtt: 490ms max-rtt: 1358ms
|
|
19
20
|
clients: 3000 95per-rtt: 1584ms min-rtt: 1ms median-rtt: 769ms max-rtt: 1644ms
|
|
@@ -24,7 +25,8 @@ clients: 7000 95per-rtt: 3907ms min-rtt: 1ms median-rtt: 1734ms m
|
|
|
24
25
|
clients: 8000 95per-rtt: 4479ms min-rtt: 1ms median-rtt: 2137ms max-rtt: 5469ms
|
|
25
26
|
clients: 9000 95per-rtt: 5734ms min-rtt: 1ms median-rtt: 2356ms max-rtt: 8234ms
|
|
26
27
|
clients: 10000 95per-rtt: 5292ms min-rtt: 1ms median-rtt: 2784ms max-rtt: 6454ms
|
|
27
|
-
|
|
28
|
+
|
|
29
|
+
Missing received broadcasts: expected 6600000, got 6572168
|
|
28
30
|
```
|
|
29
31
|
|
|
30
32
|
CPU: ~70%
|
|
@@ -34,10 +36,8 @@ MEM: ~ 4 GiB
|
|
|
34
36
|
## Action Cable (16 workers)
|
|
35
37
|
|
|
36
38
|
```
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
00 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:333
|
|
40
|
-
4/cable --server-type=actioncable
|
|
39
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/cable --server-type=actioncable
|
|
40
|
+
|
|
41
41
|
clients: 1000 95per-rtt: 575ms min-rtt: 1ms median-rtt: 115ms max-rtt: 846ms
|
|
42
42
|
clients: 2000 95per-rtt: 1144ms min-rtt: 1ms median-rtt: 250ms max-rtt: 1457ms
|
|
43
43
|
clients: 3000 95per-rtt: 1274ms min-rtt: 1ms median-rtt: 439ms max-rtt: 1673ms
|
|
@@ -48,7 +48,8 @@ clients: 7000 95per-rtt: 3033ms min-rtt: 1ms median-rtt: 1008ms m
|
|
|
48
48
|
clients: 8000 95per-rtt: 3275ms min-rtt: 1ms median-rtt: 1160ms max-rtt: 4268ms
|
|
49
49
|
clients: 9000 95per-rtt: 4406ms min-rtt: 1ms median-rtt: 1342ms max-rtt: 5018ms
|
|
50
50
|
clients: 10000 95per-rtt: 5414ms min-rtt: 1ms median-rtt: 1504ms max-rtt: 7039ms
|
|
51
|
-
|
|
51
|
+
|
|
52
|
+
Missing received broadcasts: expected 6600000, got 6589644
|
|
52
53
|
```
|
|
53
54
|
|
|
54
55
|
CPU: ~80-100%
|
|
@@ -60,10 +61,8 @@ MEM: ~ 5 GiB
|
|
|
60
61
|
About patch: https://github.com/rails/rails/issues/26999
|
|
61
62
|
|
|
62
63
|
```
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
ad-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/cable --serve
|
|
66
|
-
r-type=actioncable
|
|
64
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/cable --server-type=actioncable
|
|
65
|
+
|
|
67
66
|
clients: 1000 95per-rtt: 161ms min-rtt: 1ms median-rtt: 44ms max-rtt: 236ms
|
|
68
67
|
clients: 2000 95per-rtt: 292ms min-rtt: 1ms median-rtt: 43ms max-rtt: 389ms
|
|
69
68
|
clients: 3000 95per-rtt: 359ms min-rtt: 1ms median-rtt: 96ms max-rtt: 556ms
|
|
@@ -74,7 +73,8 @@ clients: 7000 95per-rtt: 717ms min-rtt: 1ms median-rtt: 95ms max
|
|
|
74
73
|
clients: 8000 95per-rtt: 679ms min-rtt: 1ms median-rtt: 19ms max-rtt: 1089ms
|
|
75
74
|
clients: 9000 95per-rtt: 561ms min-rtt: 1ms median-rtt: 25ms max-rtt: 938ms
|
|
76
75
|
clients: 10000 95per-rtt: 1038ms min-rtt: 1ms median-rtt: 59ms max-rtt: 2197ms
|
|
77
|
-
|
|
76
|
+
|
|
77
|
+
Missing received broadcasts: expected 6600000, got 5649743
|
|
78
78
|
```
|
|
79
79
|
|
|
80
80
|
CPU: ~70%
|
|
@@ -84,10 +84,8 @@ MEM: ~ 4 GiB
|
|
|
84
84
|
## ActionCable / Patched (16 workers)
|
|
85
85
|
|
|
86
86
|
```
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
ad-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/cable --serve
|
|
90
|
-
r-type=actioncable
|
|
87
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/cable --server-type=actioncable
|
|
88
|
+
|
|
91
89
|
clients: 1000 95per-rtt: 228ms min-rtt: 1ms median-rtt: 53ms max-rtt: 425ms
|
|
92
90
|
clients: 2000 95per-rtt: 277ms min-rtt: 1ms median-rtt: 63ms max-rtt: 407ms
|
|
93
91
|
clients: 3000 95per-rtt: 349ms min-rtt: 1ms median-rtt: 28ms max-rtt: 640ms
|
|
@@ -98,7 +96,8 @@ clients: 7000 95per-rtt: 466ms min-rtt: 1ms median-rtt: 90ms max
|
|
|
98
96
|
clients: 8000 95per-rtt: 530ms min-rtt: 1ms median-rtt: 26ms max-rtt: 1225ms
|
|
99
97
|
clients: 9000 95per-rtt: 459ms min-rtt: 1ms median-rtt: 39ms max-rtt: 622ms
|
|
100
98
|
clients: 10000 95per-rtt: 477ms min-rtt: 1ms median-rtt: 71ms max-rtt: 632ms
|
|
101
|
-
|
|
99
|
+
|
|
100
|
+
Missing received broadcasts: expected 6600000, got 5662008
|
|
102
101
|
```
|
|
103
102
|
|
|
104
103
|
CPU: ~80-100%
|
|
@@ -108,10 +107,8 @@ MEM: ~ 5 GiB
|
|
|
108
107
|
## Action Cable / AnyCable-Go
|
|
109
108
|
|
|
110
109
|
```
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
ad-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/cable --serve
|
|
114
|
-
r-type=actioncable
|
|
110
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/cable --server-type=actioncable
|
|
111
|
+
|
|
115
112
|
clients: 1000 95per-rtt: 172ms min-rtt: 2ms median-rtt: 9ms max-rtt: 220ms
|
|
116
113
|
clients: 2000 95per-rtt: 228ms min-rtt: 2ms median-rtt: 16ms max-rtt: 498ms
|
|
117
114
|
clients: 3000 95per-rtt: 367ms min-rtt: 2ms median-rtt: 14ms max-rtt: 798ms
|
|
@@ -122,7 +119,8 @@ clients: 7000 95per-rtt: 813ms min-rtt: 2ms median-rtt: 40ms max
|
|
|
122
119
|
clients: 8000 95per-rtt: 657ms min-rtt: 2ms median-rtt: 39ms max-rtt: 2457ms
|
|
123
120
|
clients: 9000 95per-rtt: 792ms min-rtt: 2ms median-rtt: 117ms max-rtt: 1557ms
|
|
124
121
|
clients: 10000 95per-rtt: 727ms min-rtt: 2ms median-rtt: 66ms max-rtt: 3391ms
|
|
125
|
-
|
|
122
|
+
|
|
123
|
+
Missing received broadcasts: expected 6600000, got 6588881
|
|
126
124
|
```
|
|
127
125
|
|
|
128
126
|
CPU: 15-25%
|
|
@@ -132,9 +130,8 @@ MEM: ~500 MiB
|
|
|
132
130
|
## JavaScript / uWS (clustered)
|
|
133
131
|
|
|
134
132
|
```
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
ad-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334
|
|
133
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334
|
|
134
|
+
|
|
138
135
|
clients: 1000 95per-rtt: 207ms min-rtt: 0ms median-rtt: 8ms max-rtt: 611ms
|
|
139
136
|
clients: 2000 95per-rtt: 393ms min-rtt: 2ms median-rtt: 20ms max-rtt: 750ms
|
|
140
137
|
clients: 3000 95per-rtt: 425ms min-rtt: 4ms median-rtt: 25ms max-rtt: 1196ms
|
|
@@ -145,7 +142,8 @@ clients: 7000 95per-rtt: 635ms min-rtt: 6ms median-rtt: 37ms max
|
|
|
145
142
|
clients: 8000 95per-rtt: 782ms min-rtt: 5ms median-rtt: 142ms max-rtt: 1439ms
|
|
146
143
|
clients: 9000 95per-rtt: 610ms min-rtt: 7ms median-rtt: 72ms max-rtt: 1552ms
|
|
147
144
|
clients: 10000 95per-rtt: 1216ms min-rtt: 7ms median-rtt: 91ms max-rtt: 2195ms
|
|
148
|
-
|
|
145
|
+
|
|
146
|
+
Missing received broadcasts: expected 6600000, got 6599571
|
|
149
147
|
```
|
|
150
148
|
|
|
151
149
|
CPU: 7-8%
|
|
@@ -155,9 +153,8 @@ MEM: ~400 MiB
|
|
|
155
153
|
## Go / WebSocket
|
|
156
154
|
|
|
157
155
|
```
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
ad-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/json
|
|
156
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/json
|
|
157
|
+
|
|
161
158
|
clients: 1000 95per-rtt: 27ms min-rtt: 7ms median-rtt: 16ms max-rtt: 44ms
|
|
162
159
|
clients: 2000 95per-rtt: 193ms min-rtt: 12ms median-rtt: 28ms max-rtt: 235ms
|
|
163
160
|
clients: 3000 95per-rtt: 231ms min-rtt: 15ms median-rtt: 35ms max-rtt: 433ms
|
|
@@ -168,7 +165,8 @@ clients: 7000 95per-rtt: 449ms min-rtt: 38ms median-rtt: 74ms max
|
|
|
168
165
|
clients: 8000 95per-rtt: 539ms min-rtt: 43ms median-rtt: 89ms max-rtt: 1351ms
|
|
169
166
|
clients: 9000 95per-rtt: 534ms min-rtt: 48ms median-rtt: 96ms max-rtt: 2978ms
|
|
170
167
|
clients: 10000 95per-rtt: 414ms min-rtt: 57ms median-rtt: 123ms max-rtt: 3424ms
|
|
171
|
-
|
|
168
|
+
|
|
169
|
+
Missing received broadcasts: expected 6600000, got 6593825
|
|
172
170
|
```
|
|
173
171
|
|
|
174
172
|
CPU: one core – ~80-100%, other cores – ~7-10%
|
|
@@ -178,9 +176,8 @@ MEM: ~400 MiB
|
|
|
178
176
|
## Erlang / Cowboy
|
|
179
177
|
|
|
180
178
|
```
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
ad-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/ws/cable
|
|
179
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/ws/cable
|
|
180
|
+
|
|
184
181
|
clients: 1000 95per-rtt: 204ms min-rtt: 2ms median-rtt: 11ms max-rtt: 585ms
|
|
185
182
|
clients: 2000 95per-rtt: 219ms min-rtt: 3ms median-rtt: 20ms max-rtt: 620ms
|
|
186
183
|
clients: 3000 95per-rtt: 348ms min-rtt: 6ms median-rtt: 19ms max-rtt: 1447ms
|
|
@@ -191,7 +188,8 @@ clients: 7000 95per-rtt: 542ms min-rtt: 13ms median-rtt: 76ms max
|
|
|
191
188
|
clients: 8000 95per-rtt: 737ms min-rtt: 16ms median-rtt: 57ms max-rtt: 1527ms
|
|
192
189
|
clients: 9000 95per-rtt: 634ms min-rtt: 17ms median-rtt: 74ms max-rtt: 1479ms
|
|
193
190
|
clients: 10000 95per-rtt: 792ms min-rtt: 17ms median-rtt: 79ms max-rtt: 3805ms
|
|
194
|
-
|
|
191
|
+
|
|
192
|
+
Missing received broadcasts: expected 6600000, got 6575292
|
|
195
193
|
```
|
|
196
194
|
|
|
197
195
|
cCPU: 20-30%
|
|
@@ -201,9 +199,8 @@ MEM: ~500 MiB
|
|
|
201
199
|
## Ruby / Plezi (1x8)
|
|
202
200
|
|
|
203
201
|
```
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
ad-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/
|
|
202
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/
|
|
203
|
+
|
|
207
204
|
clients: 1000 95per-rtt: 84ms min-rtt: 3ms median-rtt: 42ms max-rtt: 95ms
|
|
208
205
|
clients: 2000 95per-rtt: 211ms min-rtt: 4ms median-rtt: 60ms max-rtt: 318ms
|
|
209
206
|
clients: 3000 95per-rtt: 525ms min-rtt: 2ms median-rtt: 93ms max-rtt: 527ms
|
|
@@ -214,7 +211,8 @@ clients: 7000 95per-rtt: 1100ms min-rtt: 1ms median-rtt: 249ms ma
|
|
|
214
211
|
clients: 8000 95per-rtt: 1094ms min-rtt: 7ms median-rtt: 298ms max-rtt: 1134ms
|
|
215
212
|
clients: 9000 95per-rtt: 1265ms min-rtt: 1ms median-rtt: 342ms max-rtt: 1407ms
|
|
216
213
|
clients: 10000 95per-rtt: 1523ms min-rtt: 2ms median-rtt: 388ms max-rtt: 1555ms
|
|
217
|
-
|
|
214
|
+
|
|
215
|
+
Missing received broadcasts: expected 6600000, got 6599226
|
|
218
216
|
```
|
|
219
217
|
|
|
220
218
|
CPU: ~10-15% (only 1/2 of cores affected)
|
|
@@ -224,9 +222,8 @@ MEM: ~300 MiB
|
|
|
224
222
|
## Ruby / Plezi (8x8)
|
|
225
223
|
|
|
226
224
|
```
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
ad-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/
|
|
225
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/
|
|
226
|
+
|
|
230
227
|
clients: 1000 95per-rtt: 46ms min-rtt: 1ms median-rtt: 8ms max-rtt: 115ms
|
|
231
228
|
clients: 2000 95per-rtt: 152ms min-rtt: 1ms median-rtt: 17ms max-rtt: 241ms
|
|
232
229
|
clients: 3000 95per-rtt: 207ms min-rtt: 1ms median-rtt: 26ms max-rtt: 254ms
|
|
@@ -237,7 +234,8 @@ clients: 7000 95per-rtt: 210ms min-rtt: 1ms median-rtt: 59ms max
|
|
|
237
234
|
clients: 8000 95per-rtt: 498ms min-rtt: 2ms median-rtt: 58ms max-rtt: 749ms
|
|
238
235
|
clients: 9000 95per-rtt: 651ms min-rtt: 2ms median-rtt: 52ms max-rtt: 766ms
|
|
239
236
|
clients: 10000 95per-rtt: 796ms min-rtt: 1ms median-rtt: 90ms max-rtt: 800ms
|
|
240
|
-
|
|
237
|
+
|
|
238
|
+
Missing received broadcasts: expected 6600000, got 2736158
|
|
241
239
|
```
|
|
242
240
|
|
|
243
241
|
CPU: ~10%
|
|
@@ -253,9 +251,8 @@ EM shows great results but only for the first run (`em-websocket` bug?).
|
|
|
253
251
|
First run:
|
|
254
252
|
|
|
255
253
|
```
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
ad-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/
|
|
254
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/
|
|
255
|
+
|
|
259
256
|
clients: 1000 95per-rtt: 24ms min-rtt: 5ms median-rtt: 20ms max-rtt: 30ms
|
|
260
257
|
clients: 2000 95per-rtt: 61ms min-rtt: 13ms median-rtt: 42ms max-rtt: 73ms
|
|
261
258
|
clients: 3000 95per-rtt: 84ms min-rtt: 18ms median-rtt: 68ms max-rtt: 109ms
|
|
@@ -266,15 +263,15 @@ clients: 7000 95per-rtt: 308ms min-rtt: 43ms median-rtt: 190ms max
|
|
|
266
263
|
clients: 8000 95per-rtt: 383ms min-rtt: 52ms median-rtt: 218ms max-rtt: 458ms
|
|
267
264
|
clients: 9000 95per-rtt: 401ms min-rtt: 50ms median-rtt: 218ms max-rtt: 550ms
|
|
268
265
|
clients: 10000 95per-rtt: 429ms min-rtt: 60ms median-rtt: 246ms max-rtt: 530ms
|
|
269
|
-
|
|
266
|
+
|
|
267
|
+
Missing received broadcasts: expected 6600000, got 6599593
|
|
270
268
|
```
|
|
271
269
|
|
|
272
270
|
Second run:
|
|
273
271
|
|
|
274
272
|
```
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
ad-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/
|
|
273
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/
|
|
274
|
+
|
|
278
275
|
clients: 1000 95per-rtt: 246ms min-rtt: 47ms median-rtt: 197ms max-rtt: 287ms
|
|
279
276
|
clients: 2000 95per-rtt: 296ms min-rtt: 63ms median-rtt: 229ms max-rtt: 400ms
|
|
280
277
|
clients: 3000 95per-rtt: 325ms min-rtt: 184ms median-rtt: 261ms max-rtt: 335ms
|
|
@@ -290,9 +287,8 @@ clients: 10000 95per-rtt: 813ms min-rtt: 101ms median-rtt: 448ms max
|
|
|
290
287
|
Third run:
|
|
291
288
|
|
|
292
289
|
```
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
ad-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/
|
|
290
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/
|
|
291
|
+
|
|
296
292
|
clients: 1000 95per-rtt: 522ms min-rtt: 115ms median-rtt: 414ms max-rtt: 719ms
|
|
297
293
|
clients: 2000 95per-rtt: 558ms min-rtt: 119ms median-rtt: 444ms max-rtt: 763ms
|
|
298
294
|
clients: 3000 95per-rtt: 499ms min-rtt: 127ms median-rtt: 489ms max-rtt: 833ms
|
|
@@ -303,7 +299,8 @@ clients: 7000 95per-rtt: 960ms min-rtt: 130ms median-rtt: 571ms max
|
|
|
303
299
|
clients: 8000 95per-rtt: 1038ms min-rtt: 145ms median-rtt: 592ms max-rtt: 1179ms
|
|
304
300
|
clients: 9000 95per-rtt: 1110ms min-rtt: 140ms median-rtt: 625ms max-rtt: 1405ms
|
|
305
301
|
clients: 10000 95per-rtt: 1176ms min-rtt: 163ms median-rtt: 649ms max-rtt: 1633ms
|
|
306
|
-
|
|
302
|
+
|
|
303
|
+
Missing received broadcasts: expected 6600000, got 6599123
|
|
307
304
|
```
|
|
308
305
|
|
|
309
306
|
CPU: one core is totally f**ked up
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
# WebSocket Shootout Benchmark (2018-03-04)
|
|
2
|
+
|
|
3
|
+
Code: https://github.com/palkan/websocket-shootout
|
|
4
|
+
Client/Server instances: c3.2xlarge (8 vCPU, 15 GiB RAM).
|
|
5
|
+
|
|
6
|
+
Ruby: 2.5.0
|
|
7
|
+
Rails: 5.1.4
|
|
8
|
+
|
|
9
|
+
The benchmark measures broadcasting RTT for 10k clients.
|
|
10
|
+
|
|
11
|
+
**NOTE**: memory and peak CPU usage was measured by looking at `htop` output; avg CPU usage is a 1 minute LA.
|
|
12
|
+
|
|
13
|
+
## Action Cable (8 workers)
|
|
14
|
+
|
|
15
|
+
Command:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/cable --server-type=actioncable
|
|
19
|
+
|
|
20
|
+
clients: 1000 95per-rtt: 847ms min-rtt: 1ms median-rtt: 174ms max-rtt: 930ms
|
|
21
|
+
clients: 2000 95per-rtt: 1611ms min-rtt: 1ms median-rtt: 387ms max-rtt: 1768ms
|
|
22
|
+
clients: 3000 95per-rtt: 2107ms min-rtt: 1ms median-rtt: 644ms max-rtt: 2601ms
|
|
23
|
+
clients: 4000 95per-rtt: 2504ms min-rtt: 1ms median-rtt: 899ms max-rtt: 3118ms
|
|
24
|
+
clients: 5000 95per-rtt: 3452ms min-rtt: 1ms median-rtt: 1070ms max-rtt: 4487ms
|
|
25
|
+
clients: 6000 95per-rtt: 4044ms min-rtt: 1ms median-rtt: 1261ms max-rtt: 5018ms
|
|
26
|
+
clients: 7000 95per-rtt: 3207ms min-rtt: 1ms median-rtt: 1647ms max-rtt: 3958ms
|
|
27
|
+
clients: 8000 95per-rtt: 4115ms min-rtt: 1ms median-rtt: 1957ms max-rtt: 5059ms
|
|
28
|
+
clients: 9000 95per-rtt: 4306ms min-rtt: 1ms median-rtt: 2273ms max-rtt: 7160ms
|
|
29
|
+
clients: 10000 95per-rtt: 5147ms min-rtt: 1ms median-rtt: 2462ms max-rtt: 6734ms
|
|
30
|
+
|
|
31
|
+
Missing received broadcasts: expected 6600000, got 6554972
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
CPU (peak): ~100%
|
|
35
|
+
CPU (avg): ~30%
|
|
36
|
+
|
|
37
|
+
MEM: ~1.7 GiB
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
## AnyCable-Go 0.5.4
|
|
41
|
+
|
|
42
|
+
```
|
|
43
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/cable --server-type=actioncable
|
|
44
|
+
|
|
45
|
+
clients: 1000 95per-rtt: 61ms min-rtt: 2ms median-rtt: 18ms max-rtt: 178ms
|
|
46
|
+
clients: 2000 95per-rtt: 214ms min-rtt: 2ms median-rtt: 26ms max-rtt: 568ms
|
|
47
|
+
clients: 3000 95per-rtt: 275ms min-rtt: 2ms median-rtt: 32ms max-rtt: 645ms
|
|
48
|
+
clients: 4000 95per-rtt: 430ms min-rtt: 2ms median-rtt: 40ms max-rtt: 1463ms
|
|
49
|
+
clients: 5000 95per-rtt: 352ms min-rtt: 3ms median-rtt: 61ms max-rtt: 1017ms
|
|
50
|
+
clients: 6000 95per-rtt: 619ms min-rtt: 3ms median-rtt: 60ms max-rtt: 1630ms
|
|
51
|
+
clients: 7000 95per-rtt: 623ms min-rtt: 2ms median-rtt: 74ms max-rtt: 3099ms
|
|
52
|
+
clients: 8000 95per-rtt: 846ms min-rtt: 2ms median-rtt: 89ms max-rtt: 3165ms
|
|
53
|
+
clients: 9000 95per-rtt: 642ms min-rtt: 2ms median-rtt: 110ms max-rtt: 981ms
|
|
54
|
+
clients: 10000 95per-rtt: 1019ms min-rtt: 2ms median-rtt: 114ms max-rtt: 4759ms
|
|
55
|
+
|
|
56
|
+
Missing received broadcasts: expected 6600000, got 6580959
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
CPU (peak): ~40%
|
|
60
|
+
CPU (avg): ~3%
|
|
61
|
+
|
|
62
|
+
MEM: ~500 MiB
|
|
63
|
+
|
|
64
|
+
## AnyCable-Go 0.6.0-preview1
|
|
65
|
+
|
|
66
|
+
```
|
|
67
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 --origin http://0.0.0.0 ws://172.31.22.121:3334/cable --server-type=actioncable
|
|
68
|
+
|
|
69
|
+
clients: 1000 95per-rtt: 64ms min-rtt: 2ms median-rtt: 15ms max-rtt: 191ms
|
|
70
|
+
clients: 2000 95per-rtt: 188ms min-rtt: 2ms median-rtt: 27ms max-rtt: 325ms
|
|
71
|
+
clients: 3000 95per-rtt: 218ms min-rtt: 2ms median-rtt: 36ms max-rtt: 854ms
|
|
72
|
+
clients: 4000 95per-rtt: 483ms min-rtt: 2ms median-rtt: 37ms max-rtt: 2353ms
|
|
73
|
+
clients: 5000 95per-rtt: 388ms min-rtt: 2ms median-rtt: 63ms max-rtt: 659ms
|
|
74
|
+
clients: 6000 95per-rtt: 500ms min-rtt: 2ms median-rtt: 59ms max-rtt: 1430ms
|
|
75
|
+
clients: 7000 95per-rtt: 692ms min-rtt: 2ms median-rtt: 85ms max-rtt: 1333ms
|
|
76
|
+
clients: 8000 95per-rtt: 591ms min-rtt: 2ms median-rtt: 90ms max-rtt: 2499ms
|
|
77
|
+
clients: 9000 95per-rtt: 959ms min-rtt: 2ms median-rtt: 90ms max-rtt: 5961ms
|
|
78
|
+
clients: 10000 95per-rtt: 674ms min-rtt: 2ms median-rtt: 106ms max-rtt: 2543ms
|
|
79
|
+
|
|
80
|
+
Missing received broadcasts: expected 6600000, got 6599507
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
CPU (peak): ~40%
|
|
84
|
+
CPU (avg): ~3%
|
|
85
|
+
|
|
86
|
+
MEM: ~450 MiB
|
|
87
|
+
|
|
88
|
+
## Plezi (0.15.0) + Iodine (0.4.16) (8 workers)
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
bin/websocket-bench broadcast -l 172.31.26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --payload-padding 200 --total-steps 10 ws://172.31.22.121:3334/cable
|
|
92
|
+
|
|
93
|
+
clients: 1000 95per-rtt: 48ms min-rtt: 1ms median-rtt: 18ms max-rtt: 208ms
|
|
94
|
+
clients: 2000 95per-rtt: 236ms min-rtt: 0ms median-rtt: 24ms max-rtt: 612ms
|
|
95
|
+
clients: 3000 95per-rtt: 224ms min-rtt: 0ms median-rtt: 38ms max-rtt: 662ms
|
|
96
|
+
clients: 4000 95per-rtt: 402ms min-rtt: 0ms median-rtt: 39ms max-rtt: 3071ms
|
|
97
|
+
clients: 5000 95per-rtt: 392ms min-rtt: 1ms median-rtt: 47ms max-rtt: 1850ms
|
|
98
|
+
clients: 6000 95per-rtt: 582ms min-rtt: 1ms median-rtt: 64ms max-rtt: 1825ms
|
|
99
|
+
clients: 7000 95per-rtt: 393ms min-rtt: 1ms median-rtt: 92ms max-rtt: 729ms
|
|
100
|
+
clients: 8000 95per-rtt: 1181ms min-rtt: 1ms median-rtt: 42ms max-rtt: 5782ms
|
|
101
|
+
clients: 9000 95per-rtt: 676ms min-rtt: 1ms median-rtt: 107ms max-rtt: 2220ms
|
|
102
|
+
clients: 10000 95per-rtt: 603ms min-rtt: 1ms median-rtt: 131ms max-rtt: 5703ms
|
|
103
|
+
|
|
104
|
+
Missing received broadcasts: expected 6600000, got 6586987
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
CPU (peak): ~50%
|
|
108
|
+
CPU (avg): ~5%
|
|
109
|
+
|
|
110
|
+
MEM: ~700 MiB
|
|
111
|
+
|
|
112
|
+
*NOTE*: Plezi app is not a Rails app, thus its memory is less than in Rails examples.
|
|
113
|
+
|
|
114
|
+
# More Stress
|
|
115
|
+
|
|
116
|
+
Peak connections: 20k.
|
|
117
|
+
Concurrency: 8.
|
|
118
|
+
|
|
119
|
+
## Plezi (0.15.0) + Iodine (0.4.16)
|
|
120
|
+
|
|
121
|
+
CPU (peak): ~90%
|
|
122
|
+
CPU (avg): ~6%
|
|
123
|
+
Mem: ~1100MB
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
clients: 1000 95per-rtt: 216ms min-rtt: 1ms median-rtt: 17ms max-rtt: 364ms
|
|
128
|
+
clients: 2000 95per-rtt: 446ms min-rtt: 0ms median-rtt: 24ms max-rtt: 738ms
|
|
129
|
+
clients: 3000 95per-rtt: 348ms min-rtt: 0ms median-rtt: 46ms max-rtt: 925ms
|
|
130
|
+
clients: 4000 95per-rtt: 654ms min-rtt: 2ms median-rtt: 65ms max-rtt: 1175ms
|
|
131
|
+
clients: 5000 95per-rtt: 590ms min-rtt: 0ms median-rtt: 67ms max-rtt: 1842ms
|
|
132
|
+
clients: 6000 95per-rtt: 469ms min-rtt: 1ms median-rtt: 121ms max-rtt: 1098ms
|
|
133
|
+
clients: 7000 95per-rtt: 705ms min-rtt: 1ms median-rtt: 121ms max-rtt: 1617ms
|
|
134
|
+
clients: 8000 95per-rtt: 1090ms min-rtt: 1ms median-rtt: 159ms max-rtt: 3253ms
|
|
135
|
+
clients: 9000 95per-rtt: 869ms min-rtt: 1ms median-rtt: 163ms max-rtt: 3945ms
|
|
136
|
+
clients: 10000 95per-rtt: 1171ms min-rtt: 1ms median-rtt: 247ms max-rtt: 2326ms
|
|
137
|
+
clients: 11000 95per-rtt: 1634ms min-rtt: 1ms median-rtt: 191ms max-rtt: 4383ms
|
|
138
|
+
clients: 12000 95per-rtt: 1138ms min-rtt: 2ms median-rtt: 283ms max-rtt: 8319ms
|
|
139
|
+
clients: 13000 95per-rtt: 1234ms min-rtt: 1ms median-rtt: 306ms max-rtt: 5429ms
|
|
140
|
+
clients: 14000 95per-rtt: 947ms min-rtt: 1ms median-rtt: 346ms max-rtt: 7804ms
|
|
141
|
+
clients: 15000 95per-rtt: 1716ms min-rtt: 1ms median-rtt: 344ms max-rtt: 7372ms
|
|
142
|
+
clients: 16000 95per-rtt: 1999ms min-rtt: 1ms median-rtt: 364ms max-rtt: 3047ms
|
|
143
|
+
clients: 17000 95per-rtt: 1729ms min-rtt: 1ms median-rtt: 410ms max-rtt: 7231ms
|
|
144
|
+
clients: 18000 95per-rtt: 1455ms min-rtt: 1ms median-rtt: 442ms max-rtt: 4725ms
|
|
145
|
+
clients: 19000 95per-rtt: 2006ms min-rtt: 1ms median-rtt: 456ms max-rtt: 3811ms
|
|
146
|
+
clients: 20000 95per-rtt: 2923ms min-rtt: 1ms median-rtt: 378ms max-rtt: 11954ms
|
|
147
|
+
|
|
148
|
+
Missing received broadcasts: expected 23100000, got 23089387
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Anycable-Go 0.6.0-preview1
|
|
152
|
+
|
|
153
|
+
CPU (peak): ~60%
|
|
154
|
+
CPU (avg): ~4%
|
|
155
|
+
Mem: ~1000MB
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
clients: 1000 95per-rtt: 173ms min-rtt: 2ms median-rtt: 21ms max-rtt: 617ms
|
|
159
|
+
clients: 2000 95per-rtt: 311ms min-rtt: 2ms median-rtt: 39ms max-rtt: 594ms
|
|
160
|
+
clients: 3000 95per-rtt: 386ms min-rtt: 3ms median-rtt: 91ms max-rtt: 592ms
|
|
161
|
+
clients: 4000 95per-rtt: 539ms min-rtt: 2ms median-rtt: 93ms max-rtt: 973ms
|
|
162
|
+
clients: 5000 95per-rtt: 534ms min-rtt: 2ms median-rtt: 128ms max-rtt: 1486ms
|
|
163
|
+
clients: 6000 95per-rtt: 1092ms min-rtt: 2ms median-rtt: 110ms max-rtt: 3073ms
|
|
164
|
+
clients: 7000 95per-rtt: 726ms min-rtt: 3ms median-rtt: 185ms max-rtt: 1116ms
|
|
165
|
+
clients: 8000 95per-rtt: 1078ms min-rtt: 2ms median-rtt: 174ms max-rtt: 3296ms
|
|
166
|
+
clients: 9000 95per-rtt: 1401ms min-rtt: 8ms median-rtt: 195ms max-rtt: 6838ms
|
|
167
|
+
clients: 10000 95per-rtt: 1157ms min-rtt: 3ms median-rtt: 282ms max-rtt: 3446ms
|
|
168
|
+
clients: 11000 95per-rtt: 1804ms min-rtt: 4ms median-rtt: 271ms max-rtt: 5640ms
|
|
169
|
+
clients: 12000 95per-rtt: 1339ms min-rtt: 2ms median-rtt: 344ms max-rtt: 2251ms
|
|
170
|
+
clients: 13000 95per-rtt: 1638ms min-rtt: 3ms median-rtt: 336ms max-rtt: 3341ms
|
|
171
|
+
clients: 14000 95per-rtt: 1811ms min-rtt: 3ms median-rtt: 339ms max-rtt: 2079ms
|
|
172
|
+
clients: 15000 95per-rtt: 1407ms min-rtt: 2ms median-rtt: 435ms max-rtt: 6666ms
|
|
173
|
+
clients: 16000 95per-rtt: 2796ms min-rtt: 2ms median-rtt: 398ms max-rtt: 4769ms
|
|
174
|
+
clients: 17000 95per-rtt: 2494ms min-rtt: 6ms median-rtt: 338ms max-rtt: 36085ms
|
|
175
|
+
clients: 18000 95per-rtt: 2844ms min-rtt: 2ms median-rtt: 374ms max-rtt: 7384ms
|
|
176
|
+
clients: 19000 95per-rtt: 4010ms min-rtt: 17ms median-rtt: 370ms max-rtt: 5504ms
|
|
177
|
+
clients: 20000 95per-rtt: 2819ms min-rtt: 2ms median-rtt: 470ms max-rtt: 8598ms
|
|
178
|
+
|
|
179
|
+
Missing received broadcasts: expected 23100000, got 23065521
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
# Idle Connections Benchmark
|
|
183
|
+
|
|
184
|
+
Connection 20k idle clients at 200 connections per second rate; measuring final memory usage.
|
|
185
|
+
|
|
186
|
+
Using [cable_bench](https://github.com/palkan/cable_bench).
|
|
187
|
+
|
|
188
|
+
**Action Cable (8 workers)**: ~1500 MB
|
|
189
|
+
|
|
190
|
+
**Anycable-Go 0.6.0-preview1**: ~700 MB
|
|
191
|
+
|
|
192
|
+
**Plezi (0.15.0) + Iodine (0.4.16)**: ~800 MB (a lot of connection timeout errors and "The connection was lost" errors).
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# AnyCable RPC benchmarks
|
|
2
|
+
|
|
3
|
+
AnyCable RPC server benchmarks.
|
|
4
|
+
|
|
5
|
+
The benchmark is pretty simple:
|
|
6
|
+
- Create N concurrent _clients_ (authenticate and subscribe to `BenchmarkChannel` within the RPC app)
|
|
7
|
+
- Every client starts performing an action (`echo`) in a loop
|
|
8
|
+
- Every call is collected (request time)
|
|
9
|
+
- Wait for the specified amount of seconds and aggragate the results.
|
|
10
|
+
|
|
11
|
+
Measuring **requests per seconds**.
|
|
12
|
+
|
|
13
|
+
**NOTE:** this benchmark shows performance characteristics for both _clients_ and the server.
|
|
14
|
+
The purpose of this benchmark is to measure the thoughout of RPC connection between AnyCable services.
|
|
15
|
+
|
|
16
|
+
**NOTE 2:** "Noop RPC" is just a gRPC handling doing nothing except from responding with success result.
|
|
17
|
+
|
|
18
|
+
Sources:
|
|
19
|
+
- [Golang](https://github.com/anycable/anycable-go/blob/chore/benchmarking/cmd/rpc-bench/main.go)
|
|
20
|
+
- [Erlang](https://github.com/anycable/simple-cable-app/tree/master/benchmarks)
|
|
21
|
+
|
|
22
|
+
## Erlang single connection
|
|
23
|
+
|
|
24
|
+
RPC type \ Number of clients | 1 | 10 | 50
|
|
25
|
+
--------------------------------|------|------|----
|
|
26
|
+
AnyCable RPC | 100 | 110 | 130
|
|
27
|
+
Noop RPC | 100 | 115 | 125
|
|
28
|
+
|
|
29
|
+
Erlang client definitely has problems(
|
|
30
|
+
|
|
31
|
+
Looks like HTTP2 streaming is working in _blocking mode_.
|
|
32
|
+
|
|
33
|
+
Requires investigation.
|
|
34
|
+
|
|
35
|
+
## Erlycable connection pool (5-50)
|
|
36
|
+
|
|
37
|
+
RPC type \ Number of clients | 1 | 10 | 50
|
|
38
|
+
--------------------------------|------|------|----
|
|
39
|
+
AnyCable RPC | 100 | 800 | 1700
|
|
40
|
+
Noop RPC | 100 | 900 | 2700
|
|
41
|
+
|
|
42
|
+
## Golang single connection
|
|
43
|
+
|
|
44
|
+
RPC type \ Number of clients | 1 | 10 | 50
|
|
45
|
+
--------------------------------|------|------|----
|
|
46
|
+
AnyCable RPC | 1600 | 2200 | 2400
|
|
47
|
+
Noop RPC with connection object building\* | 2200 | 3500 | 4000
|
|
48
|
+
Noop RPC | 3000 | 4600 | 5500
|
|
49
|
+
|
|
50
|
+
\* Only build Action Cable connection object without performing an action.
|
|
51
|
+
|
|
52
|
+
## Golang connection pool (5-50)
|
|
53
|
+
|
|
54
|
+
RPC type \ Number of clients | 1 | 10 | 50
|
|
55
|
+
--------------------------------|------|------|----
|
|
56
|
+
AnyCable RPC | 1400 | 1500 | 1700
|
|
57
|
+
Noop RPC | 2100 | 3200 | 4000
|
data/benchmarks/HowTo.md
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
- Update `hosts` file and playbooks with required information (IPs, etc)
|
|
12
12
|
|
|
13
|
-
- Prepare the _client_ instance: `ansible-playbook --
|
|
13
|
+
- Prepare the _client_ instance: `ansible-playbook --tags prepare benchmark.yml`
|
|
14
14
|
|
|
15
15
|
### Running benchmarks
|
|
16
16
|
|
data/benchmarks/benchmark.yml
CHANGED
|
@@ -5,17 +5,19 @@
|
|
|
5
5
|
remote_user: ubuntu
|
|
6
6
|
gather_facts: False
|
|
7
7
|
vars:
|
|
8
|
-
server_host: '172.31.
|
|
8
|
+
server_host: '172.31.17.82'
|
|
9
9
|
hostname: ws-bench-client
|
|
10
|
-
local_ips: ['172.31.
|
|
11
|
-
local_ips_str: '-l 172.31.
|
|
12
|
-
steps:
|
|
10
|
+
local_ips: ['172.31.17.191', '172.31.17.192', '172.31.17.193', '172.31.17.194']
|
|
11
|
+
local_ips_str: '-l 172.31.17.191 -l 172.31.17.192 -l 172.31.17.193 -l 172.31.17.194'
|
|
12
|
+
steps: 20
|
|
13
13
|
step_size: 1000
|
|
14
|
-
sample_size:
|
|
14
|
+
sample_size: 100
|
|
15
|
+
concurrency: 8
|
|
16
|
+
payload_size: 200
|
|
15
17
|
prepare: False
|
|
16
18
|
tasks:
|
|
17
19
|
- name: Prepare the machine
|
|
18
|
-
|
|
20
|
+
tags: prepare
|
|
19
21
|
block:
|
|
20
22
|
- hostname:
|
|
21
23
|
name: "{{ hostname }}"
|
|
@@ -25,16 +27,41 @@
|
|
|
25
27
|
state: present
|
|
26
28
|
- shell: ip addr add {{ item }}/20 dev eth0
|
|
27
29
|
with_items: "{{ local_ips }}"
|
|
30
|
+
|
|
31
|
+
- name: Print Action Cable command
|
|
32
|
+
debug: msg="bin/websocket-bench broadcast {{ local_ips_str }} --concurrent {{ concurrency }} --sample-size {{ sample_size }} --step-size {{ step_size }} --payload-padding {{ payload_size }} --total-steps {{ steps }} --origin http://0.0.0.0 ws://{{ server_host }}:3334/cable --server-type=actioncable"
|
|
33
|
+
tags: action_cable
|
|
34
|
+
|
|
28
35
|
- name: Action Cable benchmark
|
|
29
36
|
become_user: deplo
|
|
30
|
-
shell: bin/websocket-bench broadcast {{ local_ips_str }} --concurrent
|
|
37
|
+
shell: bin/websocket-bench broadcast {{ local_ips_str }} --concurrent {{ concurrency }} --sample-size {{ sample_size }} --step-size {{ step_size }} --payload-padding {{ payload_size }} --total-steps {{ steps }} --origin http://0.0.0.0 ws://{{ server_host }}:3334/cable --server-type=actioncable
|
|
31
38
|
register: bench
|
|
32
39
|
tags: action_cable
|
|
33
40
|
args:
|
|
34
41
|
chdir: /webapps/anycable_bench
|
|
35
42
|
ignore_errors: yes
|
|
36
43
|
|
|
37
|
-
- name:
|
|
44
|
+
- name: Print Plezi command
|
|
45
|
+
debug: msg="bin/websocket-bench broadcast {{ local_ips_str }} --concurrent {{ concurrency }} --sample-size {{ sample_size }} --step-size {{ step_size }} --payload-padding {{ payload_size }} --total-steps {{ steps }} ws://{{ server_host }}:3334/cable"
|
|
46
|
+
tags: plezi
|
|
47
|
+
|
|
48
|
+
- name: Plezi benchmark
|
|
49
|
+
become_user: deplo
|
|
50
|
+
shell: bin/websocket-bench broadcast {{ local_ips_str }} --concurrent {{ concurrency }} --sample-size {{ sample_size }} --step-size {{ step_size }} --payload-padding {{ payload_size }} --total-steps {{ steps }} ws://{{ server_host }}:3334/cable
|
|
51
|
+
register: bench
|
|
52
|
+
tags: plezi
|
|
53
|
+
args:
|
|
54
|
+
chdir: /webapps/anycable_bench
|
|
55
|
+
ignore_errors: yes
|
|
56
|
+
|
|
57
|
+
- name: Benchmark results (stdout)
|
|
38
58
|
debug: var=bench.stdout_lines
|
|
39
59
|
tags:
|
|
40
60
|
- action_cable
|
|
61
|
+
- plezi
|
|
62
|
+
|
|
63
|
+
- name: Benchmark results (stderr)
|
|
64
|
+
debug: var=bench.stderr_lines
|
|
65
|
+
tags:
|
|
66
|
+
- action_cable
|
|
67
|
+
- plezi
|
data/benchmarks/hosts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
[benchmark]
|
|
2
|
-
ec2-52-
|
|
2
|
+
ec2-52-19-57-142.eu-west-1.compute.amazonaws.com ansible_ssh_private_key_file=/Users/palkan/.ssh/macos-dev
|
|
3
3
|
|
|
4
4
|
[servers]
|
|
5
|
-
ec2-
|
|
5
|
+
ec2-34-252-33-102.eu-west-1.compute.amazonaws.com ansible_ssh_private_key_file=/Users/palkan/.ssh/macos-dev
|
data/benchmarks/servers.yml
CHANGED
|
@@ -5,25 +5,32 @@
|
|
|
5
5
|
remote_user: ubuntu
|
|
6
6
|
gather_facts: False
|
|
7
7
|
vars:
|
|
8
|
-
|
|
8
|
+
web_concurrency: 8
|
|
9
9
|
tasks:
|
|
10
10
|
- name: Kill servers
|
|
11
11
|
shell: pid=$(lsof -i:{{item}} -t); kill -TERM $pid || kill -KILL $pid
|
|
12
12
|
tags:
|
|
13
13
|
- action_cable
|
|
14
14
|
- anycable
|
|
15
|
+
- plezi
|
|
15
16
|
with_items:
|
|
16
17
|
- "3334"
|
|
17
18
|
ignore_errors: true
|
|
18
19
|
- name: Run Action Cable
|
|
19
20
|
become_user: deplo
|
|
20
21
|
tags: action_cable
|
|
21
|
-
shell: WEB_CONCURRENCY={{
|
|
22
|
+
shell: WEB_CONCURRENCY={{ web_concurrency }} bundle exec rails s -p 3334 -e production
|
|
22
23
|
args:
|
|
23
24
|
chdir: /webapps/anycable_bench/ruby/action-cable-server
|
|
24
25
|
- name: Run Anycable Go
|
|
25
26
|
become_user: deplo
|
|
26
27
|
tags: anycable
|
|
27
|
-
shell: bundle exec anycable
|
|
28
|
+
shell: ANYCABLE_GO_BIN="anycable-go-0.6.0" ANYCABLE_PORT="3334" bundle exec bin/anycable
|
|
28
29
|
args:
|
|
29
|
-
chdir: /webapps/anycable_bench/ruby/action-cable-server
|
|
30
|
+
chdir: /webapps/anycable_bench/ruby/action-cable-server
|
|
31
|
+
- name: Run Iodine/Plezi
|
|
32
|
+
become_user: deplo
|
|
33
|
+
tags: plezi
|
|
34
|
+
shell: iodine -p 3334
|
|
35
|
+
args:
|
|
36
|
+
chdir: /webapps/anycable_bench/ruby/plezi-iodine
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "bundler/inline"
|
|
4
|
+
|
|
5
|
+
# This reproduction script is based on `anyt` gem
|
|
6
|
+
# (https://github.com/anycable/anyt).
|
|
7
|
+
#
|
|
8
|
+
# See more test examples here:
|
|
9
|
+
# https://github.com/anycable/anyt/tree/master/lib/anyt/tests
|
|
10
|
+
|
|
11
|
+
gemfile(true) do
|
|
12
|
+
source "https://rubygems.org"
|
|
13
|
+
|
|
14
|
+
gem "anyt"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
require "anyt"
|
|
18
|
+
require "anyt/cli"
|
|
19
|
+
require "anycable-rails"
|
|
20
|
+
|
|
21
|
+
# WebSocket server url
|
|
22
|
+
ENV['ANYT_TARGET_URL'] ||= "ws://localhost:8080/cable"
|
|
23
|
+
|
|
24
|
+
# Command to launch WebSocket server.
|
|
25
|
+
# Comment this line if you want to run WebSocket server manually
|
|
26
|
+
ENV['ANYT_COMMAND'] ||= "anycable-go"
|
|
27
|
+
|
|
28
|
+
ActionCable.server.config.logger = Rails.logger = Anycable.logger
|
|
29
|
+
|
|
30
|
+
# Test scenario
|
|
31
|
+
feature "issue_xyz" do
|
|
32
|
+
# This block defines an anonymous channel to test against
|
|
33
|
+
channel do
|
|
34
|
+
# def subscribed
|
|
35
|
+
# stream_from "a"
|
|
36
|
+
# end
|
|
37
|
+
#
|
|
38
|
+
# def perform(data)
|
|
39
|
+
# # ...
|
|
40
|
+
# end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
# You can use minitest/spec features here
|
|
44
|
+
before do
|
|
45
|
+
# `channel` contains identifier of the anonymous channel defined above
|
|
46
|
+
subscribe_request = { command: "subscribe", identifier: { channel: channel }.to_json }
|
|
47
|
+
|
|
48
|
+
# `client` represents a websocket client connected to a server
|
|
49
|
+
client.send(subscribe_request)
|
|
50
|
+
|
|
51
|
+
ack = {
|
|
52
|
+
"identifier" => { channel: channel }.to_json, "type" => "confirm_subscription"
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# `receive` method returns the first message from the incoming messages queue;
|
|
56
|
+
# waits 5s when no messages available
|
|
57
|
+
assert_equal ack, client.receive
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# describe you bug scenario here
|
|
61
|
+
scenario %{
|
|
62
|
+
Should work
|
|
63
|
+
} do
|
|
64
|
+
# ...
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Required setup/teardown
|
|
69
|
+
begin
|
|
70
|
+
Anyt::RPC.start
|
|
71
|
+
Anyt::Command.run if Anyt.config.command
|
|
72
|
+
Anyt::Tests.run
|
|
73
|
+
ensure
|
|
74
|
+
Anyt::Command.stop if Anyt.config.command
|
|
75
|
+
Anyt::RPC.stop
|
|
76
|
+
end
|
data/lib/anycable.rb
CHANGED
|
@@ -47,7 +47,8 @@ module Anycable
|
|
|
47
47
|
@pubsub ||= PubSub.new
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
#
|
|
50
|
+
# Raw broadcast message to the channel, sends only string!
|
|
51
|
+
# To send hash or object use ActionCable.server.broadcast instead!
|
|
51
52
|
def broadcast(channel, payload)
|
|
52
53
|
pubsub.broadcast(channel, payload)
|
|
53
54
|
end
|
data/lib/anycable/rpc_handler.rb
CHANGED
|
@@ -15,7 +15,7 @@ module Anycable
|
|
|
15
15
|
|
|
16
16
|
# Handle connection request from WebSocket server
|
|
17
17
|
def connect(request, _unused_call)
|
|
18
|
-
logger.debug("RPC Connect: #{request}")
|
|
18
|
+
logger.debug("RPC Connect: #{request.inspect}")
|
|
19
19
|
|
|
20
20
|
socket = build_socket(env: rack_env(request))
|
|
21
21
|
|
|
@@ -35,7 +35,7 @@ module Anycable
|
|
|
35
35
|
end
|
|
36
36
|
|
|
37
37
|
def disconnect(request, _unused_call)
|
|
38
|
-
logger.debug("RPC
|
|
38
|
+
logger.debug("RPC Disconnect: #{request.inspect}")
|
|
39
39
|
|
|
40
40
|
socket = build_socket(env: rack_env(request))
|
|
41
41
|
|
|
@@ -53,7 +53,7 @@ module Anycable
|
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
def command(message, _unused_call)
|
|
56
|
-
logger.debug("RPC Command: #{message}")
|
|
56
|
+
logger.debug("RPC Command: #{message.inspect}")
|
|
57
57
|
|
|
58
58
|
socket = build_socket
|
|
59
59
|
|
|
@@ -96,7 +96,7 @@ module Anycable
|
|
|
96
96
|
end
|
|
97
97
|
|
|
98
98
|
def build_socket(**options)
|
|
99
|
-
Anycable::Socket.new(
|
|
99
|
+
Anycable::Socket.new(options)
|
|
100
100
|
end
|
|
101
101
|
|
|
102
102
|
def build_headers(headers)
|
data/lib/anycable/server.rb
CHANGED
|
@@ -14,6 +14,7 @@ module Anycable
|
|
|
14
14
|
@grpc_server ||= build_server
|
|
15
15
|
|
|
16
16
|
Anycable.logger.info "RPC server is listening on #{Anycable.config.rpc_host}"
|
|
17
|
+
Anycable.logger.info "Broadcasting Redis channel: #{Anycable.config.redis_channel}"
|
|
17
18
|
grpc_server.run_till_terminated
|
|
18
19
|
end
|
|
19
20
|
|
data/lib/anycable/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: anycable
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.5.
|
|
4
|
+
version: 0.5.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- palkan
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2018-06-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: anyway_config
|
|
@@ -118,16 +118,16 @@ dependencies:
|
|
|
118
118
|
name: rubocop
|
|
119
119
|
requirement: !ruby/object:Gem::Requirement
|
|
120
120
|
requirements:
|
|
121
|
-
- - "
|
|
121
|
+
- - "~>"
|
|
122
122
|
- !ruby/object:Gem::Version
|
|
123
|
-
version:
|
|
123
|
+
version: 0.57.1
|
|
124
124
|
type: :development
|
|
125
125
|
prerelease: false
|
|
126
126
|
version_requirements: !ruby/object:Gem::Requirement
|
|
127
127
|
requirements:
|
|
128
|
-
- - "
|
|
128
|
+
- - "~>"
|
|
129
129
|
- !ruby/object:Gem::Version
|
|
130
|
-
version:
|
|
130
|
+
version: 0.57.1
|
|
131
131
|
- !ruby/object:Gem::Dependency
|
|
132
132
|
name: simplecov
|
|
133
133
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -187,6 +187,8 @@ files:
|
|
|
187
187
|
- assets/evlms.png
|
|
188
188
|
- benchmarks/.gitignore
|
|
189
189
|
- benchmarks/2017-02-12.md
|
|
190
|
+
- benchmarks/2018-03-04.md
|
|
191
|
+
- benchmarks/2018-05-27-rpc-bench.md
|
|
190
192
|
- benchmarks/HowTo.md
|
|
191
193
|
- benchmarks/ansible.cfg
|
|
192
194
|
- benchmarks/benchmark.yml
|
|
@@ -195,6 +197,7 @@ files:
|
|
|
195
197
|
- bin/console
|
|
196
198
|
- bin/setup
|
|
197
199
|
- circle.yml
|
|
200
|
+
- etc/bug_report_template.rb
|
|
198
201
|
- lib/anycable.rb
|
|
199
202
|
- lib/anycable/config.rb
|
|
200
203
|
- lib/anycable/handler/exceptions_handling.rb
|
|
@@ -226,7 +229,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
226
229
|
version: '0'
|
|
227
230
|
requirements: []
|
|
228
231
|
rubyforge_project:
|
|
229
|
-
rubygems_version: 2.6
|
|
232
|
+
rubygems_version: 2.7.6
|
|
230
233
|
signing_key:
|
|
231
234
|
specification_version: 4
|
|
232
235
|
summary: Polyglot replacement for ActionCable server
|