主頁 > 企業開發 > NodeJS 服務 Docker 鏡像極致優化指北

NodeJS 服務 Docker 鏡像極致優化指北

2022-10-14 13:10:49 企業開發

這段時間在開發一個騰訊檔案全品類通用的 HTML 動態服務,為了方便各品類接入的生成與部署,也順應上云的趨勢,考慮使用 Docker 的方式來固定服務內容,統一進行制品版本的管理,本篇文章就將我在服務 Docker 化的程序中積累起來的優化經驗分享出來,供大家參考,

以一個例子開頭,大部分剛接觸 Docker 的同學應該都會這樣撰寫專案的 Dockerfile,如下所示:

FROM node:14
WORKDIR /app

COPY . .
# 安裝 npm 依賴
RUN npm install

# 暴露埠
EXPOSE 8000

CMD ["npm", "start"]

構建,打包,上傳,一氣呵成,然后看下鏡像狀態,臥槽,一個簡單的 node web 服務體積居然達到了驚人的 1.3 個 G,并且鏡像傳輸與構建速度也很慢:

docker 鏡像優化前

要是這個鏡像只需要部署一個實體也就算了,但是這個服務得提供給所有開發同學進行高頻集成并部署環境的(實作高頻集成的方案可參見我的 上一篇文章),首先,鏡像體積過大必然會對鏡像的拉取和更新速度造成影響,集成體驗會變差,其次,專案上線后,同時在線的測驗環境實體可能成千上萬,這樣的容器記憶體占用成本對于任何一個專案都是無法接受的,必須找到優化的辦法解決,

發現問題后,我就開始研究 Docker 的優化方案,準備給我的鏡像動手術了,

node 專案生產環境優化

首先開刀的是當然是前端最為熟悉的領域,對代碼本身體積進行優化,之前開發專案時使用了 Typescript,為了圖省事,專案直接使用 tsc 打包生成 es5 后就直接運行起來了,這里的體積問題主要有兩個,一個是開發環境 ts 原始碼并未處理,并且用于生產環境的 js 代碼也未經壓縮,

tsc 打包

另一個是參考的 node_modules 過于臃腫,仍然包含了許多開發除錯環境中的 npm 包,如 ts-node,typescript 等等,既然打包成 js 了,這些依賴自然就該去除,

一般來說,由于服務端代碼不會像前端代碼一樣暴露出去,運行在物理機上的服務更多考慮的是穩定性,也不在乎多一些體積,因此這些地方一般也不會做處理,但是 Docker 化后,由于部署規模變大,這些問題就非常明顯了,在生產環境下需要優化的,

對于這兩點的優化的方式其實我們前端非常熟悉了,不是本文的重點就粗略帶過了,對于第一點,使用 Webpack + babel 降級并壓縮 Typescript 原始碼,如果擔心錯誤排查可以加上 sourcemap,不過對于 docker 鏡像來說有點多余,一會兒會說到,對于第二點,梳理 npm 包的 dependencies 與 devDependencies 依賴,去除不是必要存在于運行時的依賴,方便生產環境使用 npm install --production 安裝依賴,

優化專案鏡像體積

使用盡量精簡的基礎鏡像

我們知道,容器技術提供的是作業系統級別的行程隔離,Docker 容器本身是一個運行在獨立作業系統下的行程,也就是說,Docker 鏡像需要打包的是一個能夠獨立運行的作業系統級環境,因此,決定鏡像體積的一個重要因素就顯而易見了:打包進鏡像的 Linux 作業系統的體積,

一般來說,減小依賴的作業系統的大小主要需要考慮從兩個方面下手,第一個是盡可能去除 Linux 下不需要的各類工具庫,如 python,cmake, telnet 等,第二個是選取更輕量級的 Linux 發行版系統,正規的官方鏡像應該會依據上述兩個因素對每個發行版提供閹割版本,

