Zookeeper源码分析——ZK服务端初始化源码解析

news2024/11/15 18:27:05

持久化源码

快照

public interface SnapShot {
    
    /**
     * deserialize a data tree from the last valid snapshot and 
     * return the last zxid that was deserialized
     * 反序列化方法
     */
    long deserialize(DataTree dt, Map<Long, Integer> sessions) 
        throws IOException;
    
    /**
     * persist the datatree and the sessions into a persistence storage
	 * 序列化代码
     */
    void serialize(DataTree dt, Map<Long, Integer> sessions, 
            File name) 
        throws IOException;
    
    /**
     * find the most recent snapshot file
     * 查找最近的快照文件
     */
    File findMostRecentSnapshot() throws IOException;
    
    /**
     * free resources from this snapshot immediately
     * 释放资源
     */
    void close() throws IOException;
} 

操作日志

public interface TxnLog {

    /**
     * Setter for ServerStats to monitor fsync threshold exceed
     * 设置服务状态
     */
    void setServerStats(ServerStats serverStats);
    
    /**
     * roll the current
     * log being appended to
     * 滚动日志
     */
    void rollLog() throws IOException;
    /**
     * Append a request to the transaction log
     * returns true iff something appended, otw false 
     * 追加
     */
    boolean append(TxnHeader hdr, Record r) throws IOException;

    /**
     * Start reading the transaction logs
     * 读取数据
     */
    TxnIterator read(long zxid) throws IOException;
    
    /**
     * the last zxid of the logged transactions.
     * 获取最后一个 zxid
     */
    long getLastLoggedZxid() throws IOException;
    
    /**
     * truncate the log to get in sync with the 
     * leader.
     * 删除日志
     */
    boolean truncate(long zxid) throws IOException;
    
    /**
     * the dbid for this transaction log. 
     * @return the dbid for this transaction log.
     * 获取 DbId
     */
    long getDbId() throws IOException;
    
    /**
     * commit the transaction and make sure
     * they are persisted
     * 提交
     */
    void commit() throws IOException;

    /**
     *
     * @return transaction log's elapsed sync time in milliseconds
     * 日志同步时间 
     */
    long getTxnLogSyncElapsedTime();
   
    /** 
     * close the transactions logs
     * 关闭日志
     */
    void close() throws IOException;
    /**
     * an iterating interface for reading 
     * transaction logs. 
     // 读取日志的接口
     */
    public interface TxnIterator {
        /**
         * return the transaction header.
         * 获取头信息
         */
        TxnHeader getHeader();
        
        /**
         * return the transaction record.
         * 获取传输的内容
         */
        Record getTxn();
     
        /**
         * go to the next transaction record.
         * 下一条 记录
         */
        boolean next() throws IOException;
        
        /**
         * close files and release the 
         * resources
         * 关闭资源
         */
        void close() throws IOException;
        
        /**
         * Get an estimated storage space used to store transaction records
         * that will return by this iterator
         * 获取存储的大小
         */
        long getStorageSize() throws IOException;
    }
}

处理持久化的核心类

在这里插入图片描述

序列化源码

zookeeper-jute代码是关于 Zookeeper序列化相关源码

在这里插入图片描述

在这里插入图片描述

序列化和反序列化代码

public interface Record {
    public void serialize(OutputArchive archive, String tag) throws IOException;
    public void deserialize(InputArchive archive, String tag) throws IOException;
}

迭代代码

public interface Index {
    public boolean done();
    public void incr();
}

支持序列化的数据类型

