系統設計(架構師)指南4設計限速器

来源:https://www.cnblogs.com/testing-/archive/2023/09/08/17666492.html
-Advertisement-
Play Games

本文給大家介紹了什麼是"編程範式",選擇合適的編程範式可以提高代碼的可讀性、可維護性和可擴展性。 一、 什麼是編程範式? "編程範式"是一種編程思想的總稱,它是指在編寫程式時所採用的基本方法和規範。常見的編程範式有面向對象、函數式、邏輯式等。 選擇合適的編程範式可以提高代碼的可讀性、可維護性和可擴展 ...


4 設計限速器

在網路系統中,限速器用於控制客戶端或服務發送流量的速率。在HTTP世界中,限速器限制在指定時間內允許發送的客戶端請求數量。如果API請求數超過了限速器定義的閾值,超出調用都會被阻止。下麵是幾個例子:

  • 用戶每秒最多只能寫2篇文章。

  • 同一IP地址每天最多只能創建10個賬戶。

  • 同一設備每周最多可申請5次獎勵。

本章將要求您設計限速器。在開始設計之前,我們首先瞭解一下使用API限速器的好處:

  • 防止拒絕服務(DoS Denial of Service)攻擊造成的資源枯竭。

幾乎所有大型科技公司發佈的API都會強制執行某種形式的速率限制。例如,Twitter將推文數量限製為每3小時 300條。Google docs API的預設限制如下:每個用戶每60秒讀取請求300次。限速器通過阻止多餘的調用來防止有意或無意的DoS攻擊。

  • 降低成本

限制過量請求意味著減少伺服器數量,將更多資源分配給優先順序高的API。對於使用付費第三方API的公司來說,速率限制極為重要。例如,以下外部應用程式介面按調用次數收費:檢查信用、付款、檢索健康記錄等。限制調用次數對降低成本至關重要。

-防止伺服器過載

為減少伺服器負載,可使用限速器來過濾機器人或用戶不當行為造成的多餘請求。

4.1 步驟 1 - 理解問題並確定設計範圍

速率限制可以使用不同的演算法來實現,每種演算法都有其優缺點。面試官和應聘者之間的互動有助於明確我們要構建的限速器類型。

候選人:我們要設計哪種限速器?是客戶端限速器還是伺服器端API限速器?

面試官:問得好。我們的重點是伺服器端API限速器。

候選人:限速器是根據IP、用戶ID還是其他屬性來限制API請求?

面試官:限速器應該足夠靈活,以支持不同的節流規則。

應聘者:系統的規模有多大?是為初創公司還是擁有龐大用戶群的大公司構建的?

面試官:系統必須能夠處理大量請求。

應聘者:系統能否在分散式環境中運行?

面試官:可以。

應聘者:限速器是單獨的服務,還是應該在應用程式代碼中實現?

面試官:這取決於你的設計決定。

應聘者:我們需要通知被節流的用戶嗎?

面試官:需要。

要求

以下是系統要求的摘要:

  • 準確限制過多請求。
  • 低延遲。限速器不應減慢HTTP響應時間。
  • 使用儘可能少的記憶體。
  • 分散式速率限制。限速器可在多個伺服器或進程中共用。
  • 異常處理。當用戶的請求被節流時,向用戶顯示明確的異常。
  • 高容錯性。如果限速器出現任何問題(例如,緩存伺服器離線),不會影響整個系統。

4.2 第2步 - 提出概要設計方案並獲得支持

讓我們保持簡單,使用基本的客戶端和伺服器通信模型。

4.2.1 在哪裡設置限速器?

直觀地說,可以在客戶端或伺服器端實施限速器。

  • 客戶端

一般來說客戶端是實施速率限制的不可靠的,因為客戶端請求很容易被惡意行為者偽造。此外,我們可能無法控制客戶端的實施。

  • 伺服器端

假設我們的API允許每秒發出2個請求,而客戶端在一秒鐘內向伺服器發送了3個請求。前兩個請求被路由到API伺服器。但是,限速器中間件會對第三個請求進行節流,並返回HTTP狀態代碼 429。HTTP429響應狀態代碼表示用戶發送的請求過多。

雲微服務已廣為流行,速率限制通常在API網關的組件中實現。API網關是一種完全托管的服務,支持速率限制、SSL終止、身份驗證、IP白名單、靜態內容服務等。目前,我們只需知道API網關是支持速率限制的中間件。

