This is an automated email from the ASF dual-hosted git repository.

adonisling pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 0950a08efd [chore](tools) Support starting multiple FEs on single node 
(#16787)
0950a08efd is described below

commit 0950a08efd87e8993bb9d3af901b6207ca3fabda
Author: Adonis Ling <[email protected]>
AuthorDate: Tue Feb 21 10:55:36 2023 +0800

    [chore](tools) Support starting multiple FEs on single node (#16787)
    
    Introduce a tool to start multiple FEs on single node.
    
    Use case:
    
    ```
    $ ./multi-fe
    ./multi-fe start|stop|clean [OPTIONS ...]
    
        start -n <NUM> -l <LIBRARY_PATH> -p <BASE_PORT>
    
                 Start the FE cluster.
          -n     The number of FEs.
          -l     The FE library path (default: doris/output/fe/lib)
          -p     The base port to generate all needed ports (default: 9030).
    
        stop     Stop the FE cluster.
    
        clean    Stop the data (rm -rf "$(pwd)"/fe*).
    ```
---
 .gitignore                         |   1 +
 tools/single-node-cluster/multi-fe | 268 +++++++++++++++++++++++++++++++++++++
 2 files changed, 269 insertions(+)

diff --git a/.gitignore b/.gitignore
index 5ba2f22e45..c6229863aa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -92,6 +92,7 @@ tools/**/TPC-H_Tools_v*/
 tools/**/tpc-h_v*.docx
 tools/**/tpc-h_v*.pdf
 tools/**/tpch-data/
+tools/single-node-cluster/fe*
 
 # be-ut
 data_test
diff --git a/tools/single-node-cluster/multi-fe 
b/tools/single-node-cluster/multi-fe
new file mode 100755
index 0000000000..762fab14fa
--- /dev/null
+++ b/tools/single-node-cluster/multi-fe
@@ -0,0 +1,268 @@
+#!/bin/bash
+
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License.  You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied.  See the License for the
+# specific language governing permissions and limitations
+# under the License.
+
+set -e
+
+CURRENT_PATH="$(
+       cd "$(dirname "${BASH_SOURCE[0]}")"
+       pwd
+)"
+OUTPUT_PATH="$(readlink -f "${CURRENT_PATH}/../../output")"
+
+readonly CURRENT_PATH
+readonly OUTPUT_PATH
+
+function log() {
+       local level="${1}"
+       local message="${2}"
+       local date
+       date="$(date +'%Y-%m-%d %H:%M:%S')"
+       if [[ "${level}" == 'INFO' ]]; then
+               level="[\033[32;1m ${level}  \033[0m]"
+       elif [[ "${level}" == 'WARNING' ]]; then
+               level="[\033[33;1m${level}\033[0m]"
+       elif [[ "${level}" == 'ERROR' ]]; then
+               level="[\033[31;1m ${level} \033[0m]"
+       fi
+       echo -e "${level} ${date} - ${message}"
+}
+
+function log_info() {
+       local message="${1}"
+       log 'INFO' "${message}"
+}
+
+function log_warning() {
+       local message="${1}"
+       log 'WARNING' "${message}"
+}
+
+function log_error() {
+       local message="${1}"
+       log 'ERROR' "${message}"
+       exit 1
+}
+
+function help() {
+       cat >&2 <<EOF
+${BASH_SOURCE[0]} start|stop|clean [OPTIONS ...]
+
+    start -n <NUM> -l <LIBRARY_PATH> -p <BASE_PORT>
+
+             Start the FE cluster.
+      -n     The number of FEs.
+      -l     The FE library path (default: doris/output/fe/lib)
+      -p     The base port to generate all needed ports (default: 9030).
+
+    stop     Stop the FE cluster.
+
+    clean    Stop the data (rm -rf "\$(pwd)"/fe*).
+EOF
+       exit 1
+}
+
+function parse_options() {
+       NUMBER_INSTANCES=1
+       PORT=9010
+       LIBS_PATH="${OUTPUT_PATH}/fe/lib"
+
+       ACTION="${1}"
+       if ! shift 1; then
+               help
+       fi
+
+       local option
+       while getopts "+n:p:l:" option; do
+               case "${option}" in
+               n)
+                       NUMBER_INSTANCES="${OPTARG}"
+                       ;;
+               p)
+                       PORT="${OPTARG}"
+                       ;;
+               l)
+                       LIBS_PATH="$(readlink -f "${OPTARG}")"
+                       ;;
+               *)
+                       help
+                       ;;
+               esac
+       done
+
+       readonly NUMBER_INSTANCES
+       readonly PORT
+       readonly LIBS_PATH
+}
+
+function prepare() {
+       local port="${1}"
+       local doris_home="${2}"
+       local log_dir="${3}"
+       local conf_dir="${doris_home}/conf"
+       local meta_dir="${doris_home}/doris-meta"
+       local http_port=8030
+
+       mkdir -p "${doris_home}"
+       mkdir -p "${log_dir}"
+       mkdir -p "${conf_dir}"
+       mkdir -p "${meta_dir}"
+
+       cat >"${conf_dir}/fe.conf" <<EOF
+LOG_DIR = ${log_dir}
+meta_dir = ${meta_dir}
+
+edit_log_port = $((port + id))
+rpc_port = $((port + 10 + id))
+query_port = $((port + 20 + id))
+http_port = $((http_port + id))
+
+sys_log_level = INFO
+sys_log_verbose_modules = org.apache.doris
+
+mysql_service_nio_enabled = true
+
+priority_networks = 127.0.0.1/32
+EOF
+}
+
+function mysql_command() {
+       local command="${1}"
+       local query_port
+       query_port="$(grep 'query_port' "${CURRENT_PATH}/fe1/conf/fe.conf" | 
sed 's/query_port[[:space:]]*=[[:space:]]*//')"
+       mysql -h127.0.0.1 -P"${query_port}" -uroot -e "${command}" -s -N
+}
+
+function create_role_and_version() {
+       local id="${1}"
+       local http_port
+       local header
+       local meta_dir
+
+       http_port="$(grep 'http_port' "${CURRENT_PATH}/fe1/conf/fe.conf" | sed 
's/http_port[[:space:]]*=[[:space:]]*//')"
+       while true; do
+               if header="$(curl --noproxy '127.0.0.1' --silent --head --fail 
"http://127.0.0.1:${http_port}/check";)"; then
+                       break
+               fi
+               log_info "Waiting for the Master FE to be ready ..."
+               sleep 1
+       done
+       meta_dir="$(grep 'meta_dir' "${CURRENT_PATH}/fe${id}/conf/fe.conf" | 
sed 's/meta_dir[[:space:]]*=[[:space:]]*//')"
+
+       mkdir -p "${meta_dir}/image"
+       echo "${header}" | sed -n '/cluster_id/,/token/p' | sed '{s/cluster_id: 
/clusterId=/;s/token: /token=/;}' \
+               >"${meta_dir}/image/VERSION"
+
+       mysql_command "ALTER SYSTEM ADD FOLLOWER \"127.0.0.1:$((PORT + id))\"" 
>/dev/null 2>&1 || true
+       cat >"${meta_dir}/image/ROLE" <<EOF
+role=FOLLOWER
+name=$(
+               set -e
+               mysql_command "SHOW FRONTENDS" | grep "127.0.0.1_$((PORT + 
id))" | awk '{print $1}'
+       )
+EOF
+}
+
+function start_fe() {
+       local id="${1}"
+       local port="${2}"
+       local libs_path="${3}"
+       local doris_home
+       local helper
+
+       doris_home="$(pwd)/fe${id}"
+       local pid_dir="${doris_home}"
+       local log_dir="${doris_home}/log"
+
+       if [[ -f "${pid_dir}/fe.pid" ]]; then
+               if xargs kill -0 <"${pid_dir}/fe.pid"; then
+                       log_warning "FE(${id}) is running..."
+                       return
+               fi
+       fi
+
+       prepare "${port}" "${doris_home}" "${log_dir}"
+
+       local classpath
+       read -r -a classpath <<<"$(find "${libs_path}" -exec echo {} \+)"
+
+       if [[ "${id}" -gt 1 ]]; then
+               helper="-helper 127.0.0.1:$((PORT + 1))"
+               create_role_and_version "${id}"
+       fi
+
+       pushd "${doris_home}" >/dev/null
+       DORIS_HOME="${doris_home}" \
+               PID_DIR="${doris_home}" \
+               nohup java -cp "$(
+               IFS=:
+               echo "${classpath[*]}"
+       )" org.apache.doris.PaloFe ${helper:+${helper}} >>"${log_dir}/fe.out" 
2>&1 &
+       if kill -0 $!; then
+               log_info "Start FE(${id}) successfully"
+       else
+               log_warning "Failed to start FE(${id})"
+       fi
+       popd >/dev/null
+}
+
+function start() {
+       if [[ -z "${LIBS_PATH}" ]]; then
+               help
+       fi
+
+       log_info "NUMBER:       ${NUMBER_INSTANCES}"
+       log_info "BASE PORT:    ${PORT}"
+       log_info "LIBRARY_PATH: ${LIBS_PATH}"
+
+       for i in $(seq "${NUMBER_INSTANCES}"); do
+               start_fe "${i}" "${PORT}" "${LIBS_PATH}"
+       done
+}
+
+function stop() {
+       local pid
+       while read -r file; do
+               pid="$(<"${file}")"
+               if kill "${pid}"; then
+                       log_info "Stopped FE (${pid}) successfully"
+               else
+                       log_warning "Failed to stop FE (${pid})"
+               fi
+       done < <(find "$(pwd)"/fe* -name 'fe.pid')
+}
+
+function clean() {
+       rm -rf "$(pwd)"/fe*
+       log_info "Clean all data successfully"
+}
+
+function main() {
+       parse_options "${@}"
+
+       case "${ACTION}" in
+       start) start ;;
+       stop) stop ;;
+       clean) clean ;;
+       *)
+               help
+               ;;
+       esac
+}
+
+main "${@}"


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to