LoginSignup
15
11

More than 3 years have passed since last update.

図解 Locust

Last updated at Posted at 2019-01-17

はじめに

LocustDocument は分かりやすいですが、
色々気になった点があったので ソースコード を読んで図にしてみました。

Locust の動き

【 Locust の動き 】.png

補足

Locust を支えるもの

Locust は Gevent という並行処理をサポートしてくれるモジュールを使用している。
何個もの Locust は実際には単一の greenlet の中でスケジューリングされながら動いており、イベントベースで制御されている。

Task 間をまたぐ振る舞いの制御はどうするのか?

SQLite や Redis を使って管理することになるかと。

Summary に独自情報を追加したい

ソースコードを追っていくと、locust/stats.py#L553global_stats に流し込めばいいことがわかる。

global_stats.log_request('foo', 'bar', 0, 0)

ロックを取る

gevent の lock を使う。
例えば Locust の setup が、一度だけかつ全インスタンスの on_start の前に呼ばれるのも、これを使って実現されている。 => locust/core.py#L136

import gevent

_lock = gevent.lock.Semaphore()

def do_samething():
 _lock.acquire()
 # なんか処理
 _lock.release()

Taskset を nest するとどうなるか?

stackoverflow: taskset-class-vs-function-task
ソースコードを見れば違いは明らかですが、Document にも記述が確認できます

Task を動的に決めたい

schedule_task を呼べばいい。

class SampleTaskset(TaskSet):
    def on_start(self):
        if self.client.is_new:
            self.schedule_task(hoge, first=True)
        else:
            self.schedule_task(fuga, first=True)

   @task
   def hoge:
       print("hoge")

   @task
   def fuga:
       print("fuga")

client 数の取得

locust -c 6 なら 6匹。

from locust import runners

runners.locust_runner.num_clients

test は locust テスト と python 単体テストの2個書くのか?

この Issue が参考になります
Feature request: "run through" each test once

おわりに

master-slaveによる分散型負荷試験 や seq_task による task の繋がり表現、 WebUI などなどについてはドキュメント参照。
image.png

備考

図のソース。超雑。UMLとかいうの初めて書いた。

@startuml
skinparam NoteFontSize 16
skinparam TitleFontSize 24
skinparam ArrowThickness 3
title 【 Locust の動き 】

rectangle bucket #LightGreen {
   agent Locust_A as Locust_A_1
   agent Locust_A as Locust_A_2
   agent Locust_A as Locust_A_3
   agent Locust_B as Locust_B_1
   agent Locust_B as Locust_B_2
   agent Locust_C as Locust_C_1
}
note right of bucket
Locust_A,B,C の weight が 3:2:1 で locust -c 6 した時の例。
bucket は locust_classes を重み付けしたものの名称。
end note

skinparam InterfaceFontSize 20
skinparam InterfaceFontColor #Red
interface spawn_locusts
bucket ---down-> spawn_locusts
note right of spawn_locusts
locust をたくさん spawn (発生)させる。
hatch_rate に基づき、locust を random で選んで生んでいく。
end note

agent Locust_A as Locust_A_3_spawned
agent Locust_C as Locust_C_1_spawned
agent Locust_B as Locust_B_2_spawned
agent Locust_A as Locust_A_1_spawned
agent Locust_A as Locust_A_2_spawned
agent Locust_B as Locust_B_1_spawned

