Merge pull request #13363 from rabbitmq/loic-dynamic-buffer
Add dynamic socket buffer functionality to rabbit_reader
This commit is contained in:
		
						commit
						6c3789ee9a
					
				|  | @ -59,7 +59,10 @@ | |||
|          buf :: list(), | ||||
|          buf_len :: non_neg_integer(), | ||||
|          tracked_channels = maps:new() :: #{channel_number() => Session :: pid()}, | ||||
|          stats_timer :: rabbit_event:state() | ||||
|          stats_timer :: rabbit_event:state(), | ||||
|          %% dynamic buffer | ||||
|          dynamic_buffer_size = 128, | ||||
|          dynamic_buffer_moving_average = 0.0 | ||||
|         }). | ||||
| 
 | ||||
| -type state() :: #v1{}. | ||||
|  |  | |||
|  | @ -111,9 +111,10 @@ recvloop(Deb, State0 = #v1{recv_len = RecvLen, | |||
| mainloop(Deb, State = #v1{sock = Sock, buf = Buf, buf_len = BufLen}) -> | ||||
|     case rabbit_net:recv(Sock) of | ||||
|         {data, Data} -> | ||||
|             recvloop(Deb, State#v1{buf = [Data | Buf], | ||||
|                                    buf_len = BufLen + size(Data), | ||||
|                                    pending_recv = false}); | ||||
|             State1 = maybe_resize_buffer(State, Data), | ||||
|             recvloop(Deb, State1#v1{buf = [Data | Buf], | ||||
|                                     buf_len = BufLen + size(Data), | ||||
|                                     pending_recv = false}); | ||||
|         closed when State#v1.connection_state =:= closed -> | ||||
|             ok; | ||||
|         closed -> | ||||
|  | @ -130,6 +131,37 @@ mainloop(Deb, State = #v1{sock = Sock, buf = Buf, buf_len = BufLen}) -> | |||
|             end | ||||
|     end. | ||||
| 
 | ||||
| maybe_resize_buffer(State=#v1{sock=Sock, dynamic_buffer_size=BufferSize0, | ||||
|         dynamic_buffer_moving_average=MovingAvg0}, Data) -> | ||||
|     LowDynamicBuffer = 128, | ||||
|     HighDynamicBuffer = 131072, | ||||
|     DataLen = byte_size(Data), | ||||
|     MovingAvg = (MovingAvg0 * 7 + DataLen) / 8, | ||||
|     if | ||||
|         BufferSize0 < HighDynamicBuffer andalso MovingAvg > BufferSize0 * 0.9 -> | ||||
|             BufferSize = min(BufferSize0 * 2, HighDynamicBuffer), | ||||
|             case rabbit_net:setopts(Sock, [{buffer, BufferSize}]) of | ||||
|                 ok -> State#v1{ | ||||
|                     dynamic_buffer_size=BufferSize, | ||||
|                     dynamic_buffer_moving_average=MovingAvg | ||||
|                 }; | ||||
|                 {error, Reason} -> | ||||
|                     throw({inet_error, Reason}) | ||||
|             end; | ||||
|         BufferSize0 > LowDynamicBuffer andalso MovingAvg < BufferSize0 * 0.4 -> | ||||
|             BufferSize = max(BufferSize0 div 2, LowDynamicBuffer), | ||||
|             case rabbit_net:setopts(Sock, [{buffer, BufferSize}]) of | ||||
|                 ok -> State#v1{ | ||||
|                     dynamic_buffer_size=BufferSize, | ||||
|                     dynamic_buffer_moving_average=MovingAvg | ||||
|                 }; | ||||
|                 {error, Reason} -> | ||||
|                     throw({inet_error, Reason}) | ||||
|             end; | ||||
|         true -> | ||||
|             State#v1{dynamic_buffer_moving_average=MovingAvg} | ||||
|     end. | ||||
| 
 | ||||
| -spec handle_other(any(), state()) -> state() | stop. | ||||
| handle_other(emit_stats, State) -> | ||||
|     emit_stats(State); | ||||
|  |  | |||
|  | @ -32,7 +32,7 @@ | |||
|          close_connection/2, close_connections/2, close_all_connections/1, | ||||
|          close_all_user_connections/2, | ||||
|          force_connection_event_refresh/1, force_non_amqp_connection_event_refresh/1, | ||||
|          handshake/2, tcp_host/1, | ||||
|          handshake/2, handshake/3, tcp_host/1, | ||||
|          ranch_ref/1, ranch_ref/2, ranch_ref_of_protocol/1, | ||||
|          listener_of_protocol/1, stop_ranch_listener_of_protocol/1, | ||||
|          list_local_connections_of_protocol/1]). | ||||
|  | @ -551,6 +551,9 @@ failed_to_recv_proxy_header(Ref, Error) -> | |||
|     exit({shutdown, failed_to_recv_proxy_header}). | ||||
| 
 | ||||
| handshake(Ref, ProxyProtocolEnabled) -> | ||||
|     handshake(Ref, ProxyProtocolEnabled, static_buffer). | ||||
| 
 | ||||
| handshake(Ref, ProxyProtocolEnabled, BufferStrategy) -> | ||||
|     case ProxyProtocolEnabled of | ||||
|         true -> | ||||
|             case ranch:recv_proxy_header(Ref, 3000) of | ||||
|  | @ -560,23 +563,29 @@ handshake(Ref, ProxyProtocolEnabled) -> | |||
|                     failed_to_recv_proxy_header(Ref, Error); | ||||
|                 {ok, ProxyInfo} -> | ||||
|                     {ok, Sock} = ranch:handshake(Ref), | ||||
|                     ok = tune_buffer_size(Sock), | ||||
|                     ok = tune_buffer_size(Sock, BufferStrategy), | ||||
|                     {ok, {rabbit_proxy_socket, Sock, ProxyInfo}} | ||||
|             end; | ||||
|         false -> | ||||
|             {ok, Sock} = ranch:handshake(Ref), | ||||
|             ok = tune_buffer_size(Sock), | ||||
|             ok = tune_buffer_size(Sock, BufferStrategy), | ||||
|             {ok, Sock} | ||||
|     end. | ||||
| 
 | ||||
