【Linux】【部署】主机初始化

初始化服务器

#python3 init_host.py init 【主机名】 【主机ip】
python3 init_host.py init NODE01 192.168.199.10

init_host.py 文件内容

#!/usr/bin/env python
# -*- coding: utf-8 -*-
import json
import os
import sys
import logging
import time
import logging.config
import subprocess

PYTHON_VERSION = sys.version_info.major
CURRENT_DIR = os.path.dirname(os.path.abspath(__file__))

if PYTHON_VERSION == 2:
    reload(sys)
    sys.setdefaultencoding('utf-8')

# ---- 日志定义部分 ----
# 日志配置 建议输入绝对路径,默认生成日志会添加 时间字段
LOG_PATH = "/tmp/init_host_standalone.log"
# 屏幕输出日志级别
CONSOLE_LOG_LEVEL = logging.INFO
# 文件日志级别
FILE_LOG_LEVEL = logging.DEBUG


def generate_log_filepath(log_path):
    """生成日志名称"""
    time_str = time.strftime('%Y-%m-%d-%H-%M-%S', time.localtime(time.time()))
    dirname = os.path.dirname(log_path)
    name_split = os.path.basename(log_path).split('.')
    if len(name_split) == 1:
        name = "{0}_{1}".format(name_split[0], time_str)
        file_path = os.path.join(dirname, name)
    else:
        name_split.insert(-1, time_str)
        file_path = os.path.join(dirname, '.'.join(name_split))
    return file_path


# 日志配置
log_path = generate_log_filepath(LOG_PATH)
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s',
    datefmt='%a, %d %b %Y %H:%M:%S',
    filename=log_path,
    filemode='a')
console = logging.StreamHandler()
console.setLevel(logging.INFO)
formatter = logging.Formatter(
    '%(asctime)s %(filename)s[line:%(lineno)d] %(levelname)s %(message)s')
console.setFormatter(formatter)
logger = logging.getLogger()
logger.addHandler(console)

KERNEL_PARAM = """# Disable IPv6
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
# ARP
net.ipv4.conf.default.rp_filter = 0
net.ipv4.conf.all.rp_filter = 0
net.ipv4.neigh.default.gc_stale_time = 120
net.ipv4.conf.default.arp_announce = 2
net.ipv4.conf.all.arp_announce = 2
net.ipv4.conf.lo.arp_announce = 2
# TCP Memory
net.core.rmem_default = 2097152
net.core.wmem_default = 2097152
net.core.rmem_max = 4194304
net.core.wmem_max = 4194304
net.ipv4.tcp_rmem = 4096 8192 4194304
net.ipv4.tcp_wmem = 4096 8192 4194304
net.ipv4.tcp_mem = 524288 699050 1048576
# TCP SYN
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_synack_retries = 1
net.ipv4.tcp_syn_retries = 1
net.ipv4.tcp_max_syn_backlog = 16384
net.core.netdev_max_backlog = 16384
# TIME_WAIT
net.ipv4.route.gc_timeout = 100
net.ipv4.tcp_max_tw_buckets = 5000
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_fin_timeout = 2
net.ipv4.ip_local_port_range = 20000 50000
# TCP keepalive
net.ipv4.tcp_keepalive_probes = 3
net.ipv4.tcp_keepalive_time = 60
net.ipv4.tcp_keepalive_intvl = 10
# Other TCP
net.ipv4.tcp_max_orphans = 65535
net.core.somaxconn = 16384
net.ipv4.tcp_sack = 1
net.ipv4.tcp_window_scaling = 1
vm.max_map_count=262144
vm.min_free_kbytes=512000
vm.swappiness = 0"""