public interface OutputArchive {
    public void writeByte(byte b, String tag) throws IOException;
    public void writeBool(boolean b, String tag) throws IOException;
    public void writeInt(int i, String tag) throws IOException;
    public void writeLong(long l, String tag) throws IOException;
    public void writeFloat(float f, String tag) throws IOException;
    public void writeDouble(double d, String tag) throws IOException;
    public void writeString(String s, String tag) throws IOException;
    public void writeBuffer(byte buf[], String tag) throws IOException;
    public void writeRecord(Record r, String tag) throws IOException;
    public void startRecord(Record r, String tag) throws IOException;
    public void endRecord(Record r, String tag) throws IOException;
    public void startVector(List<?> v, String tag) throws IOException;
    public void endVector(List<?> v, String tag) throws IOException;
    public void startMap(TreeMap<?,?> v, String tag) throws IOException;
    public void endMap(TreeMap<?,?> v, String tag) throws IOException;
}

支持反序列化的数据类型

public interface InputArchive {
    public byte readByte(String tag) throws IOException;
    public boolean readBool(String tag) throws IOException;
    public int readInt(String tag) throws IOException;
    public long readLong(String tag) throws IOException;
    public float readFloat(String tag) throws IOException;
    public double readDouble(String tag) throws IOException;
    public String readString(String tag) throws IOException;
    public byte[] readBuffer(String tag) throws IOException;
    public void readRecord(Record r, String tag) throws IOException;
    public void startRecord(String tag) throws IOException;
    public void endRecord(String tag) throws IOException;
    public Index startVector(String tag) throws IOException;
    public void endVector(String tag) throws IOException;
    public Index startMap(String tag) throws IOException;
    public void endMap(String tag) throws IOException;
}

ZK 服务端初始化源码解析

在这里插入图片描述

ZK 服务端启动脚本分析

Zookeeper 服务的启动命令是zkServer.sh start

ZOOBIN="${BASH_SOURCE-$0}"
ZOOBIN="$(dirname "${ZOOBIN}")"
ZOOBINDIR="$(cd "${ZOOBIN}"; pwd)"

if [ -e "$ZOOBIN/../libexec/zkEnv.sh" ]; then
  . "$ZOOBINDIR"/../libexec/zkEnv.sh
else
  . "$ZOOBINDIR"/zkEnv.sh //相当于获取zkEnv.sh 中的环境变量(ZOOCFG="zoo.cfg")
fi
...

zkServer.sh start底层的实际执行内容

nohup "$JAVA" + 一堆提交参数
+ $ZOOMAIN org.apache.zookeeper.server.quorum.QuorumPeerMain
+ "$ZOOCFG" zkEnv.sh文件中 ZOOCFG="zoo.

在这里插入图片描述

所以程序的入口是 QuorumPeerMain.java类

ZK服务端启动入口

在这里插入图片描述

initializeAndRun

protected void initializeAndRun(String[] args)
        throws ConfigException, IOException, AdminServerException
    {
    	// 管理 zk的配置信息
        QuorumPeerConfig config = new QuorumPeerConfig();
        if (args.length == 1) {
            // 解析参数 zoo.cfg和 myid
            config.parse(args[0]);
        }

        // Start and schedule the the purge task
    // 启动 定时 任务, 对过期的快照,执行删除 (默认该功能关闭
        DatadirCleanupManager purgeMgr = new DatadirCleanupManager(config
                .getDataDir(), config.getDataLogDir(), config
                .getSnapRetainCount(), config.getPurgeInterval());
        purgeMgr.start();

        if (args.length == 1 && config.isDistributed()) {
            // 启动集群
            runFromConfig(config);
        } else {
            LOG.warn("Either no config or no quorum defined in config, running "
                    + " in standalone mode");
            // there is only server in the quorum -- run as standalone
            ZooKeeperServerMain.main(args);
        }
    }

在这里插入图片描述

解析参数 zoo.cfg和 myid

QuorumPeerConfig.java

在这里插入图片描述

QuorumPeerConfig.java

