Hadoop集群安装配置

最近需要做大数据的分析,研究了一下HADOOP,作为第一步,配置HADOOP集群是最基础的工作。这里简单记录一下流程。

一、配置每台机器的网络。包括修改hostname,hosts

二、配置每台机器之间的SSH免密码认证(注意.ssh文件夹和其内文件的权限)

三、配置防火墙

四、安装JAVA环境并配置环境变量

1
2
export JAVA_HOME=/usr/lib/jvm/java-1.7.0-openjdk
source ~/.bashrc

五、安装HADOOP并配置环境变量

1
2
3
4
5
6
7
8
9
# Hadoop Environment Variables
export HADOOP_HOME=/usr/local/hadoop
export HADOOP_INSTALL=$HADOOP_HOME
export HADOOP_MAPRED_HOME=$HADOOP_HOME
export HADOOP_COMMON_HOME=$HADOOP_HOME
export HADOOP_HDFS_HOME=$HADOOP_HOME
export YARN_HOME=$HADOOP_HOME
export HADOOP_COMMON_LIB_NATIVE_DIR=$HADOOP_HOME/lib/native
export PATH=$PATH:$HADOOP_HOME/sbin:$HADOOP_HOME/bin
1
source ~/.bashrc

六、配置PATH变量(hadoop/bin和hadoop/sbin)

七、配置文件slaves、core-site.xml、hdfs-site.xml、mapred-site.xml、yarn-site.xml

1、slaves内为slaves机器名

2、core-site.xml为

1
2
3
4
5
6
7
8
9
10
11
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://Master:9000</value>
</property>
<property>
<name>hadoop.tmp.dir</name>
<value>file:/usr/local/hadoop/tmp</value>
<description>Abase for other temporary directories.</description>
</property>
</configuration>

3、hdfs-site.xml,dfs.replication 为datanode个数,一般设为 3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<configuration>
<property>
<name>dfs.namenode.secondary.http-address</name>
<value>Master:50090</value>
</property>
<property>
<name>dfs.replication</name>
<value>3</value>
</property>
<property>
<name>dfs.namenode.name.dir</name>
<value>file:/usr/local/hadoop/tmp/dfs/name</value>
</property>
<property>
<name>dfs.datanode.data.dir</name>
<value>file:/usr/local/hadoop/tmp/dfs/data</value>
</property>
</configuration>

4、mapred-site.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<configuration>
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
<property>
<name>mapreduce.jobhistory.address</name>
<value>Master:10020</value>
</property>
<property>
<name>mapreduce.jobhistory.webapp.address</name>
<value>Master:19888</value>
</property>
</configuration>

5、yarn-site.xml

1
2
3
4
5
6
7
8
9
10
<configuration>
<property>
<name>yarn.resourcemanager.hostname</name>
<value>Master</value>
</property>
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>
</configuration>

八、复制主节点hadoop及配置文件到所有节点

九、初始化namenode

1
hdfs namenode -format   

十、启动或关闭hadoop集群

1
2
3
start-dfs.sh
start-yarn.sh
mr-jobhistory-daemon.sh start historyserver
1
2
3
stop-yarn.sh
stop-dfs.sh
mr-jobhistory-daemon.sh stop historyserver

JPS 查看进程
hdfs dfsadmin -report 查看报告

git commit emoji

commit 格式

git commit 时,提交信息遵循以下格式:

1
2
3
4
5
:emoji1: :emoji2: 主题

提交信息主体

Ref <###>

初次提交示例:

1
git commit -m ":tada: Initialize Repo"

emoji 指南

emoji emoji 代码 commit 说明
🎨 (调色板) :art: 改进代码结构/代码格式
⚡ (闪电)🐎 (赛马) :zap:``:racehorse: 提升性能
🔥 (火焰) :fire: 移除代码或文件
🐛 (bug) :bug: 修复 bug
🚑 (急救车) :ambulance: 重要补丁
✨ (火花) :sparkles: 引入新功能
📝 (备忘录) :memo: 撰写文档
🚀 (火箭) :rocket: 部署功能
💄 (口红) :lipstick: 更新 UI 和样式文件
🎉 (庆祝) :tada: 初次提交
✅ (白色复选框) :white_check_mark: 增加测试
🔒 (锁) :lock: 修复安全问题
🍎 (苹果) :apple: 修复 macOS 下的问题
🐧 (企鹅) :penguin: 修复 Linux 下的问题
🏁 (旗帜) :checked_flag: 修复 Windows 下的问题
🔖 (书签) :bookmark: 发行/版本标签
🚨 (警车灯) :rotating_light: 移除 linter 警告
🚧 (施工) :construction: 工作进行中
💚 (绿心) :green_heart: 修复 CI 构建问题
⬇️ (下降箭头) :arrow_down: 降级依赖
⬆️ (上升箭头) :arrow_up: 升级依赖
👷 (工人) :construction_worker: 添加 CI 构建系统
📈 (上升趋势图) :chart_with_upwards_trend: 添加分析或跟踪代码
🔨 (锤子) :hammer: 重大重构
➖ (减号) :heavy_minus_sign: 减少一个依赖
🐳 (鲸鱼) :whale: Docker 相关工作
➕ (加号) :heavy_plug_sign: 增加一个依赖
🔧 (扳手) :wrench: 修改配置文件
🌐 (地球) :globe_with_meridians: 国际化与本地化
✏️ (铅笔) :pencil2: 修复 typo

参考

折腾斐讯K2刷LEDE

昨天又看到有人上车,于是没有经受住诱惑,撸了一台蓝色的斐讯K2,不知道能不能安全下车。颜值嘛还可以。做功嘛略显粗糙。打开看了一下配置。MT7620,64M的RAM和8M的ROM。。。这也能标399的价格,也是呵呵了。

首先刷一个优秀的Bootloader,这里我选择Breed,毕竟当年的U-Boot已经不行了。
这里有一个神奇的方法可以刷入Breed,不禁让我对作者的脑洞感到由衷的佩服。只有一句“这TM也行”可以表达我的内心想法了。

http://www.right.com.cn/forum/thread-204435-1-1.html

刷完Breed以后重启长按reset就可以进入刷机模式,就可以刷入系统固件了。
多年经验告诉我Openwrt是个好固件,然而去年openwrt内部出现了一些问题。导致有一部分核心人员独立出来成立了LEDE-Project。全称Linux Embedded Development Environment(名字起的好霸气啊),想想以前那么多的openwrt版本,那么混乱的Issue管理和补丁发布。这次还是试试LEDE吧。毕竟是新项目,又是openwrt的核心团队搞的,应该会不错的。

LEDE官网在此

在官网一搜,居然有K2的专门版本。这下好了,不用自己编译了。交叉编译搞死人。搜索PHICOMM K2 PSG1218就可以找到了。这里也贴一下下载地址
刷完之后重启。看到一个丑丑的Luci界面。

配置好密码和网络等基本配置。还剩90%的剩余空间。爽啊。果断准备安装全套[不可描述]、[不可描述]和[不可描述]的软件。
安装过程中就不写了。水表已拆。说一句现在安装和编译东西比几年前我搞hg255d的时候简单方便多了。又不用考虑剩余内存。简直是一帆风顺啊。
嗯再放一个获取中国国内IP列表的脚本吧。

wget -O- 'http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest' | awk -F\| '/CN\|ipv4/ { printf("%s/%d\n", $4, 32-log($5)/log(2)) }' > /etc/不可描述.txt

最后装一个luci-i18n汉化包和theme包美化一下。结束战斗。

测试一下2.4G+5G(虽然我只开了5G)信号都还是不错的。速度也还算稳定。[不可描述]的速度也能跑满带宽。十分满意。最后贴个界面图,这个 luci-theme-material还是挺好看的。
图

MYSQL事务隔离级别

Mysql有四种事务隔离级别,分别是:
Read Uncommitted
Read Committed
Repeatable Read
Serializable

关于这四个隔离级别的介绍:

未提交读(READ UNCOMMITTED)。另一个事务修改了数据,但尚未提交,而本事务中的SELECT会读到这些未被提交的数据(脏读)。

提交读(READ COMMITTED)。本事务读取到的是最新的数据(其他事务提交后的)。问题是,在同一个事务里,前后两次相同的SELECT会读到不同的结果(不重复读)。

可重复读(REPEATABLE READ)。在同一个事务里,SELECT的结果是事务开始时时间点的状态,因此,同样的SELECT操作读到的结果会是一致的。但是,会有幻读现象(稍后解释)。

串行化(SERIALIZABLE)。读操作会隐式获取共享锁,可以保证不同事务间的互斥。

这四个级别逐渐增强,每个级别解决一个问题

脏读,最容易理解。另一个事务修改了数据,但尚未提交,而本事务中的SELECT会读到这些未被提交的数据。

不重复读。解决了脏读后,会遇到,同一个事务执行过程中,另外一个事务提交了新数据,因此本事务先后两次读到的数据结果会不一致。

幻读。解决了不重复读,保证了同一个事务里,查询的结果都是事务开始时的状态(一致性)。但是,如果另一个事务同时提交了新数据,本事务再更新时,就会“惊奇的”发现了这些新数据,貌似之前读到的数据是“鬼影”一样的幻觉。

可以通过select @@tx_isolation来查看当前隔离级别

通过set [ global | session ] transaction isolation level Read uncommitted | Read committed | Repeatable | Serializable来修改事务隔离级别

如果选择global,意思是此语句将应用于之后的所有session,而当前已经存在的session不受影响。

如果选择session,意思是此语句将应用于当前session内之后的所有事务。

如果什么都不写,意思是此语句将应用于当前session内的下一个还未开始的事务。

采用Arduino IDE对ESP8266进行编程

话说ESP8266真是个神奇的芯片,不仅可以使用NodeMCU和micropython等固件,还可以直接支持采用Arduino IDE环境进行编程和烧写。本身又有wifi和gpio,又便宜。简直是折腾神器。

采用Arduino编程的最大好处是,很多库可以直接引用。不用再写一些很底层的代码去驱动外设。这大大提高的开发效率,并且像上篇文章里写的,采用lua语言的NodeMCU还是有一些局限性的。比如不支持微秒级的延时。

要采用Arduino对ESP8266进行编程,首先要有一个1.6.4版本以上的Arduino IDE

其次在设置里需要把additional board manager URLs 设置为http://arduino.esp8266.com/stable/package_esp8266com_index.json

这样在工具里的开发板选择里就有了NodeMCU1.0选项。

下载完工具链就可以直接编写了。

下面是用Arduino写的gp2y1010au0f粉尘检测来测AQI的代码。测试通过