速率限制器應該在哪裡實施,是在伺服器端還是在網關中?這個問題沒有絕對的答案。這取決於貴公司當前的技術堆棧、工程資源、優先順序、目標等。以下是幾條一般指導原則:

評估當前的技術堆棧,如編程語言、緩存服務等。確保您當前的編程語言能夠有效地在伺服器端實施速率限制。

確定適合您業務需求的速率限制演算法。在伺服器端實施一切時,您可以完全控制演算法。但是,如果使用第三方網關,您的選擇可能會受到限制。

  • 如果您已經使用了微服務架構,併在設計中加入了API網關來執行身份驗證、IP白名單等功能,您可以在API網關中添加速率限制器。

  • 創建自己的速率限制服務需要時間。如果沒有足夠的工程資源來實施速率限制器,商業API網關是更好的選擇。

參考資料

4.2.2 限速演算法

限速可以使用不同的演算法來實現,每種演算法都有明顯的優缺點。儘管本章的重點不是演算法,但從高層次瞭解這些演算法有助於選擇合適的演算法或演算法組合,以適應我們的使用情況。以下是常用演算法的列表:

  • 令牌桶(Token bucket)
  • 泄漏桶(Leaking bucket)
  • 固定視窗計數器(Fixed window counter)
  • 滑動視窗日誌(Sliding window log)
  • 滑動視窗計數器(Sliding window counter)

4.2.2.1 令牌桶演算法

令牌桶演算法廣泛用於限速。它簡單易懂,常用於互聯網公司。亞馬遜和都使用這種演算法。

令牌桶演算法的工作原理如下:

  • 令牌桶是一個具有預定容量的容器。令牌以預設的速率定期放入令牌桶。一旦桶滿,就不再添加令牌。如圖所示,令牌桶的容量為4,加油員每秒向桶中投入2枚令牌。一旦桶滿,多餘的代幣就會溢出。

  • 每個請求消耗一個代幣。當請求到達時,我們會檢查桶中是否有足夠的代幣。
    • 如果有足夠的令牌,我們會為每個請求取出令牌,然後請求通過。
    • 如果沒有足夠的令牌,請求就會被放棄。

令牌桶演算法需要兩個參數:

  • 令牌桶大小:令牌桶中允許的最大令牌數量

  • 填充率:每秒放入代幣桶的代幣數量

我們需要多少代幣桶?這取決於限速規則。下麵是幾個例子。

  • 通常需要為不同的API端點設置不同的桶。例如,如果允許用戶每秒發表1篇文章,每天添加150個好友,每秒喜歡5篇文章,那麼每個用戶需要3個桶。
  • 如果我們需要根據IP地址來限制請求,那麼每個IP地址都需要一個桶。
  • 如果系統每秒最多允許 10,000 個請求,那麼所有請求共用一個全局桶是合理的。

優點

  • 演算法易於實現。
  • 記憶體效率高。
  • 代幣桶允許短時間內的突發流量。只要還有代幣,請求就可以通過。

缺點

  • 演算法中的兩個參數是代幣桶大小和代幣填充率。然而,對它們進行適當調整可能具有挑戰性。

4.2.2.2 漏桶演算法

泄漏桶演算法與令牌桶類似,只是以固定速率處理請求。它通常使用先進先出隊列(FIFO)來實現。該演算法的工作原理如下:

  • 當請求到達時,系統會檢查隊列是否已滿。如果隊列未滿,則將請求添加到隊列中。
  • 否則,請求將被丟棄。
  • 從隊列中取出請求,並定期進行處理。

泄漏桶演算法需要以下兩個參數:

  • 桶大小:等於隊列大小。隊列容納以固定速率處理的請求。

  • 流出率:它定義了以固定速率(通常以秒為單位)處理的請求數量。

電子商務公司Shopify使用泄漏桶來限速。

優點

-由於隊列大小有限,因此記憶體效率高。
-請求以固定速率處理,因此適用於需要穩定流出速率的用例。

缺點

-突發流量會使隊列中充滿舊請求,如果不及時處理,最近的請求就會受到速率限制。
-演算法中有兩個參數。演算法中有兩個參數,可能不容易正確調整。

4.2.2.3 固定視窗計數器演算法

固定視窗計數器演算法的工作原理如下:

  • 將時間線劃分為固定大小的時間視窗,併為每個視窗分配一個計數器。

  • 每次請求都會使計數器遞增1。

  • 一旦計數器達到預定義的閾值,新的請求就會被放棄,直到新的時間視窗開始。

