centrifugal / centrifuge

Real-time messaging library for Go. The simplest way to add feature-rich and scalable WebSocket support to your application. The core of Centrifugo server.

Home Page:https://pkg.go.dev/github.com/centrifugal/centrifuge

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Protocol structure changes – avoid layering

FZambia opened this issue · comments

I am thinking about changing a structure of client protocol schema in a way so that we won't have several Raw data layers in messages. Specifically I mean sth like this:

diff --git a/client.proto b/client.proto
index abe5268..53bae89 100644
--- a/client.proto
+++ b/client.proto
@@ -27,12 +27,26 @@ message Command {
   }
   MethodType method = 2;
   bytes params = 3;
+
+  ConnectRequest connect = 4;
+  SubscribeRequest subscribe = 5;
+  UnsubscribeRequest unsubscribe = 6;
+  PublishRequest publish = 7;
+  PresenceRequest presence = 8;
+  PresenceStatsRequest presence_stats = 9;
+  HistoryRequest history = 10;
+  PingRequest ping = 11;
+  SendRequest send = 12;
+  RPCRequest rpc = 13;
+  RefreshRequest refresh = 14;
+  SubRefreshRequest sub_refresh = 15;
 }
 
 message Reply {
   uint32 id = 1;
   Error error = 2;
   bytes result = 3;
+  Push push = 4;
 }
 
 message Push {
@@ -50,6 +64,16 @@ message Push {
   PushType type = 1;
   string channel = 2;
   bytes data = 3;
+
+  Publication pub = 4;
+  Join join = 5;
+  Leave leave = 6;
+  Unsubscribe unsubscribe = 7;
+  Message message = 8;
+  Subscribe subscribe = 9;
+  Connect connect = 10;
+  Disconnect disconnect = 11;
+  Refresh refresh = 12;
 }

So publication in channel will look:

{"push":{"channel":"test","pub":{"data":{"input":"i"}}}}

instead of current:

{"result":{"channel":"test","data":{"data":{"input":"i"}}}}

And similar changes for requests.

Why?

  • Better introspection of messages written into connection in OnTransportWrite callback - no need to decode to get contents.
  • Removing many complicated pieces currently used to make serialization fast (buffer pools, byte slice pools)
  • Constructing messages will be more straighforward
  • More readable JSON representation

Performance

Overall the performance should be a bit faster for proposed schema as shown below. But while new structure is faster in terms of serialization speed it involves more allocs on heap since more pointer types escape from function inside Reply object on marshaling. For unmarshaling we benefit in both allocs and speed.

BenchmarkReplyJSONMarshal-12                      	 2218264	       540.1 ns/op	     816 B/op	       3 allocs/op
BenchmarkReplyJSONMarshalNew-12                   	 2512666	       470.6 ns/op	     752 B/op	       4 allocs/op

BenchmarkReplyJSONMarshalParallel-12              	 4736026	       254.9 ns/op	     817 B/op	       3 allocs/op
BenchmarkReplyJSONMarshalParallelNew-12           	 6682945	       176.6 ns/op	     752 B/op	       4 allocs/op

BenchmarkReplyJSONUnmarshal-12                    	 3032642	       395.2 ns/op	     328 B/op	       3 allocs/op
BenchmarkReplyJSONUnmarshalNew-12                 	 4051048	       285.7 ns/op	     304 B/op	       2 allocs/op

BenchmarkReplyJSONUnmarshalParallel-12            	10702466	       113.4 ns/op	     328 B/op	       3 allocs/op
BenchmarkReplyJSONUnmarshalParallelNew-12         	12536810	        86.55 ns/op	     304 B/op	       2 allocs/op

BenchmarkReplyProtobufMarshal-12                  	 4115287	       288.6 ns/op	     752 B/op	       3 allocs/op
BenchmarkReplyProtobufMarshalNew-12               	 4451221	       265.2 ns/op	     720 B/op	       4 allocs/op

BenchmarkReplyProtobufMarshalParallel-12          	 7056967	       160.2 ns/op	     752 B/op	       3 allocs/op
BenchmarkReplyProtobufMarshalParallelNew-12       	10134794	       119.0 ns/op	     720 B/op	       4 allocs/op

BenchmarkReplyProtobufUnmarshal-12               	 5471642	       207.9 ns/op	     320 B/op	       4 allocs/op
BenchmarkReplyProtobufUnmarshalNew-12            	 6323160	       182.9 ns/op	     309 B/op	       3 allocs/op

BenchmarkReplyProtobufUnmarshalParallel-12       	16424490	        69.96 ns/op	     320 B/op	       4 allocs/op
BenchmarkReplyProtobufUnmarshalParallelNew-12    	18111056	        63.67 ns/op	     309 B/op	       3 allocs/op

Also benchmark in centrifuge-go repo shows CPU reduction, the bigger payload size the bigger CPU drop.

Not a one of?

There is a problem with easyjson message generation – so we should most probably go without oneof.

Backwards compatibility

I don't want to break existing clients. Client connectors most probably need to support both protocol formats for some time. Old approach will be deprecated - but it should be possible to support old format using an option on the server.