溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶(hù)服務(wù)條款》

Ranch模塊的作用是什么

發(fā)布時(shí)間:2021-07-30 15:18:12 來(lái)源:億速云 閱讀:211 作者:Leah 欄目:大數(shù)據(jù)

Ranch模塊的作用是什么,很多新手對(duì)此不是很清楚,為了幫助大家解決這個(gè)難題,下面小編將為大家詳細(xì)講解,有這方面需求的人可以來(lái)學(xué)習(xí)下,希望你能有所收獲。

ranch_listener_sup模塊

介紹

此模塊是ranch調(diào)用的一個(gè)模塊,用來(lái)處理所有的監(jiān)聽(tīng)和網(wǎng)絡(luò)連接中心。
該模塊的創(chuàng)建時(shí)由ranch:start_listener函數(shù)啟動(dòng)的基于監(jiān)督者進(jìn)程ranch_sup的子進(jìn)程

功能函數(shù)介紹

  • erlang的map結(jié)構(gòu) #{},#{name =>"test"} 注意區(qū)分兩種表達(dá)式: =>(可以用來(lái)更新映射和創(chuàng)建新的映射) :=(只能更新映射,在鍵不存在時(shí)會(huì)拋出異常)

  • start_link:創(chuàng)建supervisor進(jìn)程,并且將創(chuàng)建這個(gè)進(jìn)程的參數(shù)保存到ranch_server中。
    1.Ref 監(jiān)聽(tīng)者實(shí)例別名
    2.Transport socket進(jìn)程的創(chuàng)建者
    3.protocol 實(shí)際的功能執(zhí)行者

  • init:ranch_listener_sup進(jìn)程創(chuàng)建成功的調(diào)用函數(shù)。
    主要做了下面的事情:
    1.創(chuàng)建子進(jìn)程ranch_conns_sup,傳入的參數(shù)有Ref,Transport,Protocol三個(gè)。這個(gè)進(jìn)程的功能是管理所有的外部連接。
    2.創(chuàng)建子進(jìn)程ranch_acceptors_sup,傳入?yún)?shù)是Ref,Transport(可選兩種:tcp,ssl).這個(gè)進(jìn)程就是實(shí)際的對(duì)外端口監(jiān)聽(tīng)者
    3.將該進(jìn)程的{Ref,self()(自己的進(jìn)程pid)}存入到ranch_server
    4.進(jìn)程是以reset_for_one的方式啟動(dòng)這兩個(gè)進(jìn)程,則表明這兩個(gè)進(jìn)程是有依賴(lài)關(guān)系的。如果ranch_conns_sup掛了,則一定也會(huì)掛掉ranch_acceptors_sup,然后重新一次重啟這兩個(gè)進(jìn)程
    5.實(shí)際中,ranch_acceptors_sup的啟動(dòng)是依賴(lài)ranch_conns_sup進(jìn)程的,所以,必須ranch_conns_sup進(jìn)程必須先啟動(dòng)

ranch_conns_sup模塊

介紹

接受socket連接的進(jìn)程,創(chuàng)建Protocol進(jìn)程,并且監(jiān)控這些進(jìn)程的退出