/**
     * Parse config from a Properties.
     * @param zkProp Properties to parse from.
     * @throws IOException
     * @throws ConfigException
     */
    public void parseProperties(Properties zkProp)
    throws IOException, ConfigException {
        int clientPort = 0;
        int secureClientPort = 0;
        String clientPortAddress = null;
        String secureClientPortAddress = null;
        // 读取 zoo.cfg文件中的属性值,并赋值给 QuorumPeerConfig的类对象
        VerifyingFileFactory vff = new VerifyingFileFactory.Builder(LOG).warnForRelativePath().build();
        for (Entry<Object, Object> entry : zkProp.entrySet()) {
            String key = entry.getKey().toString().trim();
            String value = entry.getValue().toString().trim();
            if (key.equals("dataDir")) {
                dataDir = vff.create(value);
            } else if (key.equals("dataLogDir")) {
                dataLogDir = vff.create(value);
            } else if (key.equals("clientPort")) {
                clientPort = Integer.parseInt(value);
            } else if (key.equals("localSessionsEnabled")) {
                localSessionsEnabled = Boolean.parseBoolean(value);
            } else if (key.equals("localSessionsUpgradingEnabled")) {
                localSessionsUpgradingEnabled = Boolean.parseBoolean(value);
            } else if (key.equals("clientPortAddress")) {
                clientPortAddress = value.trim();
            }
            ...
    }

QuorumPeerConfig.java

    void setupQuorumPeerConfig(Properties prop, boolean configBackwardCompatibilityMode)
            throws IOException, ConfigException {
        quorumVerifier = parseDynamicConfig(prop, electionAlg, true, configBackwardCompatibilityMode);
        setupMyId();
        setupClientPort();
        setupPeerType();
        checkValidity();
    }
    private void setupMyId() throws IOException {
        File myIdFile = new File(dataDir, "myid");
        // standalone server doesn't need myid file.
        if (!myIdFile.isFile()) {
            return;
        }
        BufferedReader br = new BufferedReader(new FileReader(myIdFile));
        String myIdString;
        try {
            myIdString = br.readLine();
        } finally {
            br.close();
        }
        try {
            // 将解析 myid文件中的 id赋值给 serverId
            serverId = Long.parseLong(myIdString);
            MDC.put("myid", myIdString);
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("serverid " + myIdString
                    + " is not a number");
        }
    }

过期快照删除

可以启动定时任务,对过期的快照,执行删除 。默认该功能时关闭的

QuorumPeerMain.java

protected void initializeAndRun(String[] args)
        throws ConfigException, IOException, AdminServerException
    {
    	// 管理 zk的配置信息
        QuorumPeerConfig config = new QuorumPeerConfig();
        if (args.length == 1) {
        // 1解析参数, zoo.cfg和 myid
            config.parse(args[0]);
        }

        // Start and schedule the the purge task
    // 2启动 定时 任务, 对过期的快照,执行删除 (默认是关闭
    // config.getSnapRetainCount() = 3 最少保留的快照个数
	// config.getPurgeInterval() = 0 默认 0表示关闭
        DatadirCleanupManager purgeMgr = new DatadirCleanupManager(config
                .getDataDir(), config.getDataLogDir(), config
                .getSnapRetainCount(), config.getPurgeInterval());
        purgeMgr.start();

        if (args.length == 1 && config.isDistributed()) {
            // 3 启动集群
            runFromConfig(config);
        } else {
            LOG.warn("Either no config or no quorum defined in config, running "
                    + " in standalone mode");
            // there is only server in the quorum -- run as standalone
            // 本地模式
            ZooKeeperServerMain.main(args);
        }
    }

DatadirCleanupManager.java

跟进定时任务的start方法

定义一个静态内部类实现定时删除快照的任务

public void start() {
        if (PurgeTaskStatus.STARTED == purgeTaskStatus) {
            LOG.warn("Purge task is already running.");
            return;
        }
    // 默认情况 purgeInterval=0,该任务关闭,直接返回
        // Don't schedule the purge task with zero or negative purge interval.
        if (purgeInterval <= 0) {
            LOG.info("Purge task is not scheduled.");
            return;
        }
		// 创建一个定时器
        timer = new Timer("PurgeTask", true);
        // 创建一个清理快照任务
        TimerTask task = new PurgeTask(dataLogDir, snapDir, snapRetainCount);
    	// 如果 purgeInterval设置的值是 1,表示 1小时检查一次,判断是否有过期快照,有则删除
        timer.scheduleAtFixedRate(task, 0, TimeUnit.HOURS.toMillis(purgeInterval));

        purgeTaskStatus = PurgeTaskStatus.STARTED;
    }

    /**
     * Shutdown the purge task.
     */
    public void shutdown() {
        if (PurgeTaskStatus.STARTED == purgeTaskStatus) {
            LOG.info("Shutting down purge task.");
            timer.cancel();
            purgeTaskStatus = PurgeTaskStatus.COMPLETED;
        } else {
            LOG.warn("Purge task not started. Ignoring shutdown!");
        }
    }

    static class PurgeTask extends TimerTask {
        private File logsDir;
        private File snapsDir;
        private int snapRetainCount;

        public PurgeTask(File dataDir, File snapDir, int count) {
            logsDir = dataDir;
            snapsDir = snapDir;
            snapRetainCount = count;
        }

        @Override
        public void run() {
            LOG.info("Purge task started.");
            try {
                // 清理过期的数据
                PurgeTxnLog.purge(logsDir, snapsDir, snapRetainCount);
            } catch (Exception e) {
                LOG.error("Error occurred while purging.", e);
            }
            LOG.info("Purge task completed.");
        }
    }

查看具体清理过期数据的方法

PurgeTxnLog.java

    /**
     * Purges the snapshot and logs keeping the last num snapshots and the
     * corresponding logs. If logs are rolling or a new snapshot is created
     * during this process, these newest N snapshots or any data logs will be
     * excluded from current purging cycle.
     */
    public static void purge(File dataDir, File snapDir, int num) throws IOException {
        if (num < 3) {
            throw new IllegalArgumentException(COUNT_ERR_MSG);
        }

        FileTxnSnapLog txnLog = new FileTxnSnapLog(dataDir, snapDir);

        List<File> snaps = txnLog.findNRecentSnapshots(num);
        int numSnaps = snaps.size();
        if (numSnaps > 0) {
            purgeOlderSnapshots(txnLog, snaps.get(numSnaps - 1));
        }
    }

初始化通信组件

protected void initializeAndRun(String[] args)
        throws ConfigException, IOException, AdminServerException
    {
    	// 管理 zk的配置信息
        QuorumPeerConfig config = new QuorumPeerConfig();
        if (args.length == 1) {
        // 1解析参数, zoo.cfg和 myid
            config.parse(args[0]);
        }

        // Start and schedule the the purge task
    // 2启动 定时 任务, 对过期的快照,执行删除 (默认是关闭
    // config.getSnapRetainCount() = 3 最少保留的快照个数
	// config.getPurgeInterval() = 0 默认 0表示关闭
        DatadirCleanupManager purgeMgr = new DatadirCleanupManager(config
                .getDataDir(), config.getDataLogDir(), config
                .getSnapRetainCount(), config.getPurgeInterval());
        purgeMgr.start();

        if (args.length == 1 && config.isDistributed()) {
            // 3 启动集群
            runFromConfig(config);
        } else {
            LOG.warn("Either no config or no quorum defined in config, running "
                    + " in standalone mode");
            // there is only server in the quorum -- run as standalone
            // 本地模式
            ZooKeeperServerMain.main(args);
        }
    }

通信协议默认 NIO(可以支持 Netty

进入启动集群的方法

public void runFromConfig(QuorumPeerConfig config)
            throws IOException, AdminServerException
    {
      try {
          ManagedUtil.registerLog4jMBeans();
      } catch (JMException e) {
          LOG.warn("Unable to register log4j JMX control", e);
      }

      LOG.info("Starting quorum peer");
      try {
          ServerCnxnFactory cnxnFactory = null;
          ServerCnxnFactory secureCnxnFactory = null;
		  // 通信组件初始化,默认是 NIO通信
          if (config.getClientPortAddress() != null) {
              cnxnFactory = ServerCnxnFactory.createFactory();
              cnxnFactory.configure(config.getClientPortAddress(),
                      config.getMaxClientCnxns(),
                      false);
          }

          if (config.getSecureClientPortAddress() != null) {
              secureCnxnFactory = ServerCnxnFactory.createFactory();
              secureCnxnFactory.configure(config.getSecureClientPortAddress(),
                      config.getMaxClientCnxns(),
                      true);
          }
		  // 把解析的参数赋值给该 zookeeper节点
          quorumPeer = getQuorumPeer();
          quorumPeer.setTxnFactory(new FileTxnSnapLog(
                      config.getDataLogDir(),
                      config.getDataDir()));
          quorumPeer.enableLocalSessions(config.areLocalSessionsEnabled());
          quorumPeer.enableLocalSessionsUpgrading(
              config.isLocalSessionsUpgradingEnabled());
          //quorumPeer.setQuorumPeers(config.getAllMembers());
          quorumPeer.setElectionType(config.getElectionAlg());
          quorumPeer.setMyid(config.getServerId());
          quorumPeer.setTickTime(config.getTickTime());
          quorumPeer.setMinSessionTimeout(config.getMinSessionTimeout());
          quorumPeer.setMaxSessionTimeout(config.getMaxSessionTimeout());
          quorumPeer.setInitLimit(config.getInitLimit());
          quorumPeer.setSyncLimit(config.getSyncLimit());
          quorumPeer.setConfigFileName(config.getConfigFilename());
          // 管理 zk数据的存储
          quorumPeer.setZKDatabase(new ZKDatabase(quorumPeer.getTxnFactory()));
          quorumPeer.setQuorumVerifier(config.getQuorumVerifier(), false);
          if (config.getLastSeenQuorumVerifier()!=null) {
              quorumPeer.setLastSeenQuorumVerifier(config.getLastSeenQuorumVerifier(), false);
          }
          quorumPeer.initConfigInZKDatabase();
          // 管理 zk的通信
          quorumPeer.setCnxnFactory(cnxnFactory);
          quorumPeer.setSecureCnxnFactory(secureCnxnFactory);
          quorumPeer.setSslQuorum(config.isSslQuorum());
          quorumPeer.setUsePortUnification(config.shouldUsePortUnification());
          quorumPeer.setLearnerType(config.getPeerType());
          quorumPeer.setSyncEnabled(config.getSyncEnabled());
          quorumPeer.setQuorumListenOnAllIPs(config.getQuorumListenOnAllIPs());
          if (config.sslQuorumReloadCertFiles) {
              quorumPeer.getX509Util().enableCertFileReloading();
          }

          // sets quorum sasl authentication configurations
          quorumPeer.setQuorumSaslEnabled(config.quorumEnableSasl);
          if(quorumPeer.isQuorumSaslAuthEnabled()){
              quorumPeer.setQuorumServerSaslRequired(config.quorumServerRequireSasl);
              quorumPeer.setQuorumLearnerSaslRequired(config.quorumLearnerRequireSasl);
              quorumPeer.setQuorumServicePrincipal(config.quorumServicePrincipal);
              quorumPeer.setQuorumServerLoginContext(config.quorumServerLoginContext);
              quorumPeer.setQuorumLearnerLoginContext(config.quorumLearnerLoginContext);
          }
          quorumPeer.setQuorumCnxnThreadsSize(config.quorumCnxnThreadsSize);
          quorumPeer.initialize();
          // 启动 zk
          quorumPeer.start();
          quorumPeer.join();
      } catch (InterruptedException e) {
          // warn, but generally this is ok
          LOG.warn("Quorum Peer interrupted", e);
      }
    }

通信初始化具体实现代码

ServerCnxnFactory.java

static public ServerCnxnFactory createFactory() throws IOException {
        String serverCnxnFactoryName =
            System.getProperty(ZOOKEEPER_SERVER_CNXN_FACTORY);
        if (serverCnxnFactoryName == null) {
            serverCnxnFactoryName = NIOServerCnxnFactory.class.getName();
        }
        try {
            ServerCnxnFactory serverCnxnFactory = (ServerCnxnFactory) Class.forName(serverCnxnFactoryName)
                    .getDeclaredConstructor().newInstance();
            LOG.info("Using {} as server connection factory", serverCnxnFactoryName);
            return serverCnxnFactory;
        } catch (Exception e) {
            IOException ioe = new IOException("Couldn't instantiate "
                    + serverCnxnFactoryName);
            ioe.initCause(e);
            throw ioe;
        }
    }

在这里插入图片描述

zookeeperAdmin.md 文件中

在这里插入图片描述

初始化 NIO服务端 Socket(并未启动)

public void configure(InetSocketAddress addr, int maxcc, boolean secure) throws IOException {
        if (secure) {
            throw new UnsupportedOperationException("SSL isn't supported in NIOServerCnxn");
        }
        configureSaslLogin();

        maxClientCnxns = maxcc;
        sessionlessCnxnTimeout = Integer.getInteger(
            ZOOKEEPER_NIO_SESSIONLESS_CNXN_TIMEOUT, 10000);
        // We also use the sessionlessCnxnTimeout as expiring interval for
        // cnxnExpiryQueue. These don't need to be the same, but the expiring
        // interval passed into the ExpiryQueue() constructor below should be
        // less than or equal to the timeout.
        cnxnExpiryQueue =
            new ExpiryQueue<NIOServerCnxn>(sessionlessCnxnTimeout);
        expirerThread = new ConnectionExpirerThread();

        int numCores = Runtime.getRuntime().availableProcessors();
        // 32 cores sweet spot seems to be 4 selector threads
        numSelectorThreads = Integer.getInteger(
            ZOOKEEPER_NIO_NUM_SELECTOR_THREADS,
            Math.max((int) Math.sqrt((float) numCores/2), 1));
        if (numSelectorThreads < 1) {
            throw new IOException("numSelectorThreads must be at least 1");
        }

        numWorkerThreads = Integer.getInteger(
            ZOOKEEPER_NIO_NUM_WORKER_THREADS, 2 * numCores);
        workerShutdownTimeoutMS = Long.getLong(
            ZOOKEEPER_NIO_SHUTDOWN_TIMEOUT, 5000);

        LOG.info("Configuring NIO connection handler with "
                 + (sessionlessCnxnTimeout/1000) + "s sessionless connection"
                 + " timeout, " + numSelectorThreads + " selector thread(s), "
                 + (numWorkerThreads > 0 ? numWorkerThreads : "no")
                 + " worker threads, and "
                 + (directBufferBytes == 0 ? "gathered writes." :
                    ("" + (directBufferBytes/1024) + " kB direct buffers.")));
        for(int i=0; i<numSelectorThreads; ++i) {
            selectorThreads.add(new SelectorThread(i));
        }
		// 初始化 NIO服务端 socket,绑定 2181端口,可以接收客户端请求
        this.ss = ServerSocketChannel.open();
        ss.socket().setReuseAddress(true);
        LOG.info("binding to port " + addr);
        // 绑定 2181端口
        ss.socket().bind(addr);
        ss.configureBlocking(false);
        acceptThread = new AcceptThread(ss, addr, selectorThreads);
    }

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

在Linux中搭建Apache和多个版本PHP源码的集群

ApachePHP安装在公网IP为x.x.x.x的服务器上 需要下载安装的软件版本&#xff1a;httpd-2.4php-5.6php-7.4php-8.0 安装httpd 第一步&#xff0c;查看Linux系统中是否安装了apache。 命令&#xff1a;rpm -qa | grep httpd 若已经安装了&#xff0c;则需要使用命令“yum -y…

前端学习:HTML图像、表格、列表

目录 图像 一、图像标签和源属性(Src) 二、替换文本属性(Alt) 三、设置图片样式基本属性 四、图像标签 表格 一、标签 补充: 二、表格的表头 三、表格常用标签和属性 标签 属性 列表 一、无序列表 二、有序列表 三、定义列表 四、列表常用标签属性 图像 一、…

MATLAB三相LCL滤波型PWM逆变器仿真设计matlab代码(链接在文章结尾)

MATLAB三相LCL滤波型PWM逆变器仿真设计 参考并网电流外环电容电流前馈内环的双闭环控制结构&#xff0c;可以用于光伏和风力发电网侧变换器中进行改造。 三相逆变器通常采用三相桥式逆变电路&#xff0c;采用IGBT作为开关器件的电压型三相桥式逆变电路 在并网逆变器系统中,滤波…

MySQL数据库学习笔记(七)实验课三之拼命的李绿

一来就是实验课三了&#xff0c;那么实验课二呢&#xff1f;实验课二是装配mysql环境那些东西&#xff0c;而我们在前面的笔记中也有关于配置环境的&#xff0c;所以在这里就不再赘述了。 文章目录注意&#xff1a;1&#xff0c;本地文件导入2&#xff0c;数据范围3&#xff0c…

paddle 进行数字识别 (使用ocr数据集)

要点&#xff1a; 喵了个喵&#xff0c;没使用 OCR参考文档&#xff1a; PaddleOCR数字仪表识别——2.数据合成及数据集制作_数字仪表数据集https://blog.csdn.net/castlehe/category_10459202.html?spm1001.2014.3001.5482最佳参考&#xff1a; 基于PaddleOCR的数字显示器字…

SpringBoot ElasticSearch 【SpringBoot系列16】

SpringCloud 大型系列课程正在制作中&#xff0c;欢迎大家关注与提意见。 程序员每天的CV 与 板砖&#xff0c;也要知其所以然&#xff0c;本系列课程可以帮助初学者学习 SpringBooot 项目开发 与 SpringCloud 微服务系列项目开发 elasticsearch是一款非常强大的开源搜索引擎&a…

Logstash:部署和扩展 Logstash

Elastic Stack 用于大量用例&#xff0c;从操作日志和指标分析到企业和应用程序搜索。 确保你的数据可扩展、持久且安全地传输到 Elasticsearch 非常重要&#xff0c;尤其是对于任务关键型环境。 本文档的目的是强调 Logstash 最常见的架构模式以及如何随着部署的增长而有效扩…

c++学习之c++对c的扩展2

目录 1.c/c中的const 1 const概述 2 c/c中const的区别 c中的&#xff1a; c中的const&#xff1a; c/c中的const异同 c中const修饰的变量,分配内存情况 尽量以const替换define 2.引用 函数的引用&#xff1a; 引用的本质 指针的引用 5 常量引用 内联函数 内联函数…

(排序7)归并排序(递归)

归并排序 归并排序采用的是两个有序数组的归并。比如说现在想让一个数组有序。之前我们讲过&#xff0c;如果说你现在有两个有序数组的话&#xff0c;那么我们就可以把这两个有序数组给他合并成一个有序数组。两个有序区间归并的思路其实很简单&#xff08;这个也是归并的单趟…

Android 自定义View 之 计时文字

计时文字前言正文一、XML样式二、构造方法三、API方法四、使用五、源码前言 在Android开发中&#xff0c;常常会有计时的一些操作&#xff0c;例如收验证码的时候倒计时&#xff0c;秒表的计时等等&#xff0c;于是我就有了一个写自定义View的想法&#xff0c;本文效果图。 正文…

Vue2-黑马(八)

目录&#xff1a; &#xff08;1&#xff09;router-动态路由 &#xff08;2&#xff09;router-重置路由 &#xff08;3&#xff09;router-页面刷新 &#xff08;1&#xff09;router-动态路由 我们有这样一个需求&#xff0c;不同的用户根据自己的身份不一样&#xff0c;…

Seaborn 数据可视化基础

目录 介绍 知识点 Seaborn 介绍 快速优化图形 Seaborn 绘图 API 一、散点图&#xff1a; 参数hue hue hue_order 参数style 二 、线形图 三、类别图 绘制箱线图 绘制小提琴图 绘制增强箱线图 绘制点线图 绘制条形图 绘制计数条形图 四、分布图 五、回归图 …

nginx配置

单线程应用 稳定性高 系统资源消耗低 线程切换消耗小 对HTTP并发连接处理能力高 单台服务器可支持2w个并发请求 nginx与apache区别 Nginx相对于Apache的优点: 轻量级&#xff0c;同样是 web 服务&#xff0c;比Apache 占用更少的内存及资源&#xff0c;高并发&#xff0…

攻防世界-file_include(convert.iconv的使用)

代码审计&#xff0c;存在文件包含&#xff0c;直接上伪协议 发现不行&#xff0c;应该是存在字符过滤 知识盲区&#xff1a; 1.file://协议&#xff0c;需要填写绝对路径&#xff0c;只能读取txt文件&#xff0c;后面直接跟绝对路径。 file:///etc/passwd 2.php://filter …

深入浅出 Golang 内存管理

了解内存管理~ 前言&#xff1a; 本节课主要介绍了内存管理知识与自动内存管理机制&#xff0c;并对目前 Go 内存管理过程中存在的问题提出了解决方案&#xff0c;同时结合了上次课程学习的《Go 语言性能优化》相关知识&#xff0c;提供可行性的优化建议 … 自动内存管理 Go…

spring-boot怎么扫描不在启动类所在包路径下的bean

前言&#xff1a; 项目中有多个模块&#xff0c;其中有些模块的包路径不在启动类的子路径下&#xff0c;此时我们怎么处理才能加载到这些类&#xff1b; 1 使用SpringBootApplication 中的scanBasePackages 属性; SpringBootApplication(scanBasePackages {"com.xxx.xx…

C++linux高并发服务器项目实践 day5

Clinux高并发服务器项目实践 day5程序和进程单道、多道程序设计时间片并行和并发进程控制块&#xff08;PCB&#xff09;进程状态转换进程的状态进程相关命令进程号和相关函数进程创建父子进程的关系GDB多进程调试程序和进程 程序是包含一系列信息的文件&#xff0c;这些信息描…

你知道怎么实现定时任务吗?

诸位读者都知道笔者写东西都是用到才写&#xff0c;笔者的学习足迹自从参加工作之后就是 非系统 学习了&#xff0c;公司里源代码只要有笔者不知道的技术细节&#xff0c;笔者就会仔细的研究清楚&#xff0c;笔者是不喜欢给自己留下问题的那种学习习惯。 为何要写 笔者最近负…

如何使用Thymeleaf给web项目中的网页渲染显示动态数据?

编译软件&#xff1a;IntelliJ IDEA 2019.2.4 x64 操作系统&#xff1a;win10 x64 位 家庭版 服务器软件&#xff1a;apache-tomcat-8.5.27 目录一. 什么是Thymeleaf&#xff1f;二. MVC2.1 为什么需要MVC&#xff1f;2.2 MVC是什么&#xff1f;2.3 MVC和三层架构之间的关系及工…

AI绘图体验:想象力无限,创作无穷!(文生图)

基础模型&#xff1a;3D二次元 PIXEL ART &#xff08;1&#xff09;16-bit pixel art, outside of caf on rainy day, light coming from windows, cinematic still(电影剧照), hdr (2) 16-bit pixel art, island in the clouds, by studio ghibli&#xff08;吉卜力工作室…