spawn_locusts -[#green]down-> Locust_A_3_spawned: 1/hatch_rate 秒後。\nLocust の setup()
spawn_locusts --[#green]down-> Locust_C_1_spawned: 2/hatch_rate 秒後。\nLocust の setup()
spawn_locusts ---[#green]down-> Locust_B_2_spawned: 3/hatch_rate 秒後。\nLocust の setup()
spawn_locusts ----[#green]down-> Locust_A_1_spawned: 4/hatch_rate 秒後。
spawn_locusts -----[#green]down-> Locust_A_2_spawned: 5/hatch_rate 秒後。
spawn_locusts ------[#green]down-> Locust_B_1_spawned
note on link
☆☆☆
setup(), teardown() は、クラスにつき一度だけ実行される。
この2つのメソッドが並列に実行されることはない。重要
これは上手く図示できてないけど...
☆☆☆
end note

agent Locust_A_TaskSet as Locust_A_1_TaskSet
agent Locust_A_TaskSet as Locust_A_2_TaskSet
agent Locust_A_TaskSet as Locust_A_3_TaskSet
agent Locust_B_TaskSet as Locust_B_1_TaskSet
agent Locust_B_TaskSet as Locust_B_2_TaskSet
agent Locust_C_TaskSet as Locust_C_1_TaskSet
Locust_A_1_spawned -down-> Locust_A_1_TaskSet
Locust_A_2_spawned -down-> Locust_A_2_TaskSet
Locust_A_3_spawned -down-> Locust_A_3_TaskSet: TaskSet の setup()
Locust_B_1_spawned -down-> Locust_B_1_TaskSet
Locust_B_2_spawned -down-> Locust_B_2_TaskSet: TaskSet の setup()
Locust_C_1_spawned -down-> Locust_C_1_TaskSet: TaskSet の setup()

usecase on_start as on_start_Locust_A_1_TaskSet
usecase on_stop as on_stop_Locust_A_1_TaskSet
rectangle loop as task_A_1 {
   control tasks as task_A_1_control
}

usecase on_start as on_start_Locust_A_2_TaskSet
usecase on_stop as on_stop_Locust_A_2_TaskSet
rectangle loop as task_A_2 {
   control tasks as task_A_2_control
}

usecase on_start as on_start_Locust_A_3_TaskSet
usecase on_stop as on_stop_Locust_A_3_TaskSet
rectangle loop as task_A_3 {
   control tasks as task_A_3_control
}

usecase on_start as on_start_Locust_B_1_TaskSet
note right: 「さて、攻撃するぞ〜」(今回だと6並列の攻撃が展開されている)
usecase on_stop as on_stop_Locust_B_1_TaskSet
note right: 「疲れはてたよ...」
rectangle loop as task_B_1 {
   control tasks as task_B_1_control
}

usecase on_start as on_start_Locust_B_2_TaskSet
usecase on_stop as on_stop_Locust_B_2_TaskSet
rectangle loop as task_B_2 {
   control tasks as task_B_2_control
}

usecase on_start as on_start_Locust_C_1_TaskSet
usecase on_stop as on_stop_Locust_C_1_TaskSet
rectangle loop as task_C_1 {
   control tasks as task_C_1_control
}

Locust_A_1_TaskSet -down-> on_start_Locust_A_1_TaskSet
on_start_Locust_A_1_TaskSet -down-> task_A_1
task_A_1 -down-> on_stop_Locust_A_1_TaskSet

Locust_A_2_TaskSet -down-> on_start_Locust_A_2_TaskSet
on_start_Locust_A_2_TaskSet -down-> task_A_2
task_A_2 -down-> on_stop_Locust_A_2_TaskSet

Locust_A_3_TaskSet -down-> on_start_Locust_A_3_TaskSet
on_start_Locust_A_3_TaskSet -down-> task_A_3
task_A_3 -down-> on_stop_Locust_A_3_TaskSet

Locust_B_1_TaskSet -down-> on_start_Locust_B_1_TaskSet
on_start_Locust_B_1_TaskSet -down-> task_B_1
task_B_1 -down-> on_stop_Locust_B_1_TaskSet
note left of task_B_1
run-time 指定がなければ無限ループ。
Exception が起きても loop は継続する。
内部的な intterupt が来たら reschedule されて継続する。

request の結果を得たい時は locust の用意している hooks を使う。
request_success.fire() みたいに。
こうしないと task を実行しているスレッドを待機させてしまい、
次の task に移らないのでダメ。
end note

Locust_B_2_TaskSet -down-> on_start_Locust_B_2_TaskSet
on_start_Locust_B_2_TaskSet -down-> task_B_2
task_B_2 -down-> on_stop_Locust_B_2_TaskSet

Locust_C_1_TaskSet -down-> on_start_Locust_C_1_TaskSet
on_start_Locust_C_1_TaskSet -down-> task_C_1
task_C_1 -down-> on_stop_Locust_C_1_TaskSet

agent All_locusts_dead
on_stop_Locust_A_3_TaskSet ---------down-> All_locusts_dead: TaskSet, Locust の teardown()
on_stop_Locust_C_1_TaskSet --------down-> All_locusts_dead: TaskSet, Locust の teardown()
on_stop_Locust_B_2_TaskSet -------down-> All_locusts_dead: TaskSet, Locust の teardown()
on_stop_Locust_A_1_TaskSet ------down-> All_locusts_dead
on_stop_Locust_A_2_TaskSet -----down-> All_locusts_dead
on_stop_Locust_B_1_TaskSet ----down-> All_locusts_dead
@enduml

参考: PlantUML Reference

15
11
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
11