• 2020系统综合实践 第4次实践作业


    2020系统综合实践 第4次实践作业

    一、使用Docker-compose实现Tomcat+Nginx负载均衡

    要求:

    • 理解nginx反向代理原理;
    • nginx代理tomcat集群,代理2个以上tomcat;
    • 了解nginx的负载均衡策略,并至少实现nginx的2种负载均衡策略;

    参考资料:

    1.nginx反向代理原理及相关概念:

    • 反向代理概念:反向代理(Reverse Proxy)方式是指以代理服务器来接受Internet上的连接请求,然后将请求转发给内部网络上的服务器;并将从服务器上得到的结果返回给Internet上请求连接的客户端,此时代理服务器对外就表现为一个服务器。通常的代理服务器,只用于代理内部网络对Internet的连接请求,客户机必须指定代理服务器,并将本来要直接发送到Web服务器上的http请求发送到代理服务器中。当一个代理服务器能够代理外部网络上的主机,访问内部网络时,这种代理服务的方式称为反向代理服务

    • 反向代理服务器的工作原理:反向代理服务器通常有两种模型,它可以作为内容服务器的替身,也可以作为内容服务器集群的负载均衡器。Nginx在做反向代理时,提供性能稳定,并且能够提供配置灵活的转发功能。Nginx可以根据不同的正则匹配,采取不同的转发策略,并且Nginx对返回结果进行错误页跳转,异常判断等。如果被分发的服务器存在异常,他可以将请求重新转发给另外一台服务器,然后自动去除异常服务器。反向代理的原理图如下所示:

    • 负载均衡:Nginx提供的负载均衡策略有2种:内置策略和扩展策略。内置策略为轮询,加权轮询,Ip hash等。其中轮询和加权轮询的算法实现如下所示:

    2.nginx代理tomcat集群,代理2个以上tomcat:

    1.创建的文件夹Tomcat,其目录结构如下所示:

    2.编写相关配置文件:

    首先使用的是轮询算法(默认情况下),具体配置内容如下:

    • default.conf:
    #使用轮询策略
    upstream tomcats {
        server cyk_tomcat1:8080; 
        server cyk_tomcat2:8080; 
        server cyk_tomcat3:8080; 
    }
    
    server {
        listen 2430;
        server_name localhost;
    
        location / {
            proxy_pass http://tomcats; # 请求转向tomcats
        }
    }
    
    • docker-compose.yml:
    version: "3.8"
    services:
        nginx:
            image: nginx
            container_name: cyk_ngx
            ports:
                - 80:2430
            volumes:
                - ./nginx/default.conf:/etc/nginx/conf.d/default.conf # 挂载配置文件
            depends_on:
                - tomcat01
                - tomcat02
                - tomcat03
    
        tomcat01:
            image: tomcat
            container_name: cyk_tomcat1
            volumes:
                - ./tomcat01:/usr/local/tomcat/webapps/ROOT # 挂载web目录
    
        tomcat02:
            image: tomcat
            container_name: cyk_tomcat2
            volumes:
                - ./tomcat02:/usr/local/tomcat/webapps/ROOT
    
        tomcat03:
            image: tomcat
            container_name: cyk_tomcat3
            volumes:
                - ./tomcat03:/usr/local/tomcat/webapps/ROOT
    
    • index.html:
    It is the tomcat 1!  #为tomcat01文件夹下的index.html
    It is the tomcat 2!  #为tomcat02文件夹下的index.html
    It is the tomcat 3!  #为tomcat03文件夹下的index.html
    

    3.在编写相关配置文件后,进入Tomcat文件夹下打开终端开始构建容器,如下所示:

    sudo docker-compose up -d --build
    

    构建成功后可查看到相关的正在运行的容器:

    在浏览器访问localhost可看到相关页面,并且刷新页面可看到结果会轮询:

    3.实现nginx的2种负载均衡策略:

    • 使用轮询策略测试负载均衡:

    创建py文件test1.py来进行测试:

    import requests
    url = 'http://localhost'
    for i in range(1,10):
        response=requests.get(url)
        print(response.text)
    

    执行test1.py可发现是三个tomcat服务器是轮流执行的,即三个服务器出现的频率是一样的,如下所示:

    • 使用权重策略测试负载均衡

    先更改default.conf文件:

    #使用权重策略
    upstream tomcats {
        server cyk_tomcat1:8080 weight=2;   #weight后面的数字表示权重
        server cyk_tomcat2:8080 weight=4;   #tomcat的默认端口号为8080
        server cyk_tomcat3:8080 weight=6;
    }
    
    server {
        listen 2430;
        server_name localhost;
    
        location / {
            proxy_pass http://tomcats; #请求转向tomcats
        }
    }
    

    重新构建容器并将容器重启一下:

    sudo docker-compose up -d --build
    


    在浏览器访问localhost,可看到tomcat3服务器出现的频率更高:

    再次执行文件test1.py来进行测试:

    由于tomcat3所占的权重比较大,因此其出现的频率比较高,其次是tomcat2,出现频率最低的是tomcat1。

    二、使用Docker-compose部署javaweb运行环境

    要求:

    • 分别构建tomcat、数据库等镜像服务;
    • 成功部署Javaweb程序,包含简单的数据库操作;
    • 为上述环境添加nginx反向代理服务,实现负载均衡。

    参考资料:

    由于对javaweb程序的部署不是很懂,因此这里使用了老师给的javaweb参考项目

    1.创建项目文件夹Javaweb,文件结构如下所示:

    2.编写相关配置文件:

    • docker-compose.yml:
    version: "3"   #版本
    services:     #服务节点
      tomcat:     #tomcat 服务
        image: tomcat    #镜像
        hostname: hostname       #容器的主机名
        container_name: tomcat00   #容器名
        ports:      #端口
         - "5050:8080"
        volumes:  #数据卷
         - "./webapps:/usr/local/tomcat/webapps"
         - ./wait-for-it.sh:/wait-for-it.sh
        networks:   #网络设置静态IP
          webnet:
            ipv4_address: 15.22.0.15
      mymysql:  #mymysql服务
        build: .   #通过MySQL的Dockerfile文件构建MySQL
        image: mymysql:test
        container_name: mymysql
        ports:
          - "3309:3306" 
    #红色的外部访问端口不修改的情况下,要把Linux的MySQL服务停掉
    #service mysql stop
    #反之,将3306换成其它的
        command: [
                '--character-set-server=utf8mb4',
                '--collation-server=utf8mb4_unicode_ci'
        ]
        environment:
          MYSQL_ROOT_PASSWORD: "123456"
        networks:
          webnet:
            ipv4_address: 15.22.0.6
      nginx:
          image: nginx
          container_name: "nginx-tomcat"
          ports:
              - 8080:8080
          volumes:
              - ./default.conf:/etc/nginx/conf.d/default.conf # 挂载配置文件
          tty: true
          stdin_open: true
          networks:
           webnet:
            ipv4_address: 15.22.0.7
    networks:   #网络设置
     webnet:
       driver: bridge  #网桥模式
       ipam:
         config:
          - 
           subnet: 15.22.0.0/24   #子网
    
    • default.conf:
    upstream tomcat123{
        server tomcat00:8080; 
    
    }
    
    server {
        listen 8080;
        server_name localhost;
    
        location / {
            proxy_pass http://tomcat123;
        }
    }
    
    • docker-entrypoint.sh:
    #!/bin/bash
    mysql -uroot -p123456 << EOF
    source /usr/local/grogshop.sql;
    
    • dockerfile:
    #  这个是构建MySQL的dockerfile
     
    FROM registry.saas.hand-china.com/tools/mysql:5.7.17
     
    # mysql的工作位置
    ENV WORK_PATH /usr/local/
    
    # 定义会被容器自动执行的目录
    ENV AUTO_RUN_DIR /docker-entrypoint-initdb.d
     
    #复制gropshop.sql到/usr/local 
    COPY grogshop.sql  /usr/local/
    #把要执行的shell文件放到/docker-entrypoint-initdb.d/目录下,容器会自动执行这个shell
    COPY docker-entrypoint.sh  $AUTO_RUN_DIR/
     
    #给执行文件增加可执行权限
    RUN chmod a+x $AUTO_RUN_DIR/docker-entrypoint.sh
     
    # 设置容器启动时执行的命令
    #CMD ["sh", "/docker-entrypoint-initdb.d/import.sh"]
    

    其他项目文件可参考老师所给的javaweb项目。

    3.查看本机IP地址并修改连接数据库的IP:

    • 通过命令ifconfig -a查看本机ip地址,ens32对应的IP(192.168.37.139)即为本机IP(当然也可通过虚拟机的连接信息来查看到本机的IP地址):

    • 修改jdbc.properties文件对应的ip地址和对应的端口号:

    vim ~/javaweb/webapps/ssmgrogshop_war/WEB-INF/classes/jdbc.properties
    


    4.进入javaweb文件夹,打开终端来构建相应容器:

    sudo docker-compose up -d
    

    构建容器成功后,即可通过浏览器访问前端页面:

    http://127.0.0.1:8080/ssmgrogshop_war
    

    使用相关账号登录后即可进行简单的数据库操作:

    • 通过客房新增模块来新增一间客房,如下所示:

    • 通过客房修改模块来修改相应的客房信息,如下所示:

    5.添加nginx反向代理服务,实现负载均衡:

    • 修改default.conf配置文件:
    upstream tomcats{
            server tt1:8080 ;
            server tt2:8080 ;
            server tt3:8080 ;
    
    }
    server {
        listen 2508;
        server_name localhost;
    
    location / {
        root   /usr/share/nginx/html;
        index  index.html index.htm;
        proxy_pass http://tomcats;
    }
    
    }
    
    • 修改docker-compose.yml文件,新增如下内容:
    tomcat01:     
        image: tomcat    
        hostname: hostname       
        container_name: tomcat01   
        ports:      
         - "5051:8080"          #后面访问网页的时候要选择对应的端口号5050
        volumes:  #数据卷
         - "./webapps:/usr/local/tomcat/webapps"
         - ./wait-for-it.sh:/wait-for-it.sh
        networks:   #网络设置静态IP
          webnet:
            ipv4_address: 15.22.0.16
      tomcat02:     
        image: tomcat    
        hostname: hostname       
        container_name: tomcat02   
        ports:      
         - "5052:8080"          #后面访问网页的时候要选择对应的端口号5050
        volumes:  #数据卷
         - "./webapps:/usr/local/tomcat/webapps"
         - ./wait-for-it.sh:/wait-for-it.sh
        networks:   #网络设置静态IP
          webnet:
            ipv4_address: 15.22.0.17
      nginx:
        depends_on:
         - tomcat00
         - tomcat01
         - tomcat02 
    
    • 重新构建容器,并通过浏览器查看结果:
    sudo docker-compose up -d
    

    重新运行容器后,可以发现在三个端口下都可以访问nginx,说明实现了负责均衡:

    三、使用Docker搭建大数据集群环境

    直接用机器搭建Hadoop集群,会因为不同机器配置等的差异,遇到各种各样的问题;也可以尝试用多个虚拟机搭建,但是这样对计算机的性能要求比较高,通常无法负载足够的节点数;使用Docker搭建Hadoop集群,将Hadoop集群运行在Docker容器中,使Hadoop开发者能够快速便捷地在本机搭建多节点的Hadoop集群。

    要求:

    • 完成hadoop分布式集群环境配置,至少包含三个节点(一个master,两个slave);
    • 成功运行hadoop 自带的测试实例。

    参考资料:

    1.搭建hadoop环境:
    • 这里所使用的hadoop环境为:
    ubuntu 18.04 LST
    openjdk 1.8
    hadoop 3.1.3
    
    • 先拉取一个ubantu镜像(这里使用的是18.04版本):
    sudo docker pull ubuntu:18.04
    

    • 创建hadoop文件夹,其目录结构如下所示:

    • 编写相关配置文件:

    Dockerfile:

    #Base images 基础镜像
    FROM ubuntu:18.04
    #MAINTAINER 维护者信息
    MAINTAINER cyk2430
    COPY ./sources.list /etc/apt/sources.list
    

    source.list(改文件用于将镜像换源以提高速度):

    # 默认注释了源码镜像以提高 apt update 速度,如有需要可自行取消注释
    deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse
    # deb-src http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse
    deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse
    # deb-src http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse
    deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse
    # deb-src http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse
    deb http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-security main restricted universe multiverse
    # deb-src http://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-security main restricted universe multiverse
    
    • 创建并运行容器:
    sudo docker build -t ubuntu:18.04 .
    sudo docker run -it --name cyk_ ubuntu ubuntu:18. 04
    

    2.对创建的容器进行初始化:
    • 更新系统软件源:
    apt-get update
    

    • 安装vim:
    apt-get install vim
    
    • 安装ssh(在开启分布式Hadoop时,需要用到ssh连接slave):
    apt-get install ssh
    

    安装成功后开启sshd服务器:

    /etc/init.d/ssh start
    

    把启动命令写进~/.bashrc文件,实现进入Ubuntu系统时,都能自动启动sshd服务:

    vim ~/.bashrc          #通过vim修改bashrc文件
    /etc/init.d/ssh start  #在文件的最后一行添加此项内容
    
    • 实现ssh无密码登陆:

    获取密钥:

    ssh-keygen -t rsa #用于获取密钥,执行后一直按回车键即可
    

    免密登入sshd:

    cd ~/.ssh 
    cat id_rsa.pub >> authorized_keys #这一步要在~/.ssh目录下进行
    

    • 安装JDK:

    1.下载java8版本:

    apt install openjdk-8-jdk
    

    2.安装成功后需要配置环境变量:

    先打开配置文件:

    vim ~/.bashrc  #打开配置文件
    

    在文件末尾添加以下两行,配置Java环境变量:

    export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/
    export PATH=$PATH:$JAVA_HOME/bin
    

    使配置环境生效:

    source ~/.bashrc # 使.bashrc生效
    

    查看java版本:

    java -version
    

    • 新打开一个终端,进行存档,以将该容器保存为镜像(可先查看当前正在运行的容器,然后获得刚刚使用的容器ID,以便对其存档):
    sudo docker commit 55867a9bd8f9 ubuntu/ jdk8
    

    • 安装Hadoop:

    先下载好Hadoop,这里下载的是3.1.3的版本,然后通过cp复制到挂载的文件目录下,解压文件,并验证安装。具体步骤如下所示(其中第一步在桌面新开个终端运行,其余步骤在容器内运行):

    1.挂载~/build目录,实现文件共享:

    sudo docker run -it -v /home/cyk/build:/root/build --name ubuntu-jdk8 ubuntu/jdk8
    

    2.通过cp将hadoop压缩包复制到挂载的文件目录下:

    sudo cp /home/cyk/hadoop/build/hadoop-3.1.3.tar.gz /home/cyk/build
    

    3.解压hadoop压缩包:

    tar -zxvf hadoop-3.1.3.tar.gz -C /usr/local
    

    4.验证hadoop是否安装成功:

    cd /usr/local/hadoop-3.1.3
    ./bin/hadoop version
    

    • 配置Hadoop集群:

    1.进入配置文件存放目录:

    cd /usr/local/hadoop-3.1.3/etc/hadoop #进入配置文件存放目录
    

    2.修改环境变量:

    vim hadoop-env.sh
    export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/ # 在任意位置添加
    

    3.修改core-site.xml:

    vim core-site.xml
    
    <?xml version="1.0" encoding="UTF-8" ?>
    <?xml-stylesheet type="text/xsl" href="configuration.xsl" ?>
    <configuration>
              <property> 
                      <name>hadoop.tmp.dir</name>
                      <value>file:/usr/local/hadoop-3.1.3/tmp</value>
                      <description>Abase for other temporary directories.</description>
              </property>
              <property>
                      <name>fs.defaultFS</name>
                      <value>hdfs://master:9000</value>
              </property>
    </configuration>
    

    4.修改hdfs-site.xml:

    vim hdfs-site.xml
    
    <?xml version="1.0" encoding="UTF-8" ?>
    <?xml-stylesheet type="text/xsl" href="configuration.xsl" ?>
    <configuration>
            <property>
                    <name>dfs.replication</name>
                    <value>1</value>
            </property>
            <property>
                    <name>dfs.namenode.name.dir</name>
    		        <value>file:/usr/local/hadoop-3.1.3/tmp/dfs/name</value>
    	</property>
    	<property>
                    <name>dfs.datanode.data.dir</name>
                    <value>file:/usr/local/hadoop-3.1.3/tmp/dfs/data</value>
    	</property>
    	<property>
                    <name>dfs.permissions.enabled</name>
                    <value>false</value>
            </property>
    </configuration>
    

    5.修改mapred-site.xml:

    vim mapred-site.xml
    
    <?xml version="1.0" ?>
    <?xml-stylesheet type="text/xsl" href="configuration.xsl" ?>
    <configuration>
        <property>
            <name>mapreduce.framework.name</name>
            <value>yarn</value>
        </property>
        <property>
            <name>yarn.app.mapreduce.am.env</name>
            <value>HADOOP_MAPRED_HOME=/usr/local/hadoop-3.1.3</value>
        </property>
        <property>
            <name>mapreduce.map.env</name>
            <value>HADOOP_MAPRED_HOME=/usr/local/hadoop-3.1.3</value>
        </property>
        <property>
            <name>mapreduce.reduce.env</name>
            <value>HADOOP_MAPRED_HOME=/usr/local/hadoop-3.1.3</value>
        </property>
    </configuration>
    

    6.修改yarn-site.xml:

    vim yarn-site.xml
    
    <?xml version="1.0" ?>
    <configuration>
    <!-- Site specific YARN configuration properties -->
            <property>
                   <name>yarn.nodemanager.aux-services</name>
                   <value>mapreduce_shuffle</value>
            </property>
            <property>
                   <name>yarn.resourcemanager.hostname</name>
                   <value>Master</value>
            </property>
            <!--虚拟内存和物理内存比,不加这个模块程序可能跑不起来-->
            <property>
                   <name>yarn.nodemanager.vmem-pmem-ratio</name>
                   <value>2.5</value>
            </property>
    </configuration>
    

    7.修改脚本文件:

    先进入脚本文件存放目录:

    cd /usr/local/hadoop-3.1.3/sbin
    

    对于start-dfs.sh和stop-dfs.sh文件,添加下列参数:

    HDFS_DATANODE_USER=root
    HADOOP_SECURE_DN_USER=hdfs
    HDFS_NAMENODE_USER=root
    HDFS_SECONDARYNAMENODE_USER=root
    

    对于start-yarn.sh和stop-yarn.sh,添加下列参数:

    YARN_RESOURCEMANAGER_USER=root
    HADOOP_SECURE_DN_USER=yarn
    YARN_NODEMANAGER_USER=root
    

    8.打开新的终端保存镜像:

    sudo docker commit 容器ID ubuntu/hadoop
    
    • 利用构建好的镜像运行Hadoop集群:

    1.开启三个终端分别运行ubuntu/hadoop镜像,分别表示Hadoop集群中的master,slave01和slave02:

    # 第一个终端
    docker run -it -h master --name master ubuntu/hadoop
    # 第二个终端
    docker run -it -h slave01 --name slave01 ubuntu/hadoop
    # 第三个终端
    docker run -it -h slave02 --name slave02 ubuntu/hadoop
    

    2.分别修改/etc/hosts(要注意根据容器的ip地址修改,可先通过vim /etc/hosts来查看容器各自的IP,然后再进行修改):

    172.17.0.4      master
    172.17.0.5      slave01
    172.17.0.6      slave02
    

    3.测试ssh:

    在master结点测试ssh是否可以连接到slave01结点:

    ssh slave01
    

    在slave01结点测试ssh是否可以连接到master结点:

    ssh master
    

    4.在master主机上修改workers:

    vim /usr/local/hadoop-3.1.3/etc/hadoop/workers
    

    将里面的localhost替换为如下:

    slave01
    slave02
    

    5.在master上测试hadoop集群:

    cd /usr/local/hadoop-3.1.3
    bin/hdfs namenode -format # 格式化文件系统
    sbin/start-dfs.sh # 开启NameNode和DataNode服务
    sbin/start-yarn.sh
    

    使用jps查看服务是否开启成功:

    jps
    

    3.运行hadoop 自带的测试实例:

    • 在master终端执行:
    bin/hdfs dfs -mkdir -p /user/hadoop/input
    bin/hdfs dfs -put ./etc/hadoop/*.xml /user/hadoop/input
    bin/hdfs dfs -ls /user/hadoop/input
    

    • 运行示例并在hdfs上的output目录下查看运行结果:
    bin/hadoop jar share/hadoop/mapreduce/hadoop-mapreduce-examples-3.1.3.jar grep /user/hadoop/input output 'dfs[a-z.]+'
    ./bin/hdfs dfs -cat output/*  #查看运行结果
    

    四、记录完成作业所花的时间:

    项目 时间(估算)
    Tomcat+Nginx负载均衡 2h
    部署javaweb运行环境 6h
    用Docker搭建大数据集群环境 8h
    写博客 4h

    五、记录实验过程的主要问题和解决方法:

    整个实验过程中第一部分完成的还是相对顺利,遇到的问题主要是第二部分和第三部分的内容:

    1.在第三部分测试ssh时,出现了master结点无法连接到slave01结点的问题,如下所示:

    解决办法:通过在班级询问,我知道了出现这个问题的原因主要是我之前忘记设置sshd服务自启动了,后面通过修改bashrc文件实现sshd服务自启动,然后再再commit镜像解决了这个问题。

    2.在第三部分使用jps查看服务是否开启成功时,一直无法开启NameNode和DataNode服务,如下所示:

    解决办法:这个问题困扰了我超级久,后面在网上查了很多资料,才发现了是之前在修改core-site.xml、hdfs-site.xml等配置文件时,由于配置时不小心出错了所导致了,最后重新将这些文件都配置了一下,然后再保存镜像解决了这个问题。

    3.第二部分在构造镜像后,发现能访问到登录页面却一直登录不上那个酒店管理系统,登录时一直超时,后面报了一段错误,如下所示:

    解决办法:这个问题在群里很多同学都反应过,有同学说是IP地址和端口号配置不对所导致的,但是我多次重新配了IP地址和端口号还是登录不上。最后我是把之前创建的mymysql等镜像都删了,然后重新修改配置文件(修改后的配置文件就在实验第二部分里),重新构造镜像后就能登录上了。

    六、实验感想:

    首先,先让我小小的吐槽一下,这次实验的第一部分相对简单,但第二部分和第三部分就真的是做的我自闭了,第三部分我从早上九点一直做到了晚上八点,主要是中间一直出现很多七七八八的问题错误,然后每一个问题都要花很长时间去解决,加上第三部分需要修改很多的配置文件,在这个过程中我就一个不小心,导致后面再测试ssh和测试hadoop集群上一直出错,最后直接返工再来一遍(真是辛酸o(╥﹏╥)o)。第二部分刚开始还算顺利,但最后能访问到登录页面却一直登录不上那个酒店管理系统,看了群里很多同学有和我一样的问题,但是却没有比较有效的办法,还好最后通过删了之前的容器再重新构建容器成功登录了上去,不然心态真的要炸了!虽然过程十分非常的艰辛,但是这次实验带给我的收获真的很多,让我接触和了解了第一个javaweb项目(虽然是老师给的参考,但是让我对其有了初步了解),同时,我还学会了如何使用Docker-compose实现Tomcat+Nginx负载均衡、使用Docker搭建大数据集群环境、部署javaweb运行环境等内容,不仅加深了相关理论基础,动手实践的能力也得到了很大的提高。但还是希望以后的实验能够相对简单一些,不然真的是太难了。。
  • 相关阅读:
    Mybatis数据库操作的返回值
    Java中设置classpath、path、JAVA_HOME的作用?
    mysql备份与还原,增量备份;使用ibd和frm文件恢复数据
    SQLAlchemy会话与事务控制:互斥锁和共享锁
    log4j设置,以及中文乱码,通过过滤器输出指定级别的日志,或者指定级别范围的日志
    SQL重复记录查询-count与group by having结合查询重复记录
    css样式美化 下拉框 select 样式
    人人都是 DBA(XIII)索引信息收集脚本汇编
    java线程安全问题之静态变量、实例变量、局部变量
    java uuid第一次性能
  • 原文地址:https://www.cnblogs.com/chenyoukun/p/12908782.html
Copyright © 2020-2023  润新知