T之家 12 月 21 日消息,部分 Win11 用戶反饋,在升級 KB5021255(適用于 22H2)和 KB5021234(適用于 21H2)累積更新之后,導致系統出現重大問題。不過目前微軟官方并未承認這兩個 12 月補丁星期二活動日發布的累積更新存在問題。
安裝失敗,出現 0x800f081f 錯誤
IT之家了解到,根據用戶反饋,用戶在嘗試下載 KB5021255 和 KB5021234 累積更新時報告無法正常安裝。當安裝失敗時,用戶會收到一個無意義的錯誤,但沒有明確說明具體是哪個原因導致的。
此外還有部分用戶更新失敗后收到錯誤代碼 0x800f081f,在安裝失敗之后就會回滾到此前版本,但是并未提供更多的細節。
國外科技媒體 Windows Lastest 通過調查發現,Win11 22H2 功能更新用戶反饋安裝失敗問題比較多,21H2 雖然也有但是相關報告并不多。
一位用戶指出:“我有一臺裝有 Windows 11 22H2 的 Surface Book 2。KB5021255 無法通過 Windows Update 更新,也無法從 Windows Update Catalog 下載的獨立安裝程序安裝,錯誤為 0x800f081f”。
AMD CPU 設備出現卡死情況
除了安裝失敗之外,安裝之后也有用戶反饋出現了嚴重的性能問題。AMD CPU 在升級之后會出現卡死數分鐘的情況。一位用戶反饋 Ryzen 5 4600GE 在內的 AMD 硬件受到影響,不過相同 CPU 的 Win11 21H2 并未受到影響。
和修改開始菜單和任務欄的第三方應用沖突
此外在安裝上述兩個累積更新之后,用于修改開始菜單和任務欄的第三方應用程序將無法正常運行。一位用戶反饋:“在我嘗試點擊開始圖標之后,并未跳出相應的菜單。我查看了 CrashDumps 文件夾并看到:‘StartMenuExperienceHost.exe.10884.dmp’”。
在這種情況下,一個名為“Explorer Patcher”的第三方應用程序似乎與 Windows 11 的 12 月更新有沖突,它可能會破壞“開始”菜單。
如果“開始”菜單不起作用,請按 Windows + R 并鍵入“控制面板”。在控制面板中,轉到程序和功能,然后查找“Explorer Patcher”或類似的應用程序。最后,單擊“卸載”按鈕。
剛工作那會,有一次,上游調用我服務的老哥說,你的服務報"502錯誤了,快去看看是為什么吧"。
當時那個服務里正好有個調用日志,平時會記錄各種200,4xx狀態碼的信息。于是我跑到服務日志里去搜索了一下502這個數字,毫無發現。于是跟老哥說,"服務日志里并沒有502的記錄,你是不是搞錯啦?"
現在想來,多少有些不好意思。
不知道有多少老哥是跟當時的我是一樣的,這篇文章,就來聊聊502錯誤是什么?
我們從狀態碼是什么開始聊起。
我們平時在瀏覽器里逛的某寶和某度,其實都是一個個前端網頁。
一般來說,前端并不存儲太多數據,大部分時候都需要從后端服務器那獲取數據。
于是前后端之間需要通過TCP協議去建立連接,然后在TCP的基礎上傳輸數據。
而TCP是基于數據流的協議,傳輸數據時,并不會為每個消息加入數據邊界,直接使用裸的TCP進行數據傳輸會有"粘包"問題。
因此需要用特地的協議格式去對數據進行解析。于是在此基礎上設計了HTTP協議。詳細的內容可以看我之前寫的《既然有HTTP協議,為什么還要有RPC》。
比如,我想要看某個商品的具體信息,其實就是前端發的HTTP請求中傳入商品的id,后端返回的HTTP響應中返回商品的價格,商店名,發貨地址的信息等。
這樣,表面上,我們是在刷著各種網頁,實際上背后正有多次HTTP消息在不斷進行收發。
但問題就來了,上面提到的都是正常情況,如果有異常情況呢,比如前端發的數據,根本就不是個商品id,而是一張圖片,這對于后端服務端來說是不可能給出正常響應的,于是就需要設計一套HTTP狀態碼,用來標識這次HTTP請求響應流程是否正常。通過這個可以影響瀏覽器的行為。
比方說一切正常,那服務端返回個200狀態碼,前端收到后,可以放心使用響應的數據。但如果服務端發現客戶端發的東西異常,就響應個4xx狀態碼,意思是這是個客戶端的錯誤,4xx里頭的xx可以根據錯誤的類型,再細分成各種碼,比如401是客戶端沒權限,404是客戶端請求了一個根本不存在的網頁。反過來,如果是服務器有問題,就返回5xx狀態碼。
但問題就來了。
服務端都有問題了,搞嚴重點,服務器可能直接就崩潰了,那它還怎么給你返回狀態碼?
是的,這種情況,服務端是不可能給客戶端返回狀態碼的。所以說,一般情況下5xx的狀態碼其實并不是服務器返回給客戶端的。
它們是由網關返回的,常見的網關,比如nginx。
回到前后端交互數據的話題上,如果前端用戶少,那后端處理起請求來,游刃有余。但隨著用戶越來越多,后端服務器受資源限制,cpu或者內存都可能會嚴重不足,這時候解決方案也很簡單,多搞幾臺一樣的服務器,這樣就能將這些前端請求均攤給幾個服務器,從而提升處理能力。
但要實現這樣的效果,前端就得知道后端具體有哪些個服務器,并一一跟他們建立TCP連接。
也不是不行,但就是麻煩。
但這時候如果能有個中間層擋在它們中間就好了,這樣客戶端只需要跟中間層連接,中間層再和服務器建立連接。
于是,這個中間層就成了這幫服務器的一個代理人一樣,客戶端有啥事都找代理人,只管發出自己的請求,再由代理人去找某個服務器去完成響應。整個過程下來,客戶端只知道自己的請求被代理人幫忙搞定了,但代理人具體找了那個服務器去完成,客戶端并不知道,也不需要知道。
像這種,屏蔽掉具體有哪些服務器的代理方式就是所謂的反向代理。
反過來,屏蔽掉具體有哪些客戶端的代理方式,就是所謂的正向代理。
而這個中間層的角色,一般由nginx這類網關來充當。
另外,由于背后的服務器可能性能配置各不相同,有些4核8G,有些2核4G,nginx能為它們加上不同的訪問權重,權重高的多轉發點請求,通過這個方式實現不同的負載均衡策略。
有了nginx這一中間層后,客戶端從直連服務端,變成客戶端直連nginx,再由nginx直連服務端。從一個TCP連接變成兩個TCP連接。
于是,當服務器發生異常時,nginx發送給服務器的那條TCP連接就不能正常響應,nginx在得到這一信息后,就會返回5xx錯誤碼給客戶端,也就是說5xx的報錯,其實是由nginx識別出來,并返回給客戶端的,服務端本身,并不會有5xx的日志信息。所以才會出現文章開頭的一幕,上游收到了我服務的502報錯,但我在自己的服務日志里卻搜索不到這一信息。
在rfc7231中有關于502錯誤碼的官方解釋是
502 Bad Gateway
The 502 (Bad Gateway) status code indicates that the server, while acting as a gateway or proxy, received an invalid response from an inbound server it accessed while attempting to fulfill the request.
復制代碼
翻譯一下就是,502 (Bad Gateway) 狀態代碼表示服務器在充當網關或代理時,在嘗試滿足請求時從它訪問的入站服務器接收到無效響應。
汝聽,人言否?
這對于大部分編程小白來說,不僅沒解釋到問題,反而只會冒出更多的問號。比如,這上面提到的無效響應到底指的是什么?
我來解釋下,它其實是說,502其實是由網關代理(nginx)發出的,是因為網關代理把客戶端的請求轉發給了服務端,但服務端卻發出了無效響應,而這里的無效響應,一般是指TCP的RST報文或四次揮手的FIN報文。
四次揮手估計大家背的很熟了,所以略過,我們來重點說下RST報文是什么。
我們都知道TCP正常情況下斷開連接是用四次揮手,那是正常時候的優雅做法。
但異常情況下,收發雙方都不一定正常,連揮手這件事本身都可能做不到,所以就需要一個機制去強行關閉連接。
RST 就是用于這種情況,一般用來異常地關閉一個連接。它是TCP包頭中的一個標志位,在收到置這個標志位的數據包后,連接就會被關閉,此時接收到 RST的一方,在應用層會看到一個 connection reset 或 connection refused 的報錯。
而之所以發出RST報文,一般有兩個常見原因。
nginx與服務端之間有一條TCP連接,在nginx將客戶端請求轉發給服務端時,他兩之間按道理會一直保持這條連接,直到服務端將結果正常返回后,再斷開連接。
但如果服務端過早斷開連接,而nginx卻還繼續發消息過去,nginx就會收到服務端內核返回的RST報文或四次揮手的FIN報文,迫使nginx那邊的連接結束。
過早斷開連接的原因常見的有兩個。
第一個是,服務端設置的超時時間過短。不管是用的哪種編程語言,一般都有現成的HTTP庫,服務端一般都會有幾個timeout參數,比如golang的HTTP服務框架里有個寫超時(WriteTimeout),假設設置了2s,那它的含義就是,服務端在收到請求后需要在2s內處理完并將結果寫到響應中,如果等不到,就會將連接給斷掉。
比如你的接口處理時間是5s,而你的WriteTimeout卻只有2s,在沒等到響應寫完之前,HTTP框架就會主動將連接給斷開。nginx此時就有可能收到四次揮手的FIN報文(有些框架也可能發RST報文),然后斷開連接,于是客戶端就會收到一個502報錯。
遇到這種問題,將WriteTimeout的時間調大一些就好了。
第二個原因,也是造成502狀態碼最常見的原因,就是服務端應用進程崩了(crash)。
服務端崩了,也就是當前沒有一個進程在監聽服務器端口,而此時你卻嘗試向一個不存在的端口發數據,服務器的linux內核協議棧就會響應一個RST數據包。同樣,這時候nginx也會給客戶端一個502。
在開發過程中,這種情況是最常見的。
現在我們大部分的服務器都會將掛掉的服務重啟,因此我們需要判斷下服務是否曾經崩潰過。
如果你有對服務端的cpu或者內存做過監控,可以看下CPU或內存的監控圖是否出現過斷崖式的突然下跌。如果有,十有八九百,就是你的服務端應用程序曾經崩潰過。
除此之外你還通過下面的命令,看下進程上次的啟動時間是什么時候。
ps -o lstart {pid}
復制代碼
比如我要看的進程id是13515,命令就需要像下面這樣。
# ps -o lstart 13515
STARTED
Wed Aug 31 14:28:53 2022
復制代碼
可以看到它上次的啟動時間是8月31日,這個時間如果跟你印象中的操作時間有差距,那說明進程可能是崩了之后被重新拉起了。
遇到這種問題,最重要的是找出崩潰的原因,崩潰的原因就多種多樣了,比如,對未初始化的內存地址進行寫操作,或者內存訪問越界(數組arr長度明明只有2,代碼卻讀arr[3])。
這種情況幾乎都是程序有代碼邏輯問題,崩潰一般也會留下代碼堆棧,可以根據堆棧報錯去排查問題,修復之后就好了。比如下面這張圖是golang的報錯堆棧信息,其他語言的也類似。
但有一些情況,有時候根本不留下堆棧。
比如內存泄露導致進程占用內存越來越多,最后導致超過服務器的最大內存限制,觸發OOM(out of memory), 進程直接就被操作系統kill掉。
還有更隱蔽的,代碼邏輯里隱藏了主動退出進程的操作。比如golang的日志打印里有個方法叫log.Fatalln(),打印完日志還會順便執行os.Exit()直接退出進程,對源碼不了解的新手很容易犯這個錯。
如果你很明確,你的服務沒有崩過。那繼續往下看。
nginx是通過配置的形式來代理多個服務器。這個配置一般是放在 /etc/nginx/nginx.conf 中。
打開它,你可能會看到類似下面這樣的信息。
upstream xiaobaidebug.top {
server 10.14.12.19:9235 weight=2;
server 10.14.16.13:8145 weight=5;
server 10.14.12.133:9702 weight=8;
server 10.14.11.15:7035 weight=10;
}
復制代碼
上面配置的含義是,如果客戶端訪問xiaobaidebug.top域名,nginx就會將客戶端的請求轉發到下面的4個服務器ip上,ip邊上還有個weight權重,權重越高,被轉發到的次數就越多。
可以看出,nginx具有相當豐富的配置能力。但要注意的是,這些個文件是需要自己手動配置的。對于服務器少,且不怎么變化的情況,這當然沒問題。
但現在已經是云原生時代了,很多公司內部都有自己的云產品,服務自然也會上云。一般來說每次更新服務,都可能會將服務部署到一臺新的機器上。而這個ip也會隨著改變,難道每發布一次服務,都需要手動去nginx上改配置嗎?這顯然不現實。
如果能在服務啟動時,讓服務主動將自己的ip告訴nginx,然后nginx自己生成這樣的一個配置并重新加載,那事情就簡單多了。
為了實現這樣一個服務注冊的功能,不少公司都會基于nginx進行二次開發。
但如果這個服務注冊功能有問題,比方說服務啟動后,新服務沒注冊上,但老服務已經被銷毀了。這時候nginx還將請求打到老服務的IP上,由于老服務所在的機器已經沒有這個服務了,所以服務器內核就會響應RST,nginx收到RST后回復502給客戶端。
要排查這種問題也不難。
這個時候,你可以看下nginx側是否有打印相關的日志,看下轉發的IP端口是否符合預期。
如果不符合預期,可以去找找做這個基礎組件的同事,進行一波友好的交流。
簡單來說就是服務器沒有相應,也就是我們的web服務器沒有接到有效的信息導致的,產生錯誤的原因有很多,連接超時、設置代理、請求過多導致無法響應等等,都有可能導致請求502 Bad Gateway。
以下是搜集整理的一些502錯誤的排查方法,供參考:
502錯誤的原因比較多,首先排查一下訪問的電腦有沒有設置代理。
是因為在代理模式下訪問也是有可能報502的。
502 bad gateway
第二是用ipconfig命令或右鍵網絡圖形化界面查看ip和DNS,看下是否有問題
502 bad gateway
DNS 緩沖或者DNS設置不正確都有可能導致502。 這種情況的通常原因是因為你在未開啟vpn的情況下訪問了facebook這樣的網站。這個時候自然訪問不上,同時卻在本機留下了緩沖。 這種情況通常在幾分鐘之內就可以訪問了。也可以嘗試 在dos窗口運行 ipconfig /flushdns,該命令會刷新DNS緩沖dns 被劫持了,即使使用國外的dns,也會被劫持。有些機子開vpn能夠訪問,有些 機子確不能。
并且排除了代理、防火墻、本地網絡的原因。這個時候同時ping遠程網站,比如facebook。不能訪問的機子通常獲取了一個怪異的ip, 從任何地方都ping不通的ip。而能訪問的機子ip,在不能訪問的機子上直接可以訪問,也可以ping通。這種情況我們可以去掉VPN服務器的DNS。切換另外的dns。在windows系統中,可以在本地網絡連接的屬性中, 去掉默認的dns,選用國外的dns,比如google的114的。或opendns。
上面幾部都檢查完了,最后清楚一下瀏覽器的緩存,CTRL+F5強制刷新頁面。
如果是Nginx搭建的服務,則嘗試如下方法。
Nginx服務器上發現502錯誤,很多情況下并非Nginx本身的問題。就以Nginx+PHP+MySQL這種架構說明。Nginx本身設置等cgi接口返回的數據延時太短,要延長這個時間。如同前面說的,很多情況下并非Nginx本身的問題,這樣操作后常常并不能緩解問題。此時,就要考慮對應cgi接口的配置,比php-fpm.conf 的配置,腳本執行時間的超時情況限制。這可以通過跟蹤php-fpm的 slow log 來排查,對相關代碼優化,減少延時。另外很大的問題在MySQL數據庫這一塊如果數據庫執行命令超時也會大延長php腳本的執行時間,導致 Nginx 等待超時??梢詍y.cnf的 slow log進行確認效能低下的sql語句是哪些,進行優化配置。通過優化 php-fpm 及 MySQL的配置都大大減少Nginx的等待超時的情況。
fastcgi緩沖區設置過小
確認這個問題首先要看nginx的日志文件,目錄為/var/log/nginx,如果在日志中發現了類似如下錯誤。
0: *16 upstream sent too big header while reading response header from upstream
則是nginx緩沖區有一個bug造成的,我們網站的頁面消耗占用緩沖區可能過大。
增加緩沖區即可,徹底解決了Nginx 502 Bad Gateway的問題。方法如下:
http {
fastcgi_buffers 8 16k;
fastcgi_buffer_size 32k;
請根據服務器已經網站的情況自行增大上述兩個配置項。
二、代理緩沖區設置過小
如果你使用的是nginx反向代理,如果header過大,超出了默認的1k,就會引發上述的upstream sent too big header (說白了就是nginx把外部請求給后端處理,后端返回的header太大,nginx處理不過來就會導致502。
server {
listen 80;
server_name *.lxy.me;
location / {
###############添加這3行
proxy_buffer_size 64k;
proxy_buffers 32 32k;
proxy_busy_buffers_size 128k;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
00001.
三、默認php-cgi的進程數設置過少
在安裝好使用過程中出現502問題,一般是因為默認php-cgi進程是5個,可能因為phpcgi進程不夠用而造成502,需要修改/usr/local/php/etc/php-fpm.conf 將其中的max_children值適當增加。也有可能是max_requests值不夠用。需要說明的是這連個配置項占用內存很大,請根據服務器配置進行設置。否則可能起到反效果。
四、php執行超時
php執行超時,修改/usr/local/php/etc/php.ini 將max_execution_time 改為300
五、nginx等待時間超時
部分PHP程序的執行時間超過了Nginx的等待時間,可以適當增加nginx.conf配置文件中FastCGI的timeout時間
fastcgi_connect_timeout 300;
fastcgi_send_timeout 300;
fastcgi_read_timeout 300;
502 bad gateway
502錯誤還有一個經常出現情況就是后端主機宕機。在配置里有這么一項配置:,這個配置指定了在從一個后端主機取數據遇到何種錯誤時會轉到下一個后端主機,里頭寫上的就是會出現502的所有情況拉,默認是。就是宕機、斷線之類的,就是讀取堵塞超時,比較容易理解。我一般是全寫上的:
默認的進程數設置過少在安裝好使用過程中出現502問題,一般是因為默認進程是5個,可能因為進程不夠用而造成502,需要修改/usr//php/etc/.conf將其中的值適當增加。也有可能是值不夠用。需要說明的是這連個配置項占用內存很大,請根據服務器配置進行設置。否則可能起到反效果。
將請求提交給網關如執行,但是由于某些原因沒有執行完畢導致進程終止執行。說到此,這個問題就很明了了,與網關服務如的配置有關了。.conf配置文件中有兩個參數就需要你考慮到,分別是和。最大子進程數,在高并發請求下,達到最大響應數,后續的請求就會出現502錯誤的??梢酝ㄟ^命令來查看當前連接數。設置單個請求的超時終止時間。還應該注意到php.ini中的參數。當請求終止時,也會出現502錯誤的。當積累了大量的php請求,你重啟釋放資源,但一兩分鐘不到,502又再次呈現,這是什么原因導致的呢?這時還應該考慮到數據庫,查看下數據庫進程是否有大量的進程,數據庫死鎖導致超時,前端終止了繼續請求,但是SQL語句還在等待釋放鎖,這時就要重啟數據庫服務了或kill掉死鎖SQL進程了。
好了,關于502 bad gateway 報錯就先討論到這里,如果在開發過程中還有其他原因,歡迎在評論區留言評論。