1.1 應用架構

本課程專為初學者設計,因為您不會長時間設計嚴肅應用程序的架構。但別擔心,好的架構是例外而不是規則。在構建應用程序之前選擇正確的應用程序架構是非常困難的。

大型服務器應用程序的流行架構示例:

  • 分層架構(Layered Architecture)。
  • 分層架構。
  • 面向服務的體系結構 (SOA)。
  • 微服務架構(Microservice Architecture)。

他們每個人都有其優點和缺點。但是研究它們不會給你任何東西。架構是對“如何組織系統內數千個對象的交互”這個問題的答案。在您體驗到問題的全部複雜性之前,您將無法理解解決方案的全部多功能性。

所有應用程序都使用某種架構,或者至少假裝使用某種架構。因此,了解流行的應用程序設計方法將使您能夠快速更好地理解應用程序的工作原理。這意味著在您需要的地方進行更改。

“必要時進行更改”是什麼意思?有沒有不需要修改的地方?確切地。

具體來說,假設您正在從事一個中型後端項目。它由一個 20 人的團隊編寫了 5 年。該項目耗時 100 人年,包含約 10 萬行代碼。它總共包含兩千個類,分為 10 個不同大小的模塊。

並添加一個嚴酷的現實。一些任務的邏輯分佈在幾個模塊中。此外,業務邏輯可以在前端(用 JavaScript 編寫)和/或直接在數據庫中作為存儲過程編寫。您仍然確定可以立即確定要進行更改的確切位置嗎?

這不是我為了嚇唬你而編造的噩夢。這是一個典型的項目。情況更糟。為什麼會這樣?可能有多種原因,但幾乎總是這樣:

  • 很多人都在從事這個項目——他們每個人的看法都有所不同。
  • 5年,項目換了10個人,新人不太懂。
  • 創建軟件是不斷做出改變,不斷改變一切。
  • 五年前,當我們決定架構時,項目的想法有些不同。

但最主要的是,無論項目的架構如何,從事該項目的所有程序員都對這個項目的工作方式有著相同的理解。讓我們從最簡單的概念開始——客戶端-服務器架構。

1.2 客戶端-服務器交互的概念

現在我們將理解作為客戶端-服務器體系結構基礎的概念,並將讓您更好地理解 Internet 上數百萬程序的交互是如何組織的。

顧名思義,這個概念涉及兩方:客戶端服務器。這裡的一切就像生活一樣:客戶端是這個或那個服務的客戶,服務器是服務提供者。客戶端和服務器在物理上是程序,例如典型的客戶端是瀏覽器

可以給出以下示例作為服務器:

  • Web 服務器,例如 Tomcat。
  • 數據庫服務器,例如 MySQL。
  • 像 Stripe 這樣的支付網關。

客戶端和服務器通常通過 Internet 進行通信(儘管它們可以在同一局域網中工作,並且通常可以在任何其他類型的網絡中工作)。通信通過標準協議(如 HTTP、FTP)或較低級別的協議(如 TCP 或 UDP)進行。

通常根據服務器提供的服務類型來選擇協議。例如,如果是視頻通話,那麼通常使用UDP。

還記得 Tomcat 及其 servlet 是如何工作的嗎?服務器接收 HTTP 消息,將其解包,從那裡提取所有必要的信息並將其傳遞給 servlet 進行處理。然後將處理結果打包回 HTTP 響應並發送給客戶端。

這是典型的客戶端-服務器交互。瀏覽器是 Web 客戶端,Tomcat 是 Web 服務器。Tomcat 甚至被稱為網絡服務器。

但仔細想想,重要的不是名字,而是本質——程序之間的角色分配。您在 HTML 頁面中運行的 JS 腳本可以稱為客戶端,而您的 servlet可以稱為服務器。畢竟,它們在客戶端-服務器概念的框架內成對工作。

1.3 一個重要的細微差別

還值得注意的是,客戶端-服務器交互基於這樣的交互由客戶端發起的原則:服務器只回答客戶端並報告它是否可以向客戶端提供服務,如果可以,在什麼條件下.

客戶端的物理位置和服務器的位置無關緊要。客戶端軟件和服務器軟件通常安裝在不同的機器上,但也可以在同一台計算機上運行。

這個概念是作為簡化複雜系統的第一步而開發的。她有這些優點:

  • 邏輯簡化:服務器不知道客戶端的任何信息以及將來如何使用其數據。
  • 可能存在弱客戶端:所有資源密集型任務都可以轉移到服務器。
  • 獨立開發客戶端代碼和服務端代碼。
  • 許多不同的客戶端,例如 Tomcat 和不同的瀏覽器。

最基本的客戶端與服務端交互的版本如圖所示:

客戶端服務器

重要的是要注意這裡的兩個細節。一、圖片顯示多個客戶端可以訪問一台服務器。其次,他們可以同時訪問它。這也是服務器的重要組成部分。

一個客戶端通常與一個用戶交互,因此通常甚至不需要授權。但是,服務器處理來自數千個客戶端的請求,在為其開發代碼時,您需要能夠區分授權和身份驗證。

服務器並行處理數千個請求也很重要。這意味著在開發後端代碼時,您將需要不斷考慮並發訪問資源的任務。此外,服務器代碼極有可能出現競爭條件(線程競爭)、死鎖(線程相互阻塞)。

必須監控重要對象的生命週期:

您不能通過new Thread().start(). 相反,您需要有一個將在所有服務線程之間共享的線程池。

此外,您不能只啟動一個異步任務,因為它們也是在單獨的線程中執行的。創建這樣的任務時,您應該始終知道哪個線程池正在執行它,以及如果這樣的池溢出會發生什麼。

所有對文件和目錄的操作都必須通過 try-with-resources 完成。如果在正常的應用程序中您忘記關閉流或文件,這是一個問題嗎?當您退出程序時它會自行關閉。但是如果你忘記在代碼中某處關閉服務器上的文件,而你的服務器已經運行了幾個月......很快,成千上萬個這樣未關閉的文件將累積起來,操作系統將停止打開新文件進行讀取(work with files由操作系統控制)。Teamlead 不會拍你的頭...

1.4 客戶端-服務器架構

另一個重點。客戶端-服務器體系結構只定義了計算機之間交互的一般原則,交互的細節由各種協議決定。

這個概念(客戶端-服務器)告訴我們,我們需要將網絡上的機器分為客戶端機器和服務器機器,客戶端機器總是需要一些東西,而服務器機器則提供他們需要的東西。在這種情況下,客戶端始終啟動交互,交互發生的規則由協議描述。

客戶端-服務器交互架構有兩種類型:第一種稱為雙層客戶端-服務器架構,第二種是多層客戶端-服務器架構(有時稱為三層架構或三層架構,但這是一個特例)。

客戶端-服務器交互的兩層體系結構的操作原理是請求的處理髮生在一台服務器上,而在此處理過程中不引用其他服務器。

兩層客戶端-服務器交互模型可以畫成一個簡單的圖。

兩層客戶端-服務器架構

這裡可以看到第一層是客戶端的一切,第二層是服務端的一切。