新手问题 Sidekiq 如何 load balance queue 和 worker

leijun · 2019年03月22日 · 最后由 leijun 回复于 2019年03月29日 · 670 次阅读

大家好,我还是新手,来询问一个关于sidekiq 和redis 相关的问题 我现在遇到一个难题,现在的项目做公司分析 平均一个公司分析大概耗时40秒,我们把它放在sidekiq 里 后台执行。 每一个客户可以有很多公司分析. 问题来了,

第一种情况 : 如果客户A开启1000个公司分析., 另外客户B在1分钟后开启一个公司分析., 那么我们不想要客户B 等客户A分析完1000个公司, 然后再分析客户B的单个公司分析。 我的提议的使用两个不同的queue

queues:
  - [normal_client, 20]
  - [urgent_client, 40]

这样客户B就能先插队

第二种情况 : 如果客户A开启1000个公司分析, 另外客户B在1分钟后也开启100公司分析, 这样我们不希望客户B的100个公司分析要等到客户A的1000个公司分析 之后, 我希望找一个好的解决方案, 比如客户A和客户B交互分析, 客户A分析一下,然后客户B分析一下, 这样大概 客户A分析完前100个客户的时候, 客户B的100也要分析完毕。 这种情况下该如何设计queue, 或者如何设计如何把job放进worker里? 或者前面再来一层数据结构 ?

第三张情况: 我希望每个客户都能有大概时间等待现实, 现在不止两个客户, 我们假设有很多客户,每个客户有不同数量的公司分析,如果 客户A 开始分析 , 然后 客户B C D etc.. 开始 插队。 那势必导致客户A不断延长他的等待时间,这将造成我们刚开始给客户A的等待时间不断延长, 这将到底客户A的不信任感, 客户A 会想, 我可是你们的大金主,什么阿猫阿狗都能插我的队 ! 那这种情况下该有什么好的解决方案?

这个帖子 我想和大家探讨学习。 先提前感谢大家

共收到 18 条回复

也许是我水平有限。但感觉题中的问题不应该是用Sidekiq来做的。

你说的「公司分析」,猜测起来应该是一个Worker Class,毕竟都是「公司分析」,不应该因为完全可变的外部信息客户ABC而弄出多种Worker,否则搞出 AbcWorker、ZzzWorker了?

另外你Sidekiq的配置里的权重数不好,Sidekiq只关心比例,所以20-40应该改成1-2。

urgent_client单独启一个worker咯

进程调度问题

给每个用户 100 个额度,用完了再分配。

第一个和第二个问题 假设 A 算 1000 个单位,就先让他算 100 个,算完了再分给他 100。这个时候,B 进来了,B 插入 100 个任务,B 就会先算完。

第三个问题 加优先级就可以,爸爸们都放到爸爸队列里,爸爸们有任务,就先算爸爸的。还可以,如果是爸爸,就分配 200 个单位。

还可以从需求上解决,比如算完 1 个就给反馈什么的。

yfractal 回复

感觉你抓住了问题的重点。 谢谢, 我先去研究一下如何给每个用户额度, 和我组的CTO 讨论讨论该提议能不能管用。 然后看看该如何写代码。 你说起进程调度问题, 我看到有个GEM sidekiq scheduling, 不知道这个gem有没有用

hooopo 回复

谢谢, 我会考虑考虑的

blacklee 回复

所以客户使用该服务的时候都使用同一个worker. 一个服务对应一个worker.

leijun 回复

这个 Gem 不是定时任务的 Gem 么

leijun 回复

那个 gem 还真没了解过 😅

@leijun 多起几个进程,每个进程可以有不同的配置,我们每个docker container起两个 sidekiq进程,

  • 一个进程要保证任务成功用了 sidekiq-pro,
  • 另一个进程只读数据库,不需要写,所以可以不用sidekiq-pro,崩溃了也无所谓,没用sidekiq-pro在redis效率上应该会更高一点。

一个进程太多threads感觉不是很好,考虑多起几个服务器多几个进程吧。

如果你的服务器一下子来了很多任务 你都希望尽快完成,那你就需要考虑auto scaling,我们有个定时任务 定时去redis里查 有多少个key,如果某个queue里的key 增加到一定数量就会触发 增加服务器,启动更多的sidekiq进程。Task Count就是服务器数量, key少了就减少服务器。自动扩展需要考虑数据库max connection,设置个服务器上限和下限。

yakjuly 回复

为啥不用多线程做?ruby 多线程不靠谱吗?

yfractal 回复

可以用sidekiq thread,thread多了,任务满载,cpu和memory容易100%。 进程也是一样的,不过你可以在不同的服务器上开进程,不用把所有资源都放在一个服务器上,自己控制threads,把cpu,memory控制在合理范围内就好。

这种要自己定义规则了吧,感觉数据库最适合,再加一个worker去数据库定期取数据放在queue里

不要把分析N个公司作为一次原子操作,

建议把分析一个公司, 变为一次原子操作

用那种加权方式 比如 A 客户等级是 100 B 客户等级是 10 , 之后A 客户的一个企业分析权值就是100, B的一个企业分析一次分析就是10

之后一个true 循环这个大数组, 每循环一次, 数组里所有权值 + 1 , 之后再把权值最大的任务执行掉, 拿出去.

这里的重点, 是每检测循环一次, 数组所有的权值+1

这样, 具有最高权值的任务就会优先执行, 低权值的数据, 也会因为遍历次数的增长, 而变成高权值的数据, 不至于在这个循环里没有执行的机会

yakjuly 回复

明白,看来八成是 cpu 密集型任务,多线程没啥意义。亦或是sidkiq 调度多任务的时候,消耗比较大……

nouse 回复

这个定期取数据的worker 是独立的是吧? 启动server以后就开启这个worker, 比如 每10秒观察Redis数据库里的这个特别queue. 看到有就启动我们的别的worker.perform_async ?

nouse 回复

你好, 这里放在数据库里定期去取, 这里哪种数据库比较好 , 是PG还是 Redis? 我看到Redis 好难操作啊 , 不知道如何存储

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册