大数据原生集群 (Hadoop2.X为核心) 本地测试环境搭建六

本篇软件版本

Datax
MongDB_linux-x86_64-4.0.10
clickhouse20.8.3.18-1
集群最后完善


DataX

Datax和sqoop是一样的作用,但是区别就在于datax是阿里研发的项目,完全符合中国人的使用习惯,运行使用指定json格式配置文件的方式运行,且它的数据链相当丰富

第一步:将下载好的datax.tar.gz上传到hdp2的/opt

第二步:解压datax.tar.gz到/opt

tar -zxvf datax.tar.gz -C /opt

第三步:运行自检脚本

cd /opt/datax/bin/
python datax.py /opt/module/datax/job/job.json

运行成功则安装成功

MongDB

Mongdb是一个很早的非关系内存数据库,它操作等都是基于json,在开发之初是为了电商服务

第一步:上传压缩包到虚拟机中

第二步:解压
tar -zxvf mongodb-linux-x86_64-4.0.10.tgz -C /opt/

第三步:重命名路径

mv mongodb-linux-x86_64-4.0.10/ mongodb

第四步:创建数据库目录

MongoDB的数据存储默认在data目录的db目录下,但是这个目录在安装过程不会自动创建,所以需要手动创建data目录,并在data目录中创建db目录。

mkdir -p /data/db
chmod 777 -R /data/db/

第五步:启动MongoDB服务

bin/mongod

第六步:进入shell页面

cd /opt/mongodb
bin/mongo

运行之后正常情况下就可以正常使用了

ClickHouse列式数据库集群方式安装

ClickHouse 是俄罗斯的Yandex于2016年开源的列式存储数据库(DBMS),主要用于在线分析处理查询(OLAP),能够使用SQL查询实时生成分析数据报告。

第一步:给所有要安装ClickHouse的节点安装依赖

yum install libicu.x86_64

第二步:给所有要安装ClickHouse节点上传下列的四个组件包并运行rpm -ivh 包名安装,这里我使用三台集群。

clickhouse-client-20.8.3.18-1.el7.x86_64.rpm
clickhouse-common-static-20.8.3.18-1.el7.x86_64.rpm
clickhouse-server-20.8.3.18-1.el7.x86_64.rpm
clickhouse-server-common-20.8.3.18-1.el7.x86_64.rpm

安装的时候如果报错提示如下内容,则在安装命令后添加--nodeps --force强制安装
在这里插入图片描述
第三步:所有节点分别修改/etc/clickhouse-server/config.xml文件,注意千万不能修改一个后通过分发方式同步,一定要分别去修改,不然会出现服务启动不了的坑。

进入文件后找到下面的配置,这样就可使得任意节点都可访问ClickHouse

<listen_host>::1</listen_host>
修改为
<listen_host>::</listen_host>

第四步:在所有节点的etc目录下新建metrika.xml文件,并写入如下内容,注意修改为你们各自的配置

<yandex>
	<!-- clickhouse节点IP和端口 -->
	<clickhouse_remote_servers>
		<clickhouse_cluster>
			<shard>
				 <internal_replication>true</internal_replication>
				<replica>
					<host>hdp1</host>
					<port>9091</port>
				</replica>
			</shard>
			<shard>
				<replica>
					<internal_replication>true</internal_replication>
					<host>hdp2</host>
					<port>9091</port>
				</replica>
			</shard>
			<shard>
				<internal_replication>true</internal_replication>
				<replica>
					<host>hdp3</host>
					<port>9091</port>
				</replica>
			</shard>
		</clickhouse_cluster>
	</clickhouse_remote_servers>

	<!-- zookeeper节点IP和端口 -->
	<zookeeper-servers>
	    <node index="1">
	        <host>hdp1</host>
	        <port>2181</port>
	    </node>

	    <node index="2">
		    <host>hdp2</host>
		    <port>2181</port>
	    </node>
	    <node index="3">
		    <host>hdp3</host>
		    <port>2181</port>
	    </node>
	</zookeeper-servers>

	<!-- 当前clickhouse节点 -->
	<macros>
		<replica>hdp3</replica>
	</macros>


	<networks>
	    <ip>::/0</ip>
	</networks>


	<clickhouse_compression>
	    <case>
	      <min_part_size>10000000000</min_part_size>
	      <min_part_size_ratio>0.01</min_part_size_ratio>                                                                                                                                       
	      <method>lz4</method>
	    </case>
	</clickhouse_compression>