以 node 官方提供的版本 node:14 為例,默認版本中,它的運行基礎環境是 Ubuntu,是一個大而全的 Linux 發行版,以保證最大的兼容性,去除了無用工具庫的依賴版本稱為 node:14-slim 版本,而最小的鏡像發行版稱為 node:14-alpine,Linux alpine 是一個高度精簡,僅包含基本工具的輕量級 Linux 發行版,本身的 Docker 鏡像只有 4~5M 大小,因此非常適合制作最小版本的 Docker 鏡像,

在我們的服務中,由于運行該服務的依賴是確定的,因此為了盡可能的縮級訓礎鏡像的體積,我們選擇 alpine 版本作為生產環境的基礎鏡像,

分級構建

這時候,我們遇到了新的問題,由于 alpine 的基本工具庫過于簡陋,而像 webpack 這樣的打包工具背后可能使用的插件庫極多,構建專案時對環境的依賴較大,并且這些工具庫只有編譯時需要用到,在運行時是可以去除的,對于這種情況,我們可以利用 Docker 的分級構建的特性來解決這一問題,

首先,我們可以在完整版鏡像下進行依賴安裝,并給該任務設立一個別名(此處為build),

# 安裝完整依賴并構建產物
FROM node:14 AS build
WORKDIR /app

COPY package*.json /app/
RUN ["npm", "install"]
COPY . /app/

RUN npm run build

之后我們可以啟用另一個鏡像任務來運行生產環境,生產的基礎鏡像就可以換成 alpine 版本了,其中編譯完成后的原始碼可以通過--from引數獲取到處于build任務中的檔案,移動到此任務內,

FROM node:14-alpine AS release
WORKDIR /release

COPY package*.json /
RUN ["npm", "install", "--registry=http://r.tnpm.oa.com", "--production"]

# 移入依賴與原始碼
COPY public /release/public
COPY --from=build /app/dist /release/dist

# 啟動服務
EXPOSE 8000

CMD ["node", "./dist/index.js"]

Docker 鏡像的生成規則是,生成鏡像的結果僅以最后一個鏡像任務為準,因此前面的任務并不會占用最終鏡像的體積,從而完美解決這一問題,

當然,隨著專案越來越復雜,在運行時仍可能會遇到工具庫報錯,如果曝出問題的工具庫所需依賴不多,我們可以自行補充所需的依賴,這樣的鏡像體積仍然能保持較小的水平,

其中最常見的問題就是對node-gypnode-sass庫的參考,由于這個庫是用來將其他語言撰寫的模塊轉譯為 node 模塊,因此,我們需要手動增加g++ make python這三個依賴,

# 安裝生產環境依賴(為兼容 node-gyp 所需環境需要對 alpine 進行改造)
FROM node:14-alpine AS dependencies

RUN apk add --no-cache python make g++
COPY package*.json /
RUN ["npm", "install", "--registry=http://r.tnpm.oa.com", "--production"]
RUN apk del .gyp

詳情可見:https://github.com/nodejs/docker-node/issues/282

合理規劃 Docker Layer

構建速度優化

我們知道,Docker 使用 Layer 概念來創建與組織鏡像,Dockerfile 的每條指令都會產生一個新的檔案層,每層都包含執行命令前后的狀態之間鏡像的檔案系統更改,檔案層越多,鏡像體積就越大,而 Docker 使用快取方式實作了構建速度的提升,若 Dockerfile 中某層的陳述句及依賴未更改,則該層重建時可以直接復用本地快取

如下所示,如果 log 中出現Using cache字樣時,說明快取生效了,該層將不會執行運算,直接拿原快取作為該層的輸出結果,

Step 2/3 : npm install
 ---> Using cache
 ---> efvbf79sd1eb

通過研究 Docker 快取演算法,發現在 Docker 構建程序中,如果某層無法應用快取,則依賴此步的后續層都不能從快取加載,例如下面這個例子:

COPY . .
RUN npm install

此時如果我們更改了倉庫的任意一個檔案,此時因為npm install層的上層依賴變更了,哪怕依賴沒有進行任何變動,快取也不會被復用,

因此,若想盡可能的利用上npm install層快取,我們可以把 Dockerfile 改成這樣:

COPY package*.json .
RUN npm install
COPY src .

這樣在僅變更原始碼時,node_modules的依賴快取仍然能被利用上了,

由此,我們得到了優化原則:

  1. 最小化處理變更檔案,僅變更下一步所需的檔案,以盡可能減少構建程序中的快取失效,

  2. 對于處理檔案變更的 ADD 命令、COPY 命令,盡量延遲執行,

構建體積優化

在保證速度的前提下,體積優化也是我們需要去考慮的,這里我們需要考慮的有三點:

  1. Docker 是以層為單位上傳鏡像倉庫的,這樣也能最大化的利用快取的能力,因此,執行結果很少變化的命令需要抽出來單獨成層,如上面提到的npm install的例子里,也用到了這方面的思想,

  2. 如果鏡像層數越少,總上傳體積就越小,因此,在命令處于執行鏈尾部,即不會對其他層快取產生影響的情況下,盡量合并命令,從而減少快取體積,例如,設定環境變數和清理無用檔案的指令,它們的輸出都是不會被使用的,因此可以將這些命令合并為一行 RUN 命令,

RUN set ENV=prod && rm -rf ./trash
  1. Docker cache 的下載也是通過層快取的方式,因此為了減少鏡像的傳輸下載時間,我們最好使用固定的物理機器來進行構建,例如在流水線中指定專用宿主機,能是的鏡像的準備時間大大減少,

當然,時間和空間的優化從來就沒有兩全其美的辦法,這一點需要我們在設計 Dockerfile 時,對 Docker Layer 層數做出權衡,例如為了時間優化,需要我們拆分檔案的復制等操作,而這一點會導致層數增多,略微增加空間,

這里我的建議是,優先保證構建時間,其次在不影響時間的情況下,盡可能的縮小構建快取體積,

以 Docker 的思維管理服務

避免使用行程守護

我們撰寫傳統的后臺服務時,總是會使用例如 pm2、forever 等等行程守護程式,以保證服務在意外崩潰時能被監測到并自動重啟,但這一點在 Docker 下非但沒有益處,還帶來了額外的不穩定因素,

首先,Docker 本身就是一個流程管理器,因此,行程守護程式提供的崩潰重啟,日志記錄等等作業 Docker 本身或是基于 Docker 的編排程式(如 kubernetes)就能提供了,無需使用額外應用實作,除此之外,由于守護行程的特性,將不可避免的對于以下的情況產生影響:

  1. 增加行程守護程式會使得占用的記憶體增多,鏡像體積也會相應增大,

  2. 由于守護行程一直能正常運行,服務發生故障時,Docker 自身的重啟策略將不會生效,Docker 日志里將不會記錄崩潰資訊,排障溯源困難,

  3. 由于多了個行程的加入,Docker 提供的 CPU、記憶體等監控指標將變得不準確,

因此,盡管 pm2 這樣的行程守護程式提供了能夠適配 Docker 的版本:pm2-runtime,但我仍然不推薦大家使用行程守護程式,

其實這一點其實是源自于我們的固有思想而犯下的錯誤,在服務上云的程序中,難點其實不僅僅在于寫法與架構上的調整,開發思路的轉變才是最重要的,我們會在上云的程序中更加深刻體會到這一點,

日志的持久化存盤

無論是為了排障還是審計的需要,后臺服務總是需要日志能力,按照以往的思路,我們將日志分好類后,統一寫入某個目錄下的日志檔案即可,但是在 Docker 中,任何本地檔案都不是持久化的,會隨著容器的生命周期結束而銷毀,因此,我們需要將日志的存盤跳出容器之外,

最簡單的做法是利用 Docker Manager Volume,這個特性能繞過容器自身的檔案系統,直接將資料寫到宿主物理機器上,具體用法如下:

docker run -d -it --name=app -v /app/log:/usr/share/log app

運行 docker 時,通過-v 引數為容器系結 volumes,將宿主機上的 /app/log 目錄(如果沒有會自動創建)掛載到容器的 /usr/share/log 中,這樣服務在將日志寫入該檔案夾時,就能持久化存盤在宿主機上,不隨著 docker 的銷毀而丟失了,

當然,當部署集群變多后,物理宿主機上的日志也會變得難以管理,此時就需要一個服務編排系統來統一管理了,從單純管理日志的角度出發,我們可以進行網路上報,給到云日志服務(如騰訊云 CLS)托管,或者干脆將容器進行批量管理,例如Kubernetes這樣的容器編排系統,這樣日志作為其中的一個模塊自然也能得到妥善保管了,這樣的方法很多,就不多加贅述了,

k8s 服務控制器的選擇

鏡像優化之外,服務編排以及控制部署的負載形式對性能的影響也很大,這里以最流行的Kubernetes的兩種控制器(Controller):DeploymentStatefulSet 為例,簡要比較一下這兩類組織形式,幫助選擇出最適合服務的 Controller,

StatefulSet是 K8S 在 1.5 版本后引入的 Controller,主要特點為:能夠實作 pod 間的有序部署、更新和銷毀,那么我們的制品是否需要使用 StatefulSet 做 pod 管理呢?官方簡要概括為一句話:

Deployment 用于部署無狀態服務,StatefulSet 用來部署有狀態服務,

這句話十分精確,但不易于理解,那么,什么是無狀態呢?在我看來,StatefulSet的特點可以從如下幾個步驟進行理解:

  1. StatefulSet管理的多個 pod 之間進行部署,更新,洗掉操作時能夠按照固定順序依次進行,適用于多服務之間有依賴的情況,如先啟動資料庫服務再開啟查詢服務,

  2. 由于 pod 之間有依賴關系,因此每個 pod 提供的服務必定不同,所以 StatefulSet 管理的 pod 之間沒有負載均衡的能力,

  3. 又因為 pod 提供的服務不同,所以每個 pod 都會有自己獨立的存盤空間,pod 間不共享,

  4. 為了保證 pod 部署更新時順序,必須固定 pod 的名稱,因此不像 Deployment 那樣生成的 pod 名稱后會帶一串亂數,

  5. 而由于 pod 名稱固定,因此跟 StatefulSet 對接的 Service 中可以直接以 pod 名稱作為訪問域名,而不需要提供Cluster IP,因此跟 StatefulSet 對接的 Service 被稱為 Headless Service

通過這里我們就應該明白,如果在 k8s 上部署的是單個服務,或是多服務間沒有依賴關系,那么 Deployment 一定是簡單而又效果最佳的選擇,自動調度,自動負載均衡,而如果服務的啟停必須滿足一定順序,或者每一個 pod 所掛載的資料 volume 需要在銷毀后依然存在,那么建議選擇 StatefulSet

本著如無必要,勿增物體的原則,強烈建議所有運行單個服務作業負載采用 Deployment 作為 Controller,

寫在結尾

一通研究下來,差點把一開始的目標忘了,趕緊將 Docker 重新構建一遍,看看優化成果,

docker 鏡像優化后

可以看到,對于鏡像體積的優化效果還是不錯的,達到了 10 倍左右,當然,如果專案中不需要如此高版本的 node 支持,還能進一步縮小大約一半的鏡像體積,

之后鏡像倉庫會對存放的鏡像檔案做一次壓縮,以 node14 打包的鏡像版本最終被壓縮到了 50M 以內,

鏡像倉庫優化前后

當然,除了看得到的體積資料之外,更重要的優化其實在于,從面向物理機的服務向容器化云服務在架構設計層面上的轉變,

容器化已經是看得見的未來,作為一名開發人員,要時刻保持對前沿技術的敏感,積極實踐,才能將技術轉化為生產力,為專案的進化做出貢獻,

參考資料:

  1. 《Kubernetes in action》--Marko Luk?a
  2. Optimizing Docker Images

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/514235.html

標籤:其他

上一篇:中文輸入法中游標跟隨能力觸發的瀏覽器事件探究

下一篇:HTTPS實作原理分析

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more