功能函數(shù)介紹

  • start_link:這個(gè)進(jìn)程必須的,因?yàn)樵撨M(jìn)程是以supervisor創(chuàng)建的子進(jìn)程,必須有此函數(shù)。
    該進(jìn)程不是gen_server的標(biāo)準(zhǔn),而是采用原始的proc_lib:start_link創(chuàng)建的進(jìn)程,傳入的參數(shù)包括 父進(jìn)程id,Ref,Transport,Protocol

  • init:通過(guò)start_link函數(shù)調(diào)用本模塊的init函數(shù)。
    該函數(shù)做了一下的功能:
    1.設(shè)置process_flag(trap_exit,true),標(biāo)識(shí)是可以接受link模塊的退出信息
    2.設(shè)置{Ref,self()}到ranch_server保存數(shù)據(jù)
    3.從ranch_server和TransOpts中獲取相應(yīng)的初始化信息,并保存到loop循環(huán)的#state中
    4.proc_lib:init_ack(Parent, {ok, self()}) 這是是內(nèi)部的proc_lib的實(shí)現(xiàn),標(biāo)識(shí)告訴父進(jìn)程,進(jìn)程創(chuàng)建成功了,并會(huì)返回給父進(jìn)程一個(gè){ok,Pid(當(dāng)前創(chuàng)建進(jìn)程的pid)}

  • loop:執(zhí)行主要的邏輯
    1.{?MODULE,start_protocol, To, Socket}:socket收到連接,發(fā)送該進(jìn)程,創(chuàng)建Protocol進(jìn)程。在此進(jìn)程創(chuàng)建的時(shí)候需要注意,實(shí)例進(jìn)程創(chuàng)建進(jìn)程的返回值一定要注意,{ok, Pid}表示自己對(duì)自己進(jìn)程關(guān)閉負(fù)責(zé),而{ok,SupPid,ProtocolPid}則表示,該進(jìn)程是有一個(gè)conns_sup進(jìn)程來(lái)管理這些啟動(dòng)的進(jìn)程。此處ranch是提供了兩種方法來(lái)處理。
    2.{?MODULE,active_connections,To,Tag}:獲取該進(jìn)程激活的連接數(shù)
    3.{remove_connection, Ref,Pid}:移除連接,此處注意,當(dāng)前只是計(jì)數(shù)減一,并沒(méi)有真正的關(guān)閉進(jìn)程 4.{set_max_conns}:重新設(shè)置最大的連接數(shù),如果sleeper里面有數(shù)據(jù),則會(huì)將這些鏈接重新啟用 5.{‘EXIT’,Parent,Reason}:此處Parent指的是ranch_listener_sup進(jìn)程,如果父進(jìn)程關(guān)閉,則無(wú)條件的關(guān)閉啟動(dòng)的所有連接進(jìn)程
    6.{'EXIT',Pid,Reason}:link的進(jìn)程關(guān)閉了,則清理pid.此處要注意,該進(jìn)程link的pid不能設(shè)置process_flag(trap_exit,true),負(fù)責(zé)就不會(huì)收到此斷開(kāi)信息。如果有睡眠的連接進(jìn)程等待,則激活這些連接進(jìn)程。
    7.{system,From,Request}:調(diào)用系統(tǒng)的指令.gen_server的terminate,code_change函數(shù)都和此有關(guān)系。目前看到的支持3中大類(lèi),1.suspended 掛起 2.running 獲取一些模塊的信息 3.terminating 關(guān)閉進(jìn)程
    8.{'$gen_call', {To, Tag}, Request(which_children,count_children)}:To:標(biāo)識(shí)是From,即發(fā)起者的進(jìn)程pid,Tag=erlang:monitor(process,Process)即發(fā)起者監(jiān)聽(tīng)接受方的MRef信息,在收到信息后,取消monitor,并返回信息。并且此種請(qǐng)求時(shí)通過(guò)同步的方式請(qǐng)求。具體的調(diào)用方法是:gen_server:call(SupPid,which_children)的方式請(qǐng)求

  • start_protocol:此方法由socket進(jìn)程發(fā)起,同步創(chuàng)建實(shí)例,執(zhí)行l(wèi)oop的第一種情況

  • active_connections:同步請(qǐng)求活躍的連接數(shù),和loop的第8中情況相似,也可以已第8種情況替代

  • handshake:此方法大調(diào)用于loop的第1中情況,將啟動(dòng)的實(shí)例進(jìn)程pid和socket進(jìn)行綁定。并且驗(yàn)證,啟動(dòng)實(shí)例。如果當(dāng)前的連接數(shù)已滿(mǎn),則阻塞住socket進(jìn)程。如果條件滿(mǎn)足,則確認(rèn)綁定成功。

  • terminate(#stat{shutdown=brutal_kill},Reason,):關(guān)閉此進(jìn)程,此函數(shù)是有system觸發(fā)的,system_terminate()函數(shù)調(diào)用terminate,直接結(jié)束。brutal_kill標(biāo)識(shí)是直接kill掉。

  • terminate(#state{shutdown=integer()}):表示是非直接關(guān)閉,等待進(jìn)程的自我了斷。

  • kill_children:直接殺死進(jìn)程,殺死前unlinke(Pid),避免收到進(jìn)程殺死的信息

  • shutdown_children,wait_children:這兩個(gè)函數(shù)時(shí)相互配合使用的,在exit(P,shutdown)成功時(shí),會(huì)收到wait_children的{‘DOWN,,process,Pid,’}的信息,顯示的知道有多少個(gè)進(jìn)程被中斷。

  • system_continue,system_terminate,system_code_change:這三個(gè)函數(shù),是配合system的命令在sys模塊默認(rèn)調(diào)用的,目前來(lái)看,主要有3個(gè)功能,system_continue:用來(lái)獲取一些進(jìn)程的信息;system_terminate:用來(lái)系統(tǒng)中斷進(jìn)程;system_code_change:用來(lái)進(jìn)程一些數(shù)據(jù)的更新處理

  • report_error:對(duì)錯(cuò)誤寫(xiě)日志記錄

ranch_acceptors_sup 連接接受監(jiān)督者模塊

介紹

設(shè)置監(jiān)聽(tīng)socket,將此socket同時(shí)分發(fā)給ranch_accpetor 接受者,監(jiān)聽(tīng)連接

函數(shù)分析

  • start_link:啟動(dòng)進(jìn)程的入口,使用supervisor的模式啟動(dòng)進(jìn)程

  • init:1.獲取連接監(jiān)督者,獲取Transport的配置信息,更具配置的監(jiān)聽(tīng)連接數(shù),通過(guò)one_for_one的方式創(chuàng)建一定數(shù)量的監(jiān)聽(tīng)連接進(jìn)程,來(lái)監(jiān)聽(tīng)外部連接

  • recevie 的機(jī)制

%% 通過(guò)設(shè)置receive after 0,優(yōu)先處理{alarm,X}的消息。因?yàn)樵诔瑫r(shí)時(shí)間為0的receive中,會(huì)立即觸發(fā)一個(gè)超時(shí),但是在此之前,
系統(tǒng)會(huì)嘗試對(duì)郵箱進(jìn)行模式匹配,所以此方法,可以對(duì)消息優(yōu)先處理,可以用于清空郵箱中的所有消息。
1.優(yōu)先匹配例子
priority_receive()->  
    receive
      {alarm,X}->
    after 0->
            receive
        Any->
         Any
      end
    end.
2.清空郵箱所有消息
flush(Logger) ->
	receive Msg ->
		ranch:log(warning,
			"Ranch acceptor received unexpected message: ~p~n",
			[Msg], Logger),
		flush(Logger)
	after 0 ->
		ok
	end.
  • 拓展:為什么在call一個(gè)進(jìn)程時(shí),timeout了,但是call 的進(jìn)程也會(huì)執(zhí)行完消息處理?

節(jié)選自gen.erl
do_call(Process, Label, Request, Timeout) ->
    try erlang:monitor(process, Process) of
	Mref ->
	    %% If the monitor/2 call failed to set up a connection to a
	    %% remote node, we don't want the '!' operator to attempt
	    %% to set up the connection again. (If the monitor/2 call
	    %% failed due to an expired timeout, '!' too would probably
	    %% have to wait for the timeout to expire.) Therefore,
	    %% use erlang:send/3 with the 'noconnect' option so that it
	    %% will fail immediately if there is no connection to the
	    %% remote node.

	    catch erlang:send(Process, {Label, {self(), Mref}, Request},
		  [noconnect]),
	    receive
		{Mref, Reply} ->
		    erlang:demonitor(Mref, [flush]),
		    {ok, Reply};
		{'DOWN', Mref, _, _, noconnection} ->
		    Node = get_node(Process),
		    exit({nodedown, Node});
		{'DOWN', Mref, _, _, Reason} ->
		    exit(Reason)
	    after Timeout ->
		    erlang:demonitor(Mref, [flush]),
		    exit(timeout)
	    end
    catch
	error:_ ->
	    %% Node (C/Java?) is not supporting the monitor.
	    %% The other possible case -- this node is not distributed
	    %% -- should have been handled earlier.
	    %% Do the best possible with monitor_node/2.
	    %% This code may hang indefinitely if the Process 
	    %% does not exist. It is only used for featureweak remote nodes.
	    Node = get_node(Process),
	    monitor_node(Node, true),
	    receive
		{nodedown, Node} -> 
		    monitor_node(Node, false),
		    exit({nodedown, Node})
	    after 0 -> 
		    Tag = make_ref(),
		    Process ! {Label, {self(), Tag}, Request},
		    wait_resp(Node, Tag, Timeout)
	    end
    end.

從上面代碼中可以看到,是在本地進(jìn)程monitor了被call的進(jìn)程,并且erlang:send的方式發(fā)送信息,此時(shí)再receive一個(gè)阻塞等待結(jié)果返回,然后再TimeOut的時(shí)候,如果還沒(méi)有返回,則返回給進(jìn)程exit(timeout)的錯(cuò)誤信息。所以,就會(huì)出現(xiàn),雖然timeout了,被調(diào)的進(jìn)程還是會(huì)處理完,而不能當(dāng)作被調(diào)進(jìn)程沒(méi)有收到處理。
如何避免?:1,從源頭避免,確保call的進(jìn)程處理信息足夠簡(jiǎn)單,不超時(shí) 2.采用cast,或 ! 替代處理
參考網(wǎng)址:Erlang中帶超時(shí)的receive

ranch_acceptor模塊

簡(jiǎn)介

此模塊用來(lái)接收外部的socket連接。并通知ranch_conns_sup通知業(yè)務(wù)進(jìn)程啟動(dòng)并且綁定到該socket進(jìn)程

函數(shù)介紹

  • start_link:次數(shù)采用原始的spawn_link函數(shù)啟動(dòng)一個(gè)進(jìn)程,返回{ok, Pid}

  • loop:1.通過(guò)Transport:accept阻塞進(jìn)程,直到接收到一個(gè)連接進(jìn)來(lái),然后綁定該連接的socket先到connsSup上,然后調(diào)用ranch_conns_sup:start_protocol啟動(dòng)一個(gè)實(shí)例進(jìn)程,進(jìn)行綁定。
    {ok, CSocket}:標(biāo)識(shí)連接成功,并且創(chuàng)建了一個(gè)連接的socket,進(jìn)行啟動(dòng)和綁定操作
    {error,emfile}:大量的并發(fā)操作調(diào)用,導(dǎo)致操作系統(tǒng)的文件描述符數(shù)量被瞬間用完,拋出emfile.此處應(yīng)為會(huì)同時(shí)創(chuàng)建多個(gè)連接進(jìn)程,和多個(gè)外部的socket連接,則必然會(huì)出現(xiàn)此種情況。在晚上看到過(guò),有人在使用了1024個(gè)連接,https之后,就會(huì)出現(xiàn)問(wèn)題,導(dǎo)致連接不成功。貼上網(wǎng)址如下:http://erlang.org/pipermail/erlang-questions/2015-January/082446.html
    {error,closed}:表明listening socket 關(guān)閉了
    ?MODULE:loop(_):此方法是可以保證,在版本更新時(shí),總是調(diào)用到最新的模塊函數(shù)

  • flush:每一次循環(huán)是,都清空掉該進(jìn)程接收到的其他非accepotr消息

  • 關(guān)于連接出現(xiàn){error,emfile}的問(wèn)題:
    1.此錯(cuò)誤標(biāo)識(shí)同時(shí)創(chuàng)建了多個(gè)鏈接進(jìn)程,導(dǎo)致操作系統(tǒng)的文件描述符數(shù)量被瞬間用完導(dǎo)致。
    2.有兩種I/O處理,一個(gè)異步和一個(gè)同步。異步I/O下,這個(gè)會(huì)比較容易實(shí)現(xiàn),需要給予一定的過(guò)載保護(hù),防止過(guò)分壓榨底層系統(tǒng)的性能。
    3.兩種方式:1、設(shè)置 ulimit -n 10480 2.修改 /etc/security/limit.conf文件的句柄數(shù)量

        limit.conf 
        #<domain>      <type>  <item>         <value>
        #
    
        #*               soft    core            0
        #*               hard    rss             10000
        #@student        hard    nproc           20
        #@faculty        soft    nproc           20
        #@faculty        hard    nproc           50
        #ftp             hard    nproc           0
        #@student        -       maxlogins       4
    
        * soft nproc 65535
        * hard nproc 65535
        * soft nofile 65535
        * hard nofile 65535
        # End of file


4.參考網(wǎng)址:
[erlang-questions] {error,emfile}
從EMFILE和ENFILE說(shuō)起,fd limit的問(wèn)題(一)
EMFILE,too many open files的解決方案

此處記錄問(wèn)題:

  • 1.如果設(shè)置cert密匙,客戶(hù)端是如何發(fā)送的,并且服務(wù)器又是如何驗(yàn)證的

看完上述內(nèi)容是否對(duì)您有幫助呢?如果還想對(duì)相關(guān)知識(shí)有進(jìn)一步的了解或閱讀更多相關(guān)文章,請(qǐng)關(guān)注億速云行業(yè)資訊頻道,感謝您對(duì)億速云的支持。

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI