anycable 0.5.0 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 3f3531b822f2fe18921fabc66f1d440869aa70e7
4
- data.tar.gz: b346094927f772d9a65a3095c767eb12c448987f
2
+ SHA256:
3
+ metadata.gz: '079d557557d69550f4a490d8fcbcd35b922df102af44c076ea14bc92bff5dda3'
4
+ data.tar.gz: 29339983ff86ec5f52959397b566926c00d7116fa8dd56dc4933bac4bd526689
5
5
  SHA512:
6
- metadata.gz: 85cdaf95181f6690f6cab6b0cc2b6692070a9e79f1c0dc80a78ca90de6f5778f9ca9e5381ac5d575f54251729f5d1e7f2fc58b76300b0959a7b1fefc80b4ec13
7
- data.tar.gz: 867646df97ba3723082377512ecf25bff6b68fbd7a3509fc7e794baa38a409c52a583bf9283a646276a906f3fcd9cf05c7d364b24b8009d9b6d1f2cb05211c96
6
+ metadata.gz: a4fdb1f8ccbb3c633996c4aae85ce60263ab5c8f68f13909d93ef2ebe390e5124901b2832221b7fdd809fef1e3ae04628e4e5437aa6f262da51248041b5d0030
7
+ data.tar.gz: ba3d770e79aa4775e894d2f568787f62d96f1e699828549e0dba1880a85597e01e565fe0781a51b1da42f7cd359cc7580846c7c01f297ee498e4cbfacfba8329
@@ -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'
@@ -7,7 +7,7 @@ sudo: false
7
7
  notifications:
8
8
  email: false
9
9
 
10
- matrix:
11
- include:
12
- - rvm: 2.3.3
13
- - rvm: 2.4.0
10
+ rvm:
11
+ - 2.3.6
12
+ - 2.4.3
13
+ - 2.5.0
@@ -1,8 +1,18 @@
1
1
  # Change log
2
2
 
3
- ## 0.5.0 (master)
3
+ ## master
4
4
 
