Linux服務器 | 服務器模型與三個模塊、兩種并發模式:半同步/半異步、領導者/追隨者

文章目錄

  • 兩種服務器模型及三個模塊
    • C/S模型
    • P2P模型
    • I/O處理單元、邏輯單元、存儲單元
  • 并發
    • 同步與異步
    • 半同步/半異步模式
      • 變體:半同步/半反應堆模式
      • 改進:高效的半同步/半異步模式
    • 領導者/追隨者模式
      • 組件 :句柄集、線程集、事件處理器
      • 工作流程


兩種服務器模型及三個模塊

C/S模型

即常說的 客戶端/服務器 模型,將資源(視頻、文本、圖片、軟件等)提供者視作服務器,資源請求者視為客戶端。

由于客戶端連接請求(connect函數)是隨機到達的異步事件,服務器需要使用某種 I/O模型 來監聽這一事件。例如 I/O復用技術之一的 select系統調用:當監聽到連接請求后,服務器就調用 accept函數 接收它,并分配一個 邏輯單元(新創建的子進程、子線程等) 管理這個新連接。

工作流程如下圖所示:
在這里插入圖片描述

服務器在處理一個客戶請求的同時還要繼續監聽其他客戶請求,否則就變成了效率低下的串行服務器了(必須先處理完前一個客戶的請求,才能繼續處理下一個客戶請求)。這一點上圖中是通過 select系統調用 實現的。

  • 優點: 實現簡單、適合資源相對集中的場合。
  • 缺點: 服務器是通信的中心,當訪問量過大時,可能所有客戶都將得到很慢的響應。

P2P模型

為了解決 C/S模型 的缺點而誕生,P2P(Peer to Peer,點對點)模型C/S模型 更符合網絡通信的實際情況。摒棄了以服務器為中心的格局,讓網絡上所有主機重新回歸對等的地位。

  • 優點: 每臺機器在消耗服務的同時給別人提供服務,這樣資源能夠充分、自由地共享。(P2P模型的典范:云計算機群)
  • 缺點: 用戶之間傳輸的請求過多時,網絡的負載將加重。

P2P模型的實現: 主機之間很難互相發現,所以實際使用時通常帶有一個專門的發現服務器,其還提供查找服務(甚至還可以提供內容服務),使每個客戶都能盡快地找到自己需要的資源。

在這里插入圖片描述


I/O處理單元、邏輯單元、存儲單元

可以將服務器解構為三個主要模塊:
在這里插入圖片描述

模塊單個服務器程序服務器機群
I/O處理單元等待并接受新的客戶連接、讀寫網絡數據,將服務器響應數據返回給客戶端。作為接入服務器,實現負載均衡,從所有邏輯服務器中選取負荷最小的一臺來為新客戶服務。
邏輯單元通常是一個進程或線程,處理客戶數據并將結果傳遞給 I/O 處理單元或者直接發送給客戶端(取決于事件處理模式)一臺邏輯服務器
網絡存儲單元本地數據庫、文件或緩存數據庫服務器
請求隊列各單元間的通信方式各服務器間的永久的、靜態的TCP連接,避免了動態TCP連接導致的額外系統開銷。

實際編程中,I/O處理單元常被稱作主線程,邏輯單元常被稱為工作線程。

值得注意的是:

  • 服務器通常擁有多個邏輯單元,以實現對多個客戶任務的并行處理。
  • 網絡存儲單元不是必須的,如 sshtelnet等登陸服務就不需要這個單元。
  • 請求隊列通產被實現為池的一部分,是各個單元之間的通信方式的抽象。

并發

缺點與優點:

  • 缺點: 如果程序是計算密集型,并發編程引起的任務切換反而使得效率降低。(任務切換耗時大于計算耗時)
  • 優點: 如果程序是I/O密集型,由于I/O操作耗時遠大于CPU計算耗時,因此如果程序阻塞于I/O操作將浪費大量CPU時間,解決方法是:當前被I/O操作阻塞的執行線程可以主動放棄CPU(或由操作系統調度),將執行權轉移到其他線程。此時并發引起的任務切換可以大大提高CPU利用率。