下圖中,時間單位為1秒,系統每秒最多允許3個請求。在每秒鐘的視窗中,如果收到的請求超過3個,系統就會丟棄多餘的請求。

這種演算法的一個主要問題是,時間視窗邊緣的突發流量可能會導致超過允許配額的請求通過。請考慮以下情況:

下圖,系統每分鐘最多允許5個請求,可用配額在人性化的整數分鐘重置。如圖所示,2:00:00至2:01:00之間有5個請求,2:01:00 至 2:02:00之間又有5個請求。在2:00:30和2:01:30之間的一分鐘視窗中,有10個請求通過。這是允許請求數的兩倍。

優點

-節省記憶體。
-易於理解。
-在單位時間視窗結束時重置可用配額,適合某些使用情況。

缺點

  • 視窗邊緣的尖峰流量可能導致超過允許配額的請求通過。

4.2.2.4 滑動視窗日誌演算法

如前所述,固定視窗計數器演算法有一個主要問題:它允許更多請求在視窗邊緣通過。滑動視窗日誌演算法解決了這個問題。其工作原理如下:

  • 該演算法跟蹤請求時間戳。時間戳數據通常保存在緩存中,如Redis的排序集。
  • 當有新請求時,刪除所有過期的時間戳。過時的時間戳是指比當前時間視窗開始時間更早的時間戳。
  • 將新請求的時間戳添加到日誌中。
    -如果日誌大小與允許計數相同或更小,則接受請求。否則,請求將被拒絕。

在本例中,速率限制器允許每分鐘2個請求。通常,Linux時間戳會存儲在日誌中。不過,為了提高可讀性,我們在示例中使用了人類可讀的時間表示法。

  • 當新請求在 1:00:01 到達時,日誌為空。因此,該請求是允許的。
  • 新請求在 1:00:30 到達時,時間戳 1:00:30 將被插入日誌。插入後,日誌大小為 2,不大於允許計數。因此,該請求是允許的。
  • 新請求在 1:00:50 到達,時間戳被插入日誌。插入後,日誌大小為 3,大於允許的 2。因此,即使時間戳仍保留在日誌中,該請求也會被拒絕。
  • 一個新請求在 1:01:40 到達。1:00:40,1:01:40)範圍內的請求在最新時間範圍內,但在 1:00:40 之前發送的請求已經過時。兩個過時的時間戳 1:00:01 和 1:00:30 將從日誌中刪除。刪除操作後,日誌大小變為 2,因此請求被接受。

優點

  • 該演算法實現的速率限制非常精確。在任何滾動視窗中,請求都不會超過速率限制。

缺點

  • 該演算法消耗大量記憶體,因為即使請求被拒絕,其時間戳仍可能存儲在記憶體中。

4.2.2.5 滑動視窗計數器演算法

滑動視窗計數器演算法是一種混合方法,它結合了固定視窗計數器和滑動視窗日誌。該演算法可以通過兩種不同的方法實現。我們將在本節中解釋其中一種實現方法,併在本節末尾提供另一種實現方法的參考。下圖展示了該演算法的工作原理。

假設速率限制器每分鐘最多允許7個請求,前一分鐘有5個請求,當前一分鐘有3個請求。對於到達當前分鐘 30% 位置的新請求,滾動視窗中的請求數按以下公式計算:

  • 當前視窗中的請求數 + 上一視窗中的請求數 * 滾動視窗與上一視窗的重疊百分比
  • 根據這一公式,我們得到 3 + 5 * 0.7% = 6.5 個請求。根據使用情況,該數字可以向上或向下舍入。在我們的例子中,四捨五入為6。

由於速率限制器每分鐘最多允許7個請求,因此當前請求可以通過。不過,再收到一個請求後就會達到限制。

優點

  • 由於速率基於前一個視窗的平均速率,因此可以平滑流量峰值。
  • 節省記憶體。

缺點

  • 只適用於不太嚴格的回看視窗。它是實際速率的近似值,因為它假定前一個視窗中的請求是均勻分佈的。不過,這個問題可能沒有想象中那麼嚴重。根據 Cloudflare 的實驗,在 4 億個請求中,只有 0.003% 的請求被錯誤地允許或限制了速率。

4.2.3 高層架構

我們需要一個計數器來跟蹤來自同一用戶、IP 地址等的請求數量。如果計數器大於限制,請求就會被禁止。