5
- - [#2](https://github.com/anycable/anycable/issues/2) Add support for [Redis Sentinel](https://redis.io/topics/sentinel). ([@accessd](https://github.com/accessd))
5
+ ## 0.5.2 (2018-09-06)
6
+
7
+ - [#48](https://github.com/anycable/anycable/pull/48) Add HTTP health server ([@DarthSim][])
8
+
9
+ ## 0.5.1 (2018-06-13)
10
+
11
+ Minor fixes.
12
+
13
+ ## 0.5.0 (2017-10-21)
14
+
15
+ - [#2](https://github.com/anycable/anycable/issues/2) Add support for [Redis Sentinel](https://redis.io/topics/sentinel). ([@accessd][])
6
16
 
7
17
  - [#28](https://github.com/anycable/anycable/issues/28) Support arbitrary headers. ([@palkan][])
8
18
 
@@ -85,3 +95,5 @@ Implement `Disconnect` handler, which invokes `Connection#disconnect` (along wit
85
95
 
86
96
  [@palkan]: https://github.com/palkan
87
97
  [@sadovnik]: https://github.com/sadovnik
98
+ [@accessd]: https://github.com/accessd
99
+ [@DarthSim]: https://github.com/DarthSim
data/Gemfile CHANGED
@@ -5,6 +5,4 @@ local_gemfile = "#{File.dirname(__FILE__)}/Gemfile.local"
5
5
 
6
6
  if File.exist?(local_gemfile)
7
7
  eval(File.read(local_gemfile)) # rubocop:disable Lint/Eval
8
- else
9
- # ??
10
8
  end
data/README.md CHANGED
@@ -1,5 +1,4 @@
1
1
  [![GitPitch](https://gitpitch.com/assets/badge.svg)](https://gitpitch.com/anycable/anycable/master?grs=github) [![Gem Version](https://badge.fury.io/rb/anycable.svg)](https://rubygems.org/gems/anycable) [![Build Status](https://travis-ci.org/anycable/anycable.svg?branch=master)](https://travis-ci.org/anycable/anycable) [![Circle CI](https://circleci.com/gh/anycable/anycable/tree/master.svg?style=svg)](https://circleci.com/gh/anycable/anycable/tree/master)
2
- [![Dependency Status](https://dependencyci.com/github/anycable/anycable/badge)](https://dependencyci.com/github/anycable/anycable)
3
2
  [![Gitter](https://img.shields.io/badge/gitter-join%20chat%20%E2%86%92-brightgreen.svg)](https://gitter.im/anycable/Lobby)
4
3
 
5
4
  # Anycable
@@ -16,9 +15,21 @@ Rails plug-n-play integration has been extracted to [anycable-rails](https://git
16
15
 
17
16
  ## Requirements
18
17
 
19
- - Ruby ~> 2.3
18
+ - Ruby >= 2.3, <= 2.5
20
19
  - Redis (for brodcasting, [discuss other options](https://github.com/anycable/anycable/issues/2) with us!)
21
20
 
21
+ Or you can try to [build it from source](https://github.com/grpc/grpc/blob/master/INSTALL.md#build-from-source).
22
+
23
+ For MacOS there is also [the same problem](https://github.com/google/protobuf/issues/4098) with `google-protobuf` that can be solved
24
+ the following way:
25
+
26
+ ```ruby
27
+ # Gemfile
28
+ git 'https://github.com/google/protobuf' do
29
+ gem 'google-protobuf'
30
+ end
31
+ ```
32
+
22
33
  ## How It Works?
23
34
 
24
35
  ![](https://s3.amazonaws.com/anycable/Scheme.png)
@@ -29,7 +40,17 @@ Read our [Wiki](https://github.com/anycable/anycable/wiki) for more.
29
40
 
30
41
  - [AnyCable: Action Cable on steroids!](https://evilmartians.com/chronicles/anycable-actioncable-on-steroids)
31
42
 
32
- - [Connecting LiteCable to Hanami](http://gabrielmalakias.com.br/ruby/hanami/iot/2017/05/26/websockets-connecting-litecable-to-hanami.html)
43
+ - [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)
44
+
45
+ - [From Action to Any](https://medium.com/@leshchuk/from-action-to-any-1e8d863dd4cf) by [@alekseyl](https://github.com/alekseyl)
46
+
47
+ ## Talks
48
+
49
+ - One cable to rule them all, RubyKaigi 2018, [slides](https://speakerdeck.com/palkan/rubykaigi-2018-anycable-one-cable-to-rule-them-all) and [video](https://www.youtube.com/watch?v=jXCPuNICT8s) (EN)
50
+
51
+ - 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)
52
+
53
+ - RubyConfMY 2017 [slides](https://speakerdeck.com/palkan/rubyconf-malaysia-2017-anycable) and [video](https://www.youtube.com/watch?v=j5oFx525zNw) (EN)
33
54
 
34
55
  - 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
56
 
@@ -71,6 +92,7 @@ Performing Channel Actions | +
71
92
  Streaming | +
72
93
  [Custom stream callbacks](http://edgeapi.rubyonrails.org/classes/ActionCable/Channel/Streams.html) | -
73
94
  Broadcasting | +
95
+ Custom pubsub adapter | Only redis
74
96
 
75
97
  ## Build
76
98
 
@@ -91,5 +113,7 @@ make
91
113
 
92
114
  Bug reports and pull requests are welcome on GitHub at https://github.com/anycable/anycable.
93
115
 
116
+ Please, provide reproduction script (using [this template](https://github.com/anycable/anycable/blob/master/etc/bug_report_template.rb)) when submitting bugs if possible.
117
+
94
118
  ## License
95
119
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -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", ">= 0.50"
29
+ spec.add_development_dependency "rubocop", "~> 0.58.0"
30
30
  spec.add_development_dependency "simplecov", ">= 0.3.8"
31
31
  spec.add_development_dependency "pry-byebug"
32
32
  end
@@ -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 anc CPU usage was measured by looking at `htop` output.
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
- deplo@ip-172-31-26-145:/webapps/anycable_bench$ bin/websocket-bench broadcast -l 172.31.
14
- 26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 10
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
- 2017/02/12 09:18:45 Missing received broadcasts: expected 6600000, got 6572168
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
- deplo@ip-172-31-26-145:/webapps/anycable_bench$ bin/websocket-bench broadcast -l 172.31.
38
- 26.145 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 10
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
- 2017/02/12 09:36:45 Missing received broadcasts: expected 6600000, got 6589644
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
- deplo@ip-172-31-26-145:/webapps/anycable_bench$ bin/websocket-bench broadcast -l 172.31.26.14
64
- 5 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --paylo
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
- 2017/02/12 10:33:07 Missing received broadcasts: expected 6600000, got 5649743
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
- deplo@ip-172-31-26-145:/webapps/anycable_bench$ bin/websocket-bench broadcast -l 172.31.26.14
88
- 5 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --paylo
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
- 2017/02/12 10:47:09 Missing received broadcasts: expected 6600000, got 5662008
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
- deplo@ip-172-31-26-145:/webapps/anycable_bench$ bin/websocket-bench broadcast -l 172.31.26.14
112
- 5 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --paylo
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
- 2017/02/12 09:24:35 Missing received broadcasts: expected 6600000, got 6588881
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
- deplo@ip-172-31-26-145:/webapps/anycable_bench$ bin/websocket-bench broadcast -l 172.31.26.14
136
- 5 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --paylo
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
- 2017/02/12 09:40:31 Missing received broadcasts: expected 6600000, got 6599571
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
- deplo@ip-172-31-26-145:/webapps/anycable_bench$ bin/websocket-bench broadcast -l 172.31.26.14
159
- 5 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --paylo
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
- 2017/02/12 09:49:29 Missing received broadcasts: expected 6600000, got 6593825
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
- deplo@ip-172-31-26-145:/webapps/anycable_bench$ bin/websocket-bench broadcast -l 172.31.26.14
182
- 5 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --paylo
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
- 2017/02/12 10:11:21 Missing received broadcasts: expected 6600000, got 6575292
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
- deplo@ip-172-31-26-145:/webapps/anycable_bench$ bin/websocket-bench broadcast -l 172.31.26.14
205
- 5 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --paylo
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
- 2017/02/12 10:18:07 Missing received broadcasts: expected 6600000, got 6599226
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
- deplo@ip-172-31-26-145:/webapps/anycable_bench$ bin/websocket-bench broadcast -l 172.31.26.14
228
- 5 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --paylo
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
- 2017/02/12 10:14:31 Missing received broadcasts: expected 6600000, got 2736158
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
- deplo@ip-172-31-26-145:/webapps/anycable_bench$ bin/websocket-bench broadcast -l 172.31.26.14
257
- 5 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --paylo
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
- 2017/02/12 10:22:39 Missing received broadcasts: expected 6600000, got 6599593
266
+
267
+ Missing received broadcasts: expected 6600000, got 6599593
270
268
  ```
271
269
 
272
270
  Second run:
273
271
 
274
272
  ```
275
- deplo@ip-172-31-26-145:/webapps/anycable_bench$ bin/websocket-bench broadcast -l 172.31.26.14
276
- 5 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --paylo
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
- deplo@ip-172-31-26-145:/webapps/anycable_bench$ bin/websocket-bench broadcast -l 172.31.26.14
294
- 5 -l 172.31.26.146 -l 172.31.26.147 --concurrent 4 --sample-size 100 --step-size 1000 --paylo
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
- 2017/02/12 10:28:08 Missing received broadcasts: expected 6600000, got 6599123
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
@@ -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 --extra-vars="prepare=True" benchmark.yml`
13
+ - Prepare the _client_ instance: `ansible-playbook --tags prepare benchmark.yml`
14
14
 
15
15
  ### Running benchmarks
16
16
 
@@ -5,17 +5,19 @@
5
5
  remote_user: ubuntu
6
6
  gather_facts: False
7
7
  vars:
8
- server_host: '172.31.22.14'
8
+ server_host: '172.31.17.82'
9
9
  hostname: ws-bench-client
10
- local_ips: ['172.31.21.241', '172.31.21.242', '172.31.21.243', '172.31.21.244']
11
- local_ips_str: '-l 172.31.21.241 -l 172.31.21.242 -l 172.31.21.243 -l 172.31.21.244'
12
- steps: 10
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: 40
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
- when: prepare
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 4 --sample-size {{ sample_size }} --step-size {{ step_size }} --payload-padding 200 --total-steps {{ steps }} --origin http://0.0.0.0 ws://{{ server_host }}:3334/cable --server-type=actioncable
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: Benchmark results
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
@@ -1,5 +1,5 @@
1
1
  [benchmark]
2
- ec2-52-208-189-15.eu-west-1.compute.amazonaws.com ansible_ssh_private_key_file=/Users/palkan/.ssh/macos-dev
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-52-211-15-119.eu-west-1.compute.amazonaws.com ansible_ssh_private_key_file=/Users/palkan/.ssh/macos-dev
5
+ ec2-34-252-33-102.eu-west-1.compute.amazonaws.com ansible_ssh_private_key_file=/Users/palkan/.ssh/macos-dev
@@ -5,25 +5,32 @@
5
5
  remote_user: ubuntu
6
6
  gather_facts: False
7
7
  vars:
8
- rails_webc: 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={{ rails_webc }} bundle exec rails s -p 3334 -e production
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/bin
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
@@ -47,7 +47,8 @@ module Anycable
47
47
  @pubsub ||= PubSub.new
48
48
  end
49
49
 
50
- # Broadcast message to the channel
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
@@ -14,7 +14,8 @@ module Anycable
14
14
  log_file: nil,
15
15
  log_level: :info,
16
16
  log_grpc: false,
17
- debug: false # Shortcut to enable GRPC logging and debug level
17
+ debug: false, # Shortcut to enable GRPC logging and debug level
18
+ http_health_port: nil
18
19
 
19
20
  def initialize(*)
20
21
  super
@@ -23,5 +24,9 @@ module Anycable
23
24
  self.log_level = :debug
24
25
  self.log_grpc = true
25
26
  end
27
+
28
+ def http_health_port_provided?
29
+ !http_health_port.nil? && http_health_port != ""
30
+ end
26
31
  end
27
32
  end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'webrick'
4
+ require 'anycable/server'
5
+
6
+ module Anycable
7
+ # Server for HTTP healthchecks
8
+ module HealthServer
9
+ class << self
10
+ def start(port)
11
+ return if running?
12
+
13
+ @health_server ||= build_server(port)
14
+ Thread.new { @health_server.start }
15
+
16
+ Anycable.logger.info "HTTP health server is listening on #{port}"
17
+ end
18
+
19
+ def stop
20
+ return unless running?
21
+ @health_server.shutdown
22
+ end
23
+
24
+ def running?
25
+ @health_server&.status == :Running
26
+ end
27
+
28
+ private
29
+
30
+ SUCCESS_RESPONSE = [200, "Ready"].freeze
31
+ FAILURE_RESPONSE = [503, "Not Ready"].freeze
32
+
33
+ def build_server(port)
34
+ WEBrick::HTTPServer.new(
35
+ Port: port,
36
+ Logger: Anycable.logger,
37
+ AccessLog: []
38
+ ).tap do |server|
39
+ server.mount_proc '/health' do |_, res|
40
+ res.status, res.body = Anycable::Server.running? ? SUCCESS_RESPONSE : FAILURE_RESPONSE
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -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 Disonnect: #{request}")
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(**options)
99
+ Anycable::Socket.new(options)
100
100
  end
101
101
 
102
102
  def build_headers(headers)
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'grpc'
4
4
  require 'anycable/rpc_handler'
5
+ require 'anycable/health_server'
5
6
 
6
7
  module Anycable
7
8
  # Wrapper over GRPC server
@@ -11,10 +12,9 @@ module Anycable
11
12
 
12
13
  def start
13
14
  log_grpc! if Anycable.config.log_grpc
14
- @grpc_server ||= build_server
15
15
 
16
- Anycable.logger.info "RPC server is listening on #{Anycable.config.rpc_host}"
17
- grpc_server.run_till_terminated
16
+ start_http_health_server
17
+ start_grpc_server
18
18
  end
19
19
 
20
20
  def stop
@@ -33,12 +33,27 @@ module Anycable
33
33
 
34
34
  private
35
35
 
36
+ def start_grpc_server
37
+ @grpc_server ||= build_server
38
+
39
+ Anycable.logger.info "RPC server is listening on #{Anycable.config.rpc_host}"
40
+ Anycable.logger.info "Broadcasting Redis channel: #{Anycable.config.redis_channel}"
41
+
42
+ grpc_server.run_till_terminated
43
+ end
44
+
36
45
  def build_server
37
46
  GRPC::RpcServer.new.tap do |server|
38
47
  server.add_http2_port(Anycable.config.rpc_host, :this_port_is_insecure)
39
48
  server.handle(Anycable::RPCHandler)
40
49
  end
41
50
  end
51
+
52
+ def start_http_health_server
53
+ return unless Anycable.config.http_health_port_provided?
54
+ Anycable::HealthServer.start(Anycable.config.http_health_port)
55
+ at_exit { Anycable::HealthServer.stop }
56
+ end
42
57
  end
43
58
  end
44
59
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Anycable
4
- VERSION = "0.5.0"
4
+ VERSION = "0.5.2"
5
5
  end
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.0
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - palkan
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-10-21 00:00:00.000000000 Z
11
+ date: 2018-09-06 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: '0.50'
123
+ version: 0.58.0
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: '0.50'
130
+ version: 0.58.0
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,9 +197,11 @@ 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
204
+ - lib/anycable/health_server.rb
201
205
  - lib/anycable/pubsub.rb
202
206
  - lib/anycable/rpc/rpc_pb.rb
203
207
  - lib/anycable/rpc/rpc_services_pb.rb
@@ -226,7 +230,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
226
230
  version: '0'
227
231
  requirements: []
228
232
  rubyforge_project:
229
- rubygems_version: 2.6.13
233
+ rubygems_version: 2.7.6
230
234
  signing_key:
231
235
  specification_version: 4
232
236
  summary: Polyglot replacement for ActionCable server