</yandex>

第五步:启动

启动zookeeper集群

所有ClickHouse节点运行命令启动服务

service clickhouse-server start

在任意节点上运行客户端命令

clickhouse-client

不报错并进入client后运行如下sql语句查询当前集群节点信息

select * from system.clusters

集群最后完善,下面的内容选择性安装

一、环境变量

大家要确保现在集群中每一个软件的环境变量都要有

二、hive连接hbase

有些小伙伴可能需要使用hive去连接hbase而不是之前安装的phoenix,这个很正常而且还是很常见的一种情况,所以下面我们要配置一下让hive可以连接hbase

进入到/opt/hbase-1.3.1/lib路径下,执行下面命令,路径使用自己的,将如下jar包拷贝到hive的lib就可以,如不是安装的网盘中的hbase版本,则只可参考jar包名字

cp hbase-common-1.3.1.jar /opt/hive-1.2.1/lib/
cp hbase-server-1.3.1.jar /opt/hive-1.2.1/lib/
cp hbase-client-1.3.1.jar /opt/hive-1.2.1/lib/
cp hbase-protocol-1.3.1.jar /opt/hive-1.2.1/lib/
cp hbase-it-1.3.1.jar /opt/hive-1.2.1/lib/
cp htrace-core-3.1.0-incubating.jar /opt/hive-1.2.1/lib/
cp hbase-hadoop2-compat-1.3.1.jar /opt/hive-1.2.1/lib/
cp hbase-hadoop-compat-1.3.1.jar /opt/hive-1.2.1/lib/
cp metrics-core-2.2.0.jar /opt/hive-1.2.1/lib/

同时在hive-site.xml中增加zookeeper的属性,如下:

<property>
  <name>hive.zookeeper.quorum</name>
  <value>hdp1,hdp2,hdp3</value>
  <description>The list of ZooKeeper servers to talk to. This is only needed for read/write locks.</description>
</property>
<property>
  <name>hive.zookeeper.client.port</name>
  <value>2181</value>
  <description>The port of ZooKeeper servers to talk to. This is only needed for read/write locks.</description>
</property>

同时在环境变量中要有Hbase的home和hive的home,这样hive就可以连接hbase了,具体使用时和平常的区别只是建表语句有些不一样而已,大家可以在网上查看一下这种情况下的建表语句

三、flume功能扩展之hdfs

Flume如果要作用在hdfs中则要将hadoop中lib下的一些jar放在flume中,按照我的版本着jar包如下,如不是安装同一hadoop版本,则只可参考jar包名字
在这里插入图片描述
四、下载上传

如要上传文件时使用rz或下载时使用sz则需要使用yum -y install lrzsz命令安装环境

五、hadoop优化lzo压缩,理性选择,后面还有一个压缩方式

为了hadoop的运行可以节省datenode使用的硬盘资源以及datenode存储时硬盘不够的情况,我们要在配置中,配置多个datenode数据存储位置,这是因为正式服务器中不可能只有一块硬盘,因此可以使用多个路径对应的多个盘在缓解datanode的数据存储,同时我们还要配置datanode在存储文件的时候对文件进行压缩以此进一步的优化hadoop,步骤如下

1)先下载lzo的jar项目
https://github.com/twitter/hadoop-lzo/archive/master.zip

2)下载后的文件名是hadoop-lzo-master,它是一个zip格式的压缩包,先进行解压,然后在win用maven编译。生成hadoop-lzo-0.4.20.jar,如果你是从我的网盘获取的包,那就直接使用就行。

3)将编译好后的hadoop-lzo-0.4.20.jar 放入hdp1的hadoop-2.7.2/share/hadoop/common/

/opt/hadoop-2.7.2/share/hadoop/common
ls
hadoop-lzo-0.4.20.jar

4)scp同步hadoop-lzo-0.4.20.jar到其他两台服务器,位置不要变

5)core-site.xml增加配置支持LZO压缩

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>