我們應該在哪裡存儲計數器呢?由於磁碟訪問速度較慢,使用資料庫並不是一個好主意。選擇記憶體緩存是因為它速度快,而且支持基於時間的過期策略。例如Redis是實現速率限制的常用選擇。它是一種記憶體存儲,提供兩種命令:INCREXPIRE。

  • INCR:將存儲的計數器加1。
  • EXPIRE:為計數器設置超時。如果超時,計數器將自動刪除。

  • 客戶端向限速中間件發送請求。
  • 限速中間件從Redis中相應的桶中獲取計數器,並檢查是否達到限制。
    • 如果達到限制,則拒絕請求。
    • 如果未達到限制,則將請求發送到API伺服器。同時,系統會遞增計數器並將其保存回Redis。

4.3 第3步 - 深入設計

上圖中的高層設計沒有回答以下問題:

  • 如何創建速率限制規則?規則存儲在哪裡?
  • 如何處理速率受限的請求?

4.3.1 限速規則

Lyft將其速率限制組件開源在https://github.com/lyft/ratelimit。我們將深入瞭解該組件,並舉例說明一些速率限制規則:

domain: messaging

descriptors:

  - key: message_type

    Value: marketing

    rate_limit:

      unit: day

      requests_per_unit: 5

在上例中,系統配置為每天最多允許發送5條營銷信息。下麵是另一個示例:

domain: auth

descriptors:

  - key: auth_type

    Value: login

    rate_limit:

      unit: minute

      requests_per_unit: 5

這條規則規定,1 分鐘內客戶端登錄次數不得超過5次。規則一般寫入配置文件並保存在磁碟上。

4.3.2 限速

如果請求受到限速,API會向客戶端返回HTTP響應代碼429(請求過多)。根據使用情況,我們可能會將速率受限的請求排入隊列,以便稍後處理。例如,如果一些訂單因系統超載而受到速率限制,我們可能會保留這些訂單,以便稍後處理。

4.3.3 速率限制器標頭

客戶端如何知道自己是否被節流?客戶端又如何知道被節流前允許的剩餘請求數?答案就在HTTP響應頭中。速率限制器會向客戶端返回以下HTTP頭信息:

  • X-Ratelimit-Remaining:視窗內允許的剩餘請求數。
  • X-Ratelimit-Limit:表示客戶端在每個時間視窗內可進行的調用次數。
  • X-Ratelimit-Retry-After: 在不被節流的情況下再次發出請求前需要等待的秒數。

當用戶發送的請求過多時,會向客戶端返回429請求過多錯誤和X-Ratelimit-Retry-After頭信息。

4.3.4 詳細設計

  • 規則存儲在磁碟上。工作站經常從磁碟中提取規則並將其存儲到緩存中。
  • 當客戶端向伺服器發送請求時,請求會首先發送到限速器中間件。
  • 限速器中間件從緩存中載入規則。它從Redis緩存中獲取計數器和上次請求的時間戳。根據響應,速率限制器決定
  • 如果請求不受速率限制,則將其轉發給API伺服器。
  • 如果請求有速率限制,速率限制器會向客戶端返回429請求過多錯誤信息。同時,請求會被丟棄或轉發到隊列中。

4.3.5 分散式環境中的限速器

建立能在單伺服器環境中運行的速率限制器並不困難。但是,將系統擴展到支持多台伺服器和併發線程則是另一回事。這其中有兩個難題:

  • 競賽條件
  • 同步問題

如前所述,速率限制器的高級工作原理如下:

  • 從Redis讀取計數器值。
  • 檢查(counter + 1)是否超過閾值。
  • 如果沒有,則將Redis中的計數器值遞增 1。

在高併發環境中可能會出現競賽條件。

假設Redis中的計數器值為3,如果兩個請求同時讀取計數器值,然後再寫回計數器值,那麼每個請求都會將計數器值遞增 1,然後寫回計數器值,而不會檢查其他線程。兩個請求(線程)都會認為自己的計數器值是 4。然而,正確的計數器值應該是5。

鎖是解決競賽條件最明顯的方法。但是,加鎖會大大降低系統運行速度。通常有兩種策略可以解決這個問題:Lua腳本 和 Redis中的排序集數據結構。