并發模式: I/O處理單元和多個邏輯單元之間協調完成任務的方法。

服務器主要有兩種并發編程模式:半同步/半異步模式(half-sync/half-async)、領導者/追隨者模式(Leader/Followers)。


同步與異步

  • I/O模型中,同步 or 異步 區分的是內核向應用程序通知的是 I/O就緒事件 or I/O完成事件,以及由 應用程序 還是 內核 來完成I/O讀寫。(詳見兩種高效事件處理模式一文)
  • 并發模式中,同步程序完全按照代碼序列的順序執行異步程序的執行需要由系統事件(中斷、信號等)來驅動

在這里插入圖片描述


半同步/半異步模式

按照同步/異步方式運行的線程被稱為同步線程/異步線程

  • 同步線程: 效率低、實時性差,但邏輯簡單。
  • 異步線程: 效率高、實時性強,但編程復雜且難于調試、擴展。

服務器同時使用同步線程和異步線程實現,即半同步/半異步模式。

工作流程:

  • 同步線程用于處理客戶邏輯(類似于工作線程)、異步線程用于處理注冊的I/O事件(類似于主線程)。
  • 異步線程監聽到客戶請求后,就將其封裝成一個請求對象并插入請求隊列中。
  • 請求隊列通知某個同步模式的工作線程來讀取并處理該請求對象。

在這里插入圖片描述


變體:半同步/半反應堆模式

結合兩種事件處理模式和幾種I/O模型的話,半同步/半異步模式就存在多種變體,其中一種稱為半同步/半反應堆half-sync/half-reactive)模式。

在這里插入圖片描述

工作流程

  • 異步線程只有一個,由主線程充當,負責監聽所有 socket 上的事件。
  • 如果 監聽 socket 上有可讀事件發生時(即有新的連接請求到來),主線程就接受新的 socket 連接,然后往 epoll 內核事件表中注冊該 socket 上的讀寫事件。
  • 如果接受的 連接 socket 上有讀寫事件發生(上一步注冊的),即 有新的客戶請求到了 or 有數據要發送到客戶端,主線程就將該 socket 連接 插入請求隊列中。
  • 所有的工作線程都睡眠在請求隊列上,當有任務到來時(就緒的 socket 連接被插入請求隊列中,這說明半同步/半反應堆模式采用的事件處理模式是 Reactor 模式),所有空閑工作線程通過競爭(比如申請互斥鎖)獲取任務的接管權。

事件處理模式的選擇

  • 采用 Reactor 模式意味著 工作線程 要負責 讀寫工作:既要 socket 上讀取客戶請求 ,還要 socket 寫入服務器應答 。這也是名稱中 半反應堆 的含義。
  • 當然,半同步/半反應堆模式也可以使用模擬的 Proactor 事件處理模式,即由主線程來完成數據的讀寫:
    1. 此時,主線程會將應用程序數據、任務類型等信息封裝為一個任務對象,然后將任務對象(或者是指向該任務對象的一個指針)插入請求隊列。
    2. 工作線程從請求隊列中取得任務對象之后,即可直接處理客戶請求,無須執行讀寫操作了。

缺點

  1. 主線程和工作線程共享請求隊列。 主線程往請求隊列中添加任務,或者工作線程從請求隊列中取出任務,都需要對請求隊列加鎖保護,從而白白耗費CPU時間。
  2. 每個工作線程在同一時間只能處理一個客戶請求。 如果客戶數量較多,而工作線程較少,則請求隊列中將堆積很多任務對象,客戶端的響應速度越來越慢。如果增加工作線程,則又會耗費大量CPU時間。

總而言之,耗費CPU時間。


改進:高效的半同步/半異步模式

針對上面提到的第二個缺點,可以讓每個工作線程都能同時處理多個客戶連接:
在這里插入圖片描述