/*
   NodeMCU连接夏普GP2Y1010AU0F空气质量传感器检测PM2.5
*/
/* 定义引脚 */
#define PIN_DATA_OUT A0 //连接空气质量传感器模拟量输出的IO口, NodeMCU只有A0可以作为ADC
#define PIN_LED_VCC 5 //空气质量传感器中为内部Led供电的引脚
/* 定义时间 */
const int DELAY_BEFORE_SAMPLING = 280; //采样前等待时间
const int DELAY_AFTER_SAMPLING = 40; //采样后等待时间
const int DELAY_LED_OFF = 9680; //间隔时间
/**
   读取输出电压
*/
double getOutputV() {
  digitalWrite(PIN_LED_VCC, LOW);
  delayMicroseconds(DELAY_BEFORE_SAMPLING);
  double analogOutput = analogRead(PIN_DATA_OUT);
  delayMicroseconds(DELAY_AFTER_SAMPLING);
  digitalWrite(PIN_LED_VCC, HIGH);
  delayMicroseconds(DELAY_LED_OFF);
  //Arduino模拟量读取值的范围为0~1023,以下换算为0~5v
  double outputV = analogOutput / 1024 * 5;
  return outputV;
}
/**
   根据输出电压计算灰尘密度
*/
double getDustDensity(double outputV) {
  //输出电压和灰尘密度换算公式: ug/m3 = (V - 0.9) / 5 * 1000
  double ugm3 = (outputV - 0.9) / 5 * 1000;
  //去除检测不到的范围
  if (ugm3 < 0) {
    ugm3 = 0;
  }
  return ugm3;
}
/**
   根据灰尘密度计算AQI
   环境空气质量指数(AQI)技术规定(试行)](http://kjs.mep.gov.cn/hjbhbz/bzwb/dqhjbh/jcgfffbz/201203/t20120302_224166.htm
*/
double getAQI(double ugm3) {
  double aqiL = 0;
  double aqiH = 0;
  double bpL = 0;
  double bpH = 0;
  double aqi = 0;
  //根据pm2.5和aqi对应关系分别计算aqi
  if (ugm3 >= 0 && ugm3 <= 35) {
    aqiL = 0;
    aqiH = 50;
    bpL = 0;
    bpH = 35;
  } else if (ugm3 > 35 && ugm3 <= 75) {
    aqiL = 50;
    aqiH = 100;
    bpL = 35;
    bpH = 75;
  } else if (ugm3 > 75 && ugm3 <= 115) {
    aqiL = 100;
    aqiH = 150;
    bpL = 75;
    bpH = 115;
  } else if (ugm3 > 115 && ugm3 <= 150) {
    aqiL = 150;
    aqiH = 200;
    bpL = 115;
    bpH = 150;
  } else if (ugm3 > 150 && ugm3 <= 250) {
    aqiL = 200;
    aqiH = 300;
    bpL = 150;
    bpH = 250;
  } else if (ugm3 > 250 && ugm3 <= 350) {
    aqiL = 300;
    aqiH = 400;
    bpL = 250;
    bpH = 350;
  } else if (ugm3 > 350) {
    aqiL = 400;
    aqiH = 500;
    bpL = 350;
    bpH = 500;
  }
  //公式aqi = (aqiH - aqiL) / (bpH - bpL) * (desity - bpL) + aqiL;
  aqi = (aqiH - aqiL) / (bpH - bpL) * (ugm3 - bpL) + aqiL;
  return aqi;
}
/**
   根据aqi获取级别描述
*/
String getGradeInfo(double aqi) {
  String gradeInfo;
  if (aqi >= 0 && aqi <= 50) {
    gradeInfo = String("Perfect");
  } else if (aqi > 50 && aqi <= 100) {
    gradeInfo = String("Good");
  } else if (aqi > 100 && aqi <= 150) {
    gradeInfo = String("Mild polluted");
  } else if (aqi > 150 && aqi <= 200) {
    gradeInfo = String("Medium polluted");
  } else if (aqi > 200 && aqi <= 300) {
    gradeInfo = String("Heavily polluted");
  } else if (aqi > 300 && aqi <= 500) {
    gradeInfo = String("Severely polluted");
  } else {
    gradeInfo = String("Broken roof!!!");
  }
  return gradeInfo;
}
void setup() {
  Serial.begin(115200);
  pinMode(PIN_DATA_OUT, INPUT); //定义为输入(ADC读取模拟量)
  pinMode(PIN_LED_VCC, OUTPUT); //定义为输出
}
void loop() {
  double outputV = getOutputV(); //采样获取输出电压
  double ugm3 = getDustDensity(outputV); //计算灰尘浓度
  double aqi = getAQI(ugm3); //计算aqi
  String gradeInfo = getGradeInfo(aqi); //计算级别
  //打印到串口
  Serial.println(String("outputV=") + outputV + "\tug/m3=" + ugm3 + "\tAQI=" + aqi + "\tgradeInfo=" + gradeInfo);
  //间隔1秒执行下次检测
  delay(1000);
}