locust多程序實現分散式壓測遇到的問題

DuKe渡客發表於2024-07-24

多程序分散式的實現:

locust分散式時,需藉助命令locust 一個一個啟動worker,在使用中有點繁瑣,
下面藉助於多程序,按既定worker數量,一鍵啟動;


from locust import FastHttpUser, task, User, events, HttpUser



#class WebsiteUser(FastHttpUser): 錯誤的使用!!!
class WebsiteUser(HttpUser):  #正確的使用
    tasks = [TaskSet]
    host = "https://www.baidu.com"
    wait_time = between(0, 0)

def processFun(cmd):
    os.system(cmd)


def start_by_process(tst_locust_file, slave_num, master_host='127.0.0.1', locust_web_port=8090, no_web=False,
                     user_num=10, user_rate=1, result_log='result.log', run_log='run.log'):
    p_lst = []
    if no_web:
        slave_cmd = f"locust -f {tst_locust_file}  --worker --master-host={master_host}"
        master_cmd = f"locust -f {tst_locust_file} --headless -u {user_num} -r {user_rate} --master"
    else:
        slave_cmd = f"locust -f {tst_locust_file}  --worker --master-host={master_host}"
        master_cmd = f"locust -f {tst_locust_file} --web-host {master_host} --web-port {locust_web_port} --master"
    master_cmd += f' --logfile {result_log} --loglevel INFO 1>{run_log} 2>&1'
    # 啟動master
    process_master = multiprocessing.Process(target=processFun, args=(master_cmd,))
    process_master.start()
    p_lst.append(process_master)
    # 啟動 worker
    for index_num in range(slave_num):
        process = multiprocessing.Process(target=processFun, args=(slave_cmd,))
        process.start()
        p_lst.append(process)

    # 阻塞等待
    for process in p_lst:
        process.join()
        
        
if __name__ == "__main__":
    tst_locust_path = 'wms/wms_test'
    slave_num = 3  # 計劃所啟動worker數量, 不可超過執行機的CPU數量
    master_host = '127.0.0.1'
    master_host = '192.168.1.102'
    locust_web_port = 8099  # locust web頁面掛載埠
    no_web = False
    tst_locust_file = os.path.basename(__file__)  # 本指令碼名
    os.chdir(os.getcwd().replace(tst_locust_path.replace('/', os.sep), ''))
    tst_locust_file = f'{tst_locust_path}/{tst_locust_file}'
    start_by_process(tst_locust_file, slave_num, master_host, locust_web_port, no_web=no_web)

問題:

在上述程式碼中,我使用了class WebsiteUser(FastHttpUser): 錯誤的使用!!!這個方式,來使用locust的User類,當執行壓測時,work會因CPU過高而miss掉,導致壓測終止.當切換成class WebsiteUser(HttpUser): #正確的使用時,可以正常執行locust的壓測.

HttpUser和FastHttpUser介紹:

在Locust中,HttpUserFastHttpUser 是兩種不同的使用者行為模擬類,它們分別用於模擬不同的HTTP客戶端行為。以下是這兩種類的主要區別:

HttpUser

  • HttpUser 是Locust的基本HTTP使用者模擬類,它使用requests庫來傳送HTTP請求。
  • HttpUser 支援多執行緒或多程序模式,具體取決於你的配置。
  • 它提供了豐富的功能和靈活性,包括支援重試、會話管理、以及使用requests庫的所有特性。
  • 由於requests庫本身是同步的,因此在高併發場景下,HttpUser可能會導致較高的CPU使用率,尤其是當請求之間沒有足夠的等待時間時。
  • HttpUser適用於大多數HTTP負載測試場景,特別是那些對複雜性和靈活性有較高要求的測試。

FastHttpUser

  • FastHttpUser 是一個較新的類,它使用httpx庫來傳送HTTP請求,這是一個非同步的HTTP客戶端庫。
  • FastHttpUser 提供了更高的效能和更低的CPU使用率,因為它使用了非同步I/O,可以在等待網路響應時執行其他任務。
  • 它特別適合於高併發的場景,可以顯著減少CPU使用率,尤其是在大量併發使用者的情況下。
  • FastHttpUser 相對於HttpUser來說,可能不支援requests庫的所有高階特性,但在大多數情況下,基本的功能如GET、POST請求等都是支援的。
  • 如果你的目標是進行大規模併發測試,同時保持較低的CPU使用率,FastHttpUser是一個很好的選擇。

總結

  • 如果你的測試場景需要高度定製化的請求設定或者你已經在使用requests庫的高階功能,那麼HttpUser可能更適合你。
  • 如果你希望在高併發場景下減少CPU使用率,並且能夠接受一定的功能限制,那麼FastHttpUser是一個更好的選擇。

示例

以下是使用HttpUserFastHttpUser的簡單示例:

HttpUser 示例

from locust import HttpUser, task, between

class MyHttpUser(HttpUser):
    wait_time = between(1, 5)

    @task
    def my_task(self):
        self.client.get("/some_endpoint")

FastHttpUser 示例

from locust import FastHttpUser, task, between

class MyFastHttpUser(FastHttpUser):
    wait_time = between(1, 5)

    @task
    def my_task(self):
        self.client.get("/some_endpoint")

請注意,在使用FastHttpUser時,你需要確保你的Locust版本支援該類。如果不確定,可以檢查你的Locust版本或者查閱官方文件。

原因分析:

  1. 非同步I/O與多程序的互動:
  • FastHttpUser使用httpx庫來進行非同步HTTP請求,而httpx是基於trio或anyio的非同步I/O庫。
  • 在多程序環境下,每個程序都有自己的事件迴圈,這可能導致每個程序中的非同步I/O操作無法有效地與其他程序協調,從而增加了CPU的負擔。
  1. 多程序與非同步I/O的相容性:
  • 多程序模式下,每個程序都有獨立的記憶體空間和事件迴圈,這可能意味著每個程序都在單獨執行其事件迴圈,而不是共享一個全域性的事件迴圈。這種情況下,每個程序都在嘗試同時執行大量的非同步任務,可能會導致CPU使用率上升。
  1. 事件迴圈的排程:
  • 在FastHttpUser中,每個程序可能有自己的事件迴圈,而在多程序模式下,這些事件迴圈可能沒有被有效地排程,導致CPU使用率增加。
  • httpx的非同步特性通常在單程序中表現更好,因為它可以充分利用事件驅動模型的優勢,但在多程序環境下,每個程序都需要維護自己的事件迴圈,這可能會導致額外的開銷。
  1. 併發模型的不匹配:
  • FastHttpUser的設計初衷是為了利用非同步I/O的優勢來提高效能,特別是在高併發場景下。然而,在多程序模式下,這種優勢可能會因為程序間的隔離和通訊開銷而被抵消。

總結: FastHttpUser更適合單程序下使用,HttpUser更適合多程序情況

相關文章