同步是分散式環境中需要考慮的另一個重要因素。要支持數百萬用戶,一臺速率限制器伺服器可能不足以處理流量。當使用多個速率限制器伺服器時,就需要同步。例如下圖的左側,客戶端1向速率限制器1發送請求,客戶端2向速率限制器2發送請求。由於網路層是無狀態的,客戶端可以向不同的速率限制器發送請求。如果不進行同步,速率限制器1就不包含任何有關客戶端2的數據。因此,速率限制器無法正常工作。

一種可能的解決方案是使用粘性會話,允許客戶端向同一個速率限制器發送流量。這種解決方案並不可取,因為它既不可擴展,也不靈活。更好的辦法是使用Redis等集中式數據存儲。

4.3.6 性能優化

性能優化是系統設計訪談中的一個常見話題。我們將從兩個方面進行改進。

首先,多數據中心設置對於速率限制器來說至關重要,因為對於遠離數據中心的用戶來說,延遲很高。大多數雲服務提供商都在全球建立了許多邊緣伺服器位置。例如,截至2020年5月20日,Cloudflare擁有194個地理分佈廣泛的邊緣伺服器。流量會自動路由到最近的邊緣伺服器,以減少延遲。

第二,使用最終一致性模型同步數據。

4.3.7 監控

設置速率限制器後,收集分析數據以檢查速率限制器是否有效非常重要。首先,我們要確保

  • 速率限制演算法是否有效。
  • 速率限制規則有效。

例如,如果速率限制規則過於嚴格,許多有效請求就會被丟棄。在這種情況下,我們希望稍微放寬規則。再比如,我們發現當流量突然增加(如閃購)時,我們的速率限制器就會失效。在這種情況下,我們可以更換演算法來支持突發流量。令牌桶就是一個很好的選擇。

4.4 步驟4 - 總結

在本章中,我們討論了不同的速率限制演算法及其優缺點。討論的演算法包括

  • 令牌桶
  • 泄漏桶
  • 固定視窗
  • 滑動視窗日誌
  • 滑動視窗計數器

然後,我們討論了系統架構、分散式環境中的速率限制器、性能優化和監控。與任何系統設計面試問題類似,如果時間允許,你還可以提到一些額外的談話要點:

  • 硬性與軟性速率限制。

    • 硬性:請求數不能超過閾值。
    • 軟:請求數可以在短時間內超過閾值。
  • 不同級別的速率限制。在本章中,我們只討論了應用層(HTTP:第 7 層)的速率限制。也可以在其他層應用速率限制。例如,可以使用 Iptables (IP:第 3 層)按 IP 地址限制速率。

  • 避免速率受限。以最佳實踐設計客戶端:

  • 使用客戶端緩存,避免頻繁調用API。

  • 瞭解限制,不要在短時間內發送過多請求。

  • 包含捕獲異常或錯誤的代碼,以便客戶端可以從容地從異常中恢復。

  • 為重試邏輯添加足夠的後退時間。