KERNEL_KEYWORD = [
    "net.ipv6.conf.all.disable_ipv6",
    "net.ipv6.conf.default.disable_ipv6",
    "net.ipv4.conf.default.rp_filter",
    "net.ipv4.conf.all.rp_filter",
    "net.ipv4.neigh.default.gc_stale_time",
    "net.ipv4.conf.default.arp_announce",
    "net.ipv4.conf.all.arp_announce",
    "net.ipv4.conf.lo.arp_announce",
    "net.core.rmem_default",
    "net.core.wmem_default",
    "net.core.rmem_max",
    "net.core.wmem_max",
    "net.ipv4.tcp_rmem",
    "net.ipv4.tcp_wmem",
    "net.ipv4.tcp_mem",
    "net.ipv4.tcp_syncookies",
    "net.ipv4.tcp_synack_retries",
    "net.ipv4.tcp_syn_retries",
    "net.ipv4.tcp_max_syn_backlog",
    "net.core.netdev_max_backlog",
    "net.ipv4.route.gc_timeout",
    "net.ipv4.tcp_max_tw_buckets",
    "net.ipv4.tcp_tw_reuse",
    "net.ipv4.tcp_timestamps",
    "net.ipv4.tcp_fin_timeout",
    "net.ipv4.ip_local_port_range",
    "net.ipv4.tcp_keepalive_probes",
    "net.ipv4.tcp_keepalive_time",
    "net.ipv4.tcp_keepalive_intvl",
    "net.ipv4.tcp_max_orphans",
    "net.core.somaxconn",
    "net.ipv4.tcp_sack",
    "net.ipv4.tcp_window_scaling",
    "vm.max_map_count",
    "vm.swappiness",
    "vm.min_free_kbytes"
]
TO_MODIFY_HOST_NAME = [
    "localhost",
    "localhost.localhost",
    "localhost.domain",
]


class BaseInit(object):
    """ Base class 检查权限 / 执行命令方法 """

    def check_permission(self):
        """ 检查权限 """
        logger.info("开始检查当前用户执行权限")
        if not os.getuid() == 0:
            self.__check_is_sodu()
            if not self.is_sudo:
                logging.error('当前执行用户不是root,且此用户没有sudo NOPASSWD 权限,无法初始化!')
                exit(1)
        logger.info('当前用户权限正常,开始执行脚本')

    def __check_is_sodu(self):
        """ 是否具有 sodu 权限 """
        logger.info("检查是否具有sodu免密码权限")
        _cmd = "sudo -n 'whoami' &>/dev/null"
        _, _, _code = self.cmd(_cmd)
        self.is_sudo = _code == 0
        logger.info("是否具有sodu免密码权限: {}".format(self.is_sudo))

    def cmd(self, command):
        """ 执行shell 命令 """
        if hasattr(self, 'is_sudo'):
            if command.lstrip().startswith("echo"):
                command = "sudo sh -c '{0}'".format(command)
            else:
                command = "sudo {0}".format(command)
        logger.debug("Exec command: {0}".format(command))
        p = subprocess.Popen(
            command,
            stdout=subprocess.PIPE,
            stderr=subprocess.PIPE,
            shell=True,
        )
        stdout, stderr = p.communicate()
        _out, _err, _code = stdout, stderr, p.returncode
        logger.debug(
            "Get command({0}) stdout: {1}; stderr: {2}; ret_code: {3}".format(
                command, _out, _err, _code
            )
        )
        return _out, _err, _code

    @staticmethod
    def read_file(path, mode='r', res='str'):
        """
        :param path 路径
        :param mode 模式
        :param res 返回数据类型 str/list
        """
        if not os.path.exists(path):
            logger.error('读取文件失败,文件路径错误:{}'.format(path))
            exit(1)
        with open(path, mode) as f:
            data = f.read() if res == 'str' else f.readlines()
        return data

    def __get_os_version(self):
        logging.debug('开始获取系统版本信息')
        # match = False
        _, _, _code = self.cmd('systemctl --version')
        if _code != 0:
            logger.error("执行失败,当前操作系统不支持本脚本")
            exit(1)
        self.os_version = 7
        logging.debug('获取系统版本信息完成')

    def set_opts(self, **kwargs):
        """ 根据kwargs 设置参数"""
        raise Exception("程序错误,需实现set_opts方法")

    def run(self):
        # 检查权限
        if sys.argv[1] != 'valid':
            self.check_permission()
        self.__get_os_version()
        logging.info("开始执行脚本")

        self.run_methods()

    def run_methods(self):
        try:
            assert isinstance(self.m_list, list), "m_list 类型错误 方法错误,请检查脚本"
            assert len(self.m_list) > 0, "m_list 为空,请检查脚本"
            for func_info in self.m_list:
                assert isinstance(func_info, tuple) and len(
                    func_info) == 2, "todo_list 方法错误,请检查脚本:{}".format(func_info)
                method_name, method_note = func_info
                if hasattr(self, method_name):
                    f = getattr(self, method_name)
                    logger.info("开始 执行: {}".format(method_note))
                    f()
                    logger.info("执行 完成: {}".format(method_note))
                else:
                    logger.warn("安装方法列表错误,{} 方法不存在".format(method_note))
            else:
                logging.info("执行结束, 完整日志保存在 {}".format(log_path))
        except TypeError:
            logger.error("脚本配置错误,TypeError:")
        except Exception as e:
            logger.error(e)
            logging.info("执行结束, 完整日志保存在 {}".format(log_path))
            exit(1)


class InitHost(BaseInit):
    """ 初始化节点信息 """

    def __init__(self, host_name, local_ip):
        self.m_list = [
            ('env_set_timezone', '设置时区'),
            ('env_set_firewall', '关闭防火墙'),
            ('env_set_disable_ipv6', '设置关闭ipv6'),
            ('env_set_language', '设置语言'),
            ('env_set_file_limit', '设置文件句柄数'),
            ('env_set_kernel', '设置内核参数'),
            ('env_set_disable_selinux', '关闭selinux'),
            ('set_hostname', '设置主机名'),
        ]
        # TODO
        self.hostname = host_name
        self.local_ip = local_ip

    def env_set_timezone(self):
        """ 设置时区 """
        timezone = "PRC"
        self.cmd("test -f /etc/timezone && rm -f /etc/timezone")
        self.cmd("rm -f /etc/localtimze")
        self.cmd(
            "ln -sf /usr/share/zoneinfo/{0} /etc/localtime".format(timezone))

    def env_set_firewall(self):
        """ 关闭 firewall """
        _, _, _code = self.cmd(
            "systemctl status firewalld.service | egrep -q 'Active: .*(dead)'"
        )
        if _code != 0:
            self.cmd("systemctl stop firewalld.service >/dev/null 2>&1")
            self.cmd("systemctl disable firewalld.service >/dev/null 2>&1")

    def env_set_disable_ipv6(self):
        """ 关闭ipv6 """
        _, _, _code = self.cmd("grep -q 'ipv6.disable' /etc/default/grub")
        if _code == 0:
            self.cmd(
                "sed -i 's/ipv6.disable=[0-9]/ipv6.disable=1/g' /etc/default/grub"
            )
        else:
            self.cmd(
                """sed -i '/GRUB_CMDLINE_LINUX/ s/="/="ipv6.disable=1 /' /etc/default/grub"""
            )
        self.cmd("sysctl -w net.ipv6.conf.all.disable_ipv6=1")

    def env_set_language(self):
        """ 设置语言 """
        self.cmd("localectl set-locale LANG=en_US.UTF-8")

    def env_set_file_limit(self):
        """ 设置打开的文件句柄数 """
        _file_max_out, _, _ = self.cmd("cat /proc/sys/fs/file-max")
        file_max = int(_file_max_out)
        _nr_open_out, _, _ = self.cmd("cat /proc/sys/fs/nr_open")
        nr_open = int(_nr_open_out)
        if file_max < 655350:
            self.cmd("sed -i '/fs.file-max/d' /etc/sysctl.conf")
            self.cmd("echo 'fs.file-max = 655350' >>/etc/sysctl.conf")
            self.cmd("sysctl -p 1>/dev/null")
            file_max = 655350
        else:
            file_max = 655350

        self.cmd("sed -i '/nofile/d' /etc/security/limits.conf")
        self.cmd(
            'echo "*               -       nofile          {0}" >>/etc/security/limits.conf'.format(
                file_max
            )
        )
        if os.path.exists("/etc/security/limits.d/20-nproc.conf"):
            self.cmd(
                "sed -i 's#4096#unlimited#g' /etc/security/limits.d/20-nproc.conf"
            )
        self.cmd("sed -i '/^DefaultLimitCORE/d' /etc/systemd/system.conf")
        self.cmd("sed -i '/^DefaultLimitNOFILE/d' /etc/systemd/system.conf")
        self.cmd("sed -i '/^DefaultLimitNPROC/d' /etc/systemd/system.conf")
        c = 'echo -e "DefaultLimitCORE=infinity\\nDefaultLimitNOFILE={0}\\nDefaultLimitNPROC={0}" >>/etc/systemd/system.conf'.format(
            file_max)
        self.cmd(
            c
        )
        self.cmd("ulimit -SHn {0}".format(file_max))

    def env_set_kernel(self):
        """ 设置内核参数 """
        for item in KERNEL_KEYWORD:
            self.cmd('sed -i "/{0}/d" /etc/sysctl.conf'.format(item.strip()))
        self.cmd('sed -i "/tables/d" /etc/sysctl.conf')
        self.cmd('echo "{0}" >>/etc/sysctl.conf'.format(KERNEL_PARAM))
        self.cmd("sysctl -p 1>/dev/null")

    def env_set_disable_selinux(self):
        """ 禁用 selinux """
        if os.path.exists("/etc/selinux/config"):
            self.cmd(
                "sed -i 's#^SELINUX=.*#SELINUX=disabled#g' /etc/selinux/config")
            self.cmd("setenforce 0")

    def set_hostname(self):
        """设置主机名"""
        _out, _err, _code = self.cmd("echo $(hostname)")
        if _out.strip().lower() in TO_MODIFY_HOST_NAME or _out.strip().isdigit():
            self.cmd('echo "{0}" >/etc/hostname'.format(self.hostname))
            self.cmd('echo "{0}" > /proc/sys/kernel/hostname'.format(self.hostname))
            self.cmd("hostname {0}".format(self.hostname))
            self.cmd('echo "{0}    {1}" >> /etc/hosts'.format(self.local_ip, self.hostname))


class ValidInit(BaseInit):
    def __init__(self):
        self.m_list = [
            ('valid_env_timezone', '校验时区'),
            ('valid_env_firewall', '校验防火墙'),
            ('valid_env_language', '校验语言'),
            ('valid_env_file_limit', '校验文件具柄数'),
            ('valid_env_kernel', '校验内核参数'),
            ('valid_env_disable_selinux', '校验selinux'),
            ('valid_host_name', '校验host_name'),
        ]

    def valid_env_timezone(self):
        """ 校验时区 """
        assert os.readlink(
            '/etc/localtime') == "/usr/share/zoneinfo/PRC", "时区校验失败"

    def valid_env_firewall(self):
        """ 校验防火墙 """
        _, _, _code = self.cmd(
            "systemctl status firewalld.service | egrep -q 'Active: .*(dead)'"
        )
        assert _code == 0, "防火墙校验失败"

    def valid_env_language(self):
        """ 校验语言 """
        assert self.cmd(
            "localectl status |grep LANG=en_US.UTF-8")[2] == 0, "语言环境校验失败"

    def valid_env_file_limit(self):
        """ 校验文件具柄数 """
        _err = ""
        _file_max_out, _, _ = self.cmd("cat /proc/sys/fs/file-max")
        file_max = int(_file_max_out)
        _nr_open_out, _, _ = self.cmd("cat /proc/sys/fs/nr_open")
        nr_open = int(_nr_open_out)
        if file_max < 655350:
            _err = "文件句柄数校验失败"
        else:
            file_max = 655350

        if self.cmd(
                'grep "*               -       nofile          {0}" /etc/security/limits.conf'.format(
                    file_max
                )
        )[2] != 0:
            _err = "文件 /etc/security/limits.conf 校验失败"

        if os.path.exists("/etc/security/limits.d/20-nproc.conf"):
            if self.cmd(
                    "grep unlimited /etc/security/limits.d/20-nproc.conf"
            )[2] != 0:
                _err = "文件 /etc/security/limits.d/20-nproc.conf 校验失败"
        if self.cmd('grep "DefaultLimitCORE=infinity" /etc/systemd/system.conf')[2] != 0:
            _err = "文件 /etc/systemd/system.conf DefaultLimitCORE 校验失败"
        if self.cmd('grep DefaultLimitNOFILE={0} /etc/systemd/system.conf'.format(file_max))[2] != 0:
            _err = "文件 /etc/systemd/system.conf DefaultLimitNOFILE 校验失败"
        if self.cmd('grep DefaultLimitNPROC={0} /etc/systemd/system.conf'.format(file_max))[2] != 0:
            _err = "文件 /etc/systemd/system.conf DefaultLimitNPROC 校验失败"

        assert _err == '', _err

    def valid_env_kernel(self):
        """ 校验内核参数 """
        _list = [i.strip() for i in self.read_file('/etc/sysctl.conf',
                                                   res='list') if not i.strip().startswith('#')]
        for i in KERNEL_PARAM.split('\n'):
            if i.startswith('#'):
                continue
            assert i.strip() in _list, "内核参数校验失败: {}".format(i)

    def valid_env_disable_selinux(self):
        """ 校验selinux """
        assert "SELINUX=disabled" in [
            i.strip() for i in self.read_file('/etc/selinux/config', res='list') if
            not i.strip().startswith('#')
        ], "selinux 校验失败"

    def valid_host_name(self):
        """校验host_name不含localhost"""
        _out, _err, _code = self.cmd("echo $(hostname)")
        assert _out.strip().lower() not in TO_MODIFY_HOST_NAME and not _out.strip().isdigit(), "校验主机名失败"


def add_hostname_analysis(hostname_str):
    logger.debug("传入主机信息:\n{}".format(hostname_str))
    hostnames = json.loads(hostname_str or '[]')
    with open("/etc/hosts", "r") as f:
        hosts = f.read()
    logger.debug("获取主机解析:\n{}".format(hosts))
    hosts_analysis_dict = {}
    for analysis_str in hosts.split("\n"):
        if analysis_str.lstrip().startswith("#"):
            continue
        analysis_list = list(
            filter(
                lambda x: x,
                analysis_str.strip().replace("\t", " ").split(" ")
            )
        )
        if not analysis_list:
            continue
        hosts_analysis_dict[analysis_list[0]] = analysis_str
    for hostname_dict in hostnames:
        ip = hostname_dict.get("ip")
        hostname = hostname_dict.get("hostname")
        host_analysis_str = hosts_analysis_dict.get(ip, "")
        if not host_analysis_str:
            hosts += "{} {}\n".format(ip, hostname)
        elif hostname in host_analysis_str:
            continue
        else:
            host_analysis_str_new = "{} {}".format(host_analysis_str, hostname)
            hosts = hosts.replace(host_analysis_str, host_analysis_str_new)
    logger.debug("对比获得最新主机信息:\n{}".format(hosts))
    with open("/etc/hosts", "w") as f:
        f.write(hosts)
    logger.debug("写入最新主机信息成功!")


def usage(error=None):
    script_full_path = os.path.join(CURRENT_DIR, os.path.basename(__file__))
    print("""{0} 脚本 功能为初始化节点,职能包括: 设置时区、关闭防火墙、设置文件具柄和内核参数等
    Command:
            init        <host_name>  <local_ip>  初始化节点
            valid                                校验初始化结果
            init_valid  <host_name>  <local_ip>  初始化节点,在完成初始化后执行校验

    Use "python {0} <command>" for more information about a given command.
    """.format(script_full_path))
    if error is not None:
        print("Error: {}".format(error))
        exit(1)
    exit(0)


def main():
    command_list = ('init', 'valid', 'init_valid', 'help', 'write_hostname')
    try:
        if sys.argv[1] not in command_list:
            usage(error='参数错误: {}'.format(sys.argv[1:]))
        if sys.argv[1] in ['init', 'init_valid']:
            if len(sys.argv) != 4:
                usage(error='参数错误: {}'.format(sys.argv[1:]))
            host_name = sys.argv[2]
            local_ip = sys.argv[3]
            init = InitHost(host_name, local_ip)
            init.run()
            logger.info("init success")
            if sys.argv[1] == 'init_valid':
                check = ValidInit()
                check.run()
                logger.info("valid success")
        elif sys.argv[1] == 'valid':
            check = ValidInit()
            check.run()
            logger.info("valid success")
        elif sys.argv[1] == "write_hostname":
            hosts_info = sys.argv[2]
            # '[{"ip":"10.0.9.18","hostname":"docp-9-18"}]'
            add_hostname_analysis(hosts_info)
        else:
            usage()
    except Exception as e:
        usage(error="参数错误, {}".format(e))


if __name__ == '__main__':
    main()

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/772196.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

YOLOv8入门 | 重要性能衡量指标、训练结果评价及分析及影响mAP的因素【发论文关注的指标】

秋招面试专栏推荐 &#xff1a;深度学习算法工程师面试问题总结【百面算法工程师】——点击即可跳转 &#x1f4a1;&#x1f4a1;&#x1f4a1;本专栏所有程序均经过测试&#xff0c;可成功执行&#x1f4a1;&#x1f4a1;&#x1f4a1; 专栏目录 &#xff1a;《YOLOv8改进有效…

从CVPR 2024看 NeRF 最新改进&应用

三维重建领域必不可少的NeRF技术最近又有新突破了&#xff01; 首先是SAX-NeRF框架&#xff0c;专为稀疏视角下X光三维重建设计&#xff0c;无需CT数据进行训练&#xff0c;只使用 X 光片即可&#xff0c;等于给NeRF开透视眼&#xff01; 还有清华提出的GenN2N&#xff0c;一…

Canvas合集更更更之实现由画布中心向外随机不断发散的粒子效果

实现效果 1.支持颜色设置 2.支持粒子数量设置 3.支持粒子大小设置 写在最后&#x1f352; 源码&#xff0c;关注&#x1f365;苏苏的bug&#xff0c;&#x1f361;苏苏的github&#xff0c;&#x1f36a;苏苏的码云

VSCode 自动调整格式失效了 ESLint

ESLint【最新注意2.4.4版本有问题&#xff0c;需退回2.4.2版本就恢复正常了】 参考&#xff1a;vscode自动格式化失效_vscode保存自动格式化失效-CSDN博客

【启明智显分享】手持遥控器HMI解决方案:2.8寸触摸串口屏助力实现智能化

现代生活不少家居不断智能化&#xff0c;但是遥控器却并没有随之升级。在遥控交互上&#xff0c;传统遥控器明显功能不足&#xff1a;特别是大屏智能电视&#xff0c;其功能主要由各种APP程序实现。在电脑上鼠标轻轻点击、在手机上触摸屏丝滑滑动&#xff0c;但是在电视上这些A…

新的超好用的baas服务他来了!

新的超好用的BaaS服务它来了&#xff01; 你是否厌倦了搭建服务的繁琐过程&#xff1f;你是否因为接口API的开发而头疼不已&#xff1f;你是否梦想着能够用最少的精力打造出最棒的应用&#xff1f;如果你的答案是“是”&#xff0c;那么恭喜你&#xff0c;你的救星来了&#x…

kubernetes dashboard安装

1.查看符合自己版本的kubernetes Dashboard 比如我使用的是1.23.0版本 https://github.com/kubernetes/dashboard/releases?page5 对应版本 kubectl apply -f https://raw.githubusercontent.com/kubernetes/dashboard/v2.5.1/aio/deploy/recommended.yaml修改对应的yaml,…

秋招突击——设计模式补充——单例模式、依赖倒转原则、工厂方法模式

文章目录 引言正文依赖倒转原则工厂方法模式工厂模式的实现简单工厂和工厂方法的对比 抽线工厂模式最基本的数据访问程序使用工厂模式实现数据库的访问使用抽象工厂模式的数据访问程序抽象工厂模式的优点和缺点使用反射抽象工厂的数据访问程序使用反射配置文件实现数据访问程序…

2024亚太杯中文赛数学建模选题建议及各题思路来啦!

大家好呀&#xff0c;2024年第十四届APMCM亚太地区大学生数学建模竞赛&#xff08;中文赛项&#xff09;开始了&#xff0c;来说一下初步的选题建议吧&#xff1a; 首先定下主基调&#xff0c; 本次亚太杯推荐大家选择B题目。C题目难度较高&#xff0c;只建议用过kaiwu的队伍…

决策树算法的原理与案例实现

一、绪论 1.1 决策树算法的背景介绍 1.2 研究决策树算法的意义 二、决策树算法原理 2.1 决策树的基本概念 2.2 决策树构建的基本思路 2.2 决策树的构建过程 2.3 决策树的剪枝策略 三、决策树算法的优缺点 3.1 决策树算法的优势 3.2 决策树算法的局限性 3.3 决策树算…

微服务粒度难题:找到合适的微服务大小

序言 在微服务架构风格中&#xff0c;微服务通常设计遵循SRP&#xff08;单一职责原则&#xff09;&#xff0c;作为一个独立部署的软件单元&#xff0c;专注于做一件事&#xff0c;并且做到极致。作为开发人员&#xff0c;我们常常倾向于在没有考虑为什么的情况下尽可能地将服…

全面教程:在Ubuntu上快速部署ZeroTier,实现Windows与VSCode的局域网无缝访问

文章目录 1 背景介绍2 Windows上的操作3 Ubuntu上的操作4 连接 1 背景介绍 在现代工作环境中&#xff0c;远程访问公司内网的Ubuntu主机对于开发者来说是一项基本需求。然而&#xff0c;由于内网的限制&#xff0c;传统的远程控制软件如向日葵和todesk往往无法满足这一需求。作…

二叉树之遍历

二叉树之遍历 二叉树遍历遍历分类前序遍历流程描述代码实现 中序遍历流程描述代码实现 后序遍历流程描述代码实现 层次遍历流程描述代码实现 总结 二叉树遍历 遍历分类 遍历二叉树的思路有 4 种&#xff0c;分别是&#xff1a; 前序遍历二叉树&#xff0c;有递归和非递归两种…

用dify实现简单的Agent应用(AI信息检索)

这篇文章里&#xff0c;我们来聊聊如何使用字节最新的豆包大模型&#xff0c;在 Dify 上来快速完成一个具备理解需求、自主规划、自主选择工具使用的简单智能体&#xff08;Agent&#xff09;。 准备工作 完整准备过程分为&#xff1a;准备 Docker 环境、启动 Dify 程序、启动…

线性代数基础概念:矩阵

目录 线性代数基础概念&#xff1a;矩阵 1. 矩阵的定义 2. 矩阵的运算 3. 矩阵的特殊类型 4. 矩阵的秩 5. 矩阵的初等变换 6. 矩阵的特征值与特征向量 7. 矩阵的应用 8. 矩阵总结 总结 线性代数基础概念&#xff1a;矩阵 矩阵是线性代数中的另一个重要概念&#xff0…

vue目录说明

vue目录说明 主要目录说明 .vscode - - -vscode工具的配置文件夹 node_modules - - - vue项目的运行依赖文件夹 public - - -资源文件夹&#xff08;浏览器图标&#xff09; src- - -源码文件夹 .gitignore - - -git忽略文件 index.html - - -入口html文件 package.json - - -…

windows搭建mqtt服务器,并配置DTU收集传感器数据

1.下载并安装emqx服务器 参考&#xff1a;Windows系统下本地MQTT服务器搭建&#xff08;保姆级教程&#xff09;_mqtt windows-CSDN博客 这里我下载的是emqx-5.3.0-windows-amd64.zip版本 下载好之后&#xff0c;放到服务器的路径&#xff0c;我这里放的地方是&#xff1a;C…

图像信号处理器(ISP)基础算法及处理流程

&#x1f4aa; 专业从事且热爱图像处理&#xff0c;图像处理专栏更新如下&#x1f447;&#xff1a; &#x1f4dd;《图像去噪》 &#x1f4dd;《超分辨率重建》 &#x1f4dd;《语义分割》 &#x1f4dd;《风格迁移》 &#x1f4dd;《目标检测》 &#x1f4dd;《暗光增强》 &a…

FreeRTOS之队列上锁和解锁(详解)

这篇文章将记录我学习实时操作系统FreeRTOS的队列上锁和解锁的知识&#xff0c;在此分享给大家&#xff0c;希望我的分享能给你带来不一样的收获&#xff01; 目录 一、简介 二、队列上锁函数prvLockQueue&#xff08;&#xff09; 1、函数初探 2、应用示例 三、队列解锁函…

转让北京文化传媒公司带营业性演出经纪许可证

影视文化传播倡导将健康的影视文化有效传播给观众&#xff0c;从而构建观众与电影制作者的良 性沟通与互动&#xff0c;是沟通电影制作者与电影受众的重要桥梁。影视文化泛指以电影&#xff0c;电视方式所进行的全部文化创造&#xff0c;即体现为电影&#xff0c;电视全部的存在…