Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

为什么每次spawn之前要先stop所有的job,而不是像python版那样在已有连接上增加呢? #178

Closed
xyzdev-cell opened this issue Oct 8, 2022 · 10 comments

Comments

@xyzdev-cell
Copy link

xyzdev-cell commented Oct 8, 2022

Describe the bug
因为每次stop再重新建立, 之前的连接被清理, 导致最终的请求数不准

case "spawn":
			r.state = stateSpawning
			r.stop()
			r.onSpawnMessage(msg)

参照examples中的tcp写的script, 可以认为就是用的 tcp中的client.go

2022/10/08 15:44:05 Spawning 1 clients immediately
2022/10/08 15:44:06 Spawning 2 clients immediately
2022/10/08 15:44:07 Spawning 3 clients immediately
2022/10/08 15:44:08 Spawning 4 clients immediately
2022/10/08 15:44:09 Spawning 5 clients immediately
2022/10/08 15:44:10 Spawning 6 clients immediately
2022/10/08 15:44:11 Spawning 7 clients immediately
2022/10/08 15:44:12 Spawning 8 clients immediately
2022/10/08 15:44:13 Spawning 9 clients immediately

Spawning 2 clients 把 1clients停了
Spawning 3 clients 时把 2 clients停了

而在python中, 是根据已有worker来新增或减少的

        for user_class_name, user_class_count in user_classes_count.items():
            if self.user_classes_count[user_class_name] > user_class_count:
                user_classes_stop_count[user_class_name] = self.user_classes_count[user_class_name] - user_class_count
            elif self.user_classes_count[user_class_name] < user_class_count:
                user_classes_spawn_count[user_class_name] = user_class_count - self.user_classes_count[user_class_name]

        # call spawn_users before stopping the users since stop_users
        # can be blocking because of the stop_timeout
        self.spawn_users(user_classes_spawn_count)
        self.stop_users(user_classes_stop_count)
@myzhan
Copy link
Owner

myzhan commented Oct 8, 2022

嗯,这里的实现确实跟 python 版本不一致。主要是 python 版本依赖 locustfile,master 发消息过来,它以为 worker 是知道 locustfile 里面的 task 定义的。但是编写 boomer task 的时候不需要这个文件。这里需要想想怎么关联起来。

但是目前这个实现,跟你描述的 “重新建立, 之前的连接被清理, 导致最终的请求数不准”,这两者没有直接的关联吧。一般做 TCP 压测的时候,我建议是用预先创建好的连接池,然后 task 从连接池里面取连接来发请求,避免频繁地创建和销毁连接。

@xyzdev-cell
Copy link
Author

取决于
2022/10/08 15:44:05 Spawning 1 clients immediately
2022/10/08 15:44:06 Spawning 2 clients immediately
2022/10/08 15:44:07 Spawning 3 clients immediately
这中间的创建速率, 这里有3个疑问

  1. master 每1秒发一个 spawn 要求, 但是实际 10秒过去, worker并没有每秒发1个直到10个, 而是最终master不发之后才开始创建请求
  2. 如果master发的增加 请求慢一点, worker 实际在请求中间已经开始工作了, 然后再被停止重新开始, 这就是我说的可能导致最终请求数量不准
  3. 为了能统一停止worker任务, 使用了 boomer.Events.Subscribe(boomer.EVENT_SPAWN, func(workers int, spawnRate float64) {}, 但是因为并行的原因(猜测), 触发 boomer.EVENT_STOP 时可能 boomer.EVENT_SPAWN 还没执行, 我增加了一个 WaitGroup 来保证 boomer.EVENT_SPAWN一定会先执行, 但这也拖慢了 spawn 的间隔, 更可能导致 上述疑问2的发生.

@boboalex
Copy link

boboalex commented Oct 9, 2022

实际情况确实会出现在 spawn 过程中,已经有协程开始发送请求的情况,也就是 spawnWorkers 调用了 safeRun 方法,这个方法是阻塞的,直到用户自定义的 Fn 执行完一次时候(通常做法是,用户需要在这个函数内发送请求,接收到响应,然后去 record success / failure,然后 boomer 实例会将请求数量加一)才会返回,然后 spawnWorkers 内由于 for...select,会再去获取 stopChanshutdownChan 信号,如果接收到了信号就会退出这个请求的协程,但是刚完成的请求是可以正常被记录的。
另一方面,每次接收到下一个 spawn 信号,会 close stopChan,而如前所述,相关压测协程的退出,是在执行完这一次请求结束之后,请求数量已经加一,不会丢掉这个请求数

@myzhan
Copy link
Owner

myzhan commented Oct 9, 2022

@xyzdev-cell 如果只有请求数量不准这个问题,你可以自行用 atomic 记一下请求数,然后把 runner.go 里面定时上报给 master 的 stats 信息打出来核对一下。

@kylezk777
Copy link

是否有计划将其改成类似于python这种形式,实现spawn的时候,在已有的连接上增加呢。创建一个work的线程池是否可以可以实现这种功能

@myzhan
Copy link
Owner

myzhan commented Oct 13, 2022

@kylezk777 需要先澄清一下,连接和 goroutine 数没有直接联系。后续在 goroutine 的增加和减少上,可以考虑做成 locust 那样。

@kylezk777
Copy link

kylezk777 commented Oct 13, 2022

我们目前项目想要实现阶梯性的压测,比如target是1000个goroutine,分阶段达到1000,类似于jmeter那种,目前好像只能通过手动去改变spawn,但是就像这个issue所说的,每次spawn会stop之前所有的,压力会有个骤降,然后再重新for循环开启goroutine,这种效果不是很理想。请问是否有确切的计划,去改善这方面的功能吗

@myzhan
Copy link
Owner

myzhan commented Oct 13, 2022

@kylezk777 阶梯性的压测,用 ratelimiter 来控制 RPS 能否满足?还是说一定要通过 goroutine 来实现多个并发?我目前知道要怎么改善,但是因为工作比较满,暂时没时间编码。如果你能完成,欢迎 PR。

改善这块的主要考虑点:

  1. spawn 的阶梯性递增和递减都要支持
  2. 多个 task 在递增和递减时,要按权重来分派

@MyNextWeekend
Copy link
Contributor

是否考虑引入context,增加worker 就把对应的cancelFunc 加入到cancelFuncList 。需要减少worker 的时候就从cancelFuncList尾部执行对应cancelFunc。
由于需要比对当前worker数量和目标worker数量的差值, 用于执行增加或者减少worker 。会引入锁来保护cancelFuncList以及当前worker 数量。
这样增加和减少worker 会更平滑。
可行的话我可以提pr

@myzhan
Copy link
Owner

myzhan commented Oct 24, 2023

目前已经实现。

@myzhan myzhan closed this as completed Oct 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants