在技术之路上的一些小技巧

本文记录一些工作当中常用的小工具、小技巧,有时候自己可以查看备忘,同时也给读者参考。当然,内容是在不断补充的,涉及的维度也会扩展。

Python

Python 是一种脚本语言,想要运行 Python 脚本就需要先安装 Python 环境【就像运行 Java 程序需要 JRE 一样】,安装后别忘记配置环境变量。

官方网站:python

唯一需要注意的是安装时先核对脚本的语法,是安装 v2.7.X 版本还是 v3.X 版本,它们的语法有时候不兼容,导致脚本无法跑通。

虚拟环境

在某个项目中,使用 Python 构造 Elasticsearch 请求获取结果数据,但是脚本的内容是针对 Python v3.X 环境的,而服务器上是 Python v2.7 版本的环境,而且个人没有权限更改【如果自己通过编译安装指定的版本,后续使用时如果缺失第三方模块还是需要手动安装,如果又引发模块之间的依赖,手动安装过程会崩溃的】,所以可以在服务器上面虚拟一个指定版本的 Python 环境出来。

1
2
3
4
5
6
7
8
9
10
-- 在任意目录,虚拟出 Python 2.7 环境 
virtualenv py2.7
-- 进入环境
cd py2.7/
-- 激活环境
source bin/activate
-- 如果缺失第三方模块,直接安装即可
pip install requests
-- 取消环境
source bin/deactive

缓存问题

假如跑一个脚本,把输出重定向到一个文件中:nohup python test.py > nohup.out 2>&1 &,结果发现 nohup.out 中显示不出来 python 程序中 print 的内容【或者是不及时显示,隔一段时间才会有一点内容】。

这是因为 python 的输出有缓冲机制,导致我们从 nohup.out 中并不能够马上看到输出。其实运行 python 脚本的时候有个 -u 参数,使得 python 不启用缓冲,把程序中的输出内容实时输出到文件:nohup python -u test.py > nohup.out 2>&1 &

编码问题

pythonchardet 模块,可以查看字符串的编码:chardet.detect (data)

处理文本文件

在处理 csv 文件时,遇到异常:Error: field larger than field limit <131072>,这其实是因为 Python 读取 csv 文件时有一个默认设置,某列的内容最大长度为 131072【基于 Python v2.5】。

重点在于 Error: field larger than field limit <131072>,是因为 csv 文件中的某个字段的长度大于 csv 框架能处理的最大长度,需要在文件头加上参数配置代码:csv.field_size_limit (sys.maxint) ,这样就可以支持 int 的最大值所对应的长度了。

此外,由于 csv 文件的特殊性,csv 是特定分隔符分隔的文本文件,可能会导致内容混乱的状况,比如某一列包含了大量的换行符【又没有使用双引号封装起来】,会导致 csv 文件认为就是多行数据,这样这些行都是错误的数据【因为列数不够】,如果有连续的换行符,会导致空白行出现,Python 也会报错:line contains NULL byte

Excel 的知识

对于分析人员,经常会用到 Excel 工具,用来看数据,或者操作数据。

但是,有时候文本内容过多,不再适合使用 Excel 操作了,不仅很卡,而且有崩溃的风险。

根据我的经验,以最多 5 万行内容,最大 20MB 为好,如果是 Mac OS 系统,需要更少。

下面列举一下 Excel 支持的内容上限:

Excel 2003 支持的最大行数是 65536,Excel 2007 支持的最大行数是 1048576 。

Excel 2003 支持的最大列数是 256,Excel 2007 以及以上支持的最大列数是 16384 。

更多其它规范参考官方介绍:Excel 规范与限制

文件编码转换工具

iconv 需要单独安装:

1
2
3
4
5
6
-- 转换文件内容编码,从 gb18030 转到 utf-8
iconv --list 查看支持的编码
iconv -f gb18030 -t utf-8 oldfile -o newfile

-- 查看文件编码内容简要信息
file filename

文件名编码转换工具

Linux 系统中,如果把一个以中文命名的文件上传上去【特别是从 Windows 系统上传上去】,文件名可能会乱码,导致无法使用 Shell 操作文件,此时可以使用 xx 工具转换文件名的编码。

convmv 需要单独安装:

1
2
3
4
5
6
7
-- 转换文件名编码,从 utf-8 转到 gbk
convmv --list 查看支持的编码
convmv -f utf-8 -t gbk filename 显示效果
convmv -f utf-8 -t gbk --notest filename 真的转换

-- 查看文件编码内容简要信息
file filename

常用命令

Shell

进程目录

根据进程编号找到启动进程的目录,从而判断进程的启动路径。

1
pwdx pid

负载查看

对于操作系统上面的进程导致的机器负载升高,可以查看到底是哪个进程或者线程导致的:

1
2
xxx
yyy

进程查看

查看某个进程的启动目录:

1
2
3
4
5
6
-- 筛选进程名称,获取 pid
jps | grep 'process name'
-- 根据 pid 查看目录
pwdx 'pid'
-- 进入目录
cd 'dir'

使用 sed 操作文本文件

搜索替换之类的:

1
2
3
4
5
6
7
8
9
 把文件中的 xxx 全部替换为 yyy,不带 -i 参数直接输出内容,不会更改文件 
sed -i "s/xxx/yyy/g" your_file

在文件第 n 行前插入内容 xxx,不带 -i 参数直接输出内容,不会更改文件
注意 Linux 中以换行符 LF 作为一行的判断条件,所以指定不存在的行号时无法插入数据
sed -i "ni\xxx" your_file

输出文件的第 n 到 m 行内容
sed -n "n,mp" your_file

查看 Linux 系统的发行版本

lsb_release -a,该命令适用于所有 Linux 系统,会显示出完整的版本信息,包括 Linux 系统的名称,如:DebianUbuntuCentOS 等,和对应的版本号,以及该版本的代号,例如在 Debian 8 中将会显示代号 jessie

1
2
3
4
5
6
 输出示例:
No LSB modules are available.
Distributor ID: Ubuntu
Description: Ubuntu 14.04.6 LTS
Release: 14.04
Codename: trusty

cat /etc/issue,该命令适用于所有的 Linux 系统,显示的版本信息较为简略,只有系统名称和对应的版本号。

1
2
 输出示例:
Ubuntu 14.04.6 LTS \n \l

cat /etc/redhat-release,该命令仅适用于 Redhat 系列的 Linux 系统,显示的版本信息也较为简略。

1
2
 输出示例:
CentOS release 6.10 (Final)

uname -acat /proc/version,可以查看 Linux 的内核版本:

1
2
3
4
5
 输出示例 1:
Linux wufazhuce 3.13.0-32-generic #57-Ubuntu SMP Tue Jul 15 03:51:08 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux

输出示例 2:
Linux version 3.13.0-32-generic (buildd@kissel) (gcc version 4.8.2 (Ubuntu 4.8.2-19ubuntu1) ) #57-Ubuntu SMP Tue Jul 15 03:51:08 UTC 2014

查看 Linux 系统的核数

继续阅读之前先搞清楚几个概念:物理 CPU 个数、单颗 CPU 核数、单核 CPU 线程数。

  • 一台物理机的 CPU 个数
  • 一个 CPU 的核数
  • 一个 CPU 核上面支持的线程数

当一台机器有多个物理 CPU,那么各个 CPU 之间就要通过总线进行通信,效率比较低。

多个 CPU 通过总线通信

此时可以利用多核的特性,在多核 CPU 上,不同的核之间通过 L2 cache 进行通信,存储和外设通过总线与 CPU 通信,效率提高。

多核之间通信

当然,如果利用多核超线程,即每个 CPU 核有两个逻辑的处理单元,两个线程共同分享一个 CPU 核的资源,计算起来更快。

多核超线程

因此,一台机器的总核数为:物理机的 CPU 个数 X 一个 CPU 的核数,总逻辑 CPU 个数为:物理机的 CPU 个数 X 一个 CPU 的核数 X 一个 CPU 核上面支持的线程数。

查看一台机器的 CPU 信息,主要就是 /proc/cpuinfo 文件,里面包含了关于 CPU 的信息,以 CentOS 系统为例,输出内容如下【只是截取了一小部分】:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
...
processor : 23
vendor_id : GenuineIntel
cpu family : 6
model : 62
model name : Intel (R) Xeon (R) CPU E5-2620 v2 @ 2.10GHz
stepping : 4
microcode : 1060
cpu MHz : 1200.000
cache size : 15360 KB
physical id : 1
siblings : 12
core id : 5
cpu cores : 6
apicid : 43
initial apicid : 43
fpu : yes
fpu_exception : yes
cpuid level : 13
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe syscall nx pdpe1gb rdtscp lm constant_tsc arch_perfmon pebs bts rep_good xtopology nonstop_tsc aperfmperf pni pclmulqdq dtes64 monitor ds_cpl vmx smx est tm2 ssse3 cx16 xtpr pdcm pcid dca sse4_1 sse4_2 x2apic popcnt tsc_deadline_timer aes xsave avx f16c rdrand lahf_lm ida arat epb xsaveopt pln pts dtherm tpr_shadow vnmi flexpriority ept vpid fsgsbase smep erms
bogomips : 4189.67
clflush size : 64
cache_alignment : 64
address sizes : 46 bits physical, 48 bits virtual
power management:
...

其中,model name 表示 CPU 的型号;physical id 表示物理 CPU 个数,编号从 0 开始;cpu cores 表示单颗 CPU 核数;processor 表示所有 CPU 线程数,编号从 0 开始。

因此,查看 CPU 信息时可以使用管道、过滤、查找来输出需要的内容:

1
2
3
4
5
6
7
8
9
10
11
 查看 CPU 型号信息 
cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c

查看物理 CPU 个数
cat /proc/cpuinfo | grep "physical id" | sort | uniq | wc -l

查看单颗 CPU 核数
cat /proc/cpuinfo | grep "cpu cores" | uniq

查看所有 CPU 线程数
cat /proc/cpuinfo | grep "processor" | wc -l

顺带提一下查看内存的信息:

1
cat /proc/meminfo

split 拆分文件

把文件按照 60 行一个文件进行拆分,拆分后的文件以 data_ 作为前缀,以 2 位数字作为后缀:

1
2
3
split -l 60 your_file -d -a 2 data_

拆分后的文件为 data_00、data_01、data_02 等等

curl 请求网络

可以模拟请求,传输参数:

1
2
3
4
5
6
7
8
9
10
11
POST 请求,参数放在 seeds 中 
curl --location --request POST 'url' \
--header 'content-type: application/x-www-form-urlencoded; charset=UTF-8' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'seeds=[{"keyword":" 王者荣耀 & quot;, "TOP_PAGE": "100"},{"keyword":"LOL", "TOP_N": "100"}]'

GET 请求,获取信息
curl --location --request GET url'

POST 请求,参数放在文件中
curl -X POST --data-binary @your_file url

查询 Elasticsearch 的数据:

1
2
3
4
5
-- 查询指定索引、指定类型的数据,返回 1 条数据,格式化结果 
curl -X POST 'dev:9202/your_index/your_type/_search?pretty' -d '
{
"query": { "match_all": {} },"size":1
}'

文本文件行数

获取文本文件的内容行数,返回数值:

1
wc -l 输入文件名称 

文件去重

对单个文本文件的内容进行去重,返回去重后的文本:

1
sort 输入文件 | uniq > 输出文件 

说明:| 竖线表示管道,把前一个命令的输出作为后一个命令的输入,> 右尖括号表示重定向,把前一个命令的输出内容导出到文件中,sort 表示排序,但是并不会去除重复内容,所以会有重复的行,uniq 表示去除重复的内容,则输出结果就是去重后的内容。

随机获取文本内容

随机抽取单个文件中的内容行数,例如随机输出 100 行:

1
shuf -n 行数 输入文件 > 输出文件 

说明:-n 后面紧跟着数字,表示行数,不需要空格。

计算交集差集并集

1
cat 输入文件 1 输入文件 2 | sort | uniq -d > 输出文件 

说明:cat 表示查看文件内容,uniq-d 参数表示抽取重复的内容,即出现 2 次及以上的内容,在这里得到的结果也就是交集了。

此外,还有 -u 参数表示抽取唯一的内容,则可以计算差集。

1
cat 输入文件 1 输入文件 2 输入文件 2 | sort | uniq -u > 输出文件(注意输入文件 2 故意重复 2 次)

说明:uniq-u 参数表示抽取唯一的内容,即只出现一次的内容,这样得到的输出结果必然是只在输入文件 1 中,而不在输入文件 2 中。

1
cat 输入文件 1 输入文件 2 | sort | uniq > 输出文件 

说明:这个很容易理解了,合并文件后简单去重,也就是并集了。

Kafka

查看 topic 信息:

1
kafka-topics.sh --list --zookeeper dev:2181

生产数据:

1
kafka-console-producer.sh --topic your_topic --broker-list dev:9092

消费数据:

1
kafka-console-consumer.sh --zookeeper dev:2181 --topic your_topic

查看 topic 状态:

1
kafka-topics.sh --zookeeper dev:2181 --describe --topic your_topic

查看消费情况【消费组消费量、积压量、生产量】:

1
2
3
4
kafka-consumer-offset-checker.sh --zookeeper dev:2181 --group your_group --topic your_topic

如果上述脚本不可用,可以直接引用类
kafka-run-class.sh kafka.tools.ConsumerOffsetChecker --group your_group --topic your_topic --zkconnect dev:2181

Zookeeper

操作:

1
2
3
4
5
 登录 
zkCli.sh -server ip:port

退出
quit

Redis

操作:

1
2
3
4
5
6
7
8
9
10
11
 登录,n 表示桶,默认 0
redis-cli -h host -p port -n 0 --raw

查看配置信息,例如数据量、占用内存
info

查看单个配置项,例如最大内存
config get maxmemory

退出
quit

HBase

HBase 操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
 登录 
hbase shell

帮助文档
!help

退格
ctrl + Backspace

退出
!quit

查看表信息
!list

获取数据
get ' 表名称 & apos;,'pk 值 & apos;

扫描数据
scan ' 表名称 & apos;,{LIMIT => 5}

检查 Region 状态
hbase hbck

此命令用于修复未分配,错误分配或者多次分配 Region 的问题,注意用户权限问题
hbase hbck -fixAssignments
sudo -u hbase hbase hbck -fixAssignments

检查 Region 的元数据
get 'hbase:meta','your_region_name'

检测数据表的状态
hbase hbck"YOUR_TABLE"

修复 Region 空洞问题【Region hole】,注意用户权限问题
sudo -u hbase hbase hbck -fix"YOUR_TABLE"

手动做 major_compact
major_compact "your_table_name"

phoenix 操作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 登录 
phoenix-client/bin/sqlline.py dev:2181:/hbase-unsecure

帮助文档
!help

退出
!quit

查看表信息
!tables

查询数据
select * from " 表名称 & quot; where "pk"='pk 值 & apos;;
select * from " 表名称 & quot; limit 5;

导出数据
-- 格式化输出
!outputformat csv
-- 设置导出文件到 data.csv
!record data.csv
-- 查询需要导出的数据
select * from " 表名称 & quot; limit 1000;
-- 完成导数操作
!record

格式化显示
!outputformat vertical
!outputformat csv
!outputformat table

Spark

启动 Spark 命令行,使用 spark-shell --master yarn-client,然后就可以在交互式命令行中写 scalapython 代码了。

举例:读取 2 个文件,做并集:

1
2
3
4
5
6
var list1=sc.textFile ("/tmp/pengfei/file1.txt").flatMap (x => x.split ("\\t"))
文件在 HDFS 中,一行数据有被 Tab 分隔的多条内容

var list2=sc.textFile ("/tmp/pengfei/file2.txt").flatMap (x => x.split ("\\t"))

list1.union (list2).saveAsTextFile ("/tmp/pengfei/union.txt")

触发任务后在 yarn 中就可以看到任务的运行情况,注意,启动 Spark-shell 的时候也可以直接在本地运行,但是处理数据量大的时候内存会不够用,不建议。启动 Spark-Shell 的时候,可以指定使用 yarn 模式:spark-shell --master yarn-client,如果不指定,默认在本地启动,内存与处理速度会慢。

spark-shell --help,查看启动参数详情,例如以下参数,--executor-memory 4G--total-executor-cores 4--executor-cores 2 可以加大内存,增加 core 数。

常用方法举例:dinstinct【去重】、intersection【交集】、subtract【差集】、union【并集】、saveAsTextFile【导出】、textFile【读取】。

分割去重过滤:

1
.flatMap (x=>x.split ("\\t")).distinct ().filter (x=>11>x.length ())

单词计数写回文件,按照 value 降序排列:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
val wordcount = sc.textFile ("").flatMap (line => line.split ("\\t")).map (word => (word, 1)).reduceByKey ((a, b) => a + b)

val finalresult=wordcount.filter (count => count._2 > 100)

finalresult.persist ()

finalresult.foreach (println)

finalresult.count ()

finalresult=finalresult.sortBy (_._2,false)

val textresult=finalresult.map (count => count._1 + "," + count._2)

textresult.foreach (println)

textresult.saveAsTextFile ("")

大数据任务调度系统

yarn

移动队列

在资源紧张的情况下,可以手动移动 Spark 任务的队列,合理利用空闲的资源。

如果 yarn 队列没有资源了,而自己又有 Spark 任务需要跑,在提交 Spark 任务后,可以看到任务在等待分配资源,此时可以把 Spark 任务移动到别的空闲队列去【也可以在提交 Spark 任务的时候指定队列】。

或者某些运行耗时比较长的任务,也可以先移动到别的空闲队列跑,释放自己业务的队列资源给其它任务使用。前提是确保不影响别的队列的正常使用,不能长久占用别人的队列。

使用 yarn 自带的命令:

1
2
3
-- 指定 Spark 任务的 applicationId,以及目标队列名称 
-- 注意用户权限
yarn application -movetoqueue applicationId -queue queueName

如果不熟悉这些命令,可以使用 yarn -helpyarn application -help 等命令查看帮助说明文档。

取消任务

如果想 kill 掉一个正在 yarn 环境上运行的 Spark 任务,可以直接使用 kill 命令:

1
2
-- 指定 Spark 任务的 applicationId
yarn application -kill applicationId

当然,如果使用的 yarn-client 模式提交任务,并且有权限看到 Driver 端的进程,也可以直接使用 Linux 的命令 kill 掉进程【不够优雅】。

下载日志

下载已经完成的 Spark 任务的文本日志,在 Saprk 任务的 UI 界面,可以看到 Excutor 的日志,但是当日志多的时候,看起来不方便,搜索就更不用说了。

当任务完成之后,可以使用 yarn 命令下载文本日志进行查看、分析:

1
2
-- 指定 Spark 任务的 applicationId,所属用户 
yarn logs -applicationId applicationId -appOwner userName

注意,由于用户权限的问题,在下载日志之前需要切换用户,否则获取不到日志或者抛出权限相关错误:

1
2
3
-- 切换用户,根据实际情况而定 
-- 决定着去哪个目录获取日志文件
export HADOOP_USER_NAME=xxx

操作系统

回车换行

在文本数据处理中,CRLFCR/LF 是不同操作系统上使用的换行符,表现为文本另起一行输出。

1
2
CR:Carriage Return
LF:Line Feed

下面列出常见的操作系统标准:

  • DosWindows 采用回车符 + 换行符,CR/LF 表示下一行
  • UNIX/Linux 采用换行符,LF 表示下一行
  • 苹果 MAC OS 系统则采用回车符,CR 表示下一行

还需要注意,CR 用符号 \\r 表示,十进制 ASCII 编码是 13,十六进制编码为 0x0dLF 使用 \\n 符号表示,十进制 ASCII 编码是 10,十六制编码为 0x0a

所以在 Windows 平台上的换行效果,在文本文件中是使用 0d0a 这两个字节来实现的,而 UNIX 和苹果平台上的换行效果则是使用 0a0d 一个字符来实现的,节约了存储空间。

在一个操作系统平台上使用另一种换行标准的文本文件,可能会带来意想不到的问题,特别是在程序代码中,有时候代码在编辑器中显示正常,但是在编译打包时却会因为换行符问题而出错【备注:使用 Git 版本控制系统时,Git 客户端已经根据当前的操作系统环境,自动帮助我们实时替换了换行符号】。

例如常见的一个现象,Unix/Mac 系统下的文件在 Windows 里打开的时候,会发现所有的文字变成了一行,而同理,Windows 里的文件在 Unix/Mac 下打开的话,在每行的结尾可能会多出一个 ^M 符号。

虾丸派 wechat
扫一扫添加博主,进技术交流群,共同学习进步
永不止步
0%