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

Split Meteor roles backend-frontend revisit #11317

Merged
Original file line number Diff line number Diff line change
Expand Up @@ -70,13 +70,13 @@ class FromAkkaAppsMsgSenderActor(msgSender: MessageSender)

// Whiteboard
case SendWhiteboardAnnotationEvtMsg.NAME =>
msgSender.send(fromAkkaAppsWbRedisChannel, json)
msgSender.send("from-akka-apps-frontend-redis-channel", json)
case SendCursorPositionEvtMsg.NAME =>
msgSender.send(fromAkkaAppsWbRedisChannel, json)
msgSender.send("from-akka-apps-frontend-redis-channel", json)
case ClearWhiteboardEvtMsg.NAME =>
msgSender.send(fromAkkaAppsWbRedisChannel, json)
msgSender.send("from-akka-apps-frontend-redis-channel", json)
case UndoWhiteboardEvtMsg.NAME =>
msgSender.send(fromAkkaAppsWbRedisChannel, json)
msgSender.send("from-akka-apps-frontend-redis-channel", json)

// Chat
case SendPublicMessageEvtMsg.NAME =>
Expand Down Expand Up @@ -118,6 +118,31 @@ class FromAkkaAppsMsgSenderActor(msgSender: MessageSender)
case UserRespondedToPollRecordMsg.NAME =>
//==================================================================

case ValidateAuthTokenRespMsg.NAME =>
msgSender.send(fromAkkaAppsRedisChannel, json) // needed for cases when single nodejs process is running (like in development)
msgSender.send("from-akka-apps-frontend-redis-channel", json)

// Message duplicated for frontend and backend processes
case MeetingCreatedEvtMsg.NAME =>
msgSender.send(fromAkkaAppsRedisChannel, json)
msgSender.send("from-akka-apps-frontend-redis-channel", json)

case MeetingEndingEvtMsg.NAME =>
msgSender.send(fromAkkaAppsRedisChannel, json)
msgSender.send("from-akka-apps-frontend-redis-channel", json)

case MeetingDestroyedEvtMsg.NAME =>
msgSender.send(fromAkkaAppsRedisChannel, json)
msgSender.send("from-akka-apps-frontend-redis-channel", json)

case UserLeftMeetingEvtMsg.NAME =>
msgSender.send(fromAkkaAppsRedisChannel, json)
msgSender.send("from-akka-apps-frontend-redis-channel", json)

case UserLeftVoiceConfToClientEvtMsg.NAME =>
msgSender.send(fromAkkaAppsRedisChannel, json)
msgSender.send("from-akka-apps-frontend-redis-channel", json)

case _ =>
msgSender.send(fromAkkaAppsRedisChannel, json)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,16 @@ public void init() {
log.info("HTML5LoadBalancingService initialised");
}

// Find nodejs processes associated with processing meeting events
// $ ps -u meteor -o pcpu,cmd= | grep NODEJS_BACKEND_INSTANCE_ID
// 1.1 /usr/share/node-v12.16.1-linux-x64/bin/node --max-old-space-size=2048 --max_semi_space_size=128 main.js NODEJS_BACKEND_INSTANCE_ID=1
// 1.0 /usr/share/node-v12.16.1-linux-x64/bin/node --max-old-space-size=2048 --max_semi_space_size=128 main.js NODEJS_BACKEND_INSTANCE_ID=2
public void scanHTML5processes() {
try {
this.list = new ArrayList<HTML5ProcessLine>();
Process p1 = Runtime.getRuntime().exec(new String[]{"ps", "-u", "meteor", "-o", "pcpu,cmd="});
InputStream input1 = p1.getInputStream();
Process p2 = Runtime.getRuntime().exec(new String[]{"grep", "node-"});
Process p2 = Runtime.getRuntime().exec(new String[]{"grep", HTML5ProcessLine.BBB_HTML5_PROCESS_IDENTIFIER});
OutputStream output = p2.getOutputStream();
IOUtils.copy(input1, output);
output.close(); // signals grep to finish
Expand All @@ -73,24 +77,6 @@ private boolean listItemWithIdExists(int id) {
return false;
}

public int findSuitableHTML5ProcessByLookingAtCPU() {
this.scanHTML5processes();
if (list.isEmpty()) {
log.warn("Did not find any instances of html5 process running");
return 1;
}
double smallestCPUvalue = this.list.get(0).percentageCPU;
int instanceIDofSmallestCPUValue = this.list.get(0).instanceId;
for (HTML5ProcessLine line : this.list) {
System.out.println(line.toString());
if (smallestCPUvalue > line.percentageCPU) {
smallestCPUvalue = line.percentageCPU;
instanceIDofSmallestCPUValue = line.instanceId;
}
}
return instanceIDofSmallestCPUValue;
}

public int findSuitableHTML5ProcessByRoundRobin() {
this.scanHTML5processes();
if (list.isEmpty()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,21 @@ public class HTML5ProcessLine {
public int instanceId;
public double percentageCPU;

public static final String BBB_HTML5_PROCESS_IDENTIFIER = "NODEJS_BACKEND_INSTANCE_ID";

public HTML5ProcessLine(String input) {
// System.out.println("input:" + input);
// 0.1 /usr/share/node-v12.16.1-linux-x64/bin/node main.js INFO_INSTANCE_ID=3
// $ ps -u meteor -o pcpu,cmd= | grep NODEJS_BACKEND_INSTANCE_ID
// 1.1 /usr/share/node-v12.16.1-linux-x64/bin/node --max-old-space-size=2048 --max_semi_space_size=128 main.js NODEJS_BACKEND_INSTANCE_ID=1
// 1.0 /usr/share/node-v12.16.1-linux-x64/bin/node --max-old-space-size=2048 --max_semi_space_size=128 main.js NODEJS_BACKEND_INSTANCE_ID=2

String[] a = input.trim().split(" ");
this.percentageCPU = Double.parseDouble(a[0]);
String instanceIdInfo = a[3];
this.instanceId = Integer.parseInt(instanceIdInfo.replace("INFO_INSTANCE_ID=", ""));

for (int i = 0; i < a.length; i++) {
if (a[i].toString().indexOf(BBB_HTML5_PROCESS_IDENTIFIER) > -1) {
this.instanceId = Integer.parseInt(a[i].replace(BBB_HTML5_PROCESS_IDENTIFIER + "=", ""));
}
}
}

public String toString() {
Expand Down
105 changes: 105 additions & 0 deletions bigbluebutton-html5/deploy_to_usr_share.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
#!/bin/sh -e

# Please check bigbluebutton/bigbluebutton-html5/dev_local_deployment/README.md

echo " start "
pwd
UPPER_DESTINATION_DIR=/usr/share/meteor
DESTINATION_DIR=$UPPER_DESTINATION_DIR/bundle

SERVICE_FILES_DIR=/usr/lib/systemd/system
LOCAL_PACKAGING_DIR=/home/bigbluebutton/dev/bigbluebutton/bigbluebutton-html5/dev_local_deployment

sudo rm -rf "$UPPER_DESTINATION_DIR"
sudo mkdir -p "$UPPER_DESTINATION_DIR"
sudo chown -R meteor:meteor "$UPPER_DESTINATION_DIR"

# the next 5 lines may be temporarily commented out if you are sure you are not tweaking the required node_modules after first use of the script. This will save a minute or two during the run of the script
if [ -d "node_modules" ]; then
rm -r node_modules/
fi
meteor reset
meteor npm install --production


sudo chmod 777 /usr/share/meteor
METEOR_DISABLE_OPTIMISTIC_CACHING=1 meteor build $UPPER_DESTINATION_DIR --architecture os.linux.x86_64 --allow-superuser

sudo chown -R meteor:meteor "$UPPER_DESTINATION_DIR"/
echo 'stage3'


tar -xzf $UPPER_DESTINATION_DIR/bigbluebutton-html5.tar.gz -C $UPPER_DESTINATION_DIR


cd "$DESTINATION_DIR"/programs/server/ || exit
npm i --production
echo "deployed to $DESTINATION_DIR/programs/server\n\n\n"

echo "writing $DESTINATION_DIR/mongod_start_pre.sh"
sudo cp $LOCAL_PACKAGING_DIR/mongod_start_pre.sh "$DESTINATION_DIR"/mongod_start_pre.sh

echo "writing $DESTINATION_DIR/mongo-ramdisk.conf"
sudo cp $LOCAL_PACKAGING_DIR/mongo-ramdisk.conf "$DESTINATION_DIR"/mongo-ramdisk.conf

echo "writing $DESTINATION_DIR/bbb-html5-with-roles.conf"
sudo tee "$DESTINATION_DIR/bbb-html5-with-roles.conf" >/dev/null <<HERE
# Default = 1; Min = 1; Max = 4
# On powerful systems with high number of meetings you can set values up to 4 to accelerate handling of events
NUMBER_OF_BACKEND_NODEJS_PROCESSES=2
# Default = 1; Min = 0; Max = 8
# If 0 is set, bbb-html5 will handle both backend and frontend roles in one process (default until Feb 2021)
# Set a number between 1 and 4 times the value of NUMBER_OF_BACKEND_NODEJS_PROCESSES where higher number helps with meetings
# stretching the recommended number of users in BigBlueButton
NUMBER_OF_FRONTEND_NODEJS_PROCESSES=2

HERE

echo "writing $DESTINATION_DIR/systemd_start.sh"
sudo cp $LOCAL_PACKAGING_DIR/systemd_start.sh "$DESTINATION_DIR"/systemd_start.sh

echo "writing $DESTINATION_DIR/systemd_start_frontend.sh"
sudo cp $LOCAL_PACKAGING_DIR/systemd_start_frontend.sh "$DESTINATION_DIR"/systemd_start_frontend.sh

echo "writing $DESTINATION_DIR/workers-start.sh"
sudo cp $LOCAL_PACKAGING_DIR/workers-start.sh "$DESTINATION_DIR"/workers-start.sh

sudo chown -R meteor:meteor "$UPPER_DESTINATION_DIR"/
sudo chmod +x "$DESTINATION_DIR"/mongod_start_pre.sh
sudo chmod +x "$DESTINATION_DIR"/systemd_start.sh
sudo chmod +x "$DESTINATION_DIR"/systemd_start_frontend.sh
sudo chmod +x "$DESTINATION_DIR"/workers-start.sh



echo "writing $SERVICE_FILES_DIR/bbb-html5-frontend@.service"
sudo cp $LOCAL_PACKAGING_DIR/bbb-html5-frontend@.service "$SERVICE_FILES_DIR"/bbb-html5-frontend@.service

echo "writing $SERVICE_FILES_DIR/bbb-html5-backend@.service"
sudo cp $LOCAL_PACKAGING_DIR/bbb-html5-backend@.service "$SERVICE_FILES_DIR"/bbb-html5-backend@.service

sudo systemctl daemon-reload

echo 'before stopping bbb-html5:'
ps -ef | grep node-
sudo netstat -netlp | grep -i node
echo 'before stopping bbb-html5:'
echo '_____________'

sudo systemctl stop bbb-html5

sleep 5s
echo 'after stopping bbb-html5:'
ps -ef | grep node-
sudo netstat -netlp | grep -i node
echo 'after stopping bbb-html5:'
echo '_____________'

echo 'starting bbb-html5'
sudo systemctl start bbb-html5
sleep 10s
echo 'after:...'
ps -ef | grep node-
sudo netstat -netlp | grep -i node
echo 'after:'
echo '_____________'
9 changes: 9 additions & 0 deletions bigbluebutton-html5/dev_local_deployment/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
Last change on Feb 16, 2021

This directory contains files needed for the correct deployment of bigbluebutton-html5 **on a development environment**.

They are very similar, or even identical to the files used for `bbb-html5` packaging, however, the main difference is that this set of files may be unintentionally **out of date**.

The script `deploy_to_usr_share.sh` was written to allow developers to be able to wipe out the `/usr/share/meteor` directory where `bbb-html5` package is installed, and at the same time build their local code and deploy it so it replaces the default `bbb-html5`. The script has been indispensible during the work on https://github.com/bigbluebutton/bigbluebutton/pull/11317 where multiple NodeJS processes were to run simultaneously but using different configuration.


Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[Unit]
Description=BigBlueButton HTML5 service, backend instance %i
Requires=bbb-html5.service
Before=bbb-html5.service
BindsTo=bbb-html5.service

[Service]
PermissionsStartOnly=true
#Type=simple
Type=idle
EnvironmentFile=/usr/share/meteor/bundle/bbb-html5-with-roles.conf
ExecStart=/usr/share/meteor/bundle/systemd_start.sh %i $BACKEND_NODEJS_ROLE
WorkingDirectory=/usr/share/meteor/bundle
StandardOutput=syslog
StandardError=syslog
TimeoutStartSec=10
RestartSec=10
User=meteor
Group=meteor
CPUSchedulingPolicy=fifo
Nice=19

[Install]
WantedBy=bbb-html5.service
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[Unit]
Description=BigBlueButton HTML5 service, frontend instance %i
Requires=bbb-html5.service
Before=bbb-html5.service
BindsTo=bbb-html5.service

[Service]
PermissionsStartOnly=true
#Type=simple
Type=idle
EnvironmentFile=/usr/share/meteor/bundle/bbb-html5-with-roles.conf
ExecStart=/usr/share/meteor/bundle/systemd_start_frontend.sh %i
WorkingDirectory=/usr/share/meteor/bundle
StandardOutput=syslog
StandardError=syslog
TimeoutStartSec=10
RestartSec=10
User=meteor
Group=meteor
CPUSchedulingPolicy=fifo
Nice=19

[Install]
WantedBy=bbb-html5.service
32 changes: 32 additions & 0 deletions bigbluebutton-html5/dev_local_deployment/mongo-ramdisk.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# mongod.conf

# for documentation of all options, see:
# http://docs.mongodb.org/manual/reference/configuration-options/

storage:
dbPath: /mnt/mongo-ramdisk
journal:
enabled: true
wiredTiger:
engineConfig:
cacheSizeGB: 0
journalCompressor: none
directoryForIndexes: true
collectionConfig:
blockCompressor: none
indexConfig:
prefixCompression: false

systemLog:
destination: file
logAppend: true
path: /var/log/mongodb/mongod.log

net:
port: 27017
bindIp: 127.0.1.1


replication:
replSetName: rs0

14 changes: 14 additions & 0 deletions bigbluebutton-html5/dev_local_deployment/mongod_start_pre.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#!/bin/bash

rm -rf /mnt/mongo-ramdisk/*
mkdir -p /mnt/mongo-ramdisk
if /bin/findmnt | grep -q "/mnt/mongo-ramdisk"; then
umount /mnt/mongo-ramdisk/
fi
if [ ! -f /.dockerenv ]; then
mount -t tmpfs -o size=512m tmpfs /mnt/mongo-ramdisk
fi

chown -R mongodb:mongodb /mnt/mongo-ramdisk


51 changes: 51 additions & 0 deletions bigbluebutton-html5/dev_local_deployment/systemd_start.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/bin/bash -e

#Allow to run outside of directory
cd $(dirname $0)

echo "Starting mongoDB"

#wait for mongo startup
MONGO_OK=0

while [ "$MONGO_OK" = "0" ]; do
MONGO_OK=$(netstat -lan | grep 127.0.1.1 | grep 27017 &> /dev/null && echo 1 || echo 0)
sleep 1;
done;

echo "Mongo started";

echo "Initializing replicaset"
mongo 127.0.1.1 --eval 'rs.initiate({ _id: "rs0", members: [ {_id: 0, host: "127.0.1.1"} ]})'


echo "Waiting to become a master"
IS_MASTER="XX"
while [ "$IS_MASTER" \!= "true" ]; do
IS_MASTER=$(mongo mongodb://127.0.1.1:27017/ --eval 'db.isMaster().ismaster' | tail -n 1)
sleep 0.5;
done;

echo "I'm the master!"

if [ -z $1 ]
then
INSTANCE_ID=1
else
INSTANCE_ID=$1
fi

PORT=$(echo "3999+$INSTANCE_ID" | bc)

echo "instanceId = $INSTANCE_ID and port = $PORT and role is backend (in backend file)"

export INSTANCE_ID=$INSTANCE_ID
export BBB_HTML5_ROLE=backend
export ROOT_URL=http://127.0.0.1/html5client
export MONGO_OPLOG_URL=mongodb://127.0.1.1/local
export MONGO_URL=mongodb://127.0.1.1/meteor
export NODE_ENV=production
export NODE_VERSION=node-v12.16.1-linux-x64
export SERVER_WEBSOCKET_COMPRESSION=0
export BIND_IP=127.0.0.1
PORT=$PORT /usr/share/$NODE_VERSION/bin/node --max-old-space-size=2048 --max_semi_space_size=128 main.js NODEJS_BACKEND_INSTANCE_ID=$INSTANCE_ID