| tune_buffer_size(Sock) -> | ||||
|     case tune_buffer_size1(Sock) of | ||||
| tune_buffer_size(Sock, dynamic_buffer) -> | ||||
|     case rabbit_net:setopts(Sock, [{buffer, 128}]) of | ||||
|         ok         -> ok; | ||||
|         {error, _} -> rabbit_net:fast_close(Sock), | ||||
|                       exit(normal) | ||||
|     end; | ||||
| tune_buffer_size(Sock, static_buffer) -> | ||||
|     case tune_buffer_size_static(Sock) of | ||||
|         ok         -> ok; | ||||
|         {error, _} -> rabbit_net:fast_close(Sock), | ||||
|                       exit(normal) | ||||
|     end. | ||||
| 
 | ||||
| tune_buffer_size1(Sock) -> | ||||
| tune_buffer_size_static(Sock) -> | ||||
|     case rabbit_net:getopts(Sock, [sndbuf, recbuf, buffer]) of | ||||
|         {ok, BufSizes} -> BufSz = lists:max([Sz || {_Opt, Sz} <- BufSizes]), | ||||
|                           rabbit_net:setopts(Sock, [{buffer, BufSz}]); | ||||
|  |  | |||
|  | @ -99,7 +99,11 @@ | |||
|           %% throttling state, for both | ||||
|           %% credit- and resource-driven flow control | ||||
|           throttle, | ||||
|           proxy_socket}). | ||||
|           proxy_socket, | ||||
|           %% dynamic buffer | ||||
|           dynamic_buffer_size = 128, | ||||
|           dynamic_buffer_moving_average = 0.0 | ||||
| }). | ||||
| 
 | ||||
| -record(throttle, { | ||||
|   %% never | timestamp() | ||||
|  | @ -155,7 +159,8 @@ shutdown(Pid, Explanation) -> | |||
| init(Parent, HelperSups, Ref) -> | ||||
|     ?LG_PROCESS_TYPE(reader), | ||||
|     {ok, Sock} = rabbit_networking:handshake(Ref, | ||||
|         application:get_env(rabbit, proxy_protocol, false)), | ||||
|         application:get_env(rabbit, proxy_protocol, false), | ||||
|         dynamic_buffer), | ||||
|     Deb = sys:debug_options([]), | ||||
|     start_connection(Parent, HelperSups, Ref, Deb, Sock). | ||||
| 
 | ||||
|  | @ -512,8 +517,9 @@ mainloop(Deb, Buf, BufLen, State = #v1{sock = Sock, | |||
|     end, | ||||
|     case Recv of | ||||
|         {data, Data} -> | ||||
|             State1 = maybe_resize_buffer(State, Data), | ||||
|             recvloop(Deb, [Data | Buf], BufLen + size(Data), | ||||
|                      State#v1{pending_recv = false}); | ||||
|                      State1#v1{pending_recv = false}); | ||||
|         closed when State#v1.connection_state =:= closed -> | ||||
|             State; | ||||
|         closed when CS =:= pre_init andalso Buf =:= [] -> | ||||
|  | @ -536,6 +542,37 @@ mainloop(Deb, Buf, BufLen, State = #v1{sock = Sock, | |||
|             end | ||||
|     end. | ||||
| 
 | ||||
| maybe_resize_buffer(State=#v1{sock=Sock, dynamic_buffer_size=BufferSize0, | ||||
|         dynamic_buffer_moving_average=MovingAvg0}, Data) -> | ||||
|     LowDynamicBuffer = 128, | ||||
|     HighDynamicBuffer = 131072, | ||||
|     DataLen = byte_size(Data), | ||||
|     MovingAvg = (MovingAvg0 * 7 + DataLen) / 8, | ||||
|     if | ||||
|         BufferSize0 < HighDynamicBuffer andalso MovingAvg > BufferSize0 * 0.9 -> | ||||
|             BufferSize = min(BufferSize0 * 2, HighDynamicBuffer), | ||||
|             case rabbit_net:setopts(Sock, [{buffer, BufferSize}]) of | ||||
|                 ok -> State#v1{ | ||||
|                     dynamic_buffer_size=BufferSize, | ||||
|                     dynamic_buffer_moving_average=MovingAvg | ||||
|                 }; | ||||
|                 Error -> | ||||
|                     stop(Error, State) | ||||
|             end; | ||||
|         BufferSize0 > LowDynamicBuffer andalso MovingAvg < BufferSize0 * 0.4 -> | ||||
|             BufferSize = max(BufferSize0 div 2, LowDynamicBuffer), | ||||
|             case rabbit_net:setopts(Sock, [{buffer, BufferSize}]) of | ||||
|                 ok -> State#v1{ | ||||
|                     dynamic_buffer_size=BufferSize, | ||||
|                     dynamic_buffer_moving_average=MovingAvg | ||||
|                 }; | ||||
|                 Error -> | ||||
|                     stop(Error, State) | ||||
|             end; | ||||
|         true -> | ||||
|             State#v1{dynamic_buffer_moving_average=MovingAvg} | ||||
|     end. | ||||
| 
 | ||||
| -spec stop(_, #v1{}) -> no_return(). | ||||
| stop(tcp_healthcheck, State) -> | ||||
|     %% The connection was closed before any packet was received. It's | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue