From 79a2f5c17c7ecbd1303b16e9205999c914d293e1 Mon Sep 17 00:00:00 2001 From: obdev Date: Wed, 13 Mar 2024 13:20:37 +0000 Subject: [PATCH] cherry-pick check os params --- src/observer/CMakeLists.txt | 1 + src/observer/ob_check_params.cpp | 318 ++++++++++++++++++ src/observer/ob_check_params.h | 52 +++ src/observer/ob_server.cpp | 6 +- src/share/parameter/ob_parameter_seed.ipp | 6 + .../all_virtual_sys_parameter_stat.result | 1 + unittest/observer/CMakeLists.txt | 1 + unittest/observer/test_check_os_params.cpp | 65 ++++ 8 files changed, 449 insertions(+), 1 deletion(-) create mode 100644 src/observer/ob_check_params.cpp create mode 100644 src/observer/ob_check_params.h create mode 100644 unittest/observer/test_check_os_params.cpp diff --git a/src/observer/CMakeLists.txt b/src/observer/CMakeLists.txt index bf0491fad..bcf9b9f64 100644 --- a/src/observer/CMakeLists.txt +++ b/src/observer/CMakeLists.txt @@ -38,6 +38,7 @@ ob_set_subtarget(ob_server common ob_uniq_task_queue.cpp ob_startup_accel_task_handler.cpp ob_srv_rpc_handler.cpp + ob_check_params.cpp ) ob_set_subtarget(ob_server common_mixed diff --git a/src/observer/ob_check_params.cpp b/src/observer/ob_check_params.cpp new file mode 100644 index 000000000..1c74daba8 --- /dev/null +++ b/src/observer/ob_check_params.cpp @@ -0,0 +1,318 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#define USING_LOG_PREFIX SERVER +#include "observer/ob_check_params.h" + +namespace oceanbase +{ +using namespace common; +namespace observer +{ +int CheckAllParams::check_all_params(bool strict_check = true) +{ + int ret = OB_SUCCESS; + if (OB_SUCC(ret) && OB_FAIL(check_vm_max_map_count(strict_check))) {} + + if (OB_SUCC(ret) && OB_FAIL(check_vm_min_free_kbytes(strict_check))) {} + + if (OB_SUCC(ret) && OB_FAIL(check_vm_overcommit_memory(strict_check))) {} + + if (OB_SUCC(ret) && OB_FAIL(check_fs_file_max(strict_check))) {} + + if (OB_SUCC(ret) && OB_FAIL(check_ulimit_open_files(strict_check))) {} + + if (OB_SUCC(ret) && OB_FAIL(check_ulimit_max_user_processes(strict_check))) {} + + if (OB_SUCC(ret) && OB_FAIL(check_ulimit_core_file_size(strict_check))) {} + + if (OB_SUCC(ret) && OB_FAIL(check_ulimit_stack_size(strict_check))) {} + + if (OB_SUCC(ret) && OB_FAIL(check_current_clocksource(strict_check))) {} + return ret; +} + +int CheckAllParams::read_one_int(const char *file_name, int64_t &value) +{ + int ret = OB_SUCCESS; + FILE *fp = fopen(file_name, "r"); + if (fp != nullptr) { + if (1 != fscanf(fp, "%ld", &value)) { + ret = OB_IO_ERROR; + LOG_ERROR("Failed to read integer from file", K(ret)); + } + fclose(fp); + } else { + ret = OB_FILE_NOT_EXIST; + LOG_WARN("File does not exist", K(ret)); + } + return ret; +} + +bool CheckAllParams::is_path_valid(const char *file_name) +{ + return (access(file_name, F_OK) != -1); +} + +int CheckAllParams::check_vm_max_map_count(bool strict_check) +{ + int ret = OB_SUCCESS; + const char *file_path = "/proc/sys/vm/max_map_count"; + if (is_path_valid(file_path)) { + int64_t max_map_count = 0; + if (OB_FAIL(read_one_int(file_path, max_map_count))) { + LOG_DBA_ERROR(OB_ERR_UNEXPECTED, "msg", "[check OS params]:read file failed", K(file_path)); + } else if (max_map_count >= 327600) { + LOG_INFO("[check OS params]:vm.max_map_count is within the range", K(max_map_count)); + } else { + if (strict_check) { + ret = OB_IMPROPER_OS_PARAM; + LOG_DBA_ERROR( + OB_IMPROPER_OS_PARAM, "msg", "[check OS params]:vm.max_map_count is less than 327600", K(max_map_count)); + } else { + LOG_WARN("[check OS params]:vm.max_map_count is less than 327600", K(max_map_count)); + } + } + } else { + LOG_WARN("file path does not exist", K(file_path)); + } + return ret; +} + +int CheckAllParams::check_vm_min_free_kbytes(bool strict_check) +{ + int ret = OB_SUCCESS; + const char *file_path = "/proc/sys/vm/min_free_kbytes"; + if (is_path_valid(file_path)) { + int64_t vm_min_free_kbytes = 0; + if (OB_FAIL(read_one_int(file_path, vm_min_free_kbytes))) { + LOG_DBA_ERROR(OB_ERR_UNEXPECTED, "msg", "[check OS params]:read file failed", K(file_path)); + } else if (vm_min_free_kbytes >= 32768 && vm_min_free_kbytes <= 2097152) { + LOG_INFO("[check OS params]:vm.min_free_kbytes is within the range", K(vm_min_free_kbytes)); + } else { + if (strict_check) { + ret = OB_IMPROPER_OS_PARAM; + LOG_DBA_ERROR(OB_IMPROPER_OS_PARAM, + "msg", + "[check OS params]:vm.min_free_kbytes is not within the allowed range [32768, 2097152]", + K(vm_min_free_kbytes)); + } else { + LOG_WARN("[check OS params]:vm.min_free_kbytes is not within the allowed range [32768, 2097152]", K(vm_min_free_kbytes)); + } + } + } else { + LOG_WARN("file path does not exist", K(file_path)); + } + return ret; +} + +int CheckAllParams::check_vm_overcommit_memory(bool strict_check) +{ + int ret = OB_SUCCESS; + const char *file_path = "/proc/sys/vm/overcommit_memory"; + if (is_path_valid(file_path)) { + int64_t vm_overcommit_memory = 0; + if (OB_FAIL(read_one_int(file_path, vm_overcommit_memory))) { + LOG_DBA_ERROR(OB_ERR_UNEXPECTED, "msg", "[check OS params]:read file failed", K(file_path)); + } else if (vm_overcommit_memory == 0) { + LOG_INFO("[check OS params]:vm.overcommit_memory is equal to 0", K(vm_overcommit_memory)); + } else { + if (strict_check) { + ret = OB_IMPROPER_OS_PARAM; + LOG_DBA_ERROR(OB_IMPROPER_OS_PARAM, "msg", "[check OS params]:vm.overcommit_memory is not the value:0", K(vm_overcommit_memory)); + } else { + LOG_WARN("[check OS params]:vm.overcommit_memory is not within the allowed value:0", K(vm_overcommit_memory)); + } + } + } else { + LOG_WARN("file path does not exist", K(file_path)); + } + return ret; +} + +int CheckAllParams::check_fs_file_max(bool strict_check) +{ + int ret = OB_SUCCESS; + const char *file_path = "/proc/sys/fs/file-max"; + if (is_path_valid(file_path)) { + int64_t fs_file_max = 0; + if (OB_FAIL(read_one_int(file_path, fs_file_max))) { + LOG_DBA_ERROR(OB_ERR_UNEXPECTED, "msg", "[check OS params]:read file failed", K(file_path)); + } else if (fs_file_max >= 6573688) { + LOG_INFO("[check OS params]:fs.file-max is greater than or equal to 6573688", K(fs_file_max)); + } else { + if (strict_check) { + ret = OB_IMPROPER_OS_PARAM; + LOG_DBA_ERROR(OB_IMPROPER_OS_PARAM, "msg", "[check OS params]:fs.file-max is less than 6573688", K(fs_file_max)); + } else { + LOG_WARN("[check OS params]:fs.file-max is less than 6573688", K(fs_file_max)); + } + } + } else { + LOG_WARN("file path does not exist", K(file_path)); + } + return ret; +} + +int CheckAllParams::check_ulimit_open_files(bool strict_check) +{ + int ret = OB_SUCCESS; + // Check open files limit + struct rlimit rlim; + if (getrlimit(RLIMIT_NOFILE, &rlim) == 0) { + if (rlim.rlim_cur >= 655300 && rlim.rlim_max >= 655300) { + LOG_INFO("[check OS params]:open files limit is greater than or equal to 655300", K(rlim.rlim_cur), K(rlim.rlim_max)); + } else { + if (strict_check) { + ret = OB_IMPROPER_OS_PARAM; + LOG_DBA_ERROR(OB_IMPROPER_OS_PARAM, + "msg", + "[check OS params]:open files limit's soft nofile or hard nofile is less than 655300, please run 'ulimit -n' to confirm the current limit and find a way to set it to the proper value", + K(rlim.rlim_cur), + K(rlim.rlim_max)); + } else { + LOG_WARN( + "[check OS params]:open files limit's soft nofile or hard nofile is less than 655300, please run 'ulimit -n' to confirm the current limit and find a way to set it to the proper value", K(rlim.rlim_cur), K(rlim.rlim_max)); + } + } + } else { + LOG_DBA_ERROR(OB_FILE_NOT_EXIST, "msg", "read ulimit.open_file_limit file failed"); + } + return ret; +} + +int CheckAllParams::check_ulimit_max_user_processes(bool strict_check) +{ + int ret = OB_SUCCESS; + struct rlimit rlim; + // Check process limit + if (getrlimit(RLIMIT_NPROC, &rlim) == 0) { + if (rlim.rlim_cur >= 655300 && rlim.rlim_max >= 655300) { + LOG_INFO("[check OS params]:ulimit.max_user_processes is greater than or equal to 655300", K(rlim.rlim_cur), K(rlim.rlim_max)); + } else { + if (strict_check) { + ret = OB_IMPROPER_OS_PARAM; + LOG_DBA_ERROR(OB_IMPROPER_OS_PARAM, + "msg", + "[check OS params]:ulimit.max_user_processes's soft nofile or hard nofile is less than 655300, please run 'ulimit -u' to confirm the current limit and find a way to set it to the proper value", + K(rlim.rlim_cur), + K(rlim.rlim_max)); + } else { + LOG_WARN("[check OS params]:ulimit.max_user_processes's soft nofile or hard nofile is less than 655300, please run 'ulimit -u' to confirm the current limit and find a way to set it to the proper value", + K(rlim.rlim_cur), + K(rlim.rlim_max)); + } + } + } else { + LOG_DBA_ERROR(OB_FILE_NOT_EXIST, "msg", "read ulimit.max_user_processes file failed"); + } + return ret; +} +int CheckAllParams::check_ulimit_core_file_size(bool strict_check) +{ + int ret = OB_SUCCESS; + struct rlimit rlim; + // Check core file size limit + if (getrlimit(RLIMIT_CORE, &rlim) == 0) { + if (rlim.rlim_cur == RLIM_INFINITY && rlim.rlim_max == RLIM_INFINITY) { + LOG_INFO("[check OS params]:core file size limit is unlimited"); + } else { + // Violations of the recommended range will only trigger a warning, regardless of strict or non-strict checking. + LOG_WARN("[check OS params]:ulimit.core_file_size limit's soft nofile or hard nofile is limited", K(rlim.rlim_cur), K(rlim.rlim_max)); + } + } else { + LOG_DBA_ERROR(OB_FILE_NOT_EXIST, "msg", "read ulimit.core_file_size file failed"); + } + return ret; +} + +int CheckAllParams::check_ulimit_stack_size(bool strict_check) +{ + int ret = OB_SUCCESS; + struct rlimit rlim; + // Check stack size limit + if (getrlimit(RLIMIT_STACK, &rlim) == 0) { + if (rlim.rlim_cur >= (1 << 20) && rlim.rlim_max >= (1 << 20)) { + LOG_INFO("[check OS params]:stack size limit is larger than 1M", K(rlim.rlim_cur), K(rlim.rlim_max)); + } else { + if (strict_check) { + ret = OB_IMPROPER_OS_PARAM; + LOG_DBA_ERROR(OB_IMPROPER_OS_PARAM, + "msg", + "[check OS params]: ulimit.stack_size limit's soft nofile or hard nofile is smaller than 1M, please run 'ulimit -s' to confirm the current limit and find a way to set it to the proper value", + K(rlim.rlim_cur), + K(rlim.rlim_max)); + } else { + LOG_WARN( + "[check OS params]: ulimit.stack_size limit's soft nofile or hard nofile is smaller than 1M, please run 'ulimit -s' to confirm the current limit and find a way to set it to the proper value", K(rlim.rlim_cur), K(rlim.rlim_max)); + } + } + } else { + LOG_DBA_ERROR(OB_FILE_NOT_EXIST, "msg", "read ulimit.stack_size file failed"); + } + return ret; +} + +int CheckAllParams::read_one_line(const char *file_path, char *buffer, size_t buffer_size) +{ + int ret = OB_SUCCESS; + FILE *file = fopen(file_path, "r"); + if (file != nullptr) { + if (fgets(buffer, buffer_size, file) == nullptr) { + ret = OB_IO_ERROR; + LOG_ERROR("Failed to read line from file", K(file_path), K(ret)); + } + fclose(file); + } else { + ret = OB_FILE_NOT_EXIST; + LOG_WARN("File does not exist", K(ret)); + } + return ret; +} + +int CheckAllParams::check_current_clocksource(bool strict_check) +{ + int ret = OB_SUCCESS; + const char *file_path = "/sys/devices/system/clocksource/clocksource0/current_clocksource"; + if (is_path_valid(file_path)) { + char clocksource[256]; + if (OB_FAIL(read_one_line(file_path, clocksource, sizeof(clocksource)))) { + LOG_DBA_ERROR(OB_ERR_UNEXPECTED, "msg", "[check OS params]:read file failed", K(file_path)); + } else { + if (clocksource[strlen(clocksource) - 1] == '\n') { + clocksource[strlen(clocksource) - 1] = '\0'; + } + if (strcmp(clocksource, "tsc") == 0 || strcmp(clocksource, "kvm-clock") == 0 || strcmp(clocksource, "arch_sys_counter") == 0) { + LOG_INFO("[check OS params]:current_clocksource is in proper range", K(clocksource), K(ret)); + } else if (strict_check) { + ret = OB_IMPROPER_OS_PARAM; + LOG_DBA_ERROR(OB_IMPROPER_OS_PARAM, "msg", "[check OS params]:current_clocksource is not [tsc], [kvm-clock], [arch_sys_counter]", K(clocksource), K(ret)); + } else { + LOG_WARN("[check OS params]:current_clocksource is not [tsc], [kvm-clock], [arch_sys_counter]", K(clocksource), K(ret)); + } + } + } else { + LOG_WARN("file path does not exist", K(file_path)); + } + return ret; +} + +int check_os_params(bool strict_check_params = false) +{ + int ret = OB_SUCCESS; + if (OB_FAIL(CheckAllParams::check_all_params(strict_check_params))) { + LOG_DBA_ERROR(OB_IMPROPER_OS_PARAM, "msg", "check os params failed"); + } + return ret; +} +} // namespace observer +} // namespace oceanbase diff --git a/src/observer/ob_check_params.h b/src/observer/ob_check_params.h new file mode 100644 index 000000000..a0fd33a2d --- /dev/null +++ b/src/observer/ob_check_params.h @@ -0,0 +1,52 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#ifndef OCEANBASE_OBSERVER_OB_CHECK_PARAMS_ +#define OCEANBASE_OBSERVER_OB_CHECK_PARAMS_ + +#include "deps/oblib/src/lib/file/file_directory_utils.h" +#include "share/ob_define.h" +#include "share/ob_errno.h" +#include +#include +namespace oceanbase +{ +using namespace common; +namespace observer +{ +using namespace common; +class CheckAllParams +{ +public: + static int check_all_params(bool strict_check); + +private: + static int read_one_int(const char *file_name, int64_t &value); + static int read_one_line(const char* file_path, char* buffer, size_t buffer_size); + static bool is_path_valid(const char *file_name); + static int check_vm_max_map_count(bool strict_check); // 1 + static int check_vm_min_free_kbytes(bool strict_check); // 2 + static int check_vm_overcommit_memory(bool strict_check); // 3 + static int check_fs_file_max(bool strict_check); + static int check_ulimit_open_files(bool strict_check); + static int check_ulimit_max_user_processes(bool strict_check); + static int check_ulimit_core_file_size(bool strict_check); + static int check_ulimit_stack_size(bool strict_check); // 8 + static int check_current_clocksource(bool strict_check); // 9 +}; + +int check_os_params(bool strict_check_params); + +} // namespace observer +} // namespace oceanbase + +#endif diff --git a/src/observer/ob_server.cpp b/src/observer/ob_server.cpp index f33f9e16b..d47f336de 100644 --- a/src/observer/ob_server.cpp +++ b/src/observer/ob_server.cpp @@ -122,6 +122,7 @@ #ifdef OB_BUILD_ORACLE_XML #include "lib/xml/ob_libxml2_sax_handler.h" #endif +#include "ob_check_params.h" using namespace oceanbase::lib; using namespace oceanbase::common; @@ -265,7 +266,10 @@ int ObServer::init(const ObServerOptions &opts, const ObPLogWriterCfg &log_cfg) if (OB_FAIL(init_config())) { LOG_ERROR("init config failed", KR(ret)); } - + //check os params + if (OB_SUCC(ret) && OB_FAIL(check_os_params(GCONF.strict_check_os_params))) { + LOG_ERROR("check OS params failed", K(GCONF.strict_check_os_params)); + } // set large page param ObLargePageHelper::set_param(config_.use_large_pages); diff --git a/src/share/parameter/ob_parameter_seed.ipp b/src/share/parameter/ob_parameter_seed.ipp index 08e1f517b..fdb219a7c 100644 --- a/src/share/parameter/ob_parameter_seed.ipp +++ b/src/share/parameter/ob_parameter_seed.ipp @@ -1894,3 +1894,9 @@ DEF_BOOL(_enable_choose_migration_source_policy, OB_TENANT_PARAMETER, "True", DEF_BOOL(_global_enable_rich_vector_format, OB_CLUSTER_PARAMETER, "True", "Control whether use rich vector format in vectorization engine", ObParameterAttr(Section::OBSERVER, Source::DEFAULT, EditLevel::DYNAMIC_EFFECTIVE)); + +//check os params +DEF_BOOL(strict_check_os_params, OB_CLUSTER_PARAMETER, "False", + "A switch that determines whether to enable strict OS parameter check mode, defaulting to true and can be set to false to bypass strict checks." + "Value: True: allowed; False: allowed but not suggested", + ObParameterAttr(Section::OBSERVER, Source::DEFAULT, EditLevel::STATIC_EFFECTIVE)); diff --git a/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_sys_parameter_stat.result b/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_sys_parameter_stat.result index 0163a06b8..48838ef98 100644 --- a/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_sys_parameter_stat.result +++ b/tools/deploy/mysql_test/test_suite/inner_table/r/mysql/all_virtual_sys_parameter_stat.result @@ -219,6 +219,7 @@ standby_db_fetch_log_rpc_timeout standby_db_preferred_upstream_log_region standby_fetch_log_bandwidth_limit storage_meta_cache_priority +strict_check_os_params syslog_io_bandwidth_limit syslog_level system_memory diff --git a/unittest/observer/CMakeLists.txt b/unittest/observer/CMakeLists.txt index 8342c979f..f6d02225a 100644 --- a/unittest/observer/CMakeLists.txt +++ b/unittest/observer/CMakeLists.txt @@ -8,5 +8,6 @@ storage_unittest(test_ingress_bw_alloc_manager net/test_ingress_bw_alloc_manager ob_unittest(test_obkv_config tableapi/test_obkv_config.cpp) ob_unittest(test_uniq_task_queue) ob_unittest(test_table_connection tableapi/test_table_connection.cpp) +ob_unittest(test_check_os_params test_check_os_params.cpp) add_subdirectory(rpc EXCLUDE_FROM_ALL) diff --git a/unittest/observer/test_check_os_params.cpp b/unittest/observer/test_check_os_params.cpp new file mode 100644 index 000000000..7d346f6fd --- /dev/null +++ b/unittest/observer/test_check_os_params.cpp @@ -0,0 +1,65 @@ +/** + * Copyright (c) 2021 OceanBase + * OceanBase CE is licensed under Mulan PubL v2. + * You can use this software according to the terms and conditions of the Mulan PubL v2. + * You may obtain a copy of Mulan PubL v2 at: + * http://license.coscl.org.cn/MulanPubL-2.0 + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, + * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, + * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. + * See the Mulan PubL v2 for more details. + */ + +#define USING_LOG_PREFIX RS +#include +#include +#define private public +#include "observer/ob_check_params.h" +#include "share/config/ob_server_config.h" +namespace oceanbase +{ +using namespace common; +using namespace share; +namespace observer +{ +class TestEndpointIngressService : public testing::Test +{ +public: + TestEndpointIngressService() + {} + virtual ~TestEndpointIngressService() + {} + virtual void SetUp(){}; + virtual void TearDown() + {} + virtual void TestBody() + {} +}; + +TEST_F(TestEndpointIngressService, ingress_service) +{ + int ret = OB_SUCCESS; + // bool strict_check = false; + // strict_check = GCONF.strict_check_os_params; + // LOG_WARN("", K(strict_check), K(GCONF.strict_check_os_params)); + // ret = check_os_params(strict_check); + // CheckAllParams::check_all_params(strict_check); + // int64_t value = 0; + // const char* str1 = "/proc/sys/vm/max_map_count"; + // obj.read_one_int(str1 , value); + // EXPECT_EQ(value, 65536); + // bool res1 = obj.is_path_valid(str1); + // EXPECT_EQ(res1, true); + // bool res2 = obj.is_path_valid("/proc/1/sys/vm/max_map_count"); + // EXPECT_EQ(res2, false); + // obj.check_all_params(false); +} +} // namespace rootserver +} // namespace oceanbase +int main(int argc, char **argv) +{ + oceanbase::common::ObLogger::get_logger().set_log_level("INFO"); + ::testing::InitGoogleTest(&argc, argv); + return RUN_ALL_TESTS(); +} +#undef private \ No newline at end of file