工作流程:

  1. 主線程 只管理 監聽 socket連接 socket工作線程 來負責:當有新的連接 socket 到來時,主線程就接受之并將其派發給某個工作線程,此后該新 socket 上的任何IO操作都由被選中的工作線程來處理,直到客戶關閉連接。
  2. 主線程向工作線程派發 socket 的最簡單的方式,是往它和工作線程之間的管道里寫數據。工作線程檢測到管道上有數據可讀時,就分析是否是一個新的客戶連接請求到來。如果是,則把該新 socket 上的讀寫事件注冊到自己的 epoll 內核事件表中。(注冊這件事本來是主線程在做)

PS: 事實上,每個線程(主線程和工作線程)都維持自己的事件循環,它們各自獨立地監聽不同的事件,每個線程都工作在異步模式,所以它并非嚴格意義上的半同步/半異步模式。


領導者/追隨者模式

領導者/追隨者模式是:多個工作線程輪流獲得事件源集合,輪流監聽、分發并處理事件的一種模式。

  • 領導者: 在任意時間點中,程序都只會有一個領導者線程,它負責進行I/O事件的監聽
  • 追隨者: 而其他的線程則為追隨者線程,他們休眠在線程池中,等待成為新的領導者
  • 工作流程: 如果當前的領導者檢測到I/O事件,首先要從線程池中推選出新的領導者線程等待新的I/O事件的到來,然后舊的領導者處理I/O事件,以此實現并發。

用通俗點的方法來講就像是一群在營地中輪流放哨的哨兵,每次都會有一個人在值班,而其他人去休息。當值班者發現有什么特殊情況的時候就會去讓領班叫醒一個哨兵來繼續放哨,然后自己去探查情況。如果探查情況完后沒人值班,則自己繼續盯梢,否則就去休息。


組件 :句柄集、線程集、事件處理器

領導者/追隨者模式包含的組件有:句柄集(HandleSet)、線程集(ThreadSet)、事件處理器(EventHandler),之間的關系如圖所示:
在這里插入圖片描述