<configuration>

	<property>
		<name>io.compression.codecs</name>
		<value>
			org.apache.hadoop.io.compress.GzipCodec,
			org.apache.hadoop.io.compress.DefaultCodec,
			org.apache.hadoop.io.compress.BZip2Codec,
			org.apache.hadoop.io.compress.SnappyCodec,
			com.hadoop.compression.lzo.LzoCodec,
			com.hadoop.compression.lzo.LzopCodec
		</value>
	</property>

	<property>
   	 	<name>io.compression.codec.lzo.class</name>
    	<value>com.hadoop.compression.lzo.LzoCodec</value>
	</property>
</configuration>

5)同步core-site.xml到其他两台机器,xsync是自己写的脚本如果没有用scp
xsync core-site.xm

6)启动及查看集群

六、优化hive的运行引擎

Tez可以将多个有依赖的作业转换为一个作业,这样只需写一次HDFS,且中间节点较少,从而大大提升作业的计算性能。注意如果你手动优化的tez那么后续hive在其他节点运行的话,tez要和hive一起移动到运行节点上

1)下载tez的依赖包:http://tez.apache.org

2)拷贝apache-tez-0.9.1-bin.tar.gz到服务器上

3)解压缩apache-tez-0.9.1-bin.tar.gz到/opt

4)修改名称

mv apache-tez-0.9.1-bin/ tez-0.9.1

5)进入到Hive的配置目录,下面配置的时候注意我们的hive不是集群,因此hive的配置不用同步

6)在hive-env.sh文件中添加tez环境变量配置和依赖包环境变量配置
vim hive-env.sh

添加如下配置

# Set HADOOP_HOME to point to a specific hadoop install directory
export HADOOP_HOME=/opt/module/hadoop-2.7.2

# Hive Configuration Directory can be controlled by:
export HIVE_CONF_DIR=/opt/module/hive/conf

# Folder containing extra libraries required for hive compilation/execution can be controlled by:
#这个是你的tez的解压目录
export TEZ_HOME=/opt/tez-0.9.1 
#这个注意你自己的TEZ_HOME
export TEZ_JARS=""
for jar in `ls $TEZ_HOME |grep jar`; do
    export TEZ_JARS=$TEZ_JARS:$TEZ_HOME/$jar
done
for jar in `ls $TEZ_HOME/lib`; do
    export TEZ_JARS=$TEZ_JARS:$TEZ_HOME/lib/$jar
done

#lzo包之前优化hadoop的时候导入的,没有优化就不用配置,因为hive要知道hadoop的解压方式
export HIVE_AUX_JARS_PATH=/opt/hadoop-2.7.2/share/hadoop/common/hadoop-lzo-0.4.20.jar$TEZ_JARS

7)在hive-site.xml文件中添加如下配置,更改hive计算引擎

<property>
    <name>hive.execution.engine</name>
    <value>tez</value>
</property>

8)在Hive的conf下面创建一个tez-site.xml文件

添加如下内容,下面的东西什么都不用改,直接复制进去

<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
	<property>
		<name>tez.lib.uris</name>
		<value>${fs.defaultFS}/tez/tez-0.9.1,${fs.defaultFS}/tez/tez-0.9.1/lib</value>
	</property>
	<property>
		<name>tez.lib.uris.classpath</name>
		<value>${fs.defaultFS}/tez/tez-0.9.1,${fs.defaultFS}/tez/tez-0.9.1/lib</value>
	</property>
	<property>
     	<name>tez.use.cluster.hadoop-libs</name>
    	<value>true</value>
	</property>
	<property>
    	<name>tez.history.logging.service.class</name>
    	<value>org.apache.tez.dag.history.logging.ats.ATSHistoryLoggingService</value>
	</property>
</configuration>