釘釘或微信號: pythontesting 微信公眾號:pythontesting
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • # pentaho使用 先展示一下用途和效果 ![image](https://jsd.cdn.zzko.cn/gh/YuanjunXu/Images@main/src/image.1gzusdgfiiao.webp) ## 1. 環境準備 ### 1.1 pentaho是什麼? > `pentah ...
  • 在這篇文章中,我將分享一次由於操作不當導致資料庫癱瘓的經驗。通過回顧故障發生的時間、系統簡介、時間線、問題分析和經驗總結等方面的內容。討論操作時間不當、操作流程不當、缺乏執行計劃和限流機制等問題,並提出一些建議,如確認資料庫更新時間、優化更新操作、使用限流工具、設置超時時間和重試機制、調整資料庫參數... ...
  • 最近研發apk校驗服務,很多游戲安裝包兩三個G,如果整個拿去校驗,耗時基本二十多秒,這還僅僅是校驗的時間,如果加上下載的時間,等待時間太長了 網上很多方案嘗試了一下,不太行 1、fast md5 一個第三方庫,csdn有人用過說可以提升40%的速度,然後我去試了一下,本來9秒可以完成的校驗,變成了2 ...
  • 如果你會 Java, 那麼來看一看 Kotlin , 基礎入門。 如果你不理解 Kotlin 的lambda 表達式,那麼來看一看,幫助你真正理解函數類型,lambda 表達式。 ...
  • >我們是[袋鼠雲數棧 UED 團隊](http://ued.dtstack.cn/),致力於打造優秀的一站式數據中台產品。我們始終保持工匠精神,探索前端道路,為社區積累並傳播經驗價值。 >本文作者:琉易 [liuxianyu.cn](https://link.juejin.cn/?target=ht ...
  • 需求: 設計一個標題,讓中間部分隨著文字而撐大,同時文字漸變,兩邊自適應,這種情況就不能用傳統的背景圖片了,想到可以使用圖片邊框來做 解決思路: 1.需要一個大盒子和三個小盒子 2.大盒子設置display:flex; 左右兩個小盒子分別設置flex-grow; 並設置背景圖片 3.給中間盒子設置邊 ...
  • 此篇文章用於記錄柏成從零開發一個canvas九宮格手勢解鎖器的歷程。我們基於 canvas 實現了一款簡單的九宮格手勢解鎖器,用戶可以通過在九宮格中繪製特定的手勢來解鎖。 ...
  • ##一、定義 **使用原型實例指定待創建對象的類型,並且通過複製這個原型來創建新的對象。原型模式是一種創建型模式。** ##二、描述 **包含以下三個角色:** ![](https://img2023.cnblogs.com/blog/1780813/202305/1780813-202305271 ...
一周排行
    -Advertisement-
    Play Games
  • 下麵是一個標準的IDistributedCache用例: public class SomeService(IDistributedCache cache) { public async Task<SomeInformation> GetSomeInformationAsync (string na ...
  • 這個庫提供了在啟動期間實例化已註冊的單例,而不是在首次使用它時實例化。 單例通常在首次使用時創建,這可能會導致響應傳入請求的延遲高於平時。在註冊時創建實例有助於防止第一次Request請求的SLA 以往我們要在註冊的時候實例單例可能會這樣寫: //註冊: services.AddSingleton< ...
  • 最近公司的很多項目都要改單點登錄了,不過大部分都還沒敲定,目前立刻要做的就只有一個比較老的項目 先改一個試試手,主要目標就是最短最快實現功能 首先因為要保留原登錄方式,所以頁面上的改動就是在原來登錄頁面下加一個SSO登錄入口 用超鏈接寫的入口,頁面改造後如下圖: 其中超鏈接的 href="Staff ...
  • Like運算符很好用,特別是它所提供的其中*、?這兩種通配符,在Windows文件系統和各類項目中運用非常廣泛。 但Like運算符僅在VB中支持,在C#中,如何實現呢? 以下是關於LikeString的四種實現方式,其中第四種為Regex正則表達式實現,且在.NET Standard 2.0及以上平... ...
  • 一:背景 1. 講故事 前些天有位朋友找到我,說他們的程式記憶體會偶發性暴漲,自己分析了下是非托管記憶體問題,讓我幫忙看下怎麼回事?哈哈,看到這個dump我還是非常有興趣的,居然還有這種游戲幣自助機類型的程式,下次去大玩家看看他們出幣的機器後端是不是C#寫的?由於dump是linux上的程式,剛好win ...
  • 前言 大家好,我是老馬。很高興遇到你。 我們為 java 開發者實現了 java 版本的 nginx https://github.com/houbb/nginx4j 如果你想知道 servlet 如何處理的,可以參考我的另一個項目: 手寫從零實現簡易版 tomcat minicat 手寫 ngin ...
  • 上一次的介紹,主要圍繞如何統一去捕獲異常,以及為每一種異常添加自己的Mapper實現,並且我們知道,當在ExceptionMapper中返回非200的Response,不支持application/json的響應類型,而是寫死的text/plain類型。 Filter為二方包異常手動捕獲 參考:ht ...
  • 大家好,我是R哥。 今天分享一個爽飛了的面試輔導 case: 這個杭州兄弟空窗期 1 個月+,面試了 6 家公司 0 Offer,不知道問題出在哪,難道是杭州的 IT 崩盤了麽? 報名面試輔導後,經過一個多月的輔導打磨,現在成功入職某上市公司,漲薪 30%+,955 工作制,不咋加班,還不捲。 其他 ...
  • 引入依賴 <!--Freemarker wls--> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.30</version> </dependency> ...
  • 你應如何運行程式 互動式命令模式 開始一個互動式會話 一般是在操作系統命令行下輸入python,且不帶任何參數 系統路徑 如果沒有設置系統的PATH環境變數來包括Python的安裝路徑,可能需要機器上Python可執行文件的完整路徑來代替python 運行的位置:代碼位置 不要輸入的內容:提示符和註 ...