句柄集

  • 句柄(Handle 用于表示I/O資源,在 Linux 下通常就是一個文件描述符。
  • 句柄集 其實就是句柄的監控管理集合,通過調用 wait_for_event 方法來監聽這些句柄上的I/O事件,并將其中的就緒事件通知給領導者線程,而領導者線程則調用綁定Handle 上的事件處理器來處理事件。綁定是通過調用句柄集中的 register_handle 方法實現的。

線程集

線程集是所有工作線程(包括領導者和追隨者)的管理者。它負責各線程之間的同步,以及新領導者線程的推選。

線程集中的線程在任意時間都必然處于下面三種狀態之一:

  • 領導者(Leader): 線程處于領導者身份,負責監聽句柄集上的I/O事件
  • 事件處理中(Processing): 線程正在處理事件。領導者檢測到I/O事件后,轉移到 Processing 狀態進行事件的處理,并且調用 promote_new_leader 推選新的領導者。如果不想讓出領導者的地位,也可以指定其他的追隨者來處理事件(Event Handoff)。當處于 Processing 狀態的線程處理完事件之后,如果當前線程集中沒有領導者,他就會成為新的領導者,否則就直接變為追隨者。
  • 追隨者(Follower): 線程此時處于追隨者身份,此時處于休眠狀態,通過調用線程集的 join 等待被推選為新的領導者,也可能被當前的領導者指定處理新的任務。

狀態轉移圖:
在這里插入圖片描述

PS

領導者推選新的領導者追隨者等待成為新的領導者 這兩個操作都將修改線程集,因此線程集提供一個成員 Synchronizer 來同步這兩個操作,以避免竟態條件。


事件處理器

  • 事件處理器通常包含一個或者多個回調函數 handle_event,用于處理事件對應的業務邏輯。
  • 事件處理器在使用前首先需要被綁定到某個句柄之上,每當該句柄上有事件發生的時候,領導者就執行與之綁定的事件處理器中的回調函數。
  • 具體的事件處理器需要重新實現基類的 handle_event 方法,以處理特定任務。

工作流程

在這里插入圖片描述

PS

  • 由于領導者線程自己監聽I/O事件并且處理客戶請求,所以在本模式中不需要在線程之間傳遞任何額外的數據,也不需要像半同步/半反應堆模式那樣在線程之間同步對請求隊列的訪問。(CPU耗時低
  • 但是也有一個明顯的缺點就是只能支持一個事件源集合,因此無法像高效的半同步/半異步模式那樣讓每個工作線程獨立地管理多個客戶連接

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/443720.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/443720.shtml
英文地址,請注明出處:http://en.pswp.cn/news/443720.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

香農信息熵之可憐的小豬

文章目錄題目解析香農熵公式樣例具體分析代碼題目 有 n 桶液體,其其中 正好 有一桶含有毒藥,其裝的都是水。它們從外觀看起來都一樣。為了弄清楚哪只水桶含有毒藥,你可以喂一些豬喝,通過觀察豬是否會死進行判斷,實驗對…

字符串匹配之KMP(KnuthMorrisPratt)算法(圖解)

文章目錄最長相等前后綴next數組概念代碼實現圖解GetNext中的回溯改進代碼實現代碼復雜度分析最長相等前后綴 給出一個字符串 ababa 前綴集合:{a, ab, aba, abab} 后綴集合:{a, ba, aba, baba} 相等前后綴 即上面用同樣顏色標識出來的集合元素&#…

linux下tomcat6.0與jdk安裝詳細步驟

安裝Tomcat6.0和JDK1.6 在linux系統上安裝tomcat和jdk應該說是我學習linux知識的第一課了,之前只 是聽說過,從沒接觸過,但我們公司項目都是部署在linux系統上的,那天上司突 然給我發了幾個文檔,讓我看一下&#xff…

Android入門(一) | Android Studio的配置與使用

文章目錄安裝配置Android Studio使用Android Studio模擬器更改Android SDK的路徑Hello World!安裝配置Android Studio 從這一步開始: 一直點 next 即可,直到存儲路徑的選擇上,可以放到非 C 盤,這里我放到 D 盤了&am…

Android 入門(四) | Intent 實現 Activity 切換

文章目錄Intent顯式 Intent定義兩個 xml 文件android:orientationmatch_parent 和 wrap_contentIntent函數定義兩個 Activity隱式 Intent更多隱式 Intent 的用法用隱式 Intent 打開系統瀏覽器自建 Activity 以響應打開網頁的 Intent向下一個活動傳遞數據返回數據給上一個活動In…

Android入門(二) | 項目目錄及主要文件作用分析

文章目錄項目目錄分析app目錄分析AndroidManifest.xml 分析MainActivity.kt 分析build.gradle 分析最外層目錄下的 build.gradleapp 目錄下的 build.gradle項目目錄分析 我們來看一下 src/main/res 下的一些文件: .gradle 和 .idea :這兩個目錄下放置…

Android入門(三) | Android 的日志工具 Logcat

文章目錄日志工具類 android.util.LogLogcat 中的過濾器日志工具類 android.util.Log Log 從屬日志工具類 android.util.Log ,該類提供了五個方法供我們打印日志: Log.v() :用于打印那些最為瑣碎的、意義最小的日志信息。對應級別 verbose&…

Android 客戶端與服務器交互方式

突然想到一個問題就是Android客戶端與服務器交互有幾種方式,因為在腦袋里想當然的就是webservices和json。要在Android手機客戶端與pc服務器交互,需要滿足下面幾種條件:跨平臺、傳輸數據格式標準、交互方便...。 為了與服務器通訊其實無非就…

Android入門(五) | Activity 的生命周期

文章目錄Activity 的狀態及生命周期實現管理生命周期FirstActivitySecondActivityDialogActivity運行結果舊活動被回收了還能返回嗎?Activity 的狀態及生命周期 Android 的應用程序運用 棧(Back Stack) 的思想來管理 Activity: …

Android入門(六) | Activity 的啟動模式 及 生產環境中關于 Activity 的小技巧

文章目錄Activity 的啟動模式standardsingleTopsingleTasksingleInstance技巧了解當前界面是哪個 Activity隨時隨地退出程序啟動活動的最佳寫法Activity 的啟動模式 standard:默認的啟動方式,每次啟動一個活動都會重新創建singleTop:如果該活…

Android入門(七) | 常用控件

文章目錄TextView 控件:文本信息Button 控件:按鈕EditText 控件:輸入框ImageView 控件:圖片ProgressBar 控件:進度條AlertDialog 控件:提示框ProgressDialog 控件:帶有進度條的提示框TextView 控…

Android入門(八) | 常用的界面布局 及 自定義控件

文章目錄LinearLayout :線性布局android:layout_gravity :控件的對齊方式android:layout_weight:權重RelativeLayout :相對布局相對于父布局進行定位相對于控件進行定位邊緣對齊FrameLayout :幀布局Percent &#xff1…

Android入門(九)| 滾動控件 ListView 與 RecyclerView

文章目錄ListView內置類型的簡單運用定制數據類型提升效率點擊事件RecyclerView布局管理器點擊事件ListView 內置類型的簡單運用 由于手機屏幕空間有限,能夠一次性在屏幕上顯示的內容不多,當我們的程序有大量數據需要顯示的時候就可以借助 ListView 來…

關于“三門問題”的一些想法

三門問題(Monty Hall problem)亦稱為蒙提霍爾問題、蒙特霍問題或蒙提霍爾悖論,大致出自美國的電視游戲節目Let’s Make a Deal。問題名字來自該節目的主持人蒙提霍爾(Monty Hall)。參賽者會看見三扇關閉了的門&#xf…

Android入門(10)| Fragment碎片詳解

文章目錄為什么要使用碎片(Fragment)實例布局文件FragmentActivity動態添加碎片布局文件FragmentActivity碎片通信Fragment布局文件Activity生命周期為什么要使用碎片(Fragment) 我們在手機上看新聞可能是這樣的: Re…

Android開發(1) | Fragment 的應用——新聞應用

文章目錄Item&#xff1a;標題子項布局文件Java代碼標題碎片布局文件Java代碼新聞內容碎片布局文件Java代碼新聞內容活動布局文件Java代碼首界面布局文件Java代碼Item&#xff1a;標題子項 布局文件 news_item.xml&#xff1a; <TextViewxmlns:android"http://schema…

Java Web整體異常處理

在實際的J2EE項目中&#xff0c;系統內部難免會出現一些異常&#xff0c;就如StrutsSpringHibernate項目&#xff1a;通常一個頁面請求到達后臺以后&#xff0c;首先是到action&#xff08;就是MVC中的controller&#xff09;&#xff0c;在action層會調用業務邏輯層service&am…

Android入門(11)| 全局廣播與本地廣播

文章目錄廣播概念接收廣播動態注冊實例靜態注冊實例發送廣播發送標準廣播廣播的跨進程特性發送有序廣播本地廣播廣播概念 Android 中的每個應用程序都可以對自己感興趣的廣播進行注冊&#xff0c;這樣該程序就只會接收到自己所關心的廣播內容&#xff0c;這些廣播可能是來自系…

Android開發(2) | 廣播 Broadcast 的應用——強制下線功能

文章目錄功能簡介關閉所有活動登陸界面發送強制下線的廣播廣播接收器AndroidManifest.xml運行結果功能簡介 強制下線功能只需要彈出一個對話框&#xff0c;讓用戶只能點擊確定按鈕&#xff0c;回到登錄界面。 如果在每一個活動中添加一個對話框的話太過繁瑣&#xff0c;用廣播…

Android入門(12)| 數據持久化

文章目錄數據持久化文件存儲將數據存儲進文件實例從文件中讀取數據實例SharedPreferences存儲將數據存儲進文件實例從文件中讀取數據實例實現記住密碼的功能SQLite數據庫存儲創建自己的幫助類調用自己的幫助類補全 onUpgrade() 方法增刪查改增&#xff1a;SQLiteDatabase.inser…