From 39c6238f6a3505e711ce3288db42cf935c1468f8 Mon Sep 17 00:00:00 2001 From: einhirn Date: Thu, 4 Mar 2021 11:15:59 +0100 Subject: [PATCH] make @defnull's proposition into a PR --- README.md | 8 ++++++++ config/application.rb | 18 ++++++++++++++++++ lib/tasks/poll.rake | 38 ++++++++++++++++++++++++++++---------- 3 files changed, 54 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 16115c520..c2051d6c4 100644 --- a/README.md +++ b/README.md @@ -152,6 +152,14 @@ These variables are used by the service startup scripts in the Docker images, bu * `RESPONSE_TIMEOUT`: The timeout to wait for a response after sending a request to the BigBlueButton server in the load balancer and poller in seconds. Default is 10 seconds. Floating point numbers can be used for timeouts less than 1 second. * `LOAD_MIN_USER_COUNT`: Minimum user count of a meeting, used for calculating server load. Defaults to 15. * `LOAD_JOIN_BUFFER_TIME`: The time(in minutes) until the `LOAD_MIN_USER_COUNT` will be used for calculating server load. Defaults to 15. +* `LOAD_WEIGHT_MEETINGS`: The weight the number of meetings will have in calculating server load +* `LOAD_WEIGHT_USERS`: The weight the number of users will have in calculating server load +* `LOAD_WEIGHT_AUDIO`: The weight the number of audio-streams will have in calculating server load. Alternatively explicitly specify weight for rx and tx, see below. +* `LOAD_WEIGHT_VIDEO`: The weight the number of video-streams will have in calculating server load. Alternatively explicitly specify weight for rx and tx, see below. +* `LOAD_WEIGHT_AUDIO_RX`: The weight the number of received audio-streams will have in calculating server load. For more fine-grained control. +* `LOAD_WEIGHT_AUDIO_TX`: The weight the number of sent audio-streams will have in calculating server load. For more fine-grained control. +* `LOAD_WEIGHT_VIDEO_RX`: The weight the number of received video-streams will have in calculating server load. For more fine-grained control. +* `LOAD_WEIGHT_VIDEO_TX`: The weight the number of sent video-streams will have in calculating server load. For more fine-grained control. * `SERVER_ID_IS_HOSTNAME`: If set to "true", then instead of generating random UUIDs as the server ID when adding a server Scalelite will use the hostname of the server as the id. Server hostnames will be checked for uniqueness. Defaults to "false". * `CREATE_EXCLUDE_PARAMS`: List of BBB server attributes that should not be modified by create API call. Should be in the format 'CREATE_EXCLUDE_PARAMS="param1,param2,param3"'. * `JOIN_EXCLUDE_PARAMS`: List of BBB server attributes that should not be modified by join API call. Should be in the format 'JOIN_EXCLUDE_PARAMS="param1,param2,param3"'. diff --git a/config/application.rb b/config/application.rb index 4261bbacd..38533243a 100644 --- a/config/application.rb +++ b/config/application.rb @@ -95,6 +95,24 @@ class Application < Rails::Application # Whether to generate ids for servers based on the hostname rather than random UUIDs. Default to false. config.x.server_id_is_hostname = ENV.fetch('SERVER_ID_IS_HOSTNAME', 'false').casecmp?('true') + # The weight the number of meetings will have in calculating server load + config.x.weight_meetings = ENV.fetch('LOAD_WEIGHT_MEETINGS', 1.0).to_d + + # The weight the number of users will have in calculating server load + config.x.weight_users = ENV.fetch('LOAD_WEIGHT_USERS', 0).to_d + + # The weight the number of audio-rx-streams will have in calculating server load. Can use same weight for both. + config.x.weight_audio_rx = (ENV.fetch('LOAD_WEIGHT_AUDIO_RX') { ENV.fetch('LOAD_WEIGHT_AUDIO', 0) }).to_d + + # The weight the number of audio-tx-streams will have in calculating server load. Can use same weight for both. + config.x.weight_audio_tx = (ENV.fetch('LOAD_WEIGHT_AUDIO_TX') { ENV.fetch('LOAD_WEIGHT_AUDIO', 0) }).to_d + + # The weight the number of video-rx-streams will have in calculating server load. Can use same weight for both. + config.x.weight_video_rx = (ENV.fetch('LOAD_WEIGHT_VIDEO_RX') { ENV.fetch('LOAD_WEIGHT_VIDEO', 0) }).to_d + + # The weight the number of video-tx-streams will have in calculating server load. Can use same weight for both. + config.x.weight_video_tx = (ENV.fetch('LOAD_WEIGHT_VIDEO_TX') { ENV.fetch('LOAD_WEIGHT_VIDEO', 0) }).to_d + # Recording feature will be disabled, if set to 'true'. Defaults to false. config.x.recording_disabled = ENV.fetch('RECORDING_DISABLED', 'false').casecmp?('true') # List of BBB server attributes that should not be modified by create API call diff --git a/lib/tasks/poll.rake b/lib/tasks/poll.rake index 5f4d1b3f9..75718e186 100644 --- a/lib/tasks/poll.rake +++ b/lib/tasks/poll.rake @@ -38,34 +38,52 @@ namespace :poll do resp = get_post_req(encode_bbb_uri('getMeetings', server.url, server.secret)) meetings = resp.xpath('/response/meetings/meeting') - total_attendees = 0 load_min_user_count = Rails.configuration.x.load_min_user_count x_minutes_ago = Rails.configuration.x.load_join_buffer_time.ago - + weight_meetings = Rails.configuration.x.weight_meetings + weight_users = Rails.configuration.x.weight_users + weight_audio_rx = Rails.configuration.x.weight_audio_rx + weight_audio_tx = Rails.configuration.x.weight_audio_tx + weight_video_rx = Rails.configuration.x.weight_video_rx + weight_video_tx = Rails.configuration.x.weight_video_tx + + load = 0.0 meetings.each do |meeting| created_time = Time.zone.at(meeting.xpath('.//createTime').text.to_i / 1000) actual_attendees = meeting.xpath('.//participantCount').text.to_i + meeting.xpath('.//moderatorCount').text.to_i - next if meeting.xpath('.//isBreakout').text.eql?('true') - total_attendees += if created_time > x_minutes_ago - [actual_attendees, load_min_user_count].max - else - actual_attendees - end + attendees = if created_time > x_minutes_ago + [actual_attendees, load_min_user_count].max + else + actual_attendees + end + audio = meeting.at('voiceParticipantCount')&.content.to_i + video = meeting.at('videoCount')&.content.to_i + load += weight_meetings * 1 + # Account for users in main rooms only - they join two rooms at the same time. + load += weight_users * attendees if meeting.xpath('.//isBreakout').text.eql?('false') + # Audio is mixed server-side -> Only one downstream per user + load += weight_audio_rx * audio + load += weight_audio_tx * attendees if audio + # Video is NOT mixed server-side -> One downstream per user per video + load += weight_video_rx * video + load += weight_video_tx * attendees * video end + load *= server.load_multiplier.nil? ? 1.0 : server.load_multiplier.to_d + # Reset unhealthy counter so that only consecutive unhealthy calls are counted server.reset_unhealthy_counter if server.online # Update the load if the server is currently online - server.load = total_attendees * (server.load_multiplier.nil? ? 1.0 : server.load_multiplier.to_d) + server.load = load else # Only bring the server online if the number of successful requests is >= the acceptable threshold next if server.increment_healthy < Rails.configuration.x.server_healthy_threshold Rails.logger.info("Server id=#{server.id} is healthy. Bringing back online...") server.reset_counters - server.load = total_attendees * (server.load_multiplier.nil? ? 1.0 : server.load_multiplier.to_d) + server.load = load server.online = true end