9)到hadoop的配置文件中修改hadoop-env.sh,添加如下内容,export不用动,把其他两个路径改了就可以了,修改之后同步这个配置文件,之后启动hadoop,特别注意后面的那个/*啊,因为网页问题看得好像是个注释,其实不是一起拷

TEZ_CONF_DIR=/opt/hive-1.2.1/conf/tez-site.xml
TEZ_JARS=/opt/tez-0.9.1
export HADOOP_CLASSPATH=${HADOOP_CLASSPATH}:${TEZ_CONF_DIR}:${TEZ_JARS}/*:${TEZ_JARS}/lib/*

10)将tez-0.9.1上传到HDFS的/tez路径,hdfs上的路径就叫/tez不要变

hadoop fs -mkdir /tez
hadoop fs -put /opt/tez-0.9.1/ /tez
hadoop fs -ls /tez
/tez/tez-0.9.1

11)现在停止hadoop集群,开始优化hive运行Tez时被检查到用过多内存而被NodeManager杀死进程问题:

Caused by: org.apache.tez.dag.api.SessionNotRunning: TezSession has already shutdown. Application application_1546781144082_0005 failed 2 times due to AM Container for appattempt_1546781144082_0005_000002 exited with  exitCode: -103
For more detailed output, check application tracking page:http://hadoop103:8088/cluster/app/application_1546781144082_0005Then, click on links to logs of each attempt.
Diagnostics: Container [pid=11116,containerID=container_1546781144082_0005_02_000001] is running beyond virtual memory limits. Current usage: 216.3 MB of 1 GB physical memory used; 2.6 GB of 2.1 GB virtual memory used. Killing container.
这种问题是从机上运行的Container试图使用过多的内存,而被NodeManager kill掉了。
[摘录] The NodeManager is killing your container. It sounds like you are trying to use hadoop streaming which is running as a child process of the map-reduce task. The NodeManager monitors the entire process tree of the task and if it eats up more memory than the maximum set in mapreduce.map.memory.mb or mapreduce.reduce.memory.mb respectively, we would expect the Nodemanager to kill the task, otherwise your task is stealing memory belonging to other containers, which you don't want.

解决方法:
方案一:关掉虚拟内存检查。我们优先选这个,修改yarn-site.xml,修改后一定要分发,并重新启动hadoop集群。

<property>
	<name>yarn.nodemanager.vmem-check-enabled</name>
	<value>false</value>
</property>

方案二:mapred-site.xml中设置Map和Reduce任务的内存配置如下:(value中实际配置的内存需要根据自己机器内存大小及应用情况进行修改)

<property>
  <name>mapreduce.map.memory.mb</name>
  <value>1536</value>
</property>
<property>
  <name>mapreduce.map.java.opts</name>
  <value>-Xmx1024M</value>
</property>
<property>
  <name>mapreduce.reduce.memory.mb</name>
  <value>3072</value>
</property>
<property>
  <name>mapreduce.reduce.java.opts</name>
  <value>-Xmx2560M</value>
</property>

12 )删掉hive在mysql中的元数据库

13 )启动hadoop和hive,但是这里会有一个问题,随着你使用的版本不同,hive在修改完tez以后bin/hive命令提供的CLl连结方式大概率不可以使用了,你会发现就进不去,定在了一个日志打印的界面,这是正常现象,因为不同版本之间,hive和tez很可能不完全兼容,不过这不要紧,工作中我们也是直接使用hiveserver2的,因为它提供了远程连接以及更方便灵活的运行方式,因此我们使用hiveserver2来使用hive,启动hive后建表等操作没有异常,则优化成功

这里说一个如果你更改了hadoop压缩方式而且使用了tez之后常见的问题:有时候你会发现hive上一次启动使用完明明好好的,但是这回启动要不起不来,甚至hadoop你都起不来,而hive要不启动之后有着未连接的问题,这是因为你上一次启动之后hadoop集群进入了安全模式,这个问题没有办法根本杜绝,这也是一个现有的小问题,但是这种情况可以通过配置来抑制,就是说减少发生的概率,不过配置比较麻烦,不如和我一样直接写一个脚本在每次启动hadoop之前运行一下,退出安全模式

查看日志:/home/atguigu/module/hadoop-2.7.2/logs
如果进入安全模式,可以通过hadoop dfsadmin -safemode leave离开安全模式

七、hadoop优化之snappy压缩

将我网盘提供的native文件中所有文件上传到hdp1的/opt/hadoop-2.7.2/lib/native目录,并分发其他节点。
链接: https://pan.baidu.com/s/1V05HE_E6PT8c3ePeZUbZ3w 提取码: aca7

2)重新启动Hadoop。

3)检查支持的压缩方式

hadoop checknative
hadoop:  true /opt/hadoop-2.7.2/lib/native/libhadoop.so
zlib:    true /lib64/libz.so.1
snappy:  true /opt/hadoop-2.7.2/lib/native/libsnappy.so.1
lz4:     true revision:99
bzip2:   false

八、优化多个路径存放hadoop的数据

我们在正式服务器上一个大数据集群的运行会产生很多数据,这些数据单纯一个磁盘是存不下,所以我们有很多时候会配置多个路径,挂在多个磁盘,在hdfs-site.xml中配置

如果你需要对namenote的数据分多个路径存放,你可以修改此配置,用逗号隔开就可以

<property>
    <name>dfs.namenode.name.dir</name>
 <value>/pvdata/hadoopdata/name/,/opt/hadoopdata/name/</value>
</property>

你要对datenote的数据存放多个路径,你可以修改如下配置,同样的逗号隔开

<property>
    <name>dfs.datanode.data.dir</name>
 <value>/dev/sda3/hadoopdata/,/dev/sda1/hadoopdata/</value>
</property>

多个路径的时候我们要修改写入策略

<property>
 <name>dfs.datanode.fsdataset.volume.choosing.policy</name>
 <value>org.apache.hadoop.hdfs.server.datanode.fsdataset.AvailableSpaceVolumeChoosingPolicy</value>
 </property>

到此为止,我想和大家分享的测试环境搭建就是这些,但是这不是全部的大数据技术,这只是我从业以来用过的技术,如果你有其他应用需求,可以另外看我的其他博客,我也会陆续上传其他大数据的资料,不过就像我在我其他博客说的那样,原生集群除非你进的是那种非常楼比的公司,否则,原生版你就在本地虚拟机中安装上做一个本地测试环境就可以了,工作中都有集成技术的,而且现在开发,随着集成技术的完善,也就是点一点页面就可以了,就连安装也是有运维的去安装的,你会用就可以了

九、最后我们不可能每一次启动集群都要傻瓜一样的一台一台节点去启动服务,因此我们的集群中应该自己写一个启动脚本,用来操作集群的运行,下面是我给大家写的一个例子,大家改一改就行,且注意,改脚本是运作在高可用集群上,所以有些东西对你没用就删掉。

#!/bin/bash
#该脚本用来启动所有服务,通过参数决定

#集群地址
cluster = (hdp1 hdp2 hdp3)

case $1 in 
"zk_start"){
#启动zookeeper
	echo `date` > /opt/start_ap_log/zk_start.log
	for i in cluster
	do
		echo "-----------正在启动$i的zookeeper---------"
		echo "$i--zookeeper:" >> /opt/start_ap_log/zk_start.log
		ssh $i "source /etc/profile && /opt/zookeeper-3.4.10/bin/zkServer.sh start" >> /opt/start_ap_log/zk_start.log
	done
};;
"zk_stop"){
#关闭zookeeper
        echo `date` > /opt/start_ap_log/zk_stop.log
        for i in cluster
        do
                echo "-----------正在关闭$i的zookeeper---------"
                echo "$i--zookeeper:" >> /opt/start_ap_log/zk_stop.log
                ssh $i "source /etc/profile && /opt/zookeeper-3.4.10/bin/zkServer.sh stop" >> /opt/start_ap_log/zk_stop.log
        done
};;
"hdp_start"){
#开启hadoop
	echo `date` > /opt/start_ap_log/hdp_start.log
	echo "----------------开始启动namenode-hdfs----------------"
	/opt/hadoop-2.7.2/sbin/start-dfs.sh >> /opt/start_ap_log/hdp_start.log

	echo `date` > /opt/start_ap_log/yarn_start.log
	echo "----------------开始启动yarn----------------"
	echo "主yarn节点----------------------" >> /opt/start_ap_log/yarn_start.log
	ssh hdp2 "source /etc/profile && /opt/hadoop-2.7.2/sbin/start-yarn.sh" >> /opt/start_ap_log/yarn_start.log

	echo "----------------开始启动his----------------"
	echo `date` > /opt/start_ap_log/his_start.log
	ssh hdp3 "source /etc/profile && /opt/hadoop-2.7.2/sbin/mr-jobhistory-daemon.sh start historyserver" >> /opt/start_ap_log/his_start.log
};;
"hdp_stop"){
#关闭hadoop
	echo "----------------开始关闭his----------------"
	echo `date` > /opt/start_ap_log/his_stop.log
	ssh hdp3 "source /etc/profile && /opt/hadoop-2.7.2/sbin/mr-jobhistory-daemon.sh stop historyserver" >> /opt/start_ap_log/his_stop.log
	
	echo `date` > /opt/start_ap_log/yarn_stop.log
	echo "----------------开始关闭yarn----------------"
        echo "主yarn节点----------------------" >> /opt/start_ap_log/yarn_stop.log
        ssh hdp2 "source /etc/profile && /opt/hadoop-2.7.2/sbin/stop-yarn.sh" >> /opt/start_ap_log/yarn_stop.log

	echo "----------------关闭namenode-hdfs------------"
        echo `date` > /opt/start_ap_log/hdp_stop.log
        /opt/hadoop-2.7.2/sbin/stop-dfs.sh >> /opt/start_ap_log/hdp_stop.log
};;
"ntp_re"){
#重启时间同步服务
	echo `date` > /opt/start_ap_log/ntp_restart.log
	service ntpd restart >> /opt/start_ap_log/ntp_restart.log
};;
"kfk_start"){
#启动kafka集群
	echo `date` > /opt/start_ap_log/kfk_start.log
	for i in cluster
        do
                echo " --------启动 $i Kafka-------"
                ssh $i "source /etc/profile && /opt/kafka_2.11-0.11.0.2/bin/kafka-server-start.sh -daemon /opt/kafka_2.11-0.11.0.2/config/server.properties" >> /opt/start_ap_log/kfk_start.log
        done
};;
"kfk_stop"){
#关闭kafka集群
        echo `date` > /opt/start_ap_log/kfk_stop.log
        for i in cluster
        do
                echo " --------关闭 $i Kafka-------"
                ssh $i "source /etc/profile && /opt/kafka_2.11-0.11.0.2/bin/kafka-server-stop.sh" >> /opt/start_ap_log/kfk_stop.log
        done
};;
"nn_le"){
#由于优化了Tez防止关闭hdp似的hdp进入安全模式
	echo `date` > /opt/start_ap_log/hive_tez_ready.log
	/opt/hadoop-2.7.2/bin/hdfs dfsadmin -safemode leave >> /opt/start_ap_log/hive_tez_ready.log
};;
"spark_start"){
#启动spark集群
	echo "--------------开始启动spark主服务---------"
        echo `date` > /opt/start_ap_log/spark_start.log
        ssh hdp2 "source /etc/profile && /opt/spark-2.1.1/sbin/start-all.sh" >> /opt/start_ap_log/spark_start.log
        echo "--------------开始启动spark-his服务---------"
	ssh hdp3 "source /etc/profile && /opt/spark-2.1.1/sbin/start-history-server.sh" >> /opt/start_ap_log/spark_start.log
};;
"spark_stop"){
#关闭spark集群
        echo `date` > /opt/start_ap_log/spark_stop.log
        echo "--------------开始关闭spark-his服务---------"
        ssh hdp3 "source /etc/profile && /opt/spark-2.1.1/sbin/stop-history-server.sh" >> /opt/start_ap_log/spark_stop.log
	echo "--------------开始关闭spark主服务---------"
        ssh hdp2 "source /etc/profile && /opt/spark-2.1.1/sbin/stop-all.sh" >> /opt/start_ap_log/spark_stop.log
};;
"ch_start"){
#开启ClickHouse集群
        echo `date` > /opt/start_ap_log/clickhouse_start.log
        for i in hdp1 hdp2 hdp3
        do
                echo "-----------正在启动$i的clickhouse---------"
                echo "$i--clickhouse:" >> /opt/start_ap_log/clickhouse_start.log
                ssh $i "source /etc/profile && service clickhouse-server start" >> /opt/start_ap_log/clickhouse_start.log
        done
};;
"ch_stop"){
#关闭ClickHouse集群
        echo `date` > /opt/start_ap_log/clickhouse_stop.log
        for i in hdp1 hdp2 hdp3
        do
                echo "-----------正在关闭$i的clickhouse---------"
                echo "$i--clickhouse:" >> /opt/start_ap_log/clickhouse_stop.log
                ssh $i "source /etc/profile && service clickhouse-server stop" >> /opt/start_ap_log/clickhouse_stop.log
        done
};;
esac

第一篇https://blog.csdn.net/dudadudadd/article/details/109647930

第二篇https://blog.csdn.net/dudadudadd/article/details/109659923

第三篇https://blog.csdn.net/dudadudadd/article/details/109679296

第四篇https://blog.csdn.net/dudadudadd/article/details/109719624

第五篇https://blog.csdn.net/dudadudadd/article/details/109726023

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值