Skip to content

Commit 867072e

Browse files
committed
add blogs
1 parent 954e08a commit 867072e

9 files changed

+554
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
---
2+
layout: post
3+
title: "Apache Commons CLI 使用说明 "
4+
subtitle: "信息、载体、抽象、线程 设计乱谈"
5+
date: 2019-10-15
6+
author: "LSG"
7+
header-img: "img/home-bg-o.jpg"
8+
catalog: true
9+
tags:
10+
- shell
11+
- Commons-CLI
12+
- java
13+
---
14+
15+
> Apache Commons CLI 提供了很多实用的工具和类实现,方便了我们对命令行工具的开发。
16+
17+
### 1.Commons-CLI 介绍
18+
19+
> 随着科学计算可视化飞速发展,人机交互技术不断更新,但传统的命令行模式依旧被广泛应用。
20+
21+
Commons-CLI依旧广泛应用的原因是命令行界面要较图形用户界面节约更多的计算机系统资源,利于客户进行二次开发,方便应用程序的整合。
22+
23+
### 2.简单使用
24+
25+
```java
26+
private static Config parseCmdLine(String[] args) {
27+
// 1.CLI 定义阶段
28+
initOpt();
29+
// 2.CLI 解析阶段
30+
// 初始化一个命令行解析器,一般用默认的就可以
31+
CommandLineParser parser = new DefaultParser();
32+
Config config = new Config();
33+
try {
34+
// 解析后会得到一个 CommandLine 对象
35+
CommandLine cmd = parser.parse(options, args);
36+
config = new Config();
37+
// 3.CLI 询问阶段
38+
// 获取选项 -c 的参数值,如果没有则使用第二个参数所指定的默认值
39+
config.ssdbConfigPath = cmd.getOptionValue("c", "./ssdb.cfg");
40+
// 判断选项 -rm 是否存在,返回的是 boolean 值
41+
if (cmd.hasOption("rm")) {
42+
config.operation = Operation.rm;
43+
}
44+
else if (cmd.hasOption("disable")) {
45+
config.operation = Operation.disable;
46+
}
47+
else if (cmd.hasOption("get")) {
48+
config.operation = Operation.get;
49+
}
50+
else if (cmd.hasOption("mv")) {
51+
config.operation = Operation.mv;
52+
}
53+
else {
54+
config.operation = Operation.unknown;
55+
}
56+
} catch (ParseException e) {
57+
System.out.println(e.getMessage());
58+
// 解析失败是用 HelpFormatter 打印 帮助信息
59+
HelpFormatter formatter = new HelpFormatter();
60+
formatter.printHelp(
61+
"java ssdb-del-helper-1.0-SNAPSHOT-jar-with-dependencies.jar",
62+
options);
63+
}
64+
return config;
65+
}
66+
67+
private static Config initOpt(String[] args) {
68+
// 定义一个可选选项集
69+
Options options = new Options();
70+
// 添加一个选项 c ,并加上对应的简短说明,第二个参数表明这个选项是否跟有参数
71+
options.addOption("c", true, "configOpt file, default path is ./ssdb.cfg");
72+
73+
// 定义一个选项组,这个组限定其所包含的选项是互斥的
74+
OptionGroup optionGroup = new OptionGroup();
75+
// 这里的 Option 方法只有两个参数,表明这个命令行选项不带参数
76+
optionGroup.addOption(new Option("rm", "remove K/V from ssdb"));
77+
optionGroup.addOption(new Option("disable", "disable K/V from ssdb with data remained"));
78+
optionGroup.addOption(new Option("get", "get value from ssdb"));
79+
optionGroup.addOption(new Option("mv", "mv from new client to old"));
80+
// 设定此选项组是必选的,从而实现上面 4 个选项必须且只能选择一个
81+
optionGroup.setRequired(true);
82+
options.addOptionGroup(optionGroup);
83+
}
84+
85+
private static class Config {
86+
String ssdbConfigPath;
87+
Operation operation = Operation.unknown;
88+
}
89+
```
90+
91+
### 3.设计思想
92+
#### 3.1 CLI 定义阶段
93+
初始化Options:
94+
95+
- CLI 定义阶段的目标结果就是创建 Options 实例
96+
97+
代码片段:
98+
```java
99+
// 创建 Options 对象
100+
Options options = new Options();
101+
 
102+
// 添加 -h 参数
103+
options.addOption("h", false, "Lists short help");
104+
 
105+
// 添加 -t 参数
106+
options.addOption("t", true, "Sets the HTTP communication protocol for CIM connection");
107+
```
108+
109+
#### 3.2 CLI 解析阶段
110+
创建 CommandLine 实例:
111+
112+
- 在 CommandLineParser 类中定义的 parse 方法将用 CLI 定义阶段中产生的 Options 实例和一组字符串作为输入,并返回解析后生成的 CommandLine。
113+
114+
代码片段:
115+
```java
116+
CommandLineParser parser = new PosixParser();
117+
CommandLine cmd = parser.parse(options, args);
118+
 
119+
if(cmd.hasOption("h")) {
120+
   // 这里显示简短的帮助信息
121+
}
122+
```
123+
124+
#### 3.3 CLI 询问阶段
125+
通过查询 CommandLine,应用程序做出对应的判断:
126+
127+
- 将所有通过命令行以及处理参数过程中得到的文本信息传递给用户的代码。
128+
129+
代码片段:
130+
```java
131+
// 获取 -t 参数值
132+
String protocol = cmd.getOptionValue("t");
133+
134+
if(protocol == null) {
135+
// 设置默认的 HTTP 传输协议
136+
} else {
137+
// 设置用户自定义的 HTTP 传输协议
138+
}
139+
```
140+
141+
### 4.流程图
142+
![image.png](https://cdn.nlark.com/yuque/0/2020/png/152121/1578904003536-bb7388ca-749f-46c9-b25e-f75b03a8c17e.png#align=left&display=inline&height=665&name=image.png&originHeight=665&originWidth=583&size=97228&status=done&style=none&width=583)
143+
命令行执行流程图
144+
### Reference
145+
146+
- [Java Commons-CLI 命令行参数解析](https://www.zfl9.com/java-commons-cli.html)
147+
- [简书: java 使用 commons-cli 实现命令行参数](https://www.jianshu.com/p/cf325454be07)
148+
- [IBM: 使用 Apache Commons CLI 开发命令行工具](https://www.ibm.com/developerworks/cn/java/j-lo-commonscli/)

_posts/2019/2019-10-24-linux-commend.markdown

+38
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,44 @@ do
277277
true > $logfile
278278
done
279279
```
280+
## 当文件大小大于85%时,删除日志,写入定时任务中,3h检测一次
281+
282+
```sh
283+
#!/usr/bin/env bash
284+
#usage:clean disk
285+
#time:2020-01-13
286+
limit=85
287+
function is_overusage(){
288+
usedrate=$(df -hl | grep /data | awk '{print $5}'|awk -F "%" '{print $1}')
289+
echo $usedrate
290+
if [ $usedrate -gt $limit ]
291+
then
292+
return 1
293+
else
294+
return 0
295+
fi
296+
}
297+
function clean_logs(){
298+
find /data/log/**/INFO/ -mtime +12 -name "*.log" -exec echo {} > /data/log/logname.txt \;
299+
find /data/log/**/WARN/ -mtime +12 -name "*.log" -exec echo {} >> /data/log/logname.txt \;
300+
find /data/log/**/**/{INFO,WARN} -mtime +12 -name "*.log" -exec echo {} >> /data/log/logname.txt \;
301+
sed -i '/ReportPlatform/d' /data/log/logname.txt
302+
find /data/log/ReportPlatform/ReportPlatform-172.16.6.122/INFO/ -mtime +60 -name "*.log" -exec echo {} >> /data/log/logname.txt \;
303+
for logfile in `cat /data/log/logname.txt`
304+
do
305+
# echo $logfile
306+
true > $logfile
307+
done
308+
}
309+
is_overusage
310+
if [ $? -eq 1 ]
311+
then
312+
clean_logs
313+
# echo "over"
314+
fi
315+
```
316+
317+
280318

281319
## 脚本开机启动
282320

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
---
2+
layout: post
3+
title: "spark调优总结 "
4+
subtitle: "信息、载体、抽象、线程 设计乱谈"
5+
date: 2019-11-21
6+
author: "LSG"
7+
header-img: "img/post-bg-os-metro.jpg"
8+
catalog: true
9+
tags:
10+
- hadoop
11+
- spark
12+
- java
13+
---
14+
15+
> 使用Spark的一些调优经验
16+
17+
## 一.Spark优化图解
18+
![image.png](https://cdn.nlark.com/yuque/0/2020/png/152121/1578893635262-b8e45c2d-d2cf-44cf-a27c-018478eeb978.png#align=left&display=inline&height=899&name=image.png&originHeight=899&originWidth=2410&size=237657&status=done&style=none&width=2410)
19+
20+
## 二.Spark
21+
### 2.1代码把公共常用的配置项直接优先配置,之后具体实例可以覆盖配置
22+
23+
- 配置内容:
24+
- 序列化方式: KryoSerializer
25+
- 调度模式
26+
- spark.streaming.stopGracefullyOnShutdown
27+
- spark.reducer.maxSizeInFlight = 128m
28+
29+
```java
30+
/**
31+
* 所有任务公共配置
32+
*
33+
* @desc https://spark.apache.org/docs/latest/configuration.html
34+
*/
35+
public static SparkConf getDefaultSparkConf() {
36+
return new SparkConf()
37+
.set("spark.scheduler.mode", "FIFO")
38+
.set("spark.shuffle.file.buffer", "1024k")
39+
.set("spark.reducer.maxSizeInFlight", "128m")
40+
.set("spark.shuffle.memoryFraction", "0.3")
41+
.set("spark.streaming.stopGracefullyOnShutdown", "true")
42+
.set("spark.streaming.kafka.maxRatePerPartition", "300")
43+
.set("spark.serializer", KryoSerializer.class.getCanonicalName())
44+
.registerKryoClasses(SERIALIZER_CLASS);
45+
}
46+
```
47+
48+
### 2.2 子任务继承并得到sparkConf的配置
49+
50+
- 配置内容:
51+
- 允许动态分区
52+
-
53+
54+
55+
```java
56+
SparkConf sparkConf = SparkFactory.getDefaultSparkConf()
57+
//动态分区
58+
.set("hive.exec.dynamic.partition.mode", "nonstrict")
59+
.set("hive.exec.dynamic.partition", "true")
60+
.set("hive.exec.max.dynamic.partitions.pernode", "100000")
61+
.set("hive.exec.max.dynamic.partitions", "100000")
62+
.set("hive.exec.max.created.files", "100000")
63+
//缓解map端内存压力
64+
.set("spark.sql.shuffle.partitions", "100")
65+
//当内存剩余多少空间开始shuffle 向硬盘转移数据( reduce端聚合内存占比,默认0.2)
66+
.set("spark.shuffle.memoryFraction", "0.1")
67+
//解决map端产生大量文件,map写大量文件很慢,导致shuffle 很慢
68+
.set("spark.shuffle.consolidateFiles","true")
69+
70+
.setAppName("Your app name");
71+
72+
session = SparkSession.builder()
73+
.config(sparkConf)
74+
.enableHiveSupport()
75+
.getOrCreate();
76+
//具体的业务执行
77+
handle();
78+
```
79+
80+
### 2.3 shuffle调优
81+
82+
- 设置shuffle.partitions 数量    ->   一般对应一个spark sql 插入hive表后中hive 多出的小文件数量
83+
- spark.shuffle.file.buffer                     map task的内存缓冲调节参数,默认是32kb    调优每次*2
84+
- spark.shuffle.consolidateFiles 参数来合并文件,具体的使用方式为                     调优每次+0.1
85+
86+
#### 2.3.1 关于spark.shuffle.consolidateFiles参数
87+
##### 问题:什么是shuffle?
88+
89+
> 答案:每个Spark作业启动运行的时候,首先Driver进程会将我们编写的Spark作业代码分拆为多个stage,每个stage执行一部分代码片段,并为每个stage创建一批Task,然后将这些Task分配到各个Executor进程中执行。一个stage的所有Task都执行完毕之后,在各个executor节点上会产生大量的文件,这些文件会通过IO写入磁盘(这些文件存放的时候这个stage计算得到的中间结果),然后Driver就会调度运行下一个stage。下一个stage的Task的输入数据就是上一个stage输出的中间结果。如此循环往复,直到程序执行完毕,最终得到我们想要的结果。Spark是根据shuffle类算子来进行stage的划分。如果我们的代码中执行了某个shuffle类算子(比如groupByKey、countByKey、reduceByKey、join等等)每当遇到这种类型的RDD算子的时候,划分出一个stage界限来。
90+
91+
92+
> 每个shuffle的前半部分stage的每个task都会创建出后半部分stage对应的task数量的文件,(注意是前半部分的每个task都会创建相同数量的文件)。shuffle的后半部分stage的task拉取前半部分stage中task产生的文件(这里拉取的文件是:属于自己task计算的那部分文件);然后每个task会有一个内存缓冲区,使用HashMap对值进行汇集;比如,task会对我们自己定义的聚合函数,如reduceByKey()算子,把所有的值进行累加,聚合出来得到最终的值,就完成了shuffle操作。
93+
94+
##### 当不配置该参数时:
95+
shuffle中写磁盘操作是最消耗性能的,大量的小文件到下一个task,速度很慢
96+
##### ![image.png](https://cdn.nlark.com/yuque/0/2020/png/152121/1578906963472-512548b9-bfed-4899-bda7-748f8882f415.png#align=left&display=inline&height=414&name=image.png&originHeight=414&originWidth=523&size=48690&status=done&style=none&width=523)
97+
98+
99+
##### 为了解决产生大量文件的问题,我们可以在map端输出的位置,将文件进行合并操作:
100+
101+
![image.png](https://cdn.nlark.com/yuque/0/2020/png/152121/1578898258853-7ee1c8fa-7d24-4327-b309-2aef6de4149b.png#align=left&display=inline&height=471&name=image.png&originHeight=471&originWidth=713&size=94137&status=done&style=none&width=713)
102+
103+
**配置 spark.shuffle.consolidateFiles = true**
104+
## Reference
105+
106+
- [Spark性能调优篇八之shuffle调优:重要](https://www.jianshu.com/p/069c37aad295)
107+
- [Spark内核分析之Shuffle操作流程:非常重要](https://www.jianshu.com/p/f07b3654eeaa)
108+
- [Spark性能调优篇六之调节数据本地化等待时长](https://www.jianshu.com/p/99ef69adc2b1)

0 commit comments

Comments
 (0)