数据专栏

智能大数据搬运工,你想要的我们都有

科技资讯:

科技学院:

科技百科:

科技书籍:

网站大全:

软件大全:

「深度学习福利」大神带你进阶工程师,立即查看>>>
环境信息
完全分布式集群(一)集群基础环境及zookeeper-3.4.10安装部署
hadoop集群安装配置过程
安装hive前需要先部署hadoop集群
完全分布式集群(二)hadoop2.6.5安装部署
安装hive2.1.1
下载并通过FTP工具将apache-hive-2.1.1-bin.tar.gz安装包上传至服务器,解压,并修改软件目录。因整个集群目前node225节点只作为集群的DataNode,所以本次将hive安装在node225节点上 [root@node225 ~]# gtar -xzf /home/hadoop/apache-hive-2.1.1-bin.tar.gz -C /usr/local/ [root@node225 ~]# mv /usr/local/apache-hive-2.1.1-bin /usr/local/hive-2.1.1
配置hive环境变量信息 [root@node225 ~]# vi /etc/profile #追加如下内容,目录需要结合实际修改 export HIVE_HOME=/usr/local/hive-2.1.1 export HIVE_CONF_DIR=${HIVE_HOME}/conf export PATH=${HIVE_HOME}/bin:$PATH # 使配置生效 [root@node225 ~]# source /etc/profile
在集群的任意节点上创建hive配置需要的目录并设置操作权限,前提是确保hadoop集群正常启动,如下在node222节点创建。 [hadoop@node222 ~]$ hdfs dfs -mkdir -p /user/hive/warehouse [hadoop@node222 ~]$ hdfs dfs -chmod 777 /user/hive/warehouse [hadoop@node222 ~]$ hdfs dfs -mkdir -p /tmp/hive/ [hadoop@node222 ~]$ hdfs dfs -chmod 777 /tmp/hive
本次安装为多用户模式,需要在mysql上创建hive元数据库 -- 创建hive数据库 ipems_dvp@localhost : (none) 10:26:05> create database hive; Query OK, 1 row affected (0.01 sec) -- 创建hive用户并设置密码 ipems_dvp@localhost : (none) 10:27:01> create user 'hive'@'%' identified by 'Aa123456789'; Query OK, 0 rows affected (0.07 sec) -- 授权 ipems_dvp@localhost : (none) 10:36:12> grant all privileges on hive.* to 'hive'@'%'; Query OK, 0 rows affected (0.07 sec) -- 刷新权限 ipems_dvp@localhost : (none) 10:36:26> flush privileges; Query OK, 0 rows affected (0.02 sec)
拷贝模板生成hive配置文件,并修改文件内容,为屏蔽每次hive连接时提示“WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set.”是Mysql数据库的SSL连接问题,提示警告不建议使用没有带服务器身份验证的SSL连接。在javax.jdo.option.ConnectionURL配置项中增加“&useSSL=false”,其中“&”为XML中的“&”符号。 [root@node225 ~]# cp /usr/local/hive-2.1.1/conf/hive-default.xml.template /usr/local/hive-2.1.1/conf/hive-site.xml # hive-site.xml默认里边配置项非常多,可先清空,后填充如下内容 [root@node225 ~]# cat "" /usr/local/hive-2.1.1/conf/hive-site.xml [root@node225 ~]# vi /usr/local/hive-2.1.1/conf/hive-site.xml # 配置项 hive.default.fileformat TextFile javax.jdo.option.ConnectionURL jdbc:mysql://192.168.0.200:3306/hive?createDatabaseIfNotExist=true&useSSL=false javax.jdo.option.ConnectionDriverName com.mysql.jdbc.Driver javax.jdo.option.ConnectionUserName hive javax.jdo.option.ConnectionPassword Aa123456789 hive.metastore.schema.verification false
将mysql的jdbc连接驱动上传至hive的lib目录 [root@node225 ~]# ls /usr/local/hive-2.1.1/lib/mysql-connector-java-5.1.40-bin.jar /usr/local/hive-2.1.1/lib/mysql-connector-java-5.1.40-bin.jar
将hadoop的home和hive配置目录环境信息追加至/usr/local/hive-2.1.1/conf/hive-env.sh [root@node225 ~]# vi /usr/local/hive-2.1.1/conf/hive-env.sh # 追加内容 export HADOOP_HOME=/usr/local/hadoop-2.6.5 export HIVE_CONF_DIR=/usr/local/hive-2.1.1/conf export HIVE_AUX_JARS_PATH=/usr/local/hive-2.1.1/lib
初始化hive元数据库 [root@node225 ~]# /usr/local/hive-2.1.1/bin/schematool -initSchema -dbType mysql which: no hbase in (.:/usr/local/jdk1.8.0_66//bin:/usr/local/zookeeper-3.4.10/bin:ZK_HOME/sbin:ZK_HOME/lib:/usr/local/hadoop-2.6.5//bin:/usr/local/hadoop-2.6.5//sbin:/usr/local/hadoop-2.6.5//lib:/usr/local/hive-2.1.1/bin:/usr/local/mongodb/bin:.:/usr/local/jdk1.8.0_66//bin:/usr/local/zookeeper-3.4.10/bin:ZK_HOME/sbin:ZK_HOME/lib:/usr/local/hadoop-2.6.5//bin:/usr/local/hadoop-2.6.5//sbin:/usr/local/hadoop-2.6.5//lib:/usr/local/hive-2.1.1/bin/bin:/usr/local/mongodb/bin:/usr/local/zookeeper-3.4.10/bin:ZK_HOME/sbin:ZK_HOME/lib:/usr/local/hadoop-2.6.5//bin:/usr/local/hadoop-2.6.5//sbin:/usr/local/hadoop-2.6.5//lib:/usr/local/jdk1.8.0_66//bin:/usr/local/mongodb/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin) ...... Sun Sep 30 10:52:41 CST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification. schemaTool completed
通过hiveCLI连接测试,正常进入,并执行简单的hiveQL命令测试 [root@node225 ~]# /usr/local/hive-2.1.1/bin/hive which: no hbase in (.:/usr/local/jdk1.8.0_66//bin:/usr/local/zookeeper-3.4.10/bin:ZK_HOME/sbin:ZK_HOME/lib:/usr/local/hadoop-2.6.5//bin:/usr/local/hadoop-2.6.5//sbin:/usr/local/hadoop-2.6.5//lib:/usr/local/hive-2.1.1/bin:/usr/local/mongodb/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin) Logging initialized using configuration in jar:file:/usr/local/hive-2.1.1/lib/hive-common-2.1.1.jar!/hive-log4j2.properties Async: true Hive-on-MR is deprecated in Hive 2 and may not be available in the future versions. Consider using a different execution engine (i.e. spark, tez) or using Hive 1.X releases. hive> show databases;
连接如果提示如下"SLF4J: Class path contains multiple SLF4J bindings."是SLF4J相关提示是因为发生jar包冲突了,本次采用hadoop的jar包,所以重命名hive的对应jar包, # 提示信息 SLF4J: Class path contains multiple SLF4J bindings. SLF4J: Found binding in [jar:file:/usr/local/hive-2.1.1/lib/log4j-slf4j-impl-2.4.1.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: Found binding in [jar:file:/usr/local/hadoop-2.6.5/share/hadoop/common/lib/slf4j-log4j12-1.7.5.jar!/org/slf4j/impl/StaticLoggerBinder.class] SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation. SLF4J: Actual binding is of type [org.apache.logging.slf4j.Log4jLoggerFactory] # 处理方法 [root@node225 ~]# mv /usr/local/hive-2.1.1/lib/log4j-slf4j-impl-2.4.1.jar /usr/local/hive-2.1.1/lib/log4j-slf4j-impl-2.4.1.jar.bak
如果提示“Exception in thread "main" java.lang.RuntimeException: org.apache.hadoop.ipc.RemoteException(org.apache.hadoop.ipc.StandbyException): Operation category READ is not supported in state standby”是因为两个互为HA的namenode节点均处于standby 状态,通过50070端口查看确定该状态,启动NameNode节点上的zkfc服务 [hadoop@node222 ~]$ /usr/local/hadoop-2.6.5/sbin/hadoop-daemon.sh start zkfc [hadoop@node224 ~]$ /usr/local/hadoop-2.6.5/sbin/hadoop-daemon.sh start zkfc
大数据
2018-10-09 22:46:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
本系列博文将记录在3台CentOS7环境下搭建完全分布式数据分析平台环境。
基础环境配置
环境信息

设置机器名
设置服务器的机器名,3台都设依次分别设置为node222,node224,node225,root用户操作,示例如node222。 hostnamectl set-hostname node222
修改各服务器的/etc/hosts文件,追加3台服务器的IP和hostname信息,3台服务器信息一致,root用户操作。 127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4 ::1 localhost localhost.localdomain localhost6 localhost6.localdomain6 192.168.0.222 node222 192.168.0.224 node224 192.168.0.225 node225
切一次用户测试配置是否设置生效,同时测试通过hostname互ping是否正常。 su - root ping node222
关闭防火墙
CentOS7默认防火墙服务是firewalld,3台服务器都要执行,root用户操作,如果安装了iptables服务也要关闭。 systemctl stop firewalld.service systemctl disable firewalld.service systemctl stop iptables.service systemctl disable iptables.service
关闭SElinux
修改/etc/selinux/config文件,将SELINUX设置为disabled,3台服务器均需安装,root用户操作。 # This file controls the state of SELinux on the system. # SELINUX= can take one of these three values: # enforcing - SELinux security policy is enforced. # permissive - SELinux prints warnings instead of enforcing. # disabled - No SELinux policy is loaded. SELINUX=disabled # SELINUXTYPE= can take one of three two values: # targeted - Targeted processes are protected, # minimum - Modification of targeted policy. Only selected processes are protected. # mls - Multi Level Security protection. SELINUXTYPE=targeted
安装JDK8
JDK8或最新版本可在oracle官方网站下载,本次采用jdk-8u66-linux-x64.gz,下载后通过FTP工具上传至服务器,解压,配置环境变量即可。3台服务器均需安装,root用户操作。 gtar -xzf /home/hadoop/jdk-8u66-linux-x64.gz -C /usr/local/ ls /usr/local/jdk1.8.0_66/ # 编辑/etc/profile文件添加如下内容 export JAVA_HOME=/usr/local/jdk1.8.0_66/ export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar export PATH=$JAVA_HOME/bin:$PATH vi /etc/profile # 使配置生效 source /etc/profile # 测试JDK环境 java -version java version "1.8.0_66" Java(TM) SE Runtime Environment (build 1.8.0_66-b17) Java HotSpot(TM) 64-Bit Server VM (build 25.66-b17, mixed mode)
以上各步骤操作完成后,重启各服务器,再次检查各配置项是否生效,如一切正常,即完成初始服务器环境配置。
安装zookeeper集群
ZooKeeper是一个分布式的,开放源码的分布式应用程序协调服务,是Google的Chubby一个开源的实现,是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的软件,提供的功能包括:配置维护、域名服务、分布式同步、组服务等。
以下记录zookeeper-3.4.10版本的3节点完全分布式集群环境安装部署过程。
下载zookeeper-3.4.10.tar.gz,通过FTP工具上传至一台服务器并解压,一台服务器上操作,root用户操作。 tar -zxf /rpmpackages/hbase/zookeeper-3.4.10.tar.gz -C /usr/local/
创建数据和日志目录 mkdir -p /usr/local/zookeeper-3.4.10/zkdata mkdir -p /usr/local/zookeeper-3.4.10/zklogs
复制模板生成配置文件,修改以下配置项 cp /usr/local/zookeeper-3.4.10/conf/zoo_sample.cfg /usr/local/zookeeper-3.4.10/conf/zoo.cfg vi /usr/local/zookeeper-3.4.10/conf/zoo.cfg # 修改的内容 tickTime=2000 initLimit=5 syncLimit=2 dataDir=/usr/local/zookeeper-3.4.10/zkdata clientPort=2181 #最好用机器名 server.1=node222:2888:3888 server.2=node224:2888:3888 server.3=node225:2888:3888
相关配置参数说明:
#tickTime:
Zookeeper 服务器之间或客户端与服务器之间维持心跳的时间间隔,也就是每个 tickTime 时间就会发送一个心跳,单位是毫秒。
#initLimit:
配置zookeeper集群中follower与leader初始化连接时能容忍的tickTime个数,那么容忍的时长就等于initLimit*tickTime
#syncLimit:
配置 Leader 与Follower 之间发送消息,请求和应答时间长度,最长不能超过多少个 tickTime 的时间长度,总的时间长度就是syncLimit*tickTime
#dataDir:
快照日志的存储路径
#dataLogDir:
事物日志的存储路径,如果不配置这个那么事物日志会默认存储到dataDir制定的目录,这样会严重影响zk的性能,当zk吞吐量较大的时候,产生的事物日志、快照日志太多
#clientPort:
这个端口就是客户端连接 Zookeeper 服务器的端口,Zookeeper 会监听这个端口,接受客户端的访问请求。
#server.1 这个1是服务器的标识也可以是其他的数字, 表示这个是第几号服务器,这个标识要写到快照目录下面myid文件里
#node222为集群里的hostname,第一个端口是master和slave之间的通信端口,默认是2888,第二个端口是leader选举的端口,集群刚启动的时候选举或者leader挂掉之后进行新的选举的端口默认是3888
编辑bin/zkEnv.sh设置日志目录 if [ "x${ZOO_LOG_DIR}" = "x" ] then ZOO_LOG_DIR="/usr/local/zookeeper-3.4.10/zklogs" fi
拷贝zookeeper安装文件至其他节点 scp -r /usr/local/zookeeper-3.4.10 root@node224:/usr/local/ scp -r /usr/local/zookeeper-3.4.10 root@node225:/usr/local/
给集群的每台服务器分别创建自己的myid文件,文件内的号码要与配置文件中的配置一致 [root@node222 zookeeper-3.4.10]# echo "1" > zkdata/myid [root@node224 zookeeper-3.4.10]# echo "2" > zkdata/myid [root@node225 zookeeper-3.4.10]# echo "3" > zkdata/myid
配置zookeeper的环境变量,3台服务均要配置。 vi /etc/profile # 追加如下内容 export ZK_HOME=/usr/local/zookeeper-3.4.10 export PATH=$ZK_HOME/bin:ZK_HOME/sbin:ZK_HOME/lib:$PATH # 使配置生效 source /etc/profile
启动节点上的zookeeper服务 /usr/local/zookeeper-3.4.10/bin/zkServer.sh start ZooKeeper JMX enabled by default Using config: /usr/local/zookeeper-3.4.10/bin/../conf/zoo.cfg Starting zookeeper ... STARTED
检查各节点的zookeeper服务状态,正常应该有一个leader,两个follower。 # leader节点状态 /usr/local/zookeeper-3.4.10/bin/zkServer.sh status ZooKeeper JMX enabled by default Using config: /usr/local/zookeeper-3.4.10/bin/../conf/zoo.cfg Mode: leader # follower节点状态 /usr/local/zookeeper-3.4.10/bin/zkServer.sh status ZooKeeper JMX enabled by default Using config: /usr/local/zookeeper-3.4.10/bin/../conf/zoo.cfg Mode: follower
集群中如果有三个节点,关闭两个节点后,第三个节点的状态会出现异常。启动一个节点(两个节点)状态又可以恢复;主节点关闭后,会选举新的主节点,原主节点启动后会作为从节点。
客户端shell操作
zookeeper可通过zkCli.sh客户端工具连接,进行简单的shell操作。 /usr/local/zookeeper-3.4.10/bin/zkCli.sh -server node224:2181 Connecting to node224:2181 ...... WATCHER:: WatchedEvent state:SyncConnected type:None path:null [zk: node224:2181(CONNECTED) 0] [zk: node224:2181(CONNECTED) 0] ls / [zookeeper] [zk: node224:2181(CONNECTED) 1] ls /zookeeper [quota] [zk: node224:2181(CONNECTED) 2] ls /zookeeper/quota [] [zk: node224:2181(CONNECTED) 3] create /zk_test my_data Created /zk_test [zk: node224:2181(CONNECTED) 4] ls / [zookeeper, zk_test] [zk: node224:2181(CONNECTED) 5] ls /zk_test [] [zk: node224:2181(CONNECTED) 6] get /zk_test
大数据
2018-10-09 21:22:00
「深度学习福利」大神带你进阶工程师,立即查看>>> package com.unilife.utils.persistence; import java.io.IOException; import org.apache.hadoop.conf.Configuration; import org.apache.hadoop.hbase.HBaseConfiguration; import org.apache.hadoop.hbase.HColumnDescriptor; import org.apache.hadoop.hbase.HTableDescriptor; import org.apache.hadoop.hbase.KeyValue; import org.apache.hadoop.hbase.client.Delete; import org.apache.hadoop.hbase.client.Get; import org.apache.hadoop.hbase.client.HBaseAdmin; import org.apache.hadoop.hbase.client.HTable; import org.apache.hadoop.hbase.client.Put; import org.apache.hadoop.hbase.client.Result; import org.apache.hadoop.hbase.client.ResultScanner; import org.apache.hadoop.hbase.client.Scan; import org.apache.hadoop.hbase.util.Bytes; public class Hbase { // 声明静态配置 static Configuration conf = null; static { conf = HBaseConfiguration.create(); conf.set("hbase.zookeeper.quorum", "master"); } /* * 创建表 * * @tableName 表名 * * @family 列族列表 */ public static void creatTable(String tableName, String[] family) throws Exception { HBaseAdmin admin = new HBaseAdmin(conf); HTableDescriptor desc = new HTableDescriptor(tableName); for (int i = 0; i < family.length; i++) { desc.addFamily(new HColumnDescriptor(family[i])); } if (admin.tableExists(tableName)) { System.out.println("table Exists!"); System.exit(0); } else { admin.createTable(desc); System.out.println("create table Success!"); } } /* * 为表添加数据(适合知道有多少列族的固定表) * * @rowKey rowKey * * @tableName 表名 * * @column1 第一个列族列表 * * @value1 第一个列的值的列表 * * @column2 第二个列族列表 * * @value2 第二个列的值的列表 */ public static void addData(String rowKey, String tableName, String[] column1, String[] value1, String[] column2, String[] value2) throws IOException { Put put = new Put(Bytes.toBytes(rowKey));// 设置rowkey HTable table = new HTable(conf, Bytes.toBytes(tableName));// HTabel负责跟记录相关的操作如增删改查等// // 获取表 HColumnDescriptor[] columnFamilies = table.getTableDescriptor() // 获取所有的列族 .getColumnFamilies(); for (int i = 0; i < columnFamilies.length; i++) { String familyName = columnFamilies[i].getNameAsString(); // 获取列族名 if (familyName.equals("article")) { // article列族put数据 for (int j = 0; j < column1.length; j++) { put.add(Bytes.toBytes(familyName), Bytes.toBytes(column1[j]), Bytes.toBytes(value1[j])); } } if (familyName.equals("author")) { // author列族put数据 for (int j = 0; j < column2.length; j++) { put.add(Bytes.toBytes(familyName), Bytes.toBytes(column2[j]), Bytes.toBytes(value2[j])); } } } table.put(put); System.out.println("add data Success!"); } /* * 根据rwokey查询 * * @rowKey rowKey * * @tableName 表名 */ public static Result getResult(String tableName, String rowKey) throws IOException { Get get = new Get(Bytes.toBytes(rowKey)); HTable table = new HTable(conf, Bytes.toBytes(tableName));// 获取表 Result result = table.get(get); for (KeyValue kv : result.list()) { System.out.println("family:" + Bytes.toString(kv.getFamily())); System.out .println("qualifier:" + Bytes.toString(kv.getQualifier())); System.out.println("value:" + Bytes.toString(kv.getValue())); System.out.println("Timestamp:" + kv.getTimestamp()); System.out.println("-------------------------------------------"); } return result; } /* * 遍历查询hbase表 * * @tableName 表名 */ public static void getResultScann(String tableName) throws IOException { Scan scan = new Scan(); ResultScanner rs = null; HTable table = new HTable(conf, Bytes.toBytes(tableName)); try { rs = table.getScanner(scan); for (Result r : rs) { for (KeyValue kv : r.list()) { System.out.println("row:" + Bytes.toString(kv.getRow())); System.out.println("family:" + Bytes.toString(kv.getFamily())); System.out.println("qualifier:" + Bytes.toString(kv.getQualifier())); System.out .println("value:" + Bytes.toString(kv.getValue())); System.out.println("timestamp:" + kv.getTimestamp()); System.out .println("-------------------------------------------"); } } } finally { rs.close(); } } /* * 遍历查询hbase表 * * @tableName 表名 */ public static void getResultScann(String tableName, String start_rowkey, String stop_rowkey) throws IOException { Scan scan = new Scan(); scan.setStartRow(Bytes.toBytes(start_rowkey)); scan.setStopRow(Bytes.toBytes(stop_rowkey)); ResultScanner rs = null; HTable table = new HTable(conf, Bytes.toBytes(tableName)); try { rs = table.getScanner(scan); for (Result r : rs) { for (KeyValue kv : r.list()) { System.out.println("row:" + Bytes.toString(kv.getRow())); System.out.println("family:" + Bytes.toString(kv.getFamily())); System.out.println("qualifier:" + Bytes.toString(kv.getQualifier())); System.out .println("value:" + Bytes.toString(kv.getValue())); System.out.println("timestamp:" + kv.getTimestamp()); System.out .println("-------------------------------------------"); } } } finally { rs.close(); } } /* * 查询表中的某一列 * * @tableName 表名 * * @rowKey rowKey */ public static void getResultByColumn(String tableName, String rowKey, String familyName, String columnName) throws IOException { HTable table = new HTable(conf, Bytes.toBytes(tableName)); Get get = new Get(Bytes.toBytes(rowKey)); get.addColumn(Bytes.toBytes(familyName), Bytes.toBytes(columnName)); // 获取指定列族和列修饰符对应的列 Result result = table.get(get); for (KeyValue kv : result.list()) { System.out.println("family:" + Bytes.toString(kv.getFamily())); System.out .println("qualifier:" + Bytes.toString(kv.getQualifier())); System.out.println("value:" + Bytes.toString(kv.getValue())); System.out.println("Timestamp:" + kv.getTimestamp()); System.out.println("-------------------------------------------"); } } /* * 更新表中的某一列 * * @tableName 表名 * * @rowKey rowKey * * @familyName 列族名 * * @columnName 列名 * * @value 更新后的值 */ public static void updateTable(String tableName, String rowKey, String familyName, String columnName, String value) throws IOException { HTable table = new HTable(conf, Bytes.toBytes(tableName)); Put put = new Put(Bytes.toBytes(rowKey)); put.add(Bytes.toBytes(familyName), Bytes.toBytes(columnName), Bytes.toBytes(value)); table.put(put); System.out.println("update table Success!"); } /* * 查询某列数据的多个版本 * * @tableName 表名 * * @rowKey rowKey * * @familyName 列族名 * * @columnName 列名 */ public static void getResultByVersion(String tableName, String rowKey, String familyName, String columnName) throws IOException { HTable table = new HTable(conf, Bytes.toBytes(tableName)); Get get = new Get(Bytes.toBytes(rowKey)); get.addColumn(Bytes.toBytes(familyName), Bytes.toBytes(columnName)); get.setMaxVersions(5); Result result = table.get(get); for (KeyValue kv : result.list()) { System.out.println("family:" + Bytes.toString(kv.getFamily())); System.out .println("qualifier:" + Bytes.toString(kv.getQualifier())); System.out.println("value:" + Bytes.toString(kv.getValue())); System.out.println("Timestamp:" + kv.getTimestamp()); System.out.println("-------------------------------------------"); } /* * List< > results = table.get(get).list(); Iterator< > it = * results.iterator(); while (it.hasNext()) { * System.out.println(it.next().toString()); } */ } /* * 删除指定的列 * * @tableName 表名 * * @rowKey rowKey * * @familyName 列族名 * * @columnName 列名 */ public static void deleteColumn(String tableName, String rowKey, String falilyName, String columnName) throws IOException { HTable table = new HTable(conf, Bytes.toBytes(tableName)); Delete deleteColumn = new Delete(Bytes.toBytes(rowKey)); deleteColumn.deleteColumns(Bytes.toBytes(falilyName), Bytes.toBytes(columnName)); table.delete(deleteColumn); System.out.println(falilyName + ":" + columnName + "is deleted!"); } /* * 删除指定的列 * * @tableName 表名 * * @rowKey rowKey */ public static void deleteAllColumn(String tableName, String rowKey) throws IOException { HTable table = new HTable(conf, Bytes.toBytes(tableName)); Delete deleteAll = new Delete(Bytes.toBytes(rowKey)); table.delete(deleteAll); System.out.println("all columns are deleted!"); } /* * 删除表 * * @tableName 表名 */ public static void deleteTable(String tableName) throws IOException { HBaseAdmin admin = new HBaseAdmin(conf); admin.disableTable(tableName); admin.deleteTable(tableName); System.out.println(tableName + "is deleted!"); } public static void main(String[] args) throws Exception { // 创建表 String tableName = "blog2"; String[] family = { "article", "author" }; creatTable(tableName, family); // 为表添加数据 String[] column1 = { "title", "content", "tag" }; String[] value1 = { "Head First HBase", "HBase is the Hadoop database. Use it when you need random, realtime read/write access to your Big Data.", "Hadoop,HBase,NoSQL" }; String[] column2 = { "name", "nickname" }; String[] value2 = { "nicholas", "lee" }; addData("rowkey1", "blog2", column1, value1, column2, value2); addData("rowkey2", "blog2", column1, value1, column2, value2); addData("rowkey3", "blog2", column1, value1, column2, value2); // 遍历查询 getResultScann("blog2", "rowkey4", "rowkey5"); // 根据row key范围遍历查询 getResultScann("blog2", "rowkey4", "rowkey5"); // 查询 getResult("blog2", "rowkey1"); // 查询某一列的值 getResultByColumn("blog2", "rowkey1", "author", "name"); // 更新列 updateTable("blog2", "rowkey1", "author", "name", "bin"); // 查询某一列的值 getResultByColumn("blog2", "rowkey1", "author", "name"); // 查询某列的多版本 getResultByVersion("blog2", "rowkey1", "author", "name"); // 删除一列 deleteColumn("blog2", "rowkey1", "author", "nickname"); // 删除所有列 deleteAllColumn("blog2", "rowkey1"); // 删除表 deleteTable("blog2"); } }
大数据
2018-10-09 19:12:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
在将数据加载进Hive时,经常需要对数据进行初步的多文件合并,分隔符替换统一等初步数据清洗需求,针对此种场景可以使用shell简单高效的完成相关工作,一下简单总结记录。 将目录下的多个文件合并成一个文件 1、进入目录, cat a.txt b.txt c.txt > all.txt cat *.txt > all.txt 2、命令将当前目录下的文件合并 find . -type f -exec cat {} \;>all_files.txt 3、通过命名特征查询合并 find . -name "*.txt" | xargs cat > all.txt 4、合并并设置默认换行符 find . -name "*.txt" | xargs sed 'a\' > all_a.txt 替换文件中的字符串 1、将当前目录下包含jack串的文件中,jack字符串替换为tom sed -i "s/jack/tom/g" `grep "jack" -rl ./` 2、将某个文件中的jack字符串替换为tom sed -i "s/jack/tom/g" test.txt 3、替换fileName文件中的空格 sed s/[[:space:]]//g fileName 4、替换fileName文件中的空行 grep -v "^$" fileName 5、统计fileName文件中文本行数 awk 'END{print NR}' fileName 6、对fileName1文件中的内容进行去重并输出到fileName2中 cat fileName1 | sort -n | sort -u > fileName2 sort -n 表示 排序 sort -u 表示 去重 sort -r 表示 对当前排序取反 sort -o 可以重定向到原文件(即为在源文件上修改)
大数据
2018-10-09 17:38:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
背景
kafka早期作为一个日志消息系统,很受运维欢迎的,配合ELK玩起来很happy,在kafka慢慢的转向流式平台的过程中,开发也慢慢介入了,一些业务系统也开始和kafka对接起来了,也还是很受大家欢迎的,由于业务需要,一部分小白也就免不了接触kafka了,这些小白总是会安奈不住好奇心,要精确的查看kafka中的某一条数据,作为服务提供方,我也很方啊,该怎么怼?业务方不敢得罪啊,只能写consumer去消费,然后人肉查询。
需求
有什么方法能直接查询kafka中已有的数据呢?那时候presto就映入眼帘了,初步探索后发现presto确实强大,和我们在用的impala有的一拼,支持的数据源也更多,什么redis、mongo、kafka都可以用sql来查询,真是救星啊,这样那群小白就可以直接使用presto来查询里面的数据了。不过presto在不开发插件的情况下,对kafka的数据有格式要求,支持json、avro。关于presto的调研见 presto实战 。但是我只是想用sql查询kafka,而presto功能过于强大,必然整个框架就显得比较厚重了,功能多嘛。有什么轻量级的工具呢?
介绍
某一天,kafka的亲儿子KSQL就诞生了,KSQL是一个用于Apache kafka的流式SQL引擎,KSQL降低了进入流处理的门槛,提供了一个简单的、完全交互式的SQL接口,用于处理Kafka的数据,可以让我们在流数据上持续执行 SQL 查询,KSQL支持广泛的强大的流处理操作,包括聚合、连接、窗口、会话等等。
KSQL在内部使用Kafka的Streams API,并且它们共享与Kafka流处理相同的核心抽象,KSQL有两个核心抽象,它们对应于到Kafka Streams中的两个核心抽象,让你可以处理kafka的topic数据。关于这两个核心抽象下章节解读。
架构
部署架构
由一个KSQL服务器进程执行查询。一组KSQL进程可以作为集群运行。可以通过启动更多的KSQL实例来动态添加更多的处理能力。这些KSQL实例是容错的,如果一个实例失败了,其他的就会接管它的工作。查询是使用交互式的KSQL命令行客户端启动的,该客户端通过REST API向集群发送命令。命令行允许检查可用的stream和table,发出新的查询,检查状态并终止正在运行的查询。KSQL内部是使用Kafka的stream API构建的,它继承了它的弹性可伸缩性、先进的状态管理和容错功能,并支持Kafka最近引入的一次性处理语义。KSQL服务器将此嵌入到一个分布式SQL引擎中(包括一些用于查询性能的自动字节代码生成)和一个用于查询和控制的REST API。
处理架构
抽象概念
KSQL简化了流应用程序,它集成了stream和table的概念,允许使用表示现在发生的事件的stream来连接表示当前状态的table。 Apache Kafka中的一个topic可以表示为KSQL中的STREAM或TABLE,具体取决于topic处理的预期语义。下面看看两个核心的解读。
stream:流是无限制的结构化数据序列,stream中的fact是不可变的,这意味着可以将新fact插入到stream中,但是现有fact永远不会被更新或删除。 stream可以从Kafka topic创建,或者从现有的stream和table中派生。
table:一个table是一个stream或另一个table的视图,它代表了一个不断变化的fact的集合,它相当于传统的数据库表,但通过流化等流语义来丰富。表中的事实是可变的,这意味着可以将新的事实插入到表中,现有的事实可以被更新或删除。可以从Kafka主题中创建表,也可以从现有的流和表中派生表。
部署
ksql支持kafka0.11之后的版本,在confluent的V3和V4版本中默认并没有加入ksql server程序,当然V3和V4是支持ksql的,在V5版本中已经默认加入ksql了,为了方便演示,我们使用confluent kafka V5版本演示,zk和kafka也是单实例启动。
下载 wget https://packages.confluent.io/archive/5.0/confluent-oss-5.0.0-2.11.tar.gz tar zxvf confluent-oss-5.0.0-2.11.tar.gz -C /opt/programs/confluent_5.0.0
启动zk cd /opt/programs/confluent_5.0.0 bin/zookeeper-server-start -daemon etc/kafka/zookeeper.properties
启动kafka cd /opt/programs/confluent_5.0.0 bin/kafka-server-start -daemon etc/kafka/server.properties
创建topic和data
confluent自带了一个ksql-datagen工具,可以创建和产生相关的topic和数据,ksql-datagen可以指定的参数如下: [bootstrap-server= (defaults to localhost:9092)] [quickstart= (case-insensitive; one of 'orders', 'users', or 'pageviews')] schema= [schemaRegistryUrl= (defaults to http://localhost:8081)] format= (case-insensitive; one of 'avro', 'json', or 'delimited') topic= key= [iterations= (defaults to 1,000,000)] [maxInterval= (defaults to 500)] [propertiesFile=]
创建pageviews,数据格式为delimited cd /opt/programs/confluent_5.0.0/bin ./ksql-datagen quickstart=pageviews format=delimited topic=pageviews maxInterval=500
ps:以上命令会源源不断在stdin上输出数据,就是工具自己产生的数据,如下样例 8001 --> ([ 1539063767860 | 'User_6' | 'Page_77' ]) ts:1539063767860 8011 --> ([ 1539063767981 | 'User_9' | 'Page_75' ]) ts:1539063767981 8021 --> ([ 1539063768086 | 'User_5' | 'Page_16' ]) ts:1539063768086
不过使用consumer消费出来的数据是如下样式 1539066430530,User_5,Page_29 1539066430915,User_6,Page_74 1539066431192,User_4,Page_28 1539066431621,User_6,Page_38 1539066431772,User_7,Page_29 1539066432122,User_8,Page_34
创建users,数据格式为json cd /opt/programs/confluent_5.0.0/bin ./ksql-datagen quickstart=users format=json topic=users maxInterval=100
ps:以上命令会源源不断在stdin上输出数据,就是工具自己产生的数据,如下样例 User_5 --> ([ 1517896551436 | 'User_5' | 'Region_5' | 'MALE' ]) ts:1539063787413 User_7 --> ([ 1513998830510 | 'User_7' | 'Region_4' | 'MALE' ]) ts:1539063787430 User_6 --> ([ 1514865642822 | 'User_6' | 'Region_2' | 'MALE' ]) ts:1539063787481
不过使用consumer消费出来的数据是如下样式 {"registertime":1507118206666,"userid":"User_6","regionid":"Region_7","gender":"OTHER"} {"registertime":1506192314325,"userid":"User_1","regionid":"Region_1","gender":"MALE"} {"registertime":1489277749526,"userid":"User_6","regionid":"Region_4","gender":"FEMALE"} {"registertime":1497188917765,"userid":"User_9","regionid":"Region_3","gender":"OTHER"} {"registertime":1493121964253,"userid":"User_4","regionid":"Region_3","gender":"MALE"} {"registertime":1515609444511,"userid":"User_5","regionid":"Region_9","gender":"FEMALE"}
启动ksql cd /opt/programs/confluent_5.0.0 bin/ksql-server-start -daemon etc/ksql/ksql-server.properties
连接ksql cd /opt/programs/confluent_5.0.0 bin/ksql http://10.205.151.145:8088

创建stream和table
stream
根据topic pageviews创建一个stream pageviews_original,value_format为DELIMITED ksql>CREATE STREAM pageviews_original (viewtime bigint, userid varchar, pageid varchar) WITH \ (kafka_topic='pageviews', value_format='DELIMITED');
table
根据topic users创建一个table users_original,value_format为json ksql>CREATE TABLE users_original (registertime BIGINT, gender VARCHAR, regionid VARCHAR, userid VARCHAR) WITH \ (kafka_topic='users', value_format='JSON', key = 'userid');
查询数据 ksql> SELECT * FROM USERS_ORIGINAL LIMIT 3; ksql> SELECT * FROM pageviews_original LIMIT 3;
ps:ksql默认是从kafka最新的数据查询消费的,如果你想从开头查询,则需要在会话上进行设置:SET 'auto.offset.reset' = 'earliest';
持久化查询
持久化查询可以源源不断的把查询出的数据发送到你指定的topic中去,查询的时候在select前面添加create stream关键字即可创建持久化查询。
创建查询 ksql> CREATE STREAM pageviews2 AS SELECT userid FROM pageviews_original;
查询新stream ksql> SHOW STREAMS;
ps:可以看到新创建了stream PAGEVIEWS2,并且创建了topic PAGEVIEWS2
查询执行任务 ksql> SHOW QUERIES;
ps:可以看到ID为CSAS_PAGEVIEWS2_0的任务在执行,并且有显示执行的语句
消费新数据 cd /opt/programs/confluent_5.0.0/bin ./kafka-console-consumer --bootstrap-server 10.205.151.145:9092 --from-beginning --topic PAGEVIEWS2
ps:可以看到PAGEVIEWS2 topic里面正是我们通过select筛选出来的数据
终止查询任务 ksql> TERMINATE CSAS_PAGEVIEWS2_0;
大数据
2018-10-09 17:34:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
大数据分析:
大数据分析是指对规模巨大的数据进行分析。大数据可以概括为4个V, 数据量大(Volume)、速度快(Velocity)、类型多(Variety)、价值(Value)。
大数据作为时下最火热的IT行业的词汇,随之而来的数据仓库、数据安全、数据分析、数据挖掘等等围绕大数据的商业价值的利用逐渐成为行业人士争相追捧的利润焦点。随着大数据时代的来临,大数据分析也应运而生。
大数据分析的六个基本方面: Analytic Visualizations(可视化分析)
  不管是对数据分析专家还是普通用户,数据可视化是数据分析工具最基本的要求。可视化可以直观的展示数据,让数据自己说话,让观众听到结果。 Data Mining Algorithms(数据挖掘算法)
  可视化是给人看的,数据挖掘就是给机器看的。集群、分割、孤立点分析还有其他的算法让我们深入数据内部,挖掘价值。这些算法不仅要处理大数据的量,也要处理大数据的速度。 Predictive Analytic Capabilities(预测性分析能力)
  数据挖掘可以让分析员更好的理解数据,而预测性分析可以让分析员根据可视化分析和数据挖掘的结果做出一些预测性的判断。 Semantic Engines(语义引擎)
  我们知道由于非结构化数据的多样性带来了数据分析的新的挑战,我们需要一系列的工具去解析,提取,分析数据。语义引擎需要被设计成能够从“文档”中智能提取信息。 Data Quality and Master Data Management(数据质量和数据管理)
数据质量和数据管理是一些管理方面的最佳实践。通过标准化的流程和工具对数据进行处理可以保证一个预先定义好的高质量的分析结果。
假如大数据真的是下一个重要的技术革新的话,我们最好把精力关注在大数据能给我们带来的好处,而不仅仅是挑战。 数据存储,数据仓库
数据仓库是为了便于多维分析和多角度展示数据按特定模式进行存储所建立起来的关系型数据库。在商业智能系统的设计中,数据仓库的构建是关键,是商业智能系统的基础,承担对业务系统数据整合的任务,为商业智能系统提供数据抽取、转换和加载(ETL),并按主题对数据进行查询和访问,为联机数据分析和数据挖掘提供数据平台。
阿里云大学互联网学院: 大数据分析专业首页
掌握最前沿大数据分析知识,成为最优秀大数据分析工程师;
理论结合实战,掌握常用大数据分析平台及工具,实操企业大数据处理业务场景,带你快速掌握大数据分析在实际工作中的应用。
适用人群:
数据分析爱好者、开发者——准备从事大数据分析的开发者,其它互联网人员或大数据爱好者
学习时长:
5个月——每周3小时,全面掌握大数据分析工程师所需技能
先修知识:
数据分析基础知识——有SQL、机器学习算法、数学等基础知识
实战项目:
18个场景化项目——名师授课,掌握大数据分析实战项目最新技能
更多详情:
阿里云大学互联网学院首页 (专业制分班型教学,学完后可获取证书,找到理想工作)
大数据
2018-10-09 14:08:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
此示例演示用 pageoffice 在线打开编辑保存office 办公文档
需要用到的jar包( http://www.zhuozhengsoft.com/dowm/?v=4 )下载试用程序包
pageoffice4.5.0.4.jar
1.WEB.XML poserver com.zhuozhengsoft.pageoffice.poserver.Server poserver /poserver.zz poserver /sealsetup.exe poserver /posetup.exe poserver /pageoffice.js poserver /jquery.min.js poserver /pobstyle.css adminseal com.zhuozhengsoft.pageoffice.poserver.AdminSeal adminseal /adminseal.zz adminseal /loginseal.zz adminseal /sealimage.zz mht message/rfc822 adminseal-password 111111 chapter2 org.springframework.web.servlet.DispatcherServlet contextConfigLocation /WEB-INF/spring-servlet.xml 1 chapter2 *.do
2:spring-servlet.xml
3:JSP页面
(1):index.jsp
(2)WordOrExcel.jsp
<% PageOfficeCtrl poCtrl = (PageOfficeCtrl) request .getAttribute("pageoffice"); %> <%=poCtrl.getHtmlCode("PageOfficeCtrl1")%>

4:后台代码
打开文档代码 @RequestMapping("open") public String openword(HttpServletRequest request, HttpServletResponse response) { String type = request.getParameter("type"); PageOfficeCtrl poCtrl = new PageOfficeCtrl(request); // 设置服务器页面 poCtrl.setServerPage(request.getContextPath() + "/poserver.zz"); // 设置保存的action poCtrl.setSaveFilePage("savefile.do"); // 设置打开的文档 // 打开word if ("word".equals(type)) { poCtrl.webOpen("doc/test.doc", OpenModeType.docAdmin, "张三"); } if ("excel".equals(type)) { poCtrl.webOpen("doc/test.xls", OpenModeType.docAdmin, "张三"); } request.setAttribute("pageoffice", poCtrl); return "WordOrExcel"; }
保存代码 @RequestMapping("savefile") public void savefile(HttpServletRequest request, HttpServletResponse response){ FileSaver fs = new FileSaver(request, response); fs.saveToFile(request.getSession().getServletContext().getRealPath("doc/") + "/" + fs.getFileName()); fs.close(); }


最后打开文档的效果


打开文档的时候需要注册,这是一个试用的序列号
IMTG6-BSXJ-JGZ6-3BIWM
大数据
2018-10-09 13:06:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
很多牛逼的公司都宣称在建立数据科学部门,这个部门该如何组建,大家都在摸石头过河。O‘reilly Strata今年 六月份发布了报告 《Analyzing the Analyzers 》,比较清晰的阐述了数据科学部门所需要的不同角色及其技能。重点内容翻译如下:
数据科学家的分类研究方法
自我认识
请被调查者用常用的5级标准(从完全同意到完全不同意)来回答 “我觉得自己是一个XX” 这样的问题,能够获得数据科学家的自我认识结果。调查结果将数据科学家分为以下四类:Data Businesspeople、Data Creatives、Data Developer、Data Researchers。
技能需求
请被调查者对数据科学家所需的以下22项技能进行排序,分析不同类型的数据科学家的技能要求。其中的ML是机器学习的简写,OR指运筹学(Operations Research)
将它们结合起来分析
根据受访者的自我认知和技能排序,可以识别出不同类型的数据科学家所需要的技能。
大数据
2018-10-09 11:10:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
NO.1
索罗斯在1987年撰写的 《金融炼金术》 一书中,曾经提出过一个重要的命题:I believe the market prices are always wrong in the sense that they present a biased view of the future.
市场有效假说只是理论上的假设,实际上市场参与者并不总是理性的,并且在每一个时间点上,参与者不可能完全获取和客观解读所有的信息,再者就算是同样的信息,每个人的反馈都不尽相同。
也就是说,价格本身就已经包含了市场参与者的错误预期,所以本质上市场价格总错误的。这或许是套利者的利润来源。

NO.2
根据上述原理,我们也就知道,在一个非有效的期货市场中,不同时期交割合约之间受到市场影响也并不总是同步,其定价也并非完全有效的原因。
那么,根据同一种交易标的的不同时期交割合约价格为基础,如果两个价格出现了较大的价差幅度,就可以同时买卖不同时期的期货合约,进行跨期套利。
与商品期货一样,数字货币也有与之相关的跨期套利合约组合。如在 OkEX 交易所中就有:ETC 当周、ETC 次周、ETC 季度。
举个例子,假设 ETC 当周和 ETC 季度的价差长期维持在 5 左右。如果某一天价差达到 7,我们预计价差会在未来某段时间回归到 5。那么就可以卖出 ETC 当周,同时买入 ETC 季度,来做空这个价差。反之亦然。

NO.3
尽管这种价差是存在的,但是人工操作耗时、准确性差以及价格变化的影响,人工套利往往存在诸多不确定性。
通过量化模型捕捉套利机会并制定套利交易策略,以及程序化算法自动向交易所下达交易订单,快速准确捕捉机会,高效稳定赚取收益,这就是量化套利的魅力所在。

本篇将会教大家如何在数字货币交易中,利用发明者量化交易平台和 OkEX 交易所中 ETC 期货合约,以一个简单的套利策略,来演示如果捕捉瞬时的套利机会,把握住每一次可以看得到的利润,同时对冲有可能遇到的风险。

NO.4
创建一个数字货币跨期套利策略
难易度:普通级

策略环境 交易标的:以太经典(ETC) 价差数据:ETC 当周 - ETC 季度(省略协整性检验) 交易周期:5 分钟 头寸匹配:1:1 交易类型:同品种跨期

策略逻辑 做多价差开仓条件:如果当前账户没有持仓,并且价差小于 boll 下轨,就做多价差。即:买开 ETC 当周,卖开 ETC 季度。 做空价差开仓条件:如果当前账户没有持仓,并且价差大于 boll 上轨,就做空价差。即:卖开 ETC 当周,买开 ETC 季度。 做多价差平仓条件:如果当前账户持有 ETC 当周多单,并且持有 ETC 季度空单,并且价差大于 boll 中轨,就平多价差。即:卖平 ETC 当周,买平 ETC 季度。 做空价差平仓条件:如果当前账户持有 ETC 当周空单,并且持有 ETC 季度多单,并且价差小于 boll 中轨,就平空价差。即:买平 ETC 当周,卖平 ETC 季度。

NO.5
上面是一个简单的数字货币跨期套利策略逻辑描述,那么如何在程序中实现自己的想法呢?我们试着在发明者量化交易平台先把框架搭建起来。

策略框架: /* 全局变量 */ // 基础数据 function Data(tradeTypeA, tradeTypeB) {} // 获取持仓 Data.prototype.mp = function (tradeType, type) {} // 合成新K线数据和boll指标数据 Data.prototype.boll = function (num, timeCycle) {} // 下单 Data.prototype.trade = function (tradeType, type) {} // 取消订单 Data.prototype.cancelOrders = function () {} // 处理持有单个合约 Data.prototype.isEven = function () {} // 画图 Data.prototype.drawingChart = function (boll) {} // 交易条件 function onTick() { var data; // 获取基础数据对象 data.accountData.Stocks; // 获取账户余额 data.boll; // 获取boll指标数据 data.mp; // 获取持仓状态 data.cancelOrders(); // 撤单 data.drawingChart(boll); // 画图 data.isEven(); // 处理持有单个合约 } //入口函数 function main() { /* 交易策略预处理 */ while (true) { // 进入轮询模式 onTick(); // 执行onTick函数 Sleep(500); // 休眠0.5秒 } }
对照着策略思路以及交易流程,可以很轻松把策略框架搭建起来。整个策略可以简化为三个步骤: 交易前预处理。 获取并计算数据。获取并计算数据。 下单并对后续处理。下单并对后续处理。

NO.6
接下来,我们就需要根据实际交易流程和交易细节,在策略框架里面填充必要的细节代码。

一、交易前预处理
第1步:在全局环境中,声明必要的全局变量。 声明一个配置图表的 chart 对象 var chart = { } 调用 Chart 函数,初始化图表 var ObjChart = Chart ( chart ) 声明一个空数组,用来存储价差序列 var bars = [ ] 声明一个记录历史数据时间戳变量 var oldTime = 0

第2步:配置策略的外部参数。

第3步:定义数据处理函数
基础数据函数:Data ( )
创建一个构造函数 Data,并定义它的内部属性。包括:账户数据、持仓数据、K线数据时间戳、套利A/B合约的买/卖一价、正/反套价差。 // 基础数据 function Data(tradeTypeA, tradeTypeB) { // 传入套利A合约和套利B合约 this.accountData = _C(exchange.GetAccount); // 获取账户信息 this.positionData = _C(exchange.GetPosition); // 获取持仓信息 var recordsData = _C(exchange.GetRecords); //获取K线数据 exchange.SetContractType(tradeTypeA); // 订阅套利A合约 var depthDataA = _C(exchange.GetDepth); // 套利A合约深度数据 exchange.SetContractType(tradeTypeB); // 订阅套利B合约 var depthDataB = _C(exchange.GetDepth); // 套利B合约深度数据 this.time = recordsData[recordsData.length - 1].Time; // 获取最新数据时间 this.askA = depthDataA.Asks[0].Price; // 套利A合约卖一价 this.bidA = depthDataA.Bids[0].Price; // 套利A合约买一价 this.askB = depthDataB.Asks[0].Price; // 套利B合约卖一价 this.bidB = depthDataB.Bids[0].Price; // 套利B合约买一价 // 正套价差(合约A卖一价 - 合约B买一价) this.basb = depthDataA.Asks[0].Price - depthDataB.Bids[0].Price; // 反套价差(合约A买一价 - 合约B卖一价) this.sabb = depthDataA.Bids[0].Price - depthDataB.Asks[0].Price; }


获取持仓函数:mp ( )
遍历整个持仓数组,返回指定合约、指定方向的持仓数量,如果没有就返回 false // 获取持仓 Data.prototype.mp = function (tradeType, type) { var positionData = this.positionData; // 获取持仓信息 for (var i = 0; i < positionData.length; i++) { if (positionData[i].ContractType == tradeType) { if (positionData[i].Type == type) { if (positionData[i].Amount > 0) { return positionData[i].Amount; } } } } return false; }

K线和指标函数:boll ( )
根据正/反套价差数据,合成新的K线序列。并返回由boll指标计算的上轨、中轨、下轨数据。 // 合成新K线数据和boll指标数据 Data.prototype.boll = function (num, timeCycle) { var self = {}; // 临时对象 // 正套价差和反套价差中间值 self.Close = (this.basb + this.sabb) / 2; if (this.timeA == this.timeB) { self.Time = this.time; } // 对比两个深度数据时间戳 if (this.time - oldTime > timeCycle * 60000) { bars.push(self); oldTime = this.time; } // 根据指定时间周期,在K线数组里面传入价差数据对象 if (bars.length > num * 2) { bars.shift(); // 控制K线数组长度 } else { return; } var boll = TA.BOLL(bars, num, 2); // 调用talib库中的boll指标 return { up: boll[0][boll[0].length - 1], // boll指标上轨 middle: boll[1][boll[1].length - 1], // boll指标中轨 down: boll[2][boll[2].length - 1] // boll指标下轨 } // 返回一个处理好的boll指标数据 }

下单函数:trade ( )
传入下单合约名称和下单类型,然后以对价下单,并返回下单后的结果。由于需要同时下两个不同方向的单子,所以在函数内部根据下单合约名称对买/卖一价做了转换。 // 下单 Data.prototype.trade = function (tradeType, type) { exchange.SetContractType(tradeType); // 下单前先重新订阅合约 var askPrice, bidPrice; if (tradeType == tradeTypeA) { // 如果是A合约下单 askPrice = this.askA; // 设置askPrice bidPrice = this.bidA; // 设置bidPrice } else if (tradeType == tradeTypeB) { // 如果是B合约下单 askPrice = this.askB; // 设置askPrice bidPrice = this.bidB; // 设置bidPrice } switch (type) { // 匹配下单模式 case "buy": exchange.SetDirection(type); // 设置下单模式 return exchange.Buy(askPrice, unit); case "sell": exchange.SetDirection(type); // 设置下单模式 return exchange.Sell(bidPrice, unit); case "closebuy": exchange.SetDirection(type); // 设置下单模式 return exchange.Sell(bidPrice, unit); case "closesell": exchange.SetDirection(type); // 设置下单模式 return exchange.Buy(askPrice, unit); default: return false; } }

取消订单函数:cancelOrders ( )
获取所有未成交订单数组,并逐个取消。并且如果有未成交的订单就返回false,如果没有未成交的订单就返回true。 // 取消订单 Data.prototype.cancelOrders = function () { Sleep(500); // 撤单前先延时,因为有些交易所你懂的 var orders = _C(exchange.GetOrders); // 获取未成交订单数组 if (orders.length > 0) { // 如果有未成交的订单 for (var i = 0; i < orders.length; i++) { //遍历未成交订单数组 exchange.CancelOrder(orders[i].Id); //逐个取消未成交的订单 Sleep(500); //延时0.5秒 } return false; // 如果取消了未成交的单子就返回false } return true; //如果没有未成交的订单就返回true }


处理持有单个合约:isEven ( )
在处理套利交易中出现单腿情况,这里直接用简单的平掉所有仓位处理。当然,也可以改为追单方式。 // 处理持有单个合约 Data.prototype.isEven = function () { var positionData = this.positionData; // 获取持仓信息 var type = null; // 转换持仓方向 // 如果持仓数组长度余2不等于0或者持仓数组长度不等于2 if (positionData.length % 2 != 0 || positionData.length != 2) { for (var i = 0; i < positionData.length; i++) { // 遍历持仓数组 if (positionData[i].Type == 0) { // 如果是多单 type = 10; // 设置下单参数 } else if (positionData[i].Type == 1) { // 如果是空单 type = -10; // 设置下单参数 } // 平掉所有仓位 this.trade(positionData[i].ContractType, type, positionData[i].Amount); } } }

画图函数:drawingChart ( )
调用 ObjChart.add ( ) 方法,在图表中画出必要的行情数据和指标数据:上轨、中轨、下轨、正/反套价差。 // 画图 Data.prototype.drawingChart = function (boll) { var nowTime = new Date().getTime(); ObjChart.add([0, [nowTime, boll.up]]); ObjChart.add([1, [nowTime, boll.middle]]); ObjChart.add([2, [nowTime, boll.down]]); ObjChart.add([3, [nowTime, this.basb]]); ObjChart.add([4, [nowTime, this.sabb]]); ObjChart.update(chart); }

第4步:在入口函数 main ( ) 里面,执行交易前预处理代码,这些代码在程序启动后,只运行一次。包括: 过滤控制台中不是很重要的信息 SetErrorFilter ( ) 设置要交易的数字货币币种 exchange.IO ( ) 程序启动前清空之前绘制的图表 ObjChart.reset ( ) 程序启动前清空之前的状态栏信息 LogProfitReset ( ) //入口函数 function main() { // 过滤控制台中不是很重要的信息 SetErrorFilter("429|GetRecords:|GetOrders:|GetDepth:|GetAccount|:Buy|Sell|timeout|Futures_OP"); exchange.IO("currency", name + '_USDT'); //设置要交易的数字货币币种 ObjChart.reset(); //程序启动前清空之前绘制的图表 LogProfitReset(); //程序启动前清空之前的状态栏信息 }


NO.7
定义完上述的交易前预处理,紧接着就要进入下一个步骤,进入轮询模式,重复执行 onTick ( ) 函数。
并设置 Sleep ( ) 轮询时的休眠时间,因为部分数字货币交易所的 API 对一定时间内内置了访问次数限制。 //入口函数 function main() { // 过滤控制台中不是很重要的信息 SetErrorFilter("429|GetRecords:|GetOrders:|GetDepth:|GetAccount|:Buy|Sell|timeout|Futures_OP"); exchange.IO("currency", name + '_USDT'); //设置要交易的数字货币币种 ObjChart.reset(); //程序启动前清空之前绘制的图表 LogProfitReset(); //程序启动前清空之前的状态栏信息 while (true) { // 进入轮询模式 onTick(); // 执行onTick函数 Sleep(500); // 休眠0.5秒 } }


二、获取并计算数据
第1步:获取基础数据对象、账户余额、boll 指标数据,以供交易逻辑使用。 // 交易条件 function onTick() { var data = new Data(tradeTypeA, tradeTypeB); // 创建一个基础数据对象 var accountStocks = data.accountData.Stocks; // 账户余额 var boll = data.boll(dataLength, timeCycle); // 获取boll指标数据 if (!boll) return; // 如果没有boll数据就返回 }


三、下单并对后续处理
第1步:根据上述的策略逻辑,执行买卖操作。首先会判断价格和指标条件是否成立,然后再判断持仓条件是否成立,最后执行 trade ( ) 下单函数 // 交易条件 function onTick() { var data = new Data(tradeTypeA, tradeTypeB); // 创建一个基础数据对象 var accountStocks = data.accountData.Stocks; // 账户余额 var boll = data.boll(dataLength, timeCycle); // 获取boll指标数据 if (!boll) return; // 如果没有boll数据就返回 // 价差说明 // basb = (合约A卖一价 - 合约B买一价) // sabb = (合约A买一价 - 合约B卖一价) if (data.sabb > boll.middle && data.sabb < boll.up) { // 如果sabb高于中轨 if (data.mp(tradeTypeA, 0)) { // 下单前检测合约A是否有多单 data.trade(tradeTypeA, "closebuy"); // 合约A平多 } if (data.mp(tradeTypeB, 1)) { // 下单前检测合约B是否有空单 data.trade(tradeTypeB, "closesell"); // 合约B平空 } } else if (data.basb < boll.middle && data.basb > boll.down) { // 如果basb低于中轨 if (data.mp(tradeTypeA, 1)) { // 下单前检测合约A是否有空单 data.trade(tradeTypeA, "closesell"); // 合约A平空 } if (data.mp(tradeTypeB, 0)) { // 下单前检测合约B是否有多单 data.trade(tradeTypeB, "closebuy"); // 合约B平多 } } if (accountStocks * Math.max(data.askA, data.askB) > 1) { // 如果账户有余额 if (data.basb < boll.down) { // 如果basb价差低于下轨 if (!data.mp(tradeTypeA, 0)) { // 下单前检测合约A是否有多单 data.trade(tradeTypeA, "buy"); // 合约A开多 } if (!data.mp(tradeTypeB, 1)) { // 下单前检测合约B是否有空单 data.trade(tradeTypeB, "sell"); // 合约B开空 } } else if (data.sabb > boll.up) { // 如果sabb价差高于上轨 if (!data.mp(tradeTypeA, 1)) { // 下单前检测合约A是否有空单 data.trade(tradeTypeA, "sell"); // 合约A开空 } if (!data.mp(tradeTypeB, 0)) { // 下单前检测合约B是否有多单 data.trade(tradeTypeB, "buy"); // 合约B开多 } } } }

第2步:下单完成后,需要对未成交的订单、持有单个合约等非正常情况做处理。以及绘制图表。 // 交易条件 function onTick() { var data = new Data(tradeTypeA, tradeTypeB); // 创建一个基础数据对象 var accountStocks = data.accountData.Stocks; // 账户余额 var boll = data.boll(dataLength, timeCycle); // 获取boll指标数据 if (!boll) return; // 如果没有boll数据就返回 // 价差说明 // basb = (合约A卖一价 - 合约B买一价) // sabb = (合约A买一价 - 合约B卖一价) if (data.sabb > boll.middle && data.sabb < boll.up) { // 如果sabb高于中轨 if (data.mp(tradeTypeA, 0)) { // 下单前检测合约A是否有多单 data.trade(tradeTypeA, "closebuy"); // 合约A平多 } if (data.mp(tradeTypeB, 1)) { // 下单前检测合约B是否有空单 data.trade(tradeTypeB, "closesell"); // 合约B平空 } } else if (data.basb < boll.middle && data.basb > boll.down) { // 如果basb低于中轨 if (data.mp(tradeTypeA, 1)) { // 下单前检测合约A是否有空单 data.trade(tradeTypeA, "closesell"); // 合约A平空 } if (data.mp(tradeTypeB, 0)) { // 下单前检测合约B是否有多单 data.trade(tradeTypeB, "closebuy"); // 合约B平多 } } if (accountStocks * Math.max(data.askA, data.askB) > 1) { // 如果账户有余额 if (data.basb < boll.down) { // 如果basb价差低于下轨 if (!data.mp(tradeTypeA, 0)) { // 下单前检测合约A是否有多单 data.trade(tradeTypeA, "buy"); // 合约A开多 } if (!data.mp(tradeTypeB, 1)) { // 下单前检测合约B是否有空单 data.trade(tradeTypeB, "sell"); // 合约B开空 } } else if (data.sabb > boll.up) { // 如果sabb价差高于上轨 if (!data.mp(tradeTypeA, 1)) { // 下单前检测合约A是否有空单 data.trade(tradeTypeA, "sell"); // 合约A开空 } if (!data.mp(tradeTypeB, 0)) { // 下单前检测合约B是否有多单 data.trade(tradeTypeB, "buy"); // 合约B开多 } } } data.cancelOrders(); // 撤单 data.drawingChart(boll); // 画图 data.isEven(); // 处理持有单个合约 }


NO.8
以上,我们通过 200 多行,就把一个简单的数字货币跨期套利策略完完整整的创建出来。完整的代码如下: // 全局变量 // 声明一个配置图表的 chart 对象 var chart = { __isStock: true, tooltip: { xDateFormat: '%Y-%m-%d %H:%M:%S, %A' }, title: { text: '交易盈亏曲线图(详细)' }, rangeSelector: { buttons: [{ type: 'hour', count: 1, text: '1h' }, { type: 'hour', count: 2, text: '3h' }, { type: 'hour', count: 8, text: '8h' }, { type: 'all', text: 'All' }], selected: 0, inputEnabled: false }, xAxis: { type: 'datetime' }, yAxis: { title: { text: '价差' }, opposite: false, }, series: [{ name: "上轨", id: "线1,up", data: [] }, { name: "中轨", id: "线2,middle", data: [] }, { name: "下轨", id: "线3,down", data: [] }, { name: "basb", id: "线4,basb", data: [] }, { name: "sabb", id: "线5,sabb", data: [] }] }; var ObjChart = Chart(chart); // 画图对象 var bars = []; // 存储价差序列 var oldTime = 0; // 记录历史数据时间戳 // 参数 var tradeTypeA = "this_week"; // 套利A合约 var tradeTypeB = "quarter"; // 套利B合约 var dataLength = 10; //指标周期长度 var timeCycle = 1; // K线周期 var name = "ETC"; // 币种 var unit = 1; // 下单量 // 基础数据 function Data(tradeTypeA, tradeTypeB) { // 传入套利A合约和套利B合约 this.accountData = _C(exchange.GetAccount); // 获取账户信息 this.positionData = _C(exchange.GetPosition); // 获取持仓信息 var recordsData = _C(exchange.GetRecords); //获取K线数据 exchange.SetContractType(tradeTypeA); // 订阅套利A合约 var depthDataA = _C(exchange.GetDepth); // 套利A合约深度数据 exchange.SetContractType(tradeTypeB); // 订阅套利B合约 var depthDataB = _C(exchange.GetDepth); // 套利B合约深度数据 this.time = recordsData[recordsData.length - 1].Time; // 获取最新数据时间 this.askA = depthDataA.Asks[0].Price; // 套利A合约卖一价 this.bidA = depthDataA.Bids[0].Price; // 套利A合约买一价 this.askB = depthDataB.Asks[0].Price; // 套利B合约卖一价 this.bidB = depthDataB.Bids[0].Price; // 套利B合约买一价 // 正套价差(合约A卖一价 - 合约B买一价) this.basb = depthDataA.Asks[0].Price - depthDataB.Bids[0].Price; // 反套价差(合约A买一价 - 合约B卖一价) this.sabb = depthDataA.Bids[0].Price - depthDataB.Asks[0].Price; } // 获取持仓 Data.prototype.mp = function (tradeType, type) { var positionData = this.positionData; // 获取持仓信息 for (var i = 0; i < positionData.length; i++) { if (positionData[i].ContractType == tradeType) { if (positionData[i].Type == type) { if (positionData[i].Amount > 0) { return positionData[i].Amount; } } } } return false; } // 合成新K线数据和boll指标数据 Data.prototype.boll = function (num, timeCycle) { var self = {}; // 临时对象 // 正套价差和反套价差中间值 self.Close = (this.basb + this.sabb) / 2; if (this.timeA == this.timeB) { self.Time = this.time; } // 对比两个深度数据时间戳 if (this.time - oldTime > timeCycle * 60000) { bars.push(self); oldTime = this.time; } // 根据指定时间周期,在K线数组里面传入价差数据对象 if (bars.length > num * 2) { bars.shift(); // 控制K线数组长度 } else { return; } var boll = TA.BOLL(bars, num, 2); // 调用talib库中的boll指标 return { up: boll[0][boll[0].length - 1], // boll指标上轨 middle: boll[1][boll[1].length - 1], // boll指标中轨 down: boll[2][boll[2].length - 1] // boll指标下轨 } // 返回一个处理好的boll指标数据 } // 下单 Data.prototype.trade = function (tradeType, type) { exchange.SetContractType(tradeType); // 下单前先重新订阅合约 var askPrice, bidPrice; if (tradeType == tradeTypeA) { // 如果是A合约下单 askPrice = this.askA; // 设置askPrice bidPrice = this.bidA; // 设置bidPrice } else if (tradeType == tradeTypeB) { // 如果是B合约下单 askPrice = this.askB; // 设置askPrice bidPrice = this.bidB; // 设置bidPrice } switch (type) { // 匹配下单模式 case "buy": exchange.SetDirection(type); // 设置下单模式 return exchange.Buy(askPrice, unit); case "sell": exchange.SetDirection(type); // 设置下单模式 return exchange.Sell(bidPrice, unit); case "closebuy": exchange.SetDirection(type); // 设置下单模式 return exchange.Sell(bidPrice, unit); case "closesell": exchange.SetDirection(type); // 设置下单模式 return exchange.Buy(askPrice, unit); default: return false; } } // 取消订单 Data.prototype.cancelOrders = function () { Sleep(500); // 撤单前先延时,因为有些交易所你懂的 var orders = _C(exchange.GetOrders); // 获取未成交订单数组 if (orders.length > 0) { // 如果有未成交的订单 for (var i = 0; i < orders.length; i++) { //遍历未成交订单数组 exchange.CancelOrder(orders[i].Id); //逐个取消未成交的订单 Sleep(500); //延时0.5秒 } return false; // 如果取消了未成交的单子就返回false } return true; //如果没有未成交的订单就返回true } // 处理持有单个合约 Data.prototype.isEven = function () { var positionData = this.positionData; // 获取持仓信息 var type = null; // 转换持仓方向 // 如果持仓数组长度余2不等于0或者持仓数组长度不等于2 if (positionData.length % 2 != 0 || positionData.length != 2) { for (var i = 0; i < positionData.length; i++) { // 遍历持仓数组 if (positionData[i].Type == 0) { // 如果是多单 type = 10; // 设置下单参数 } else if (positionData[i].Type == 1) { // 如果是空单 type = -10; // 设置下单参数 } // 平掉所有仓位 this.trade(positionData[i].ContractType, type, positionData[i].Amount); } } } // 画图 Data.prototype.drawingChart = function (boll) { var nowTime = new Date().getTime(); ObjChart.add([0, [nowTime, boll.up]]); ObjChart.add([1, [nowTime, boll.middle]]); ObjChart.add([2, [nowTime, boll.down]]); ObjChart.add([3, [nowTime, this.basb]]); ObjChart.add([4, [nowTime, this.sabb]]); ObjChart.update(chart); } // 交易条件 function onTick() { var data = new Data(tradeTypeA, tradeTypeB); // 创建一个基础数据对象 var accountStocks = data.accountData.Stocks; // 账户余额 var boll = data.boll(dataLength, timeCycle); // 获取boll指标数据 if (!boll) return; // 如果没有boll数据就返回 // 价差说明 // basb = (合约A卖一价 - 合约B买一价) // sabb = (合约A买一价 - 合约B卖一价) if (data.sabb > boll.middle && data.sabb < boll.up) { // 如果sabb高于中轨 if (data.mp(tradeTypeA, 0)) { // 下单前检测合约A是否有多单 data.trade(tradeTypeA, "closebuy"); // 合约A平多 } if (data.mp(tradeTypeB, 1)) { // 下单前检测合约B是否有空单 data.trade(tradeTypeB, "closesell"); // 合约B平空 } } else if (data.basb < boll.middle && data.basb > boll.down) { // 如果basb低于中轨 if (data.mp(tradeTypeA, 1)) { // 下单前检测合约A是否有空单 data.trade(tradeTypeA, "closesell"); // 合约A平空 } if (data.mp(tradeTypeB, 0)) { // 下单前检测合约B是否有多单 data.trade(tradeTypeB, "closebuy"); // 合约B平多 } } if (accountStocks * Math.max(data.askA, data.askB) > 1) { // 如果账户有余额 if (data.basb < boll.down) { // 如果basb价差低于下轨 if (!data.mp(tradeTypeA, 0)) { // 下单前检测合约A是否有多单 data.trade(tradeTypeA, "buy"); // 合约A开多 } if (!data.mp(tradeTypeB, 1)) { // 下单前检测合约B是否有空单 data.trade(tradeTypeB, "sell"); // 合约B开空 } } else if (data.sabb > boll.up) { // 如果sabb价差高于上轨 if (!data.mp(tradeTypeA, 1)) { // 下单前检测合约A是否有空单 data.trade(tradeTypeA, "sell"); // 合约A开空 } if (!data.mp(tradeTypeB, 0)) { // 下单前检测合约B是否有多单 data.trade(tradeTypeB, "buy"); // 合约B开多 } } } data.cancelOrders(); // 撤单 data.drawingChart(boll); // 画图 data.isEven(); // 处理持有单个合约 } //入口函数 function main() { // 过滤控制台中不是很重要的信息 SetErrorFilter("429|GetRecords:|GetOrders:|GetDepth:|GetAccount|:Buy|Sell|timeout|Futures_OP"); exchange.IO("currency", name + '_USDT'); //设置要交易的数字货币币种 ObjChart.reset(); //程序启动前清空之前绘制的图表 LogProfitReset(); //程序启动前清空之前的状态栏信息 while (true) { // 进入轮询模式 onTick(); // 执行onTick函数 Sleep(500); // 休眠0.5秒 } }


NO.9
本篇策略只是一个抛砖引玉,真实的实盘可不是这么简单,不过你可以照着例子发挥自己天马行空的想象。
需要提醒大家的是,以我有限的经验来看,目前的数字货币市场状况,纯粹的期期套利策略基本上全部不值得跑,不论是无风险的三角套利还是跨市场套利。
原因就在于,无论哪个数字货币交易所的期货市场,其保证金不是法币。现如今几乎所有的数字货币从今年初至今已经下跌了70%左右。也就是说策略始终都是在赚币,但是币价是下跌的。

放眼望去,数字货币市场俨然已经脱离了区块链,就像当年的郁金香一样,价格始终来自于人们的预期和信心,信心又来源于价格…

原文链接: https://quant.la/Article/View/816
大数据
2018-10-09 10:11:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
Burrow是个什么东西?这里就不做详细介绍了,之前写过相关文章 Linkedin Burrow ,本文只是实战最新版v1.1.0。最新版的配置和接口和之前的老版有些区别,github上项目还在更新,希望不要成为一个僵尸项目。
环境
监控kafka集群信息:
zookeeper:10.207.23.31:12181
kafka:10.207.23.31:19092,10.207.23.32:19092,10.207.23.33:19092,10.207.23.34:19092,10.207.23.35:19092
burrow环境信息:
zookeeper:10.205.151.145:2181
部署
之前的版本部署需要自己安装一大堆依赖,然后自己使用go来编译,不过现在github已经有每个版本预编译好的版本,可以下载下来直接使用 https://github.com/linkedin/Burrow/releases
ps:下载1.1.0版本即可
配置
burrow是一个go编写的二进制程序,只需要一个配置文件即可,burrow.toml [general] pidfile="/opt/programs/burrow_1.1.0/logs/burrow.pid" stdout-logfile="/opt/programs/burrow_1.1.0/logs/burrow.out" [logging] filename="/opt/programs/burrow_1.1.0/logs/burrow.log" level="info" maxsize=100 maxbackups=30 maxage=10 use-localtime=true use-compression=true [zookeeper] servers=[ "10.205.151.145:2181" ] timeout=6 root-path="/burrow" [cluster.jijin] class-name="kafka" servers=[ "10.207.23.31:19092", "10.207.23.32:19092", "10.207.23.33:19092", "10.207.23.34:19092", "10.207.23.35:19092", "10.207.23.36:19092", "10.207.23.37:19092", "10.207.23.38:19092", "10.207.23.39:19092" ] topic-refresh=120 offset-refresh=30 [consumer.jijin] class-name="kafka_zk" cluster="jijin" servers=[ "10.207.23.31:12181", "10.207.23.32:12181", "10.207.23.33:12181", "10.207.23.34:12181", "10.207.23.35:12181" ] [httpserver.default] address="10.205.151.145:8008" [storage.default] class-name="inmemory" workers=20 intervals=15 expire-group=604800 min-distance=1 [evaluator.mystorage] class-name="caching" expire-cache=10
ps:要注意kafka集群的版本,如果是0.8及之前的版本,consumer信息存储在zookeeper中,如果是0.8之后的版本,consumer信息存储在该kafka集群的__consumer_offsets topic中,版本的不同也会导致配置文件配置consumer参数的不同。
启动 cd /opt/programs/burrow_1.1.0 ./bin/burrow --config-dir ./config/
接口
Request Method URL Format Healthcheck GET /burrow/admin
List Clusters GET /v3/kafka
Kafka Cluster Detail GET /v3/kafka/(cluster)
List Consumers GET /v3/kafka/(cluster)/consumer
List Cluster Topics GET /v3/kafka/(cluster)/topic
Get Consumer Detail GET /v3/kafka/(cluster)/consumer/(group)
Consumer Group Status GET /v3/kafka/(cluster)/consumer/(group)/status /v3/kafka/(cluster)/consumer/(group)/lag
Remove Consumer Group DELETE /v3/kafka/(cluster)/consumer/(group)
Get Topic Detail GET /v3/kafka/(cluster)/topic/(topic)
Get General Config GET /v3/config
List Cluster Modules GET /v3/config/cluster
Get Cluster Module Config GET /v3/config/cluster/(name)
List Consumer Modules GET /v3/config/consumer
Get Consumer Module Config GET /v3/config/consumer/(name)
List Notifier Modules GET /v3/config/notifier
Get Notifier Module Config GET /v3/config/notifier/(name)
List Evaluator Modules GET /v3/config/evaluator
Get Evaluator Module Config GET /v3/config/evaluator/(name)
List Storage Modules GET /v3/config/storage
Get Storage Module Config GET /v3/config/storage/(name)
Get Log Level
Set Log Level
GET
POST
/v3/admin/loglevel
/v3/admin/loglevel
测试
list cluster curl -s http://10.205.151.145:8008/v3/kafka
cluster detail curl -s http://10.205.151.145:8008/v3/kafka/jijin
list consumers curl -s http://10.205.151.145:8008/v3/kafka/jijin/consumer
list consumer detail curl -s http://10.205.151.145:8008/v3/kafka/jijin/consumer/bd-zp-prd-kafka1
更好的输出 https://github.com/dmitryilyin/burrow-client.git
cluster信息
topic信息
consumer信息
status信息
partitions信息
总结
目前市面上还没有很好的kafka consumer lag消费监控工具,而burrow是目前开源的、轻量级更容易上手的监控工具,配合http api可以对接到各自的内部监控系统中。

大数据
2018-10-09 09:09:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
下载安装包
Apache Hadoop 官网下载hadoop安装包 hadoop-3.1.1,并解压。 [root@d1 local]# pwd /usr/local [root@d1 local]# tar -zxvf hadoop-3.1.1 [root@d1 local]# chown root:root -R hadoop-3.1.1 [root@d1 local]# ln -s hadoop-3.1.1 hadoop
修改配置
修改解压后的目录中的文件夹etc/hadoop下的xml配置文件(如果文件不存在,则自己创建)
hadoop-env.sh修改以下配置: [root@d1 hadoop]# pwd /usr/local/hadoop [root@d1 hadoop]# vi etc/hadoop/hadoop-env.sh export JAVA_HOME=/usr/java/jdk1.8.0_181-amd64 export HDFS_NAMENODE_USER=root export HDFS_DATANODE_USER=root export HDFS_SECONDARYNAMENODE_USER=root export YARN_RESOURCEMANAGER_USER=root export YARN_NODEMANAGER_USER=root
slaves文件修改为以下配置: [root@d1 hadoop]# vi etc/hadoop/slaves d1
注:以下四个XML配置文件,需在标签之间增加配置项。 [root@d1 hadoop]# vi etc/hadoop/mapred-site.xml mapreduce.framework.name yarn
core-site.xml(其中“d1”是在/etc/hosts中设置的host,如果未设置,则换为localhost): [root@d1 hadoop]# vi etc/hadoop/core-site.xml fs.default.name hdfs://d1:9000 dfs.replication 1 hadoop.tmp.dir /hadoop/hadoop_tmp_dir dfs.namenode.name.dir /hadoop/dfs/name dfs.datanode.data.dir /hadoop/dfs/data
yarn-site.xml: [root@d1 hadoop]# vi etc/hadoop/yarn-site.xml yarn.nodemanager.aux-services mapreduce_shuffle
启动服务
格式化HDFS: bin/hdfs namenode -format
启动HDFS: sbin/start-dfs.sh
启动YARN: sbin/start-yarn.sh
验证是否启动成功 [root@d1 hadoop]# jps 21697 Jps 20612 SecondaryNameNode 20308 NameNode 20933 NodeManager 20827 ResourceManager 20414 DataNode [root@d1 hadoop]#
参照:http://hadoop.apache.org/docs/stable/hadoop-project-dist/hadoop-common/SingleCluster.html
大数据
2018-10-09 08:21:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
环境信息
完全分布式集群(一)集群基础环境及zookeeper-3.4.10安装部署
创建用户用户组
在集群中各个节点执行以下命令,创建hadoop用户组,hadoop用户,设置hadoop用户的密码 groupadd hadoop useradd -g hadoop hadoop passwd hadoop
解压授权
通过FTP上传hadoop-2.6.5.tar.gz安装包,解压至/usr/local/目录,并将解压后的目录授权给hadoop用户 gtar -xzf /home/hadoop/hadoop-2.6.5.tar.gz -C /usr/local/ chown -R hadoop:hadoop /usr/local/hadoop-2.6.5
配置免密码登录
集群节点间需要相互调用访问,所以需要在各节点上配置hadoop用户免密码登录,注意此处包括节点本身也要设置免密码登录 # 每个节点上执行,切换至hadoop用户,生成各节点秘钥对 su - hadoop ssh-keygen -t rsa # 一路回车完成 Generating public/private rsa key pair. Enter file in which to save the key (/home/hadoop/.ssh/id_rsa): Created directory '/home/hadoop/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/hadoop/.ssh/id_rsa. Your public key has been saved in /home/hadoop/.ssh/id_rsa.pub. The key fingerprint is: 7f:f2:71:39:b8:9d:20:6b:9b:03:7d:f8:ab:a1:6d:b5 hadoop@node222 The key's randomart image is: +--[ RSA 2048]----+ | | | | | | | | | S. . | | ..o o. . | | .=+=.+ | | o+OE* o | | .o*++.o | +-----------------+
通过ssh-copy-id将各节点公钥复制到需要无密码登陆的服务器上, 包括节点自己 # 在yes/no处输入yes,其余一路回车 [hadoop@node222 .ssh]$ ssh-copy-id -i id_rsa.pub -p 22 hadoop@node224 The authenticity of host 'node224 (192.168.0.224)' can't be established. ECDSA key fingerprint is 12:37:f3:be:f5:f5:2b:eb:24:fd:08:b2:e0:d9:4f:03. Are you sure you want to continue connecting (yes/no)? yes /bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys hadoop@node224's password: Number of key(s) added: 1 Now try logging into the machine, with: "ssh -p '22' 'hadoop@node224'" and check to make sure that only the key(s) you wanted were added. # 同时拷贝至node225,node222(自己本节点) [hadoop@node222 .ssh]$ ssh-copy-id -i id_rsa.pub -p 22 hadoop@node225 [hadoop@node222 .ssh]$ ssh-copy-id -i id_rsa.pub -p 22 hadoop@node222 # node224 [hadoop@node224 .ssh]$ ssh-copy-id -i id_rsa.pub -p 22 hadoop@node225 [hadoop@node224 .ssh]$ ssh-copy-id -i id_rsa.pub -p 22 hadoop@node222 [hadoop@node224 .ssh]$ ssh-copy-id -i id_rsa.pub -p 22 hadoop@node224 # node225 [hadoop@node225 .ssh]$ ssh-copy-id -i id_rsa.pub -p 22 hadoop@node225 [hadoop@node225 .ssh]$ ssh-copy-id -i id_rsa.pub -p 22 hadoop@node222 [hadoop@node225 .ssh]$ ssh-copy-id -i id_rsa.pub -p 22 hadoop@node224
完成以上配置后,分别测试各节点间相互SSH免密码登录情况,正常无需密码登录即完成配置 [hadoop@node222 .ssh]$ ssh node224 Last login: Fri Sep 28 15:25:27 2018 [hadoop@node224 ~]$ exit logout Connection to node224 closed. [hadoop@node222 .ssh]$ ssh node225 Last login: Fri Sep 28 15:25:50 2018 [hadoop@node225 ~]$ exit logout
创建相关目录
创建集群所需要的配置目录,在node222节点上创建,配置完成后将相关目录拷贝至其他节点。 mkdir -p /home/hadoop/log/hadoop mkdir -p /home/hadoop/log/yarn mkdir -p /usr/local/hadoop-2.6.5/dfs mkdir -p /usr/local/hadoop-2.6.5/dfs/name mkdir -p /usr/local/hadoop-2.6.5/dfs/data mkdir -p /usr/local/hadoop-2.6.5/tmp mkdir -p /usr/local/hadoop-2.6.5/journal mkdir -p /usr/local/hadoop-2.6.5/yarn/local
分离配置文件与安装目录,方便hadoop升级,将hadoop的配置文件放置在/home/hadoop/config目录下即hadoop用户的“家目录”下,node222节点上hadoop用户操作 cp -r /usr/local/hadoop-2.6.5/etc/hadoop/ /home/hadoop/config/
修改配置文件
配置hadoop-env.sh,修改对应环境变量配置项,node222节点上hadoop用户操作 vi /home/hadoop/config/hadoop-env.sh export JAVA_HOME=/usr/local/jdk1.8.0_66/ export HADOOP_CONF_DIR=/home/hadoop/config/ export HADOOP_LOG_DIR=/home/hadoop/log/hadoop
配置yarn-env.sh,修改对应环境变量配置项,node222节点上hadoop用户操作 YARN_LOG_DIR="/home/hadoop/log/yarn" export JAVA_HOME=/usr/local/jdk1.8.0_66/
配置core-site.xml,在configuration节点中增加如下配置项,node222节点上hadoop用户操作 vi /home/hadoop/config/core-site.xml fs.defaultFS hdfs://ns1 io.file.buffer.size 131072 hadoop.tmp.dir /usr/local/hadoop-2.6.5/tmp ha.zookeeper.quorum node222:2181,node224:2181,node225:2181
配置hdfs-site.xml,在configuration节点中增加如下配置项,node222节点上hadoop用户操作 vi /home/hadoop/config/hdfs-site.xml dfs.namenode.name.dir file:///usr/local/hadoop-2.6.5/dfs/name dfs.datanode.data.dir file:///usr/local/hadoop-2.6.5/dfs/data dfs.replication 2 dfs.nameservices ns1 dfs.ha.namenodes.ns1 nn1,nn2 dfs.namenode.rpc-address.ns1.nn1 node222:9000 dfs.namenode.http-address.ns1.nn1 node222:50070 dfs.namenode.rpc-address.ns1.nn2 node224:9000 dfs.namenode.http-address.ns1.nn2 node224:50070 dfs.namenode.shared.edits.dir qjournal://node222:8485;node224:8485;node225:8485/ns1 dfs.journalnode.edits.dir /usr/local/hadoop-2.6.5/journal dfs.ha.automatic-failover.enabled.ns1 true dfs.client.failover.proxy.provider.ns1 org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider dfs.ha.fencing.methods sshfence dfs.ha.fencing.ssh.private-key-files /home/hadoop/.ssh/id_rsa dfs.permissions.enabled false
配置mapred-site.xml,默认没有mapred-site.xml,需要通过mapred-site.xml.template模板拷贝生成,在configuration节点中增加如下配置项,node222节点上hadoop用户操作 cp /home/hadoop/config/mapred-site.xml.template /home/hadoop/config/mapred-site.xml vi /home/hadoop/config/mapred-site.xml mapreduce.framework.name yarn mapreduce.jobhistory.address 0.0.0.0:10020 MapReduce JobHistory Server IPC host:port mapreduce.jobhistory.webapp.address 0.0.0.0:19888 MapReduce JobHistory Server Web UI host:port mapreduce.task.io.sort.mb 64 mapreduce.jobhistory.intermediate-done-dir /user/history/done_intermediate mapreduce.jobhistory.done-dir /user/history
配置yarn-site.xml,在configuration节点中增加如下配置项,node222节点上hadoop用户操作 vi /home/hadoop/config/yarn-site.xml yarn.resourcemanager.connect.retry-interval.ms 2000 yarn.resourcemanager.ha.enabled true yarn.resourcemanager.ha.rm-ids rm1,rm2 ha.zookeeper.quorum node222:2181,node224:2181,node225:2181 yarn.resourcemanager.ha.automatic-failover.enabled true yarn.resourcemanager.hostname.rm1 node222 yarn.resourcemanager.hostname.rm2 node224 yarn.resourcemanager.ha.id rm1 If we want to launch more than one RM in single node,we need this configuration yarn.resourcemanager.recovery.enabled true yarn.resourcemanager.zk-state-store.address node222:2181,node224:2181,node225:2181 yarn.resourcemanager.store.class org.apache.hadoop.yarn.server.resourcemanager.recovery.ZKRMStateStore yarn.resourcemanager.zk-address node222:2181,node224:2181,node225:2181 yarn.resourcemanager.cluster-id ns1-yarn yarn.app.mapreduce.am.scheduler.connection.wait.interval-ms 5000 yarn.resourcemanager.address.rm1 node222:8032 yarn.resourcemanager.scheduler.address.rm1 node222:8030 yarn.resourcemanager.webapp.address.rm1 node222:8088 yarn.resourcemanager.resource-tracker.address.rm1 node222:8031 yarn.resourcemanager.admin.address.rm1 node222:8033 yarn.resourcemanager.ha.admin.address.rm1 node222:23142 yarn.resourcemanager.address.rm2 node224:8032 yarn.resourcemanager.scheduler.address.rm2 node224:8030 yarn.resourcemanager.webapp.address.rm2 node224:8088 yarn.resourcemanager.resource-tracker.address.rm2 node224:8031 yarn.resourcemanager.admin.address.rm2 node224:8033 yarn.resourcemanager.ha.admin.address.rm2 node224:23142 yarn.nodemanager.aux-services mapreduce_shuffle yarn.nodemanager.aux-services.mapreduce.shuffle.class org.apache.hadoop.mapred.ShuffleHandler yarn.nodemanager.local-dirs /usr/local/hadoop-2.6.5/yarn/local yarn.nodemanager.log-dirs /home/hadoop/log/yarn mapreduce.shuffle.port 23080 yarn.client.failover-proxy-provider org.apache.hadoop.yarn.client.ConfiguredRMFailoverProxyProvider yarn.resourcemanager.ha.automatic-failover.zk-base-path /yarn-leader-election Optionalsetting.Thedefaultvalueis/yarn-leader-election
将要配置为DataNode的节点hostname添加至slaves 文件,node222节点上hadoop用户操作 vi /home/hadoop/config/slaves # 添加如下内容 node222 node224 node225
用root用户将hadoop拷贝至其他集群节点,因为默认的安装目录/usr/local目录hadoop用户没有权限操作。同时在其他接收节点将相关目录的权限授予hadoop用户 # node222 root用户操作 scp -r /usr/local/hadoop-2.6.5 node224:/usr/local/ scp -r /home/hadoop/config/ /home/hadoop/log/ node224:/home/hadoop/ scp -r /usr/local/hadoop-2.6.5 node225:/usr/local/ scp -r /home/hadoop/config/ /home/hadoop/log/ node225:/home/hadoop/ # node224 root用户操作 chown -R hadoop:hadoop /home/hadoop chown -R hadoop:hadoop /usr/local/hadoop-2.6.5 # node225 root用户操作 chown -R hadoop:hadoop /home/hadoop chown -R hadoop:hadoop /usr/local/hadoop-2.6.5
修改备Namenode节点上的yarn-site.xml配置文件中的yarn.resourcemanager.ha.id,其中node222为rm1,node224为rm2。node224节点上hadoop用户操作。 yarn.resourcemanager.ha.id rm1 If we want to launch more than one RM in single node,we need this configuration
将hadoop相关环境变量注入/etc/profile中,每个节点都要操作 export HADOOP_HOME=/usr/local/hadoop-2.6.5/ export HADOOP_CONF_DIR=/home/hadoop/config/ export PATH=$HADOOP_HOME/bin:$HADOOP_HOME/sbin:$HADOOP_HOME/lib:$PATH
启动hadoop集群
启动zookeeper集群并确保zk集群状态正常,具体操作见
完全分布式集群(一)集群基础环境及zookeeper-3.4.10安装部署
格式化ZooKeeper集群,在ZooKeeper集群上建立HA的相应节点。 [hadoop@node222 ~]$ /usr/local/hadoop-2.6.5/bin/hdfs zkfc -formatZK 18/09/29 09:16:54 INFO tools.DFSZKFailoverController: Failover controller configured for NameNode NameNode at node222/192.168.0.222:9000 18/09/29 09:16:54 INFO zookeeper.ZooKeeper: Client environment:zookeeper.version=3.4.6-1569965, built on 02/20/2014 09:09 GMT 18/09/29 09:16:54 INFO zookeeper.ZooKeeper: Client environment:host.name=node222 18/09/29 09:16:54 INFO zookeeper.ZooKeeper: Client environment:java.version=1.8.0_66 18/09/29 09:16:54 INFO zookeeper.ZooKeeper: Client environment:java.vendor=Oracle Corporation 18/09/29 09:16:54 INFO zookeeper.ZooKeeper: Client environment:java.home=/usr/local/jdk1.8.0_66/jre 18/09/29 09:16:54 INFO zookeeper.ZooKeeper: Client ...... 18/09/29 09:16:55 INFO ha.ActiveStandbyElector: Successfully created /hadoop-ha/ns1 in ZK. 18/09/29 09:16:55 INFO zookeeper.ZooKeeper: Session: 0x1661fcbe83d0000 closed 18/09/29 09:16:55 WARN ha.ActiveStandbyElector: Ignoring stale result from old client with sessionId 0x1661fcbe83d0000 18/09/29 09:16:55 INFO zookeeper.ClientCnxn: EventThread shut down
通过zk客户端工具检查格式化结果 [hadoop@node222 ~]$ zkCli.sh -server node222:2181 Connecting to node222:2181 2018-09-29 09:20:09,065 [myid:] - INFO [main:Environment@100] - Client environment:zookeeper.version=3.4.10-39d3a4f269333c922ed3db283be479f9deacaa0f, built on 03/23/2017 10:13 GMT ...... WATCHER:: WatchedEvent state:SyncConnected type:None path:null [zk: node222:2181(CONNECTED) 0] ls / [zookeeper, hadoop-ha] [zk: node222:2181(CONNECTED) 1] ls /hadoop-ha [ns1]
启动日志程序
依次启动各节点上的日志程序journalnode,启动后通过jps能查询到JournalNode进程及说明启动正常。 [hadoop@node222 ~]$ /usr/local/hadoop-2.6.5/sbin/hadoop-daemon.sh start journalnode starting journalnode, logging to /home/hadoop/log/hadoop//hadoop-hadoop-journalnode-node222.out [hadoop@node224 ~]$ /usr/local/hadoop-2.6.5/sbin/hadoop-daemon.sh start journalnode starting journalnode, logging to /home/hadoop/log/hadoop//hadoop-hadoop-journalnode-node224.out [hadoop@node225 ~]$ /usr/local/hadoop-2.6.5/sbin/hadoop-daemon.sh start journalnode starting journalnode, logging to /home/hadoop/log/hadoop//hadoop-hadoop-journalnode-node225.out
格式化namenode
在主节node222点上执行 [hadoop@node222 ~]$ /usr/local/hadoop-2.6.5/bin/hdfs namenode -format 18/09/29 09:27:15 INFO namenode.NameNode: STARTUP_MSG: /************************************************************ STARTUP_MSG: Starting NameNode STARTUP_MSG: host = node222/192.168.0.222 STARTUP_MSG: args = [-format] STARTUP_MSG: version = 2.6.5 STARTUP_MSG: classpath = ...... 18/09/29 09:27:20 INFO namenode.NNStorageRetentionManager: Going to retain 1 images with txid >= 0 18/09/29 09:27:20 INFO util.ExitUtil: Exiting with status 0 18/09/29 09:27:20 INFO namenode.NameNode: SHUTDOWN_MSG: /************************************************************ SHUTDOWN_MSG: Shutting down NameNode at node222/192.168.0.222 ************************************************************/
启动主节点 [hadoop@node222 ~]$ /usr/local/hadoop-2.6.5/sbin/hadoop-daemon.sh start namenode starting namenode, logging to /home/hadoop/log/hadoop//hadoop-hadoop-namenode-node222.out [hadoop@node222 ~]$ jps 4724 NameNode 3879 QuorumPeerMain 4796 Jps 4605 JournalNode
从namenode节点上同步数据
从节点上执行,在从节点上同步主节点数据,同步完成后会关闭从节点的namenode进程 [hadoop@node224 ~]$ /usr/local/hadoop-2.6.5/bin/hdfs namenode -bootstrapStandby 18/09/29 09:29:15 INFO namenode.NameNode: STARTUP_MSG: /************************************************************ STARTUP_MSG: Starting NameNode STARTUP_MSG: host = node224/192.168.0.224 STARTUP_MSG: args = [-bootstrapStandby] STARTUP_MSG: version = 2.6.5 STARTUP_MSG: classpath = ...... 18/09/29 09:29:15 INFO namenode.NameNode: createNameNode [-bootstrapStandby] ===================================================== About to bootstrap Standby ID nn2 from: Nameservice ID: ns1 Other Namenode ID: nn1 Other NN's HTTP address: http://node222:50070 Other NN's IPC address: node222/192.168.0.222:9000 Namespace ID: 172841409 Block pool ID: BP-1584106043-192.168.0.222-1538184439585 Cluster ID: CID-5cd9a86e-92ab-4fb4-b5c6-212638251d2c Layout version: -60 isUpgradeFinalized: true ===================================================== 18/09/29 09:29:17 INFO common.Storage: Storage directory /usr/local/hadoop-2.6.5/dfs/name has been successfully formatted. 18/09/29 09:29:18 INFO namenode.TransferFsImage: Opening connection to http://node222:50070/imagetransfer?getimage=1&txid=0&storageInfo=-60:172841409:0:CID-5cd9a86e-92ab-4fb4-b5c6-212638251d2c 18/09/29 09:29:18 INFO namenode.TransferFsImage: Image Transfer timeout configured to 60000 milliseconds 18/09/29 09:29:18 INFO namenode.TransferFsImage: Transfer took 0.01s at 0.00 KB/s 18/09/29 09:29:18 INFO namenode.TransferFsImage: Downloaded file fsimage.ckpt_0000000000000000000 size 322 bytes. 18/09/29 09:29:18 INFO util.ExitUtil: Exiting with status 0 18/09/29 09:29:18 INFO namenode.NameNode: SHUTDOWN_MSG: /************************************************************ SHUTDOWN_MSG: Shutting down NameNode at node224/192.168.0.224 ************************************************************/
启动从namenode节点 [hadoop@node224 ~]$ /usr/local/hadoop-2.6.5/sbin/hadoop-daemon.sh start namenode starting namenode, logging to /home/hadoop/log/hadoop//hadoop-hadoop-namenode-node224.out [hadoop@node224 ~]$ jps 5008 NameNode 4888 JournalNode 5085 Jps
启动所有DataNode节点 [hadoop@node222 ~]$ /usr/local/hadoop-2.6.5/sbin/hadoop-daemon.sh start datanode starting datanode, logging to /home/hadoop/log/hadoop//hadoop-hadoop-datanode-node222.out [hadoop@node222 ~]$ jps 4724 NameNode 3879 QuorumPeerMain 4935 Jps 4605 JournalNode 4862 DataNode [hadoop@node224 ~]$ /usr/local/hadoop-2.6.5/sbin/hadoop-daemon.sh start datanode starting datanode, logging to /home/hadoop/log/hadoop//hadoop-hadoop-datanode-node224.out [hadoop@node224 ~]$ jps 5008 NameNode 5473 QuorumPeerMain 4888 JournalNode 5530 Jps 5133 DataNode [hadoop@node225 ~]$ /usr/local/hadoop-2.6.5/sbin/hadoop-daemon.sh start datanode starting datanode, logging to /home/hadoop/log/hadoop//hadoop-hadoop-datanode-node225.out [hadoop@node225 ~]$ jps 5075 JournalNode 5446 QuorumPeerMain 5244 DataNode 5503 Jps
启动namenode节点的ZooKeeperFailoverController
否则通过hadfs的9000端口查看,两个namenode均处于standby状态 [hadoop@node222 ~]$ /usr/local/hadoop-2.6.5/sbin/hadoop-daemon.sh start zkfc starting zkfc, logging to /home/hadoop/log/hadoop//hadoop-hadoop-zkfc-node222.out [hadoop@node222 ~]$ jps 4724 NameNode 3879 QuorumPeerMain 5002 DFSZKFailoverController 5066 Jps 4605 JournalNode 4862 DataNode [hadoop@node222 ~]$ [hadoop@node224 ~]$ /usr/local/hadoop-2.6.5/sbin/hadoop-daemon.sh start zkfc starting zkfc, logging to /home/hadoop/log/hadoop//hadoop-hadoop-zkfc-node224.out [hadoop@node224 ~]$ jps 5008 NameNode 5473 QuorumPeerMain 5573 DFSZKFailoverController 5621 Jps 4888 JournalNode 5133 DataNode
启动yarn [hadoop@node222 ~]$ /usr/local/hadoop-2.6.5/sbin/yarn-daemon.sh start resourcemanager starting resourcemanager, logging to /home/hadoop/log/yarn/yarn-hadoop-resourcemanager-node222.out [hadoop@node222 ~]$ /usr/local/hadoop-2.6.5/bin/yarn rmadmin -getServiceState rm1 active [hadoop@node224 ~]$ /usr/local/hadoop-2.6.5/sbin/yarn-daemon.sh start resourcemanager starting resourcemanager, logging to /home/hadoop/log/yarn/yarn-hadoop-resourcemanager-node224.out [hadoop@node224 ~]$ /usr/local/hadoop-2.6.5/bin/yarn rmadmin -getServiceState rm2 standby
测试hdfs的故障转移
执行主从切换命令后通过web客户端查看各节点的状态,执行切换后可通过web界面确认两个namenode节点状态的切换 [hadoop@node222 ~]$ /usr/local/hadoop-2.6.5/bin/hdfs haadmin -failover nn1 nn2 Failover to NameNode at node224/192.168.0.224:9000 successful [hadoop@node222 ~]$ /usr/local/hadoop-2.6.5/bin/hdfs haadmin -failover nn2 nn1 Failover to NameNode at node222/192.168.0.222:9000 successful
web界面访问
hdfs web访问 NameNode:50070
yarn web访问web界面 NameNode:8088
start-all.sh启动hadoop集群
通过start-all.sh 启动缺少备主节点上的resourcemanager,需要手动启动 # 主节点上启动 [hadoop@node222 ~]$ /usr/local/hadoop-2.6.5/sbin/start-all.sh This script is Deprecated. Instead use start-dfs.sh and start-yarn.sh Starting namenodes on [node222 node224] node222: starting namenode, logging to /home/hadoop/log/hadoop/hadoop-hadoop-namenode-node222.out node224: starting namenode, logging to /home/hadoop/log/hadoop/hadoop-hadoop-namenode-node224.out node224: starting datanode, logging to /home/hadoop/log/hadoop/hadoop-hadoop-datanode-node224.out node222: starting datanode, logging to /home/hadoop/log/hadoop/hadoop-hadoop-datanode-node222.out node225: starting datanode, logging to /home/hadoop/log/hadoop/hadoop-hadoop-datanode-node225.out Starting journal nodes [node222 node224 node225] node225: starting journalnode, logging to /home/hadoop/log/hadoop/hadoop-hadoop-journalnode-node225.out node222: starting journalnode, logging to /home/hadoop/log/hadoop/hadoop-hadoop-journalnode-node222.out node224: starting journalnode, logging to /home/hadoop/log/hadoop/hadoop-hadoop-journalnode-node224.out starting yarn daemons starting resourcemanager, logging to /home/hadoop/log/yarn/yarn-hadoop-resourcemanager-node222.out node225: starting nodemanager, logging to /home/hadoop/log/yarn/yarn-hadoop-nodemanager-node225.out node222: starting nodemanager, logging to /home/hadoop/log/yarn/yarn-hadoop-nodemanager-node222.out node224: starting nodemanager, logging to /home/hadoop/log/yarn/yarn-hadoop-nodemanager-node224.out # 启动备namenode节点上的resourcemanager [hadoop@node224 .ssh]$ /usr/local/hadoop-2.6.5/sbin/yarn-daemon.sh start resourcemanager # 启动主备namenode节点的zkfc [hadoop@node222 ~]$ /usr/local/hadoop-2.6.5/sbin/hadoop-daemon.sh start zkfc [hadoop@node224 ~]$ /usr/local/hadoop-2.6.5/sbin/hadoop-daemon.sh start zkfc
stop-all.sh关闭集群 # 主节点上关闭 [hadoop@node222 ~]$ /usr/local/hadoop-2.6.5/sbin/stop-all.sh This script is Deprecated. Instead use stop-dfs.sh and stop-yarn.sh Stopping namenodes on [node222 node224] node224: stopping namenode node222: stopping namenode node225: stopping datanode node222: stopping datanode node224: stopping datanode Stopping journal nodes [node222 node224 node225] node222: stopping journalnode node224: stopping journalnode node225: stopping journalnode stopping yarn daemons stopping resourcemanager node222: stopping nodemanager node225: stopping nodemanager node224: stopping nodemanager no proxyserver to stop # 备namenode节点关闭resourcemanager [hadoop@node224 ~]$ /usr/local/hadoop-2.6.5/sbin/yarn-daemon.sh stop resourcemanager # 关闭namenode节点上的zkfc [hadoop@node222 ~]$ /usr/local/hadoop-2.6.5/sbin/hadoop-daemon.sh stop zkfc [hadoop@node224 ~]$ /usr/local/hadoop-2.6.5/sbin/hadoop-daemon.sh stop zkfc
执行hdfs shell命令测试集群是否正常 hdfs dfs -ls / hdfs dfs -mkdir /buaa hdfs dfs -put /home/hadoop/a.txt /buaa ......
大数据
2018-10-08 18:32:04
「深度学习福利」大神带你进阶工程师,立即查看>>>
本系列共两篇文章,主要探讨如何将Ignite和Spark进行集成。
下面简要地回顾一下在 第一篇文章 中所谈到的内容。
Ignite是一个分布式的内存数据库、缓存和处理平台,为事务型、分析型和流式负载而设计,在保证扩展性的前提下提供了内存级的性能。
Spark是一个流式数据和计算引擎,通常从HDFS或者其他存储中获取数据,一直以来,他都倾向于OLAP型业务,并且聚焦于MapReduce类型负载。
因此,这两种技术是可以互补的。
将Ignite与Spark整合
整合这两种技术会为Spark用户带来若干明显的好处: 通过避免大量的数据移动,获得真正可扩展的内存级性能; 提高RDD、DataFrame和SQL的性能; 在Spark作业之间更方便地共享状态和数据。
下图中显示了如何整合这两种技术,并且标注了显著的优势:
在 第一篇文章 中,主要聚焦于IgniteRDD,而本文会聚焦于IgniteDataFrames。
IgniteDataframes
Spark的DataFrame API为描述数据引入了模式的概念,Spark通过表格的形式进行模式的管理和数据的组织。
DataFrame是一个组织为命名列形式的分布式数据集,从概念上讲,DataFrame等同于关系数据库中的表,并允许Spark使用Catalyst查询优化器来生成高效的查询执行计划。而RDD只是跨集群节点分区化的元素集合。
Ignite扩展了DataFrames,简化了开发,改进了将Ignite作为Spark的内存存储时的数据访问时间,好处包括: 通过Ignite读写DataFrames时,可以在Spark作业之间共享数据和状态; 通过优化Spark的查询执行计划加快SparkSQL查询,这些主要是通过IgniteSQL引擎的高级索引以及避免了Ignite和Spark之间的网络数据移动实现的。
IgniteDataframes示例
下面通过一些代码以及搭建几个小程序的方式,了解Ignite DataFrames如何使用,如果想实际运行这些代码,可以从 GitHub 上下载。
一共会写两个Java的小应用,然后在IDE中运行,还会在这些Java应用中执行一些SQL。
一个Java应用会从JSON文件中读取一些数据,然后创建一个存储于Ignite的DataFrame,这个JSON文件Ignite的发行版中已经提供,另一个Java应用会从Ignite的DataFrame中读取数据然后使用SQL进行查询。
下面是写应用的代码: public class DFWriter { private static final String CONFIG = "config/example-ignite.xml"; public static void main(String args[]) { Ignite ignite = Ignition.start(CONFIG); SparkSession spark = SparkSession .builder() .appName("DFWriter") .master("local") .config("spark.executor.instances", "2") .getOrCreate(); Logger.getRootLogger().setLevel(Level.OFF); Logger.getLogger("org.apache.ignite").setLevel(Level.OFF); Dataset peopleDF = spark.read().json( resolveIgnitePath("resources/people.json").getAbsolutePath()); System.out.println("JSON file contents:"); peopleDF.show(); System.out.println("Writing DataFrame to Ignite."); peopleDF.write() .format(IgniteDataFrameSettings.FORMAT_IGNITE()) .option(IgniteDataFrameSettings.OPTION_CONFIG_FILE(), CONFIG) .option(IgniteDataFrameSettings.OPTION_TABLE(), "people") .option(IgniteDataFrameSettings.OPTION_CREATE_TABLE_PRIMARY_KEY_FIELDS(), "id") .option(IgniteDataFrameSettings.OPTION_CREATE_TABLE_PARAMETERS(), "template=replicated") .save(); System.out.println("Done!"); Ignition.stop(false); } }
在 DFWriter 中,首先创建了 SparkSession ,它包含了应用名,之后会使用 spark.read().json() 读取JSON文件并且输出文件内容,下一步是将数据写入Ignite存储。下面是 DFReader 的代码: public class DFReader { private static final String CONFIG = "config/example-ignite.xml"; public static void main(String args[]) { Ignite ignite = Ignition.start(CONFIG); SparkSession spark = SparkSession .builder() .appName("DFReader") .master("local") .config("spark.executor.instances", "2") .getOrCreate(); Logger.getRootLogger().setLevel(Level.OFF); Logger.getLogger("org.apache.ignite").setLevel(Level.OFF); System.out.println("Reading data from Ignite table."); Dataset peopleDF = spark.read() .format(IgniteDataFrameSettings.FORMAT_IGNITE()) .option(IgniteDataFrameSettings.OPTION_CONFIG_FILE(), CONFIG) .option(IgniteDataFrameSettings.OPTION_TABLE(), "people") .load(); peopleDF.createOrReplaceTempView("people"); Dataset sqlDF = spark.sql("SELECT * FROM people WHERE id > 0 AND id < 6"); sqlDF.show(); System.out.println("Done!"); Ignition.stop(false); } }
在 DFReader 中,初始化和配置与 DFWriter 相同,这个应用会执行一些过滤,需求是查找所有的id > 0 以及 < 6的人,然后输出结果。
在IDE中,通过下面的代码可以启动一个Ignite节点: public class ExampleNodeStartup { public static void main(String[] args) throws IgniteException { Ignition.start("config/example-ignite.xml"); } }
到此,就可以对代码进行测试了。
运行应用
首先在IDE中启动一个Ignite节点,然后运行 DFWriter 应用,输出如下: JSON file contents: +-------------------+---+------------------+ | department| id| name| +-------------------+---+------------------+ |Executive Committee| 1| Ivan Ivanov| |Executive Committee| 2| Petr Petrov| | Production| 3| John Doe| | Production| 4| Ann Smith| | Accounting| 5| Sergey Smirnov| | Accounting| 6|Alexandra Sergeeva| | IT| 7| Adam West| | Head Office| 8| Beverley Chase| | Head Office| 9| Igor Rozhkov| | IT| 10|Anastasia Borisova| +-------------------+---+------------------+ Writing DataFrame to Ignite. Done!
如果将上面的结果与JSON文件的内容进行对比,会显示两者是一致的,这也是期望的结果。
下一步会运行 DFReader ,输出如下: Reading data from Ignite table. +-------------------+--------------+---+ | DEPARTMENT| NAME| ID| +-------------------+--------------+---+ |Executive Committee| Ivan Ivanov| 1| |Executive Committee| Petr Petrov| 2| | Production| John Doe| 3| | Production| Ann Smith| 4| | Accounting|Sergey Smirnov| 5| +-------------------+--------------+---+ Done!
这也是期望的输出。
总结
通过本文,会发现使用Ignite DataFrames是如何简单,这样就可以通过Ignite DataFrame进行数据的读写了。
未来, 这些代码示例 也会作为Ignite发行版的一部分进行发布。
关于Ignite和Spark的集成,内容就是这些了。
大数据
2018-10-08 15:38:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
在进入主题之前,我们先思考一个问题。
问题 kafka消费者使用自动提交的模式,提交间隔为2s,消费者在获取数据的时候处理0.5s,从kafka拉取过来的数据只够处理1秒。那么消费者下次拉取过来的数据是否是已经消费完的数据?或者说由于数据已经消费,但是偏移量没有被提交,是否会造成下次获取的数据是从旧的偏移量开始拉取?
答案 不会是旧数据,kafka的消费者也有自己偏移量,这个偏移量是从kafka中读取的量,和kafka提交的偏移量不一样。假设变成自动提交偏移量,而且没有写提交的逻辑,同一个消费者,除了第一次或者rebalance会根据已提交的offset来获取数据,剩下的时候都是根据自己本地的偏移量来获取的。这个模式有点类似于用桶取水,用瓢来喝水。消费者就是桶的角色,poll就是瓢的角色。
重复消费的情况
我们把重复消费的情况分为2种,一种是想避免的,一种是故意如此的。
想避免的场景 消费者使用了自动提交模式,当还没有提交的时候,有新的消费者加入或者移除,发生了rebalance。再次消费的时候,消费者会根据提交的偏移量来,于是重复消费了数据。 使用异步提交,并且在callback里写了失败重试,但是没有注意顺序。例如提交5的时候,发送网络故障,由于是异步,程序继续运行,再次提交10的时候,提交成功,此时正好运行到5的重试,并且成功。当发生了rebalance,又会重复消费了数据。
注:这里不讨论那个消费者提交的offset的作用。
故意的场景 使用不同的组消费同一个topic。改个 group.id属性即可。 自己手动提交偏移量。 这里的麻烦的地方就是需要理解开头的问题,并不是说你提交完就可以了。你得想个办法去读取那个偏移量再次消费。下面提供一个暴力的手段,关闭消费者,然后再次开启新的。 public static void consumer(Properties properties,String info) { System.out.println(info); KafkaConsumer kafkaConsumer = new KafkaConsumer(properties); kafkaConsumer.subscribe(Arrays.asList(new String[]{"hello"})); boolean flag = false; while (true) { ConsumerRecords poll = kafkaConsumer.poll(100); if (!poll.isEmpty()) { for (ConsumerRecord o : poll) { System.out.println(o.value() + o.offset()); //假设场景为重复消费3,这里需要根据业务来提交便宜量 if (o.offset() == 3) { //手动提交偏移量 Map currentOffset = new HashMap(); //提交的偏移量,这个偏移量就是下次消费的第一条数据 currentOffset.put(new TopicPartition(o.topic(), o.partition()), new OffsetAndMetadata(o.offset()+1, "")); kafkaConsumer.commitSync(currentOffset); flag = true; break; } } } if(flag){ kafkaConsumer.close(); break; } } }
这里也必须注意,kafka并不是数据库,他保存的数据有持久化的时间和大小的限制,可能你提交的偏移量的数据已经被kafka清理掉了。
大数据
2018-10-07 19:43:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
hadoop集群搭建:
配置hosts (4个节点一致) 192.168.83.11 hd1 192.168.83.22 hd2 192.168.83.33 hd3 192.168.83.44 hd4
配置主机名(重启生效) [hadoop@hd1 ~]$ more /etc/sysconfig/network NETWORKING=yes HOSTNAME=hd1
配置用户用户组 [hadoop@hd1 ~]$ id hadoop uid=1001(hadoop) gid=10010(hadoop) groups=10010(hadoop)
配置JDK [hadoop@hd1 ~]$ env|grep JAVA JAVA_HOME=/usr/java/jdk1.8.0_11 [hadoop@hd1 ~]$ java -version java version "1.8.0_11" Java(TM) SE Runtime Environment (build 1.8.0_11-b12) Java HotSpot(TM) 64-Bit Server VM (build 25.11-b03, mixed mode)
配置ssh免密登录 ssh-keygen -t rsa ssh-keygen -t dsa cat ~/.ssh/*.pub > ~/.ssh/authorizedkeys scp ~/.ssh/authorizedkeys hdoop@hd2:/.ssh/authorizedkeys
配置环境变量: export JAVA_HOME=/usr/java/jdk1.8.0_11 export JRE_HOME=/usr/java/jdk1.8.0_11/jre export CLASSPATH=.:$CLASSPATH:$JAVA_HOME/lib:$JRE_HOME/lib export HADOOP_INSTALL=/home/hadoop/hadoop-2.7.1 export PATH=$PATH:$JAVA_HOME/bin:$JRE_HOME/bin:$HADOOP_INSTALL/bin:$HADOOP_INSTALL/sbin export PATRH=$PATH:/home/hadoop/zookeeper-3.4.6/bin
注意:hadoopo有一个小bug,在~/.bash_profile配置JAVA_HOME不生效,只能在hadoop-env.sh配置JAVA_HOME # The java implementation to use. #export JAVA_HOME=${JAVA_HOME} export JAVA_HOME=/usr/java/jdk1.8.0_11
软件准备: [hadoop@hd1 software]$ ls -l total 931700 -rw-r--r-- 1 hadoop hadoop 17699306 Oct 6 17:30 zookeeper-3.4.6.tar.gz -rw-r--r--. 1 hadoop hadoop 336424960 Jul 18 23:13 hadoop-2.7.1.tar tar -xvf /usr/hadoop/hadoop-2.7.1.tar -C /home/hadoop/ tar -xvf ../software/zookeeper-3.4.6.tar.gz -C /home/hadoop/
hadoop HA配置
参考 http://hadoop.apache.org/docs/r2.7.3/hadoop-project-dist/hadoop-hdfs/HDFSHighAvailabilityWithQJM.html。
目的:“Using the Quorum Journal Manager or Conventional Shared Storage”,使用JN( Quorum JournalNode)就是为了解决共享存储的问题,当然官方也推荐使用NFS,不过本人觉得NFS存在性能问题,不敢使用。
Architecture
官方文档有详细介绍结构,看的比较费劲,转载 yameing 的CSDN 博客片段 (全文地址请点击:https://blog.csdn.net/yameing/article/details/39696151?utm_source=copy。)
在一个普通的高可用集群里,有两台独立机器被配置为NN。在任何时间里,只有一个是处于活动状态,而另一个则处于备用状态。活动NN负责所有客户端通信,同时,备用NN只是一个简单的从节点,维护一个为了在需要时能快速故障恢复的状态。
为了备用NN能通过活动NN同步状态,两个节点通过一组独立进程JN进行通信。 任何执行在活动NN的edits,将持久地记录到大多数JN里。备用NN能够在这些JN里读取到edits,并且不断的监控记录的改变。当备用NN读取到这些edits时,就把它们执行一遍,就保证两个NN同步 。发现故障恢复时,备份NN在确保从JN中读取到所有edits后,就将自己提升为活动NN。这就确保了再发生故障恢复前命名空间已完全同步。
为了提供快速的故障恢复,备用NN拥有最新的块地址信息也是非常重要的。为了实现这个要求, DN同时配置有两个NN的地址,并且同时向两者发送块地址信息和心跳 。
在同一时间里,保证高可用集群中 只有一个活动NN 是至关重要的。否则,两个NN的状态将很快出现不一致,数据有丢失的风险,或者其他错误的结果。为了确保这种属性、防止所谓的 脑裂场景(split-brain scenario) , 在同一时间里,JN只允许一个NN写edits 。故障恢复期间,将成为活动节点的NN简单的获取写edits的角色,这将有效的阻止其他NN继续处于活动状态,允许新活动节点安全的进行故障恢复。
节点及实例规划:
NameNode 机器:运行活动NN和备用NN的硬件配置应该是一致的。这和非高可用集群的配置一样。
l JournalNode 机器:JN进程相对轻量级,所以这些进程可以合理的配置在Hadoop集群的其他机器里,如NN,JT、RM。注意: 必须至少有3个JN进程,因为edits需要写入到大多数的JN里。这就允许系统单台机器的错误 。你也可以运行3个以上JN,但为了实际提高系统对错误的容忍度,最好运行奇数个JN。执行N个JN的集群上,系统可以容忍(N-1)/2台机器错误的同时保持正常工作。
注意:在高可用集群里, 备用NN也扮演checkpoint,所以没必要再运行一个Secondary NN,CheckpointNode,或BackupNode 。事实上,这样做(运行上述几个节点)是一种错误。这也就允许复用原来指定为Secondary Namenode 的硬件,将一个非高可用的HDFS集群重新配置为高可用的。
Configuration details
To configure HA NameNodes, you must add several configuration options to your hdfs-site.xml configuration file. dfs.nameservices - the logical name for this new nameservice dfs.nameservices mycluster dfs.ha.namenodes.[nameservice ID] - unique identifiers for each NameNode in the nameservice dfs.ha.namenodes.mycluster nn1,nn2 dfs.namenode.rpc-address.[nameservice ID].[name node ID] - the fully-qualified RPC address for each NameNode to listen on dfs.namenode.rpc-address.mycluster.nn1 machine1.example.com:8020 dfs.namenode.rpc-address.mycluster.nn2 machine2.example.com:8020 dfs.namenode.http-address.[nameservice ID].[name node ID] - the fully-qualified HTTP address for each NameNode to listen on dfs.namenode.http-address.mycluster.nn1 machine1.example.com:50070 dfs.namenode.http-address.mycluster.nn2 machine2.example.com:50070 dfs.namenode.shared.edits.dir - the URI which identifies the group of JNs where the NameNodes will write/read edits dfs.namenode.shared.edits.dir qjournal://node1.example.com:8485;node2.example.com:8485;node3.example.com:8485/mycluster dfs.client.failover.proxy.provider.[nameservice ID] - the Java class that HDFS clients use to contact the Active NameNode dfs.client.failover.proxy.provider.mycluster org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider dfs.ha.fencing.methods - a list of scripts or Java classes which will be used to fence the Active NameNode during a failover.
Importantly, when using the Quorum Journal Manager, only one NameNode will ever be allowed to write to the JournalNodes, so there is no potential for corrupting the file system metadata from a split-brain scenario.
sshfence - SSH to the Active NameNode and kill the process dfs.ha.fencing.methods sshfence dfs.ha.fencing.ssh.private-key-files /home/exampleuser/.ssh/id_rsa fs.defaultFS - the default path prefix used by the Hadoop FS client when none is given.in your core-site.xml file: fs.defaultFS hdfs://mycluster dfs.journalnode.edits.dir - the path where the JournalNode daemon will store its local state dfs.journalnode.edits.dir /path/to/journal/node/local/data 配置Datanode [hadoop@hd1 hadoop]$ more slaves hd2 hd3 hd4
以上配置完成,可以把配置文件拷贝到其他的节点,完成hadoop集群配置工作。
启动: 启动JN:running the command“hadoop-daemon.sh start journalnode”。 如果是一个新的集群 ,需要先格式化NN hdfs namenode -format 在其中一个NN节点上。 如果已经格式化完成,需要拷贝NN元数据到另外的节点,这个时候需要在未格式化的NN节点上执行“hdfs namenode -bootstrapStandby”。(注意:在拷贝元数据之前,需要提前启动format过的NN,只启动一个节点),启动已经格式化的节点的NN hadoop-daemon.sh start namenode 如果把一个非HA转换成HA,需要执行“ hdfs namenode -initializeSharedEdits ”
Note: This is not yet implemented, and at present will always return success, unless the given NameNode is completely down.
格式化NN hdfs namenode -format,报错: 18/10/07 21:42:34 INFO ipc.Client: Retrying connect to server: hd2/192.168.83.22:8485. Already tried 9 time(s); retry policy is RetryUpToMaximumCountWithFixedSleep(maxRetries=10, sleepTime=1000 MILLISECONDS) 18/10/07 21:42:34 WARN namenode.NameNode: Encountered exception during format: org.apache.hadoop.hdfs.qjournal.client.QuorumException: Unable to check if JNs are ready for formatting. 1 exceptions thrown: 192.168.83.22:8485: Call From hd1/192.168.83.11 to hd2:8485 failed on connection exception: java.net.ConnectException: Connection refused; For more details see: http://wiki.apache.org/hadoop/ConnectionRefused at org.apache.hadoop.hdfs.qjournal.client.QuorumException.create(QuorumException.java:81) at org.apache.hadoop.hdfs.qjournal.client.QuorumCall.rethrowException(QuorumCall.java:223) at org.apache.hadoop.hdfs.qjournal.client.QuorumJournalManager.hasSomeData(QuorumJournalManager.java:232) at org.apache.hadoop.hdfs.server.common.Storage.confirmFormat(Storage.java:900) at org.apache.hadoop.hdfs.server.namenode.FSImage.confirmFormat(FSImage.java:184) at org.apache.hadoop.hdfs.server.namenode.NameNode.format(NameNode.java:987) at org.apache.hadoop.hdfs.server.namenode.NameNode.createNameNode(NameNode.java:1429) at org.apache.hadoop.hdfs.server.namenode.NameNode.main(NameNode.java:1554) 18/10/07 21:42:34 INFO ipc.Client: Retrying connect to server: hd3/192.168.83.33:8485. Already tried 9 time(s); retry policy is RetryUpToMaximumCountWithFixedSleep(maxRetries=10, sleepTime=1000 MILLISECONDS)
解决:在格式化NN的时候,需要连接JN,如果连接JN失败或者超时都会出现这种错误,首先检查JN是否启动,如果由于网络延迟导致 可以通过设置timeout来规避这个错误 。 2 3 ipc.client.connect.max.retries 4 100 5 Indicates the number of retries a client will make to establish a server connection. 6 7 8 ipc.client.connect.retry.interval 9 10000 10 Indicates the number of milliseconds a client will wait for before retrying to establish a server connection. 11 --------------------- 本文来自 锐湃 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/chuyouyinghe/article/details/78976933?utm_source=copy
注意:
  1) 仅对于这种由于服务没有启动完成造成连接超时的问题,都可以调整core-site.xml中的ipc参数来解决。如果目标服务本身没有启动成功,这边调整ipc参数是无效的。
  2) 该配置使namenode连接journalnode最大时间增加至1000s(maxRetries=100, sleepTime=10000),假如集群节点数过多,或者网络情况不稳定,造成连接时间超过1000s,仍会导致namenode挂掉。
Automatic Failover:
上面介绍了如何配置人工故障恢复。这种方式下,即使活动NN挂掉了,系统不会自动触发负责恢复。下面描述如何配置和部署自动故障恢复。
Automatic failover adds two new components to an HDFS deployment: a ZooKeeper quorum, and the ZKFailoverController process (abbreviated as ZKFC).
自动故障恢复增加了两个组件: Zookeeper quorum、ZKFailoverController(ZKFC) 。
Apache ZooKeeper is a highly available service for maintaining small amounts of coordination data, notifying clients of changes in that data, and monitoring clients for failures. The implementation of automatic HDFS failover relies on ZooKeeper for the following things:
Introduction
Apache Zookeeper是一个高可用的服务,它能维护少量的协调数据,通知客户数据的变化,监控客户端失败。HDFS故障自动恢复依赖ZK以下特性: Failure detection - each of the NameNode machines in the cluster maintains a persistent session in ZooKeeper. If the machine crashes, the ZooKeeper session will expire, notifying the other NameNode that a failover should be triggered.
故障检测(Failure detection) - 集群里的每个NN与ZK保持一个持久会话。如果机器宕机,ZK会话将过期,然后提醒其他NN从而触发一个故障恢复。 Active NameNode election - ZooKeeper provides a simple mechanism to exclusively select a node as active. If the current active NameNode crashes, another node may take a special exclusive lock in ZooKeeper indicating that it should become the next active.
活动NN选举(Active NameNode election) - ZK提供一个简单的机制专门用来选举活动节点。如果当前的活动NN宕机,另外一个节点会拿到一个在ZK里的特殊的独占锁,这表示这个节点将会成为下一个活动节点。
The ZKFailoverController (ZKFC) is a new component which is a ZooKeeper client which also monitors and manages the state of the NameNode. Each of the machines which runs a NameNode also runs a ZKFC, and that ZKFC is responsible for:
ZKFC是一个新的组件,它是一个ZK客户端,同时监听和管理NN的状态。 运行NN的机器上须同时运行ZKFC ,它的责任是: Health monitoring - the ZKFC pings its local NameNode on a periodic basis with a health-check command. So long as the NameNode responds in a timely fashion with a healthy status, the ZKFC considers the node healthy. If the node has crashed, frozen, or otherwise entered an unhealthy state, the health monitor will mark it as unhealthy.
健康监控(Health monitoring) - ZKFC使用“health-check”命令定期ping本地的NN。只要NN及时的响应一个健康状态,则认为这个节点是健康的。如果节点宕机,无响应或者进入了其他不健康状态,健康监控器认为它是不健康的。 ZooKeeper session management - when the local NameNode is healthy, the ZKFC holds a session open in ZooKeeper. If the local NameNode is active, it also holds a special “lock” znode. This lock uses ZooKeeper’s support for “ephemeral” nodes; if the session expires, the lock node will be automatically deleted.
ZK会话管理(ZooKeeper session management) - 当本地NN是健康的,ZKFC持有ZK的一个打开的会话。如果本地NN是活动状态,ZKFC同时持有一个特殊的锁节点(a special "lock" znode)。这个锁使用了ZK的临时节点。如果会话过期,这个锁节点将被自动删除。 ZooKeeper-based election - if the local NameNode is healthy, and the ZKFC sees that no other node currently holds the lock znode, it will itself try to acquire the lock. If it succeeds, then it has “won the election”, and is responsible for running a failover to make its local NameNode active. The failover process is similar to the manual failover described above: first, the previous active is fenced if necessary, and then the local NameNode transitions to active state.
基于ZK的选举(ZooKeeper-based election) - 如果本地节点是健康的并且ZKFC发现当前没有节点持有锁,它就尝试获取这个锁。如果成功,它就赢得了选举,执行一次故障恢复以使自己成为活动NN。这个故障恢复过程和前面介绍的人工故障恢复是相似的:1、隔离前活动节点(如果需要);2、本地NN转换成活动节点
Deploying ZooKeeper
Before you begin configuring automatic failover, you should shut down your cluster. It is not currently possible to transition from a manual failover setup to an automatic failover setup while the cluster is running.
注意:在开始配置自动故障恢复前,关闭你的集群。目前还不支持在集群运行时将人工故障恢复转换为自动故障恢复。
Installer ZooKeeper: ZK 集群模式部署
参考文档:https://zookeeper.apache.org/doc/r3.4.6/zookeeperStarted.html
解压 zookeeper-3.4.6.tar.gz
vi conf/zoo.cfg # The number of milliseconds of each tick tickTime=2000 # The number of ticks that the initial # synchronization phase can take initLimit=10 # The number of ticks that can pass between # sending a request and getting an acknowledgement syncLimit=5 # the directory where the snapshot is stored. # do not use /tmp for storage, /tmp here is just # example sakes. dataDir=/home/hadoop/zookeeper-3.4.6/tmp # the port at which the clients will connect clientPort=2181 # the maximum number of client connections. # increase this if you need to handle more clients #maxClientCnxns=60 # # Be sure to read the maintenance section of the # administrator guide before turning on autopurge. # # http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance # # The number of snapshots to retain in dataDir #autopurge.snapRetainCount=3 # Purge task interval in hours # Set to "0" to disable auto purge feature #autopurge.purgeInterval=1 server.1=hd1:2888:3888 server.2=hd2:2888:3888 server.3=hd3:2888:3888 配置ServerID
The entries of the form server.X list the servers that make up the ZooKeeper service. When the server starts up, it knows which server it is by looking for the file myid in the data directory. That file has the contains the server number,
server.X标记ZK服务,当服务启动,他会去DataDir目录下寻找一个myid的文件,这个文件包括server.X,
server.1,.2,.3是zookeeper Server.id
mkdir -p /usr/hadoop/zookeeper-3.4.6/tmp
vi /usr/hadoop/zookeeper-3.4.6/tmp/myid [hadoop@hd1 tmp]$ more myid 1 hd1 的 /usr/hadoop/zookeeper-3.4.6/tmp/myid文件写入1,hd2写入2,hd3写入3,依此类推,,, 以上完成ZK的配置工作,可以把配置文件拷贝到其他ZK节点,完成ZK集群的配置。
启动ZK : [hadoop@hd1 bin]$ sh zkServer.sh start JMX enabled by default Using config: /home/hadoop/zookeeper-3.4.6/bin/../conf/zoo.cfg Starting zookeeper ... STARTED [hadoop@hd1 bin]$ jps 1957 QuorumPeerMain 1976 Jps
Configuring automatic failover: In your hdfs-site.xml file, add: dfs.ha.automatic-failover.enabled true In your core-site.xml file, add: ha.zookeeper.quorum hd1:2181,hd2:2181,hd3:2181
This lists the host-port pairs running the ZooKeeper service.
如上地址-端口 应该运行着ZK服务。
Initializing HA state in ZooKeeper
After the configuration keys have been added, the next step is to initialize required state in ZooKeeper. You can do so by running the following command from one of the NameNode hosts .
以上配置都完成之后下一步就是初始化ZK,可以运行如下命令完成初始化: hdfs zkfc -formatZK
This will create a znode in ZooKeeper inside of which the automatic failover system stores its data.
Starting the cluster with “start-dfs.sh”
Since automatic failover has been enabled in the configuration, the start-dfs.sh script will now automatically start a ZKFC daemon on any machine that runs a NameNode. When the ZKFCs start, they will automatically select one of the NameNodes to become active.
HA 启动总结
启动JN(hd2,hd3,hd4): [hadoop@hd4 ~]$ hadoop-daemon.sh start journalnode starting journalnode, logging to /usr/hadoop/hadoop-2.7.1/logs/hadoop-hadoop-journalnode-hd4.out [hadoop@hd4 ~]$ jps 1843 JournalNode 1879 Jps NN格式化(任意一台NN执行,hd1,hd2 ): [hadoop@hd1 sbin]$ hdfs namenode -format 18/10/07 05:54:30 INFO namenode.NameNode: STARTUP_MSG: /************************************************************ STARTUP_MSG: Starting NameNode STARTUP_MSG: host = hd1/192.168.83.11 STARTUP_MSG: args = [-format] STARTUP_MSG: version = 2.7.1 ........ 18/10/07 05:54:34 INFO namenode.FSImage: Allocated new BlockPoolId: BP-841723191-192.168.83.11-1538862874971 18/10/07 05:54:34 INFO common.Storage: Storage directory /usr/hadoop/hadoop-2.7.1/dfs/name has been successfully formatted. 18/10/07 05:54:35 INFO namenode.NNStorageRetentionManager: Going to retain 1 images with txid >= 0 18/10/07 05:54:35 INFO util.ExitUtil: Exiting with status 0 18/10/07 05:54:35 INFO namenode.NameNode: SHUTDOWN_MSG: /************************************************************ SHUTDOWN_MSG: Shutting down NameNode at hd1/192.168.83.11 ************************************************************/ NN元数据拷贝(注意:在拷贝元数据之前,需要提前启动format过的NN,只启动一个节点) 启动format过的NN [hadoop@hd1 current]$ hadoop-daemon.sh start namenode starting namenode, logging to /usr/hadoop/hadoop-2.7.1/logs/hadoop-hadoop-namenode-hd1.out [hadoop@hd1 current]$ jps 1777 QuorumPeerMain 2177 Jps 在未format NN节点(hd2)执行元数据拷贝命令 [hadoop@hd2 ~]$ hdfs namenode -bootstrapStandby 18/10/07 06:07:15 INFO namenode.NameNode: STARTUP_MSG: /************************************************************ STARTUP_MSG: Starting NameNode STARTUP_MSG: host = localhost.localdomain/127.0.0.1 STARTUP_MSG: args = [-bootstrapStandby] STARTUP_MSG: version = 2.7.1 。。。。。。。。。。。。。。。。。。。。。。 ************************************************************/ 18/10/07 06:07:15 INFO namenode.NameNode: registered UNIX signal handlers for [TERM, HUP, INT] 18/10/07 06:07:15 INFO namenode.NameNode: createNameNode [-bootstrapStandby] 18/10/07 06:07:16 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable ===================================================== About to bootstrap Standby ID nn2 from: Nameservice ID: mycluster Other Namenode ID: nn1 Other NN's HTTP address: http://hd1:50070 Other NN's IPC address: hd1/192.168.83.11:8020 Namespace ID: 1626081692 Block pool ID: BP-841723191-192.168.83.11-1538862874971 Cluster ID: CID-230e9e54-e6d1-4baf-a66a-39cc69368ed8 Layout version: -63 isUpgradeFinalized: true ===================================================== 18/10/07 06:07:17 INFO common.Storage: Storage directory /usr/hadoop/hadoop-2.7.1/dfs/name has been successfully formatted. 18/10/07 06:07:18 INFO namenode.TransferFsImage: Opening connection to http://hd1:50070/imagetransfer?getimage=1&txid=0&storageInfo=-63:1626081692:0:CID-230e9e54-e6d1-4baf-a66a-39cc69368ed8 18/10/07 06:07:18 INFO namenode.TransferFsImage: Image Transfer timeout configured to 60000 milliseconds 18/10/07 06:07:18 INFO namenode.TransferFsImage: Transfer took 0.01s at 0.00 KB/s 18/10/07 06:07:18 INFO namenode.TransferFsImage: Downloaded file fsimage.ckpt_0000000000000000000 size 353 bytes. 18/10/07 06:07:18 INFO util.ExitUtil: Exiting with status 0 18/10/07 06:07:18 INFO namenode.NameNode: SHUTDOWN_MSG: /************************************************************ SHUTDOWN_MSG: Shutting down NameNode at localhost.localdomain/127.0.0.1 ************************************************************/ 启动ZK hdfs zkfc -formatZK
格式化ZK报错: 8/10/07 22:34:06 INFO zookeeper.ClientCnxn: Opening socket connection to server hd1/192.168.83.11:2181. Will not attempt to authenticate using SASL (unknown error) 18/10/07 22:34:06 INFO zookeeper.ClientCnxn: Socket connection established to hd1/192.168.83.11:2181, initiating session 18/10/07 22:34:06 INFO zookeeper.ClientCnxn: Unable to read additional data from server sessionid 0x0, likely server has closed socket, closing socket connection and attempting reconnect 18/10/07 22:34:07 INFO zookeeper.ClientCnxn: Opening socket connection to server hd2/192.168.83.22:2181. Will not attempt to authenticate using SASL (unknown error) 18/10/07 22:34:07 INFO zookeeper.ClientCnxn: Socket connection established to hd2/192.168.83.22:2181, initiating session 18/10/07 22:34:07 INFO zookeeper.ClientCnxn: Unable to read additional data from server sessionid 0x0, likely server has closed socket, closing socket connection and attempting reconnect 18/10/07 22:34:07 ERROR ha.ActiveStandbyElector: Connection timed out: couldn't connect to ZooKeeper in 5000 milliseconds 18/10/07 22:34:07 INFO zookeeper.ZooKeeper: Session: 0x0 closed 18/10/07 22:34:07 INFO zookeeper.ClientCnxn: EventThread shut down 18/10/07 22:34:07 FATAL ha.ZKFailoverController: Unable to start failover controller. Unable to connect to ZooKeeper quorum at hd1:2181,hd2:2181,hd3:2181. Please check the configured value for ha.zookeeper.quorum and ensure that ZooKeeper is running. [hadoop@hd1 ~]$

Looks like your zookeeper quorum was not able to elect a master. Maybe you have misconfigured your zookeeper?
Make sure that you have entered all 3 servers in your zoo.cfg with a unique ID. Make sure you have the same config on all 3 of your machines and and make sure that every server is using the correct myId as specified in the cfg.
修改之后重新执行: [hadoop@hd1 bin]$ hdfs zkfc -formatZK 18/10/09 20:27:21 INFO zookeeper.ZooKeeper: Client environment:java.library.path=/home/hadoop/hadoop-2.7.1/lib/native 18/10/09 20:27:21 INFO zookeeper.ZooKeeper: Client environment:java.io.tmpdir=/tmp 18/10/09 20:27:21 INFO zookeeper.ZooKeeper: Client environment:java.compiler= 18/10/09 20:27:21 INFO zookeeper.ZooKeeper: Client environment:os.name=Linux 18/10/09 20:27:21 INFO zookeeper.ZooKeeper: Client environment:os.arch=amd64 18/10/09 20:27:21 INFO zookeeper.ZooKeeper: Client environment:os.version=2.6.32-504.el6.x86_64 18/10/09 20:27:21 INFO zookeeper.ZooKeeper: Client environment:user.name=hadoop 18/10/09 20:27:21 INFO zookeeper.ZooKeeper: Client environment:user.home=/home/hadoop 18/10/09 20:27:21 INFO zookeeper.ZooKeeper: Client environment:user.dir=/home/hadoop/zookeeper-3.4.6/bin 18/10/09 20:27:21 INFO zookeeper.ZooKeeper: Initiating client connection, connectString=hd1:2181,hd2:2181,hd3:2181 sessionTimeout=5000 watcher=org.apache.hadoop.ha.ActiveStandbyElector$WatcherWithClientRef@5119fb47 18/10/09 20:27:21 INFO zookeeper.ClientCnxn: Opening socket connection to server hd1/192.168.83.11:2181. Will not attempt to authenticate using SASL (unknown error) 18/10/09 20:27:22 INFO zookeeper.ClientCnxn: Socket connection established to hd1/192.168.83.11:2181, initiating session 18/10/09 20:27:22 INFO zookeeper.ClientCnxn: Session establishment complete on server hd1/192.168.83.11:2181, sessionid = 0x16658c662c80000, negotiated timeout = 5000 18/10/09 20:27:22 INFO ha.ActiveStandbyElector: Session connected. 18/10/09 20:27:22 INFO ha.ActiveStandbyElector: Successfully created /hadoop-ha/mycluster in ZK. 18/10/09 20:27:22 INFO zookeeper.ZooKeeper: Session: 0x16658c662c80000 closed 18/10/09 20:27:22 INFO zookeeper.ClientCnxn: EventThread shut down
启动ZK: [hadoop@hd1 bin]$ ./zkServer.sh start JMX enabled by default Using config: /home/hadoop/zookeeper-3.4.6/bin/../conf/zoo.cfg Starting zookeeper ... STARTED
启动所有: [hadoop@hd1 bin]$ start-dfs.sh 18/10/09 20:36:58 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable Starting namenodes on [hd1 hd2] hd2: namenode running as process 2065. Stop it first. hd1: namenode running as process 2011. Stop it first. hd2: starting datanode, logging to /home/hadoop/hadoop-2.7.1/logs/hadoop-hadoop-datanode-hd2.out hd4: starting datanode, logging to /home/hadoop/hadoop-2.7.1/logs/hadoop-hadoop-datanode-hd4.out hd3: starting datanode, logging to /home/hadoop/hadoop-2.7.1/logs/hadoop-hadoop-datanode-hd3.out Starting journal nodes [hd2 hd3 hd4] hd4: journalnode running as process 1724. Stop it first. hd2: journalnode running as process 1839. Stop it first. hd3: journalnode running as process 1725. Stop it first. 18/10/09 20:37:10 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable Starting ZK Failover Controllers on NN hosts [hd1 hd2] hd1: zkfc running as process 3045. Stop it first. hd2: zkfc running as process 2601. Stop it first.
查看hd2 DN日志: [hadoop@hd2 logs]$ jps 1984 QuorumPeerMain 2960 Jps 2065 NameNode 2601 DFSZKFailoverController 1839 JournalNode 2018-10-09 20:37:07,674 INFO org.apache.hadoop.hdfs.server.common.Storage: Lock on /home/hadoop/hadoop-2.7.1/dfs/data/in_use.lock acquired by nodename 2787@hd2 2018-10-09 20:37:07,674 WARN org.apache.hadoop.hdfs.server.common.Storage: java.io.IOException: Incompatible clusterIDs in /home/hadoop/hadoop-2.7.1/dfs/data: namenode clusterID = CID-e28f1182-d452 -4f23-9b37-9a59d4bdeaa0; datanode clusterID = CID-876d5634-38e8-464c-be02-714ee8c72878 2018-10-09 20:37:07,675 FATAL org.apache.hadoop.hdfs.server.datanode.DataNode: Initialization failed for Block pool (Datanode Uuid unassigned) service to hd2/192.168.83.22:8020. Exiti ng. java.io.IOException: All specified directories are failed to load. at org.apache.hadoop.hdfs.server.datanode.DataStorage.recoverTransitionRead(DataStorage.java:477) at org.apache.hadoop.hdfs.server.datanode.DataNode.initStorage(DataNode.java:1361) at org.apache.hadoop.hdfs.server.datanode.DataNode.initBlockPool(DataNode.java:1326) at org.apache.hadoop.hdfs.server.datanode.BPOfferService.verifyAndSetNamespaceInfo(BPOfferService.java:316) at org.apache.hadoop.hdfs.server.datanode.BPServiceActor.connectToNNAndHandshake(BPServiceActor.java:223) at org.apache.hadoop.hdfs.server.datanode.BPServiceActor.run(BPServiceActor.java:801) at java.lang.Thread.run(Thread.java:745) 2018-10-09 20:37:07,676 FATAL org.apache.hadoop.hdfs.server.datanode.DataNode: Initialization failed for Block pool (Datanode Uuid unassigned) service to hd1/192.168.83.11:8020. Exiti ng. java.io.IOException: All specified directories are failed to load. at org.apache.hadoop.hdfs.server.datanode.DataStorage.recoverTransitionRead(DataStorage.java:477) at org.apache.hadoop.hdfs.server.datanode.DataNode.initStorage(DataNode.java:1361) at org.apache.hadoop.hdfs.server.datanode.DataNode.initBlockPool(DataNode.java:1326) at org.apache.hadoop.hdfs.server.datanode.BPOfferService.verifyAndSetNamespaceInfo(BPOfferService.java:316) at org.apache.hadoop.hdfs.server.datanode.BPServiceActor.connectToNNAndHandshake(BPServiceActor.java:223) at org.apache.hadoop.hdfs.server.datanode.BPServiceActor.run(BPServiceActor.java:801) at java.lang.Thread.run(Thread.java:745) 2018-10-09 20:37:07,683 WARN org.apache.hadoop.hdfs.server.datanode.DataNode: Ending block pool service for: Block pool (Datanode Uuid unassigned) service to hd1/192.168.83.11:8020 2018-10-09 20:37:07,684 WARN org.apache.hadoop.hdfs.server.datanode.DataNode: Ending block pool service for: Block pool (Datanode Uuid unassigned) service to hd2/192.168.83.22:8020 2018-10-09 20:37:07,687 INFO org.apache.hadoop.hdfs.server.datanode.DataNode: Removed Block pool (Datanode Uuid unassigned) 2018-10-09 20:37:09,688 WARN org.apache.hadoop.hdfs.server.datanode.DataNode: Exiting Datanode 2018-10-09 20:37:09,689 INFO org.apache.hadoop.util.ExitUtil: Exiting with status 0 2018-10-09 20:37:09,698 INFO org.apache.hadoop.hdfs.server.datanode.DataNode: SHUTDOWN_MSG: /************************************************************ SHUTDOWN_MSG: Shutting down DataNode at hd2/192.168.83.22 ************************************************************/
发现hd2 DN没有启动,从日志可以看出 namenode clusterID = CID-e28f1182-d452
-4f23-9b37-9a59d4bdeaa0; datanode clusterID = CID-876d5634-38e8-464c-be02-714ee8c72878 NN_ID和DN_ID不一致导致启动失败。回想自己的操作,由于NN重复格式化 导致NN_ID 发生变化,而DN_ID 没有变化导致不一致,解决办法很简单 把DN 数据删除重新启动DN。
重新查看hd2节点: [hadoop@hd2 dfs]$ jps 1984 QuorumPeerMain 2065 NameNode 3123 DataNode 3268 Jps 2601 DFSZKFailoverController 1839 JournalNode
到目前为止,各个节点实例都启动完毕,现在罗列一下:
hd1: [hadoop@hd1 bin]$ jps 4180 Jps 3045 DFSZKFailoverController 2135 QuorumPeerMain 2011 NameNode
hd2: [hadoop@hd2 dfs]$ jps 1984 QuorumPeerMain 2065 NameNode 3123 DataNode 3268 Jps 2601 DFSZKFailoverController 1839 JournalNode
hd3: [hadoop@hd3 bin]$ jps 2631 Jps 2523 DataNode 1725 JournalNode 1807 QuorumPeerMain
hd4: [hadoop@hd4 ~]$ jps 2311 DataNode 2425 Jps 1724 JournalNode

通过web界面访问NN(任意一个NN):
http://192.168.83.11:50070
http://192.168.83.22:50070
[hadoop @hd1 bin]$ hdfs dfs -put zookeeper.out /
18/10/09 21:11:01 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
[hadoop @hd1 bin]$ hdfs dfs -ls /
18/10/09 21:11:15 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable
Found 1 items
-rw-r--r-- 3 hadoop supergroup 25698 2018-10-09 21:11 /zookeeper.out
下面配置MR
mapred-site.xml mapreduce.framework.name yarn
yarn-site.xml yarn.resourcemanager.hostname hd1 yarn.resourcemanager.aux-services mapreduce_shuffle
web界面管理MR:
http://hd1:8088/
查看服务默认端口 可以在 http://hadoop.apache.org/docs/r2.7.3/hadoop-project-dist/hadoop-common/ClusterSetup.html 下面的configuration 配置项找。
NN手动管理:
[hadoop@hd1 bin]$ hdfs haadmin Usage: haadmin [-transitionToActive [--forceactive] ] [-transitionToStandby ] --前面定义的nn1,nn2 [-failover [--forcefence] [--forceactive] ] [-getServiceState ] [-checkHealth ] [-help ] Generic options supported are -conf specify an application configuration file -D use value for given property -fs specify a namenode -jt specify a ResourceManager -files specify comma separated files to be copied to the map reduce cluster -libjars specify comma separated jar files to include in the classpath. -archives specify comma separated archives to be unarchived on the compute machines.
This guide describes high-level uses of each of these subcommands. For specific usage information of each subcommand, you should run “ hdfs haadmin -help ”. transitionToActive and transitionToStandby - transition the state of the given NameNode to Active or Standby
These subcommands cause a given NameNode to transition to the Active or Standby state, respectively. These commands do not attempt to perform any fencing, and thus should rarely be used. Instead, one should almost always prefer to use the “ hdfs haadmin -failover ” subcommand. failover - initiate a failover between two NameNodes
This subcommand causes a failover from the first provided NameNode to the second. If the first NameNode is in the Standby state, this command simply transitions the second to the Active state without error. If the first NameNode is in the Active state, an attempt will be made to gracefully transition it to the Standby state. If this fails, the fencing methods (as configured by dfs.ha.fencing.methods ) will be attempted in order until one succeeds. Only after this process will the second NameNode be transitioned to the Active state. If no fencing method succeeds, the second NameNode will not be transitioned to the Active state, and an error will be returned. getServiceState - determine whether the given NameNode is Active or Standby
Connect to the provided NameNode to determine its current state, printing either “standby” or “active” to STDOUT appropriately. This subcommand might be used by cron jobs or monitoring scripts which need to behave differently based on whether the NameNode is currently Active or Standby. checkHealth - check the health of the given NameNode
Connect to the provided NameNode to check its health. The NameNode is capable of performing some diagnostics on itself, including checking if internal services are running as expected. This command will return 0 if the NameNode is healthy, non-zero otherwise. One might use this command for monitoring purposes.
Note: This is not yet implemented, and at present will always return success, unless the given NameNode is completely down.
大数据
2018-10-07 16:01:00
「深度学习福利」大神带你进阶工程师,立即查看>>>

节点及实例规划:

High Availability With QJM 部署要点及注意事项请参考 https://my.oschina.net/u/3862440/blog/2208568 HA 部署小节。

编辑"hdfs-site.xml"
dfs.nameservices
--配置命名服务,一个集群一个服务名,服务名下面包含多个服务和几点,对外统一提供服务。 dfs.nameservices mycluster
dfs.ha.namenodes.[nameservice ID]
--配置所有的NN的service id,一个service服务下面有多个NN节点,为了做NN高可用,集群必须知道每个节点的ID,以便区分。我这里规划了2个NN,所以NN ID有两个。 dfs.ha.namenodes.mycluster nn1,nn2
dfs.namenode.rpc-address.[nameservice ID].[name node ID]
--配置所有的NN的rpc协议(用于NN与DN或者客户端之间的数据传输),我这里配置了2个NN 3个DN,所以这里需要为这两个NN配置rpc传输协议。 dfs.namenode.rpc-address.mycluster.nn1 hd1:8020 dfs.namenode.rpc-address.mycluster.nn2 hd2:8020
dfs.namenode.http-address.[nameservice ID].[name node ID]
--配置所有NN的http传输协议,也就是客户端管理管理的web界面传输协议,这个需要连接到各个NN,所以需要配置2个NN的http协议。 dfs.namenode.http-address.mycluster.nn1 hd1:50070 dfs.namenode.http-address.mycluster.nn2 hd2:50070
dfs.namenode.shared.edits.dir
-- the URI which identifies the group of JNs where the NameNodes will write/read edits。 dfs.namenode.shared.edits.dir qjournal://hd2:8485;hd3:8485;hd4:8485/mycluster
dfs.journalnode.edits.dir (不存在需要创建)
- the path where the JournalNode daemon will store its local state。
这里需要明白JN在此处的用途,引用官方的一句话“Using the Quorum Journal Manager or Conventional Shared Storage”,可以很清楚看出JN是管理和转化 共享 存储的,所以既然是共享存储,肯定跟DN有关系,所以也需要配置3个JN,这3个JN存放的是edits日志,被所有的NN和DN所共享。 dfs.journalnode.edits.dir /home/hadoop/journal/node/local/data
dfs.client.failover.proxy.provider.[nameservice ID]
--固定配置,配置客户端连接。客户端通过这个类方法连接到集群,必须配置。 dfs.client.failover.proxy.provider.mycluster org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider
dfs.ha.fencing.methods
--配置sshfence ,这个跟配置ssh对等性(免密登录)的功能一样,但是方法不一样。因为做高可用,客户端通过集群服务名连接集群,集群内部有多个NN,我们只做了NN和DN之间的免密登录,但是集群跟NN之间的没有做,说白了就是ZK跟NN之间需要免密登录。 dfs.ha.fencing.methods sshfence dfs.ha.fencing.ssh.private-key-files /home/hadoop/.ssh/id_rsa
Configuring automatic failover 1:
--配置自动切换,自动切换需要配置ZK,由ZK统一管理NN。客户端请求ZK,ZK搜索集群内活动的NN,然后提供服务。 dfs.ha.automatic-failover.enabled true
编辑 core-site.xml
fs.defaultFS
--配置dfs默认目录 fs.defaultFS hdfs://mycluster
Configuring automatic failover 2:--配置自动切换 ha.zookeeper.quorum hd1:2181,hd2:2181,hd3:2181
配置hadoop临时目录(不存在需要创建) hadoop.tmp.dir /usr/hadoop/hadoop-2.7.1
配置Datanode [hadoop@hd1 hadoop]$ more slaves hd2 hd3 hd4
注意:masters(SNN),yarn,MR不需要配置。
拷贝配置文件到hd2,hd3,hd4节点。
配置zookeep:
解压 zookeeper-3.4.6.tar.gz
配置 dataDir=/usr/hadoop/zookeeper-3.4.6/tmp server.1=hd1:2888:3888 server.2=hd2:2888:3888 server.3=hd3:2888:3888
server.1,.2,.3是zookeeper id
mkdir -p /usr/hadoop/zookeeper-3.4.6/tmp
mkdir -p /home/hadoop/journal/node/local/data
vi /usr/hadoop/zookeeper-3.4.6/tmp/myid [hadoop@hd1 tmp]$ more myid 1
hd1 的 /usr/hadoop/zookeeper-3.4.6/tmp/myid文件写入1,hd2写入2,hd3写入3,依此类推,,,
拷贝zookeeper 到节点2,节点3 scp -r zookeeper-3.4.6/ hadoop@hd3:/usr/hadoop/
配置JN PATH路径
启动ZK(需要在hd1,hd2,hd3节点启动zk):
sh zkServer.sh start JMX enabled by default Using config: /usr/hadoop/zookeeper-3.4.6/bin/../conf/zoo.cfg Starting zookeeper ... STARTED [hadoop@hd1 bin]$ jps 1777 QuorumPeerMain 1795 Jps
启动JN(hd2,hd3,hd4): [hadoop@hd4 ~]$ hadoop-daemon.sh start journalnode starting journalnode, logging to /usr/hadoop/hadoop-2.7.1/logs/hadoop-hadoop-journalnode-hd4.out [hadoop@hd4 ~]$ jps 1843 JournalNode 1879 Jps
NN格式化(任意一台NN执行,hd1,hd2 ): [hadoop@hd1 sbin]$ hdfs namenode -format 18/10/07 05:54:30 INFO namenode.NameNode: STARTUP_MSG: /************************************************************ STARTUP_MSG: Starting NameNode STARTUP_MSG: host = hd1/192.168.83.11 STARTUP_MSG: args = [-format] STARTUP_MSG: version = 2.7.1 ........ 18/10/07 05:54:34 INFO namenode.FSImage: Allocated new BlockPoolId: BP-841723191-192.168.83.11-1538862874971 18/10/07 05:54:34 INFO common.Storage: Storage directory /usr/hadoop/hadoop-2.7.1/dfs/name has been successfully formatted. 18/10/07 05:54:35 INFO namenode.NNStorageRetentionManager: Going to retain 1 images with txid >= 0 18/10/07 05:54:35 INFO util.ExitUtil: Exiting with status 0 18/10/07 05:54:35 INFO namenode.NameNode: SHUTDOWN_MSG: /************************************************************ SHUTDOWN_MSG: Shutting down NameNode at hd1/192.168.83.11 ************************************************************/
元数据文件已经生成 ,目前只是在执行了format节点上有元数据,所以需要拷贝到另外一台NN节点
ls /usr/hadoop/hadoop-2.7.1/dfs/name/current total 16 -rw-rw-r-- 1 hadoop hadoop 353 Oct 7 05:54 fsimage_0000000000000000000 -rw-rw-r-- 1 hadoop hadoop 62 Oct 7 05:54 fsimage_0000000000000000000.md5 -rw-rw-r-- 1 hadoop hadoop 2 Oct 7 05:54 seen_txid -rw-rw-r-- 1 hadoop hadoop 205 Oct 7 05:54 VERSION
NN元数据拷贝(注意:在拷贝元数据之前,需要提前启动format过的NN,只启动一个节点) 启动format的NN [hadoop@hd1 current]$ hadoop-daemon.sh start namenode starting namenode, logging to /usr/hadoop/hadoop-2.7.1/logs/hadoop-hadoop-namenode-hd1.out [hadoop@hd1 current]$ jps 1777 QuorumPeerMain 2177 Jps 在未format NN节点(hd2)执行元数据拷贝命令 [hadoop@hd2 ~]$ hdfs namenode -bootstrapStandby 18/10/07 06:07:15 INFO namenode.NameNode: STARTUP_MSG: /************************************************************ STARTUP_MSG: Starting NameNode STARTUP_MSG: host = localhost.localdomain/127.0.0.1 STARTUP_MSG: args = [-bootstrapStandby] STARTUP_MSG: version = 2.7.1 。。。。。。。。。。。。。。。。。。。。。。 ************************************************************/ 18/10/07 06:07:15 INFO namenode.NameNode: registered UNIX signal handlers for [TERM, HUP, INT] 18/10/07 06:07:15 INFO namenode.NameNode: createNameNode [-bootstrapStandby] 18/10/07 06:07:16 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable ===================================================== About to bootstrap Standby ID nn2 from: Nameservice ID: mycluster Other Namenode ID: nn1 Other NN's HTTP address: http://hd1:50070 Other NN's IPC address: hd1/192.168.83.11:8020 Namespace ID: 1626081692 Block pool ID: BP-841723191-192.168.83.11-1538862874971 Cluster ID: CID-230e9e54-e6d1-4baf-a66a-39cc69368ed8 Layout version: -63 isUpgradeFinalized: true ===================================================== 18/10/07 06:07:17 INFO common.Storage: Storage directory /usr/hadoop/hadoop-2.7.1/dfs/name has been successfully formatted. 18/10/07 06:07:18 INFO namenode.TransferFsImage: Opening connection to http://hd1:50070/imagetransfer?getimage=1&txid=0&storageInfo=-63:1626081692:0:CID-230e9e54-e6d1-4baf-a66a-39cc69368ed8 18/10/07 06:07:18 INFO namenode.TransferFsImage: Image Transfer timeout configured to 60000 milliseconds 18/10/07 06:07:18 INFO namenode.TransferFsImage: Transfer took 0.01s at 0.00 KB/s 18/10/07 06:07:18 INFO namenode.TransferFsImage: Downloaded file fsimage.ckpt_0000000000000000000 size 353 bytes. 18/10/07 06:07:18 INFO util.ExitUtil: Exiting with status 0 18/10/07 06:07:18 INFO namenode.NameNode: SHUTDOWN_MSG: /************************************************************ SHUTDOWN_MSG: Shutting down NameNode at localhost.localdomain/127.0.0.1 ************************************************************/
检查hd2节点下是否有元数据存在 [hadoop@hd2 current]$ ls -l /usr/hadoop/hadoop-2.7.1/dfs/name/current total 16 -rw-rw-r-- 1 hadoop hadoop 353 Oct 7 06:17 fsimage_0000000000000000000 -rw-rw-r-- 1 hadoop hadoop 62 Oct 7 06:17 fsimage_0000000000000000000.md5 -rw-rw-r-- 1 hadoop hadoop 2 Oct 7 06:17 seen_txid -rw-rw-r-- 1 hadoop hadoop 205 Oct 7 06:17 VERSION
启动所有服务: [hadoop@hd1 current]$ start-dfs.sh 18/10/07 06:30:07 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable Starting namenodes on [hd1 hd2] hd2: starting namenode, logging to /usr/hadoop/hadoop-2.7.1/logs/hadoop-hadoop-namenode-hd2.out hd1: starting namenode, logging to /usr/hadoop/hadoop-2.7.1/logs/hadoop-hadoop-namenode-hd1.out hd3: starting datanode, logging to /usr/hadoop/hadoop-2.7.1/logs/hadoop-hadoop-datanode-hd3.out hd4: starting datanode, logging to /usr/hadoop/hadoop-2.7.1/logs/hadoop-hadoop-datanode-hd4.out hd2: starting datanode, logging to /usr/hadoop/hadoop-2.7.1/logs/hadoop-hadoop-datanode-hd2.out Starting journal nodes [hd2 hd3 hd4] hd4: starting journalnode, logging to /usr/hadoop/hadoop-2.7.1/logs/hadoop-hadoop-journalnode-hd4.out hd2: starting journalnode, logging to /usr/hadoop/hadoop-2.7.1/logs/hadoop-hadoop-journalnode-hd2.out hd3: starting journalnode, logging to /usr/hadoop/hadoop-2.7.1/logs/hadoop-hadoop-journalnode-hd3.out 18/10/07 06:30:27 WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using builtin-java classes where applicable Starting ZK Failover Controllers on NN hosts [hd1 hd2] hd2: starting zkfc, logging to /usr/hadoop/hadoop-2.7.1/logs/hadoop-hadoop-zkfc-hd2.out hd1: starting zkfc, logging to /usr/hadoop/hadoop-2.7.1/logs/hadoop-hadoop-zkfc-hd1.out [hadoop@hd1 current]$ jps 1777 QuorumPeerMain 3202 NameNode 3511 DFSZKFailoverController 3548 Jps
hd2: [hadoop@hd2 ~]$ jps 3216 NameNode 3617 Jps 3364 JournalNode 3285 DataNode 1915 QuorumPeerMain
hd2节点 zkfc未启动,查看日志 2018-10-07 06:30:38,441 ERROR org.apache.hadoop.ha.ActiveStandbyElector: Connection timed out: couldn't connect to ZooKeeper in 5000 milliseconds 2018-10-07 06:30:39,318 INFO org.apache.zookeeper.ZooKeeper: Session: 0x0 closed 2018-10-07 06:30:39,320 INFO org.apache.zookeeper.ClientCnxn: EventThread shut down 2018-10-07 06:30:39,330 FATAL org.apache.hadoop.ha.ZKFailoverController: Unable to start failover controller. Unable to connect to ZooKeeper quorum at hd1:2181,hd2:2181,hd3:2181. Please check the c onfigured value for ha.zookeeper.quorum and ensure that ZooKeeper is running.
zk 未格式化导致,在其中一台NN格式化zk重新启动
退到hd1节点,执行stop-dfs.sh
hdfs zkfc -formatZK
大数据
2018-10-06 18:33:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
1,ERROR Utils: Aborting task java.io.IOException: key out of order: For after package
先上代码 public static void main(String[] args) throws ClassNotFoundException { SparkConf sparkConf = new SparkConf().setAppName("SparkTest-MapFile").setMaster("local"); sparkConf.registerKryoClasses(new Class[] { Class.forName("org.apache.hadoop.io.IntWritable"), Class.forName("org.apache.hadoop.io.Text") }); JavaSparkContext ctx = new JavaSparkContext(sparkConf); JavaRDD jpr = ctx.textFile("/README.md"); jpr.foreach(v -> { System.out.println(v); }); JavaRDD words = jpr.flatMap(line -> Arrays.asList(line.split(" ")).iterator()); JavaPairRDD counts = words.mapToPair(w -> new Tuple2(w, 1)) .reduceByKey((x, y) -> x + y); counts.mapToPair(v -> new Tuple2(new Text(v._1()), new IntWritable(v._2()))) .saveAsNewAPIHadoopFile("/tmp/test6", Text.class, IntWritable.class, MapFileOutputFormat.class); }
按理说这样的写法是没有问题的,但是就是一直报错,不明原因,各种找也没有找到相应的解决办法,也没有找到有人跟我一样出现问题,然后自己就开始各种无头苍蝇乱找,后面MapFileOutputFormat改为了SequenceFileOutputFormat的方式保存就没问题,这就让纠结了,后面无意间看到 hadoop的Map存储方式有有序的,就想到是不是存储前要自己手动排序下,修改代码加入排序.sortByKey(),然后在进行运行,完美运行成功。 public static void main(String[] args) throws ClassNotFoundException { SparkConf sparkConf = new SparkConf().setAppName("SparkTest-MapFile").setMaster("local"); sparkConf.registerKryoClasses(new Class[] { Class.forName("org.apache.hadoop.io.IntWritable"), Class.forName("org.apache.hadoop.io.Text") }); JavaSparkContext ctx = new JavaSparkContext(sparkConf); JavaRDD jpr = ctx.textFile("/README.md"); jpr.foreach(v -> { System.out.println(v); }); JavaRDD words = jpr.flatMap(line -> Arrays.asList(line.split(" ")).iterator()); JavaPairRDD counts = words.mapToPair(w -> new Tuple2(w, 1)) .reduceByKey((x, y) -> x + y); counts.mapToPair(v -> new Tuple2(new Text(v._1()), new IntWritable(v._2()))) .sortByKey().saveAsNewAPIHadoopFile("/tmp/test6", Text.class, IntWritable.class, MapFileOutputFormat.class); }
猜测可能JavaPairRDD对map方式的存储需要自己排序的,真正是不是这样的原因就不知道了,希望哪位大神知道的话可以告知下
大数据
2018-10-10 17:10:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
presto 介绍 是Facebook开源的,完全基于内存的并⾏计算,分布式SQL交互式查询引擎 是一种Massively parallel processing (MPP)架构,多个节点管道式执⾏ ⽀持任意数据源(通过扩展式Connector组件),数据规模GB~PB级 使用的技术,如向量计算,动态编译执⾏计划,优化的ORC和Parquet Reader等 presto不太支持存储过程,支持部分标准sql presto的查询速度比hive快5-10倍
presto应用场景 适合:PB级海量数据复杂分析,交互式SQL查询,⽀持跨数据源查询 不适合:多个大表的join操作,因为presto是基于内存的,多张大表在内存里可能放不下
框架对比
presto:facebook开源的一个java写的分布式数据查询框架,是一个交互式查询引擎,原生集成了Hive、Hbase和关系型数据库,Presto背后所使用的执行模式与Hive有根本的不同,它没有使用MapReduce,大部分场景下比hive快一个数量级,其中的关键是所有的处理都在内存中完成。
Druid:是一个实时处理时序数据的Olap数据库,因为它的索引首先按照时间分片,查询的时候也是按照时间线去路由索引。
spark SQL:基于spark平台上的一个olap框架,本质上也是基于DAG的MPP, 基本思路是增加机器来并行计算,从而提高查询速度。
kylin:核心是Cube,cube是一种预计算技术,基本思路是预先对数据作多维索引,查询时只扫描索引而不访问原始数据从而提速。
presto总体架构
跟hive架构相似
hive:client将查询请求发送到hive server,它会和metastor交互,获取表的元信息,如表的位置结构等,之后hive server会进行语法解析,解析成语法树,变成查询计划,进行优化后,将查询计划交给执行引擎,默认是MR,然后翻译成MR
presto内部架构
这里面三个服务:
Coordinator是一个中心的查询角色,它主要的一个作用是接受查询请求,将他们转换成各种各样的任务,将任务拆解后分发到多个worker去执行各种任务的节点
1、解析SQL语句
2、⽣成执⾏计划
3、分发执⾏任务给Worker节点执⾏
Worker,是一个真正的计算的节点,执行任务的节点,它接收到task后,就会到对应的数据源里面,去把数据提取出来,提取方式是通过各种各样的connector:
1、负责实际执⾏查询任务
Discovery service,是将coordinator和woker结合到一起的服务:
1、Worker节点启动后向Discovery Server服务注册
2、Coordinator从Discovery Server获得Worker节点
coordinator和woker之间的关系是怎么维护的呢?是通过Discovery Server,所有的worker都把自己注册到Discovery Server上,Discovery Server是一个发现服务的service,Discovery Server发现服务之后,coordinator便知道在我的集群中有多少个worker能够给我工作,然后我分配工作到worker时便有了根据
最后,presto是通过connector plugin获取数据和元信息的,它不是⼀个数据存储引擎,不需要有数据,presto为其他数据存储系统提供了SQL能⼒,客户端协议是HTTP+JSON
大数据
2018-09-19 12:14:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
Hanlp是由一系列模型与算法组成的工具包,目标是普及自然语言处理在生产环境中的应用。Hanlp具备功能完善、性能高效、架构清洗、语料时新、可自定义的特点;提供词法分析(中文分词、磁性标注、命名实体识别)、句法分析、文本分类和情感分析等功能。
本篇将用户输入的语句根据词库进行分词、关键词提取、摘要提取、词库维护。
工具类名称:DKNLPBase

1、 标准分词
方法签名: List StandardTokenizer.segment(String txt);
返回:分词列表。
签名参数说明 :txt:要分词的语句。
范例: 下例验证一段话第5个分词是阿法狗。
程序清单 1

public void testSegment() throws Exception
{
String text = "商品和服务";
List termList = DKNLPBase.segment(text);
assertEquals("商品", termList.get(0).word);
assertEquals("和", termList.get(1).word);
assertEquals("服务", termList.get(2).word);
text = "柯杰解说“李世石VS阿法狗第二局” 结局竟是这样";
termList = DKNLPBase.segment(text);
assertEquals("阿法狗", termList.get(5).word); // 能够识别"阿法狗"
}

2、 关键词提取
方法签名: List extractKeyword(String txt,int keySum);
返回:关键词列表.
签名参数说明 :txt:要提取关键词的语句,keySum要提取关键词的数量
范例: 给出一段话提取一个关键词是“程序员”。
程序清单 2

public void testExtractKeyword() throws Exception
{
String content = "程序员(英文Programmer)是从事程序开发、维护的专业人员。" +
"一般将程序员分为程序设计人员和程序编码人员," +
"但两者的界限并不非常清楚,特别是在中国。" +
"软件从业人员分为初级程序员、高级程序员、系统" +
"分析员和项目经理四大类。";
List keyword = DKNLPBase.extractKeyword(content, 1);
assertEquals(1, keyword.size());
assertEquals("程序员", keyword.get(0));
}


3、 短语提取
方法签名: List extractPhrase(String txt, int phSum);
返回:短语
签名参数说明 :txt:要提取短语的语句,phSum短语数量
范例: 给出一段文字,能代表文章的五个短语,第一个短语是算法工程师。
程序清单 3

public void testExtractPhrase() throws Exception
{
String text = "算法工程师\n" +
"算法(Algorithm)是一系列解决问题的清晰指令,也就是说,能够对一定规范的输入,在有限时间内获得所要求的输出。" +
"如果一个算法有缺陷,或不适合于某个问题,执行这个算法将不会解决这个问题。不同的算法可能用不同的时间、" +
"空间或效率来完成同样的任务。一个算法的优劣可以用空间复杂度与时间复杂度来衡量。算法工程师就是利用算法处理事物的人。\n" +
"\n" +
"1职位简介\n" +
"算法工程师是一个非常高端的职位;\n" +
"专业要求:计算机、电子、通信、数学等相关专业;\n" +
"学历要求:本科及其以上的学历,大多数是硕士学历及其以上;\n" +
"语言要求:英语要求是熟练,基本上能阅读国外专业书刊;\n" +
"必须掌握计算机相关知识,熟练使用仿真工具MATLAB等,必须会一门编程语言。\n" +
"\n" +
"2研究方向\n" +
"视频算法工程师、图像处理算法工程师、音频算法工程师 通信基带算法工程师\n" +
"\n" +
"3目前国内外状况\n" +
"目前国内从事算法研究的工程师不少,但是高级算法工程师却很少,是一个非常紧缺的专业工程师。" +
"算法工程师根据研究领域来分主要有音频/视频算法处理、图像技术方面的二维信息算法处理和通信物理层、" +
"雷达信号处理、生物医学信号处理等领域的一维信息算法处理。\n" +
"在计算机音视频和图形图像技术等二维信息算法处理方面目前比较先进的视频处理算法:机器视觉成为此类算法研究的核心;" +
"另外还有2D转3D算法(2D-to-3D conversion),去隔行算法(de-interlacing),运动估计运动补偿算法" +
"(Motion estimation/Motion Compensation),去噪算法(Noise Reduction),缩放算法(scaling)," +
"锐化处理算法(Sharpness),超分辨率算法(Super Resolution),手势识别(gesture recognition),人脸识别(face recognition)。\n" +
"在通信物理层等一维信息领域目前常用的算法:无线领域的RRM、RTT,传送领域的调制解调、信道均衡、信号检测、网络优化、信号分解等。\n" +
"另外数据挖掘、互联网搜索算法也成为当今的热门方向。\n" +
"算法工程师逐渐往人工智能方向发展。";
List phraseList = DKNLPBase.extractPhrase(text, 5);
assertEquals(5, phraseList.size());
assertEquals("算法工程师", phraseList.get(0));
}

4、 自动摘要
方法签名: List extractSummary(String txt, int sSum);
返回:摘要语句
签名参数说明: txt:要提取摘要的语句,sSum摘要句子数量
范例: 自动提取三句摘要句子。
程序清单 4

public void testExtractSummary() throws Exception
{
String document = "算法可大致分为基本算法、数据结构的算法、数论算法、计算几何的算法、图的算法、动态规划以及数值分析、加密算法、排序算法、检索算法、随机化算法、并行算法、厄米变形模型、随机森林算法。\n" +
"算法可以宽泛的分为三类,\n" +
"一,有限的确定性算法,这类算法在有限的一段时间内终止。他们可能要花很长时间来执行指定的任务,但仍将在一定的时间内终止。这类算法得出的结果常取决于输入值。\n" +
"二,有限的非确定算法,这类算法在有限的时间内终止。然而,对于一个(或一些)给定的数值,算法的结果并不是唯一的或确定的。\n" +
"三,无限的算法,是那些由于没有定义终止定义条件,或定义的条件无法由输入的数据满足而不终止运行的算法。通常,无限算法的产生是由于未能确定的定义终止条件。";
List sentenceList = DKNLPBase.extractSummary(document, 3);
assertEquals(3, sentenceList.size());
}

5、 拼音转换
方法签名: List convertToPinyinList(txt);
返回:拼音列表
签名参数说明 :txt:要转换拼音的语句
范例 :给出一段文字中第二个字的拼音。
程序清单 5

public void testConvertToPinyinList() throws Exception
{
String text = "鸭绿江的绿跟绿色的绿不是一个读音";
List pinyinList = DKNLPBase.convertToPinyinList(text);
assertEquals(text.length(), pinyinList.size());
assertEquals(Pinyin.lu4, pinyinList.get(1));
}

6、 添加词库
方法签名: String addCK(String filePath);
返回:空—完成,其它—错误信息
签名参数说明 :filePath:新的词库文件,每个词使用回车换行分隔。
范例: 读取新词库文件,将文件内容中第7个词“新美“添加到词库。
程序清单 6

public void testAddCK() throws Exception
{
DKNLPBase.addCK("src/test/resources/custom_dictionary.txt");
String text = "互联网家装质量问题频繁 新美大杀入胜算几何";
List termList = DKNLPBase.segment(text);
assertEquals("新美", termList.get(6).word);
}

7、 新词发现
方法签名:
NewWordDiscover discover = new NewWordDiscover(max_word_len, min_freq, min_entropy, min_aggregation, filter);
discover.discovery(text, size);
返回:空—完成,其它—错误信息
签名参数说明: max_word_len: 控制识别结果中最长的词语长度,默认值是 4;该值越大,运算量越大,结果中出现短语的数量也会越多。
min_freq: 控制结果中词语的最低频率,低于该频率的将会被过滤掉,减少一 些运算量。由于结果是按照频率排序的,所以该参数其实意义不大。实际上,在接口中直接设为了0,意思是所有候选词都会出来。
min_entropy: 控制结果中词语的最低信息熵(信息的不确定度)的值,一般取 0.5 左右。该值越 大,越短的词语就越容易被提取出来。
min_aggregation: 控制结果中词语的最低互信息值(字和字之间的关联性),一般取 50 到 200.该值 越大,越长的词语就越容易被提取出来,有时候会出现一些短语。
Filter: 设为 true 的时候将使用内部词库过滤掉“旧词”。
Text:用于新词发现的文档。
Size:新词个数。
范例: 新词发现。
程序清 7

public void testFindNewWord() {
NewWordDiscover discover = new NewWordDiscover(4, 0.0f, 0.5f, 100f, true);

//读取文件夹下所以文档并合并成一篇文档用于新词发现
StringBuilder sbText = new StringBuilder();
File[] txtFiles = new File("src/test/resources/搜狗文本分类语料库微型版/健康").listFiles();
int i = 0;
for (File file : txtFiles)
{
System.out.printf("[%d / %d] 读取 %s 中...\n", ++i, txtFiles.length, file.getName());
sbText.append(IOUtil.readTxt(file.getPath()));
if (i == 100) break;
}
System.out.printf("对长度为%d的语料进行分析中...\n", sbText.length());
List wordInfoList = discover.discovery(sbText.toString(), 10);
//打印出发现的新词
for (WordInfo wordInfo : wordInfoList) {
System.out.println(wordInfo.text);
}
}
大数据
2018-09-19 11:15:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
本文转载自: https://blog.csdn.net/Sugar_girl/article/details/77867618 并加入了自己安装中遇到的一些问题.
本次安装部署版本: Hadoop2.8.1+Scala2.12.3+Spark2.2.0
1.环境准备
修改主机名
  我们将搭建1个master,2个slave的集群方案。首先修改主机名vi /etc/hostname,在master上修改为master,其中一个slave上修改为slave1,另一个修改为slave2。
配置hosts
  在每台主机上修改host文件 vi /etc/hosts 10.1.1.107 master 10.1.1.108 slave1 10.1.1.109 slave2
  配置之后ping一下用户名看是否生效 ping slave1 ping slave2
SSH 免密码登录
  安装Openssh server sudo apt-get install openssh-server
  在所有机器上都生成私钥和公钥 ssh-keygen -t rsa #一路回车
  需要让机器间都能相互访问,就把每个机子上的id_rsa.pub发给master节点,传输公钥可以用scp来传输。 scp ~/.ssh/id_rsa.pub tx@master:~/.ssh/id_rsa.pub.slave1
  在master上,将所有公钥加到用于认证的公钥文件authorized_keys中 cat ~/.ssh/id_rsa.pub* >> ~/.ssh/authorized_keys   将公钥文件authorized_keys分发给每台slave scp ~/.ssh/authorized_keys tx@slave1:~/.ssh/
  在每台机子上验证SSH无密码通信 ssh master ssh slave1 ssh slave2
  如果登陆测试不成功,则可能需要修改文件authorized_keys的权限(权限的设置非常重要,因为不安全的设置安全设置,会让你不能使用RSA功能 ) chmod 600 ~/.ssh/authorized_keys
  如果遇到ssh登录The authenticity of host 192.168.xxx.xxx can’t be established.的问题,执行scp报错 The authenticity of host '192.168.23.130 (192.168.23.130)' can't be established. ECDSA key fingerprint is SHA256:EsqTfeCJ34DnGV66REuRRPhoFwaLuee5wxFgEAZ8b9k. Are you sure you want to continue connecting (yes/no)? Host key verification failed. lost connection
  这时,修改/etc/ssh/ssh_config文件的配置,以后则不会再出现此问题,在最后面添加: StrictHostKeyChecking no UserKnownHostsFile /dev/null
安装 Java
  从官网下载最新版 Java 就可以,Spark官方说明 Java 只要是6以上的版本都可以,我下的是 jdk-8u144-linux-x64.tar.gz ,在~/workspace目录下直接解压。 tar -zxvf jdk-8u144-linux-x64.tar.gz
  修改环境变量sudo vi /etc/profile,添加下列内容,注意将home路径替换成你的: export WORK_SPACE=/home/tx/workspace/ export JAVA_HOME=$WORK_SPACE/jdk1.8.0_144 export JRE_HOME=/home/tx/workspace/jdk1.8.0_144/jre export PATH=$JAVA_HOME/bin:$JAVA_HOME/jre/bin:$PATH export CLASSPATH=$CLASSPATH:.:$JAVA_HOME/lib:$JAVA_HOME/jre/lib
  然后使环境变量生效,并验证 Java 是否安装成功 $ source /etc/profile #生效环境变量 $ java -version #如果打印出如下版本信息,则说明安装成功 java version "1.8.0_144" Java(TM) SE Runtime Environment (build 1.8.0_144-b01) Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode)
安装 Scala
   官方下载 Scala2.12.3,同样在~/workspace中解压. tar -zxvf scala-2.12.3.tgz
  再次修改环境变量sudo vi /etc/profile,添加以下内容: export SCALA_HOME=$WORK_SPACE/scala-2.12.3 export PATH=$PATH:$SCALA_HOME/bin
  同样的方法使环境变量生效,并验证 scala 是否安装成功 $ source /etc/profile #生效环境变量 $ scala -version #如果打印出如下版本信息,则说明安装成功 Scala code runner version 2.12.3 -- Copyright 2002-2017, LAMP/EPFL and Lightbend, Inc.
2.安装配置 Hadoop YARN
下载解压
  从官网下载 hadoop2.8.1 版本,同样在~/workspace中解压。 tar -zxvf hadoop-2.8.1.tar.gz
配置 Hadoop
  cd ~/workspace/hadoop-2.8.1/etc/hadoop进入hadoop配置目录,需要配置有以下7个文件:hadoop-env.sh,yarn-env.sh,slaves,core-site.xml,hdfs-site.xml,maprd-site.xml,yarn-site.xml 在hadoop-env.sh中配置JAVA_HOME # The java implementation to use. export JAVA_HOME=/home/tx/workspace/jdk1.8.0_144 在yarn-env.sh中配置JAVA_HOME # The java implementation to use. export JAVA_HOME=/home/tx/workspace/jdk1.8.0_144 在slaves中配置slave节点的ip或者host slave1 slave2 修改core-site.xml fs.defaultFS hdfs://master:9000/ hadoop.tmp.dir file:/home/tx/workspace/hadoop-2.8.1/tmp 修改hdfs-site.xml dfs.namenode.secondary.http-address master:9001 dfs.namenode.name.dir file:/home/tx/workspace/hadoop-2.8.1/dfs/name dfs.datanode.data.dir file:/home/tx/workspace/hadoop-2.8.1/dfs/data dfs.replication 3 修改mapred-site.xml mapreduce.framework.name yarn 修改yarn-site.xml yarn.nodemanager.aux-services mapreduce_shuffle yarn.nodemanager.aux-services.mapreduce.shuffle.class org.apache.hadoop.mapred.ShuffleHandler yarn.resourcemanager.address master:8032 yarn.resourcemanager.scheduler.address master:8030 yarn.resourcemanager.resource-tracker.address master:8035 yarn.resourcemanager.admin.address master:8033 yarn.resourcemanager.webapp.address master:8088
  将配置好的hadoop-2.8.1文件夹分发给所有slaves scp -r ~/workspace/hadoop-2.8.1 tx@slave1:~/workspace/hadoop-2.8.1
启动 Hadoop
  在 master 上执行以下操作,就可以启动 hadoop 了。 cd ~/workspace/hadoop-2.8.1 #进入hadoop目录 bin/hadoop namenode -format #格式化namenode sbin/start-dfs.sh #启动dfs sbin/start-yarn.sh #启动yarn
验证 Hadoop 是否安装成功
  可以通过jps命令查看各个节点启动的进程是否正常。在 master 上应该有以下几个进程: $ jps #run on master 3407 SecondaryNameNode 3218 NameNode 3552 ResourceManager 3910 Jps
  在每个slave上应该有以下几个进程: $ jps #run on slaves 2072 NodeManager 2213 Jps 1962 DataNode
  或者在浏览器中输入 http://master:8088 ,应该有 hadoop 的管理界面出来了,并能看到 slave1 和 slave2 节点。
  此时,如果你发现slave中datanode没有启动,则将slave的tmp、data、node文件全部删除,重启hadoop即可解决问题。
3. Spark安装
下载解压
  进入官方下载地址下载最新版 Spark。我下载的是 spark-2.2.0-bin-hadoop2.7.tgz ,你会发现下得贼慢,这时候就用迅雷下载后关机功能吧。。
在~/workspace目录下解压 tar -zxvf spark-2.2.0-bin-hadoop2.7.tgz mv spark-2.2.0-bin-hadoop2.7 spark-2.2.0 #原来的文件名太长了,修改下
配置 Spark cd ~/workspace/spark-2.2.0/conf #进入spark配置目录 cp spark-env.sh.template spark-env.sh #从配置模板复制 vi spark-env.sh #添加配置内容
  在spark-env.sh末尾添加以下内容(这是我的配置,你可以自行修改): export SCALA_HOME=/home/tx/workspace/scala-2.12.3 export JAVA_HOME=/home/tx/workspace/jdk1.8.0_144 export HADOOP_HOME=/home/tx/workspace/hadoop-2.8.1 export HADOOP_CONF_DIR=$HADOOP_HOME/etc/hadoop SPARK_MASTER_IP=master SPARK_LOCAL_DIRS=/home/tx/workspace/spark-2.2.0 SPARK_DRIVER_MEMORY=1G
  注:在设置Worker进程的CPU个数和内存大小,要注意机器的实际硬件条件,如果配置的超过当前Worker节点的硬件条件,Worker进程会启动失败。
  vi slaves在slaves文件下填上slave主机名: slave1 slave2
  将配置好的spark-2.2.0文件夹分发给所有slaves scp -r ~/workspace/spark-2.2.0 tx@slave1:~/workspace/
启动Spark sbin/start-all.sh
验证 Spark 是否安装成功
  用jps检查,在 master 上应该有以下几个进程: $ jps 7949 Jps 7328 SecondaryNameNode 7805 Master 7137 NameNode 7475 ResourceManager
  在 slave 上应该有以下几个进程: $jps 3132 DataNode 3759 Worker 3858 Jps 3231 NodeManager
  进入Spark的Web管理页面: http://master:8080
4. 运行示例 #本地模式两线程运行 ./bin/run-example SparkPi 10 --master local[2] #Spark Standalone 集群模式运行 ./bin/spark-submit \ --class org.apache.spark.examples.SparkPi \ --master spark://master:7077 \ lib/spark-examples-1.3.0-hadoop2.4.0.jar \ 100 #Spark on YARN 集群上 yarn-cluster 模式运行 ./bin/spark-submit \ --class org.apache.spark.examples.SparkPi \ --master yarn-cluster \ # can also be `yarn-client` lib/spark-examples*.jar \ 10
本人遇到的问题:
1: 执行sbin/start-all.sh后,slave节点无法启动,报错提示 连接spark://Spark-Master:7077失败,在网上找了很多资料后无法解决问题,后面找到了一个方法 是分别执行 sbin/start-master.sh [master-ip] , sbin/start-slave.sh [master-ip] 来执行解决,后面自己想ip可以应该就是hostname不匹配的原因,因为自己master机器的hostname为Spark-Master,把 master-ip Spark-Master 注册到/etc/hosts里面后 然后分发到slave机器,重新执行sbin/start-all.sh 正常启动,节点也可以看到了.
2: HDFS启动后在master:50070上访问点击tmp文件夹报Permission denied: user=dr.who, access=READ_EXECUTE, inode="/tmp":root:supergroup:drwx-wx-wx ,根据网上查找资料后执行 hdfs dfs -chmod -R 755 /tmp 可以解决,但后面启动spark-shell后报错The root scratch dir: /tmp/hive on HDFS should be writable. Current permissions are: rwxr-xr-x,在此看到提示没有写的权限,执行 hdfs dfs -chmod -R 777 /tmp ,解决问题
大数据
2018-09-19 09:44:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
1. 解压缩(bigdata用户) 链接: https://pan.baidu.com/s/19MIN_uoSwHF6F1C14OWp_g 密码:j2c4 tar -zvxf hadoop-2.7.2.tar.gz
2. 环境变量配置 vi .bash_profile HADOOP_HOME=/home/hadoopadmin/hadoop-2.7.2 PATH=$PATH:$HADOOP_HOME/bin export HADOOP_HOME //保存退出 source .bash_profile //刷新环境变量
3. Hadoop配置
-core-site.xml hadoop.tmp.dir /home/bigdata/hadoop/data fs.defaultFS hdfs://HADOOP01:8020 fs.trash.interval 60
-hdfs-site.xml dfs.namenode.secondary.http-address HADOOP01:50090 dfs.replication 3 dfs.permissions false dfs.namenode.http-address HADOOP01:50070 dfs.datanode.data.dir file:///home/bigdata/hadoop/data/dfs/dn
-mapred-site.xml(重命名mapred-site.xml.template) mapreduce.jobhistory.address HADOOP01:10020 mapreduce.jobhistory.webapp.address HADOOP01:19888 mapreduce.framework.name yarn
-yarn-site.xml yarn.resourcemanager.hostname HADOOP01 yarn.resourcemanager.resource-tracker.address HADOOP01:8031 yarn.resourcemanager.address HADOOP01:8032 yarn.resourcemanager.scheduler.address HADOOP01:8030 yarn.nodemanager.resource.memory-mb 1536 yarn.nodemanager.aux-services mapreduce_shuffle
-hadoop-env.sh export JAVA_HOME=/home/bigdata/jdk1.7.0_67
-slaves HADOOP01 HADOOP02 HADOOP03
-使用ssh拷贝文件 可将一下命令以脚本方式执行,执行前确保SSH配置正确 ==tip==:可用touch创建文件并在里面写如下命令,也可单独执行,莫不能在win环境下复制过来(会导致所有文件都复制到一个文件夹中) scp -r /home/bigdata/jdk1.8.0_171 bigdata@HADOOP02:/home/bigdata scp -r /home/bigdata/jdk1.8.0_171 bigdata@HADOOP03:/home/bigdata scp -r /home/bigdata/hadoop-2.7.2 bigdata@HADOOP02:/home/bigdata scp -r /home/bigdata/hadoop-2.7.2 bigdata@HADOOP03:/home/bigdata scp /home/bigdata/.bash_profile bigdata@HADOOP02:/home/bigdata scp /home/bigdata/.bash_profile bigdata@HADOOP03:/home/bigdata
4. HADOOP启动/停止 hdfs namenode -format //格式化namenode节点 cd /home/bigdata/hadoop-2.7.2/sbin //切换目录 ./start-all.sh //启动HADOOP ./stop-all.sh //停止HADOOP
大数据
2018-09-18 19:21:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
默认安装完 docker 后,每次执行 docker 都需要运行 sudo 命令,非常浪费时间影响效率。如果不跟 sudo,直接执行 docker images 命令会有如下问题: FATA[0000] Get http:///var/run/docker.sock/v1.18/images/json: dial unix /var/run/docker.sock: permission denied. Are you trying to connect to a TLS-enabled daemon without TLS?
于是考虑如何免 sudo 使用 docker,经过查找资料,发现只要把用户加入 docker 用户组即可,具体用法如下: //如果还没有 docker group 就添加一个 sudo groupadd docker //将用户加入该 group 内。然后退出并重新登录就生效啦。 sudo gpasswd -a ${USER} docker //重启 docker 服务 sudo service docker restart //切换当前会话到新 group newgrp - docker
注意,最后一步是必须的,否则因为 groups 命令获取到的是缓存的组信息,刚添加的组信息未能生效,所以 docker images 执行时同样有错。
大数据
2018-09-18 16:42:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
可能是不同版本不同吧,按网友的最终改为:
export --connect jdbc:mysql:// 172.16.5.100:3306/dw_test --username testuser --password ****** --table che100kv --export-dir /user/hive/warehouse/che100kv0/000000_0 --input-fields-terminated-by \001 -m 1
报错: Error during export:
Export job failed!
at org.apache.sqoop.mapreduce.ExportJobBase.runExport(ExportJobBase.java:439)
at org.apache.sqoop.manager.SqlManager.exportTable(SqlManager.java:931)
at org.apache.sqoop.tool.ExportTool.exportTable(ExportTool.java:
<<< Invocation of Sqoop command completed <<<
Hadoop Job IDs executed by Sqoop: job_1534936991079_0934
Intercepting System.exit(1)
<<< Invocation of Main class completed <<<
Failing Oozie Launcher, Main class [org.apache.oozie.action.hadoop.SqoopMain], exit code [1]
Oozie Launcher failed, finishing Hadoop job gracefully
Oozie Launcher, uploading action data to HDFS sequence file: hdfs://master:8020/user/hue/oozie-oozi/0000099-180903155753468-oozie-oozi-W/sqoop-4411--sqoop/action-data.seq
后必须 加--columns且表名 字段等对应:
export --connect jdbc:mysql://172.16.5.100:3306/dw_test --username testuser --password *** --table che100kv --export-dir /user/hive/warehouse/che100kv0 --input-fields-terminated-by \001 -m 1 --columns db_t_f,k,v --update-key db_t_f --update-mode allowinsert --batch
后又报null转化错误:
sqoop export --connect "jdbc:mysql:// 172.16.5.100:3306/dw_test?useUnicode=true&characterEncoding=utf-8 " --username testuser --password ********* --table dimbrandstylemoudle --export-dir '/user/hive/warehouse/dimbrandstylemoudle/' --input-null-string "\\\\N" --input-null-non-string "\\\\N" --input-fields-terminated-by "\001" --input-lines-terminated-by "\\n" -m 1
然后在HUE里引号转码bug无法同时兼备--!
Sqoop查看更多调式信息, 增加关键字--verbose
sqoop export --connect jdbc:mysql://192.168.119.129:3306/student?characterEncoding=utf8 --username li72 --password 123 --verbose --table dm_trlog --export-dir /home/bigdata/hive/data/db1.db/trlog --input-fields-terminated-by '\t' --null-non-string '0' --null-string '0';
类型转换最终方法,修改生成的Java类,重新打包。
每次通过sqoop导入MySql的时,都会生成一个以MySql表命名的.java文件,然后打成JAR包,给sqoop提交给hadoop 的MR来解析Hive表中的数据。那可以根据报的错误,找到对应的行,改写该文件,编译,重新打包,sqoop可以通过 -jar-file ,--class-name 组合让我们指定运行自己的jar包中的某个class。来解析该hive表中的每行数据。脚本如下:一个完整的例子如下:
./bin/sqoop export --connect "jdbc:mysql://192.168.119.129:3306/student?useUnicode=true&characterEncoding=utf-8"
--username li72 --password 123 --table dm_trlog
--export-dir /hive/warehouse/trlog --input-fields-terminated-by '\t'
--input-null-string '\\N' --input-null-non-string '\\N'
--class-name com.li72.trlog
--jar-file /tmp/sqoopTempjar/trlog.jar
上面--jar-file 参数指定jar包的路径。--class-name 指定jar包中的class。
这样就可以解决所有解析异常了。
大数据
2018-09-18 14:49:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
前言:
我们大家都知道,在Java的环境中进行office的操作是需要office的接口来实现的.目前比较流行的解决方案有POI和openoffice.首先说POI方案,它的功能局限性很大,对于excel的读取和写入挺方便,但是在对word文档操作功能显的很鸡肋.其次是openoffice,功能比POI强大,但是对于word的操作能力依然很有限,且部署麻烦,学习成本较高,文档格式易错乱.
今天我给大家介绍一款在网页上操作office如同在本地操作office一样便利且强大的中间件技术——pageoffice.
先看效果
可以看到office的工具栏和本地的功能一模一样,因为此中间件技术就是 直接将客户端本地的office软件进行封装搬到了页面上 .
如何集成(复制粘贴只需6步)
1.官网下载pageoffice( http://www.zhuozhengsoft.com/dowm/ ).
2.去刚才下载的集成文件中找到lib,将里面的内容放在项目web-inf的lib中引入jar包,然后将web.xml的pageoffice配置引入到自己项目的wb.xml中
3.在父页面aaa.jsp(需要打开文档的页面)放一个a标签或者button
写button之前先引入pageoffice需要的js文件
然后添加a标签 最简单在线打开保存Word文件(URL地址方式)
4.在父页面同级目录下创建一个Word.jsp文件 <%@ page language="java" import="java.util.*, java.awt.*" pageEncoding="utf-8"%> <% @page import="com.zhuozhengsoft.pageoffice.*, com.zhuozhengsoft.pageoffice.wordwriter.*"%> <% //***************************卓正PageOffice组件的使用******************************** PageOfficeCtrl poCtrl = new PageOfficeCtrl(request); //添加自定义按钮 poCtrl.addCustomToolButton("保存", "Save", 1); //设置服务器页面 poCtrl.setServerPage(request.getContextPath()+"/poserver.zz"); //此行必须 //设置保存页 poCtrl.setSaveDataPage("SaveData.jsp"); //设置文档打开方式 poCtrl.webOpen("test.doc", OpenModeType.docSubmitForm, "张佚名"); %> 数据区域提交表格
<%=poCtrl.getHtmlCode("PageOfficeCtrl1")%>

5.在父页面同级目录下创建一个SaveData.jsp文件(演示直接在页面将取出的word中的数据输出到页面,也可以直接保存至数据库) <%@ page language="java" import="java.util.*,com.zhuozhengsoft.pageoffice.*,com.zhuozhengsoft.pageoffice.wordreader.*" pageEncoding="utf-8"%> <% //----------- PageOffice 服务器端编程开始(可以直接放在三层架构后台代码中) -------------------// WordDocument doc = new WordDocument(request,response); DataRegion dataReg = doc.openDataRegion("PO_table"); Table table = dataReg.openTable(1); //输出提交的table中的数据(取出来的数据也可以直接保存至数据库) out.print("表格中的各个单元的格数据为:

"); StringBuilder dataStr = new StringBuilder(); for (int i = 1; i <= table.getRowsCount(); i++) { dataStr.append("
"); for (int j = 1; j <= table.getColumnsCount(); j++) { dataStr.append("
"+table.openCellRC(i,j).getValue()+"
"); } dataStr.append("
"); } out.print(dataStr.toString()); //向客户端显示提交的数据 doc.showPage(300, 300); doc.close(); %> My JSP 'SaveFile.jsp' starting page
6.将samples4文件夹下dataregionTable文件夹下doc文件夹里的test.doc文件放在父页面同级目录下.然后启动项目直接访问aaa.jsp点击链接.此时会提示安装插件,点击安装成功后提示注册,填写相关信息,填写注册码CA1XB-MF7Y-12ST-PSBP2就可以打开文档.然后保存文档后文档中的数据就会提交至后台.
注意:这些只是演示级代码,大家可以去pageoffice官网下载示例代码直接将samples4文件夹扔到Tomcat的webapps下,启动Tomcat,浏览器访问http://localhost:8080/Samples/index.html,查看示例中的下面一个链接,直接看samples4文件夹下dataregionTable文件夹里面的代码.

如有侵权,请联系小编
大数据
2018-09-18 11:47:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
摘要: OpenMessaging 是由阿里巴巴牵头发起,由 Yahoo、滴滴、Streamlio、微众银行、Datapipeline 等公司共同发起创建的分布式消息规范,其目标在于打造厂商中立,面向 Cloud Native ,同时对流计算以及大数据生态友好的下一代分布式消息标准。
OpenMessaging 是由阿里巴巴牵头发起,由 Yahoo、滴滴、Streamlio、微众银行、Datapipeline 等公司共同发起创建的分布式消息规范,其目标在于打造厂商中立,面向 Cloud Native ,同时对流计算以及大数据生态友好的下一代分布式消息标准。目前,OpenMessaging 已经进入 Linux 基金会, 并且得到了 Apache RocketMQ、Apache Pulsar(Incubating) 等多个消息平台的支持。
目前 OpenMessaging 1.0.0-preview 版本已经发布,正在接受 public review ,其中本次发布的内容包括:
1、Specification
定义了基于队列的消息模型。
新增类型系统。
对消息领域模型中的元数据进行了定义。
更多改进请参考: https://github.com/openmessaging/specification
2、Runtime interface(Java&CPP)
去除了 ResourceManager 中过多的定义不够明确的操作策略,新增了路由以及过滤两种操作。
合并 Pullconsumer 以及 Pushconsumer 接口为 Consumer 接口,减少不必要的概念。
合并 BatchProducer 以及 Producer 接口为 Producer 接口,减少不必要的概念。
定义了明确的错误码以及异常。
暂时去除了 StreamingConsumer 接口,未来将于 Consumer 接口进行合并。
定义了明确的消息格式,去除了 Key-Value 无法进行限制的 header 。
重新定义了事务消息相关接口。
去除了过多的 Key-Value 的属性。
对一些接口进行了重新命名。
更多改进请参考: https://github.com/openmessaging/openmessaging-java
作者:中间件小哥
原文链接
大数据
2018-09-18 11:34:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
最近学习es,记录下怎么安装ik分词器,方便参考。
ik分词器安装很简单, 进入https://github.com/medcl/elasticsearch-analysis-ik/releases
下载对应es版本的zip包,该包是无需用mvn打包版本,解压zip,在es的plugins目录下创建名为ik的文件夹,将解压后的文件放到ik文件夹下面
重启es即可;
测试:
创建名为“index”的索引,浏览器输入如下: http://localhost:9200/index/_analyze?analyzer=ik&pretty=true&text= 我是中国人
结果只要不是单个分词结果就表明成功了!
切记:路径绝对不能有空格,否则会报错IKanalyze.cfg.xml找不到,或者 AccessControlException read 读取问题!
es 6.5.3版本es的安装(应该适用6.x版本)
进入es的bin目录下运行命令(docker安装亦同,进入容器/bin目录执行如下命令ji'ke): elasticsearch-plugin install https://github.com/medcl/elasticsearch-analysis-ik/releases/download/v6.5.3/elasticsearch-analysis-ik-6.5.3.zip
出现如下窗口说明安装成功(也可查看plugins目录下是否有ik的文件夹):

如果已安装则会提示卸载,运行如下命令即可: elasticsearch-plugin remove analysis-ik;

2019/1/28追加记录:
es内置分词器
standard分词器:(默认的)它将词汇单元转换成小写形式,并去掉停用词(a、an、the等没有实际意义的词)和标点符号,支持中文采用的方法为单字切分(例如,‘你好’切分为‘你’和‘好’)。
simple分词器:首先通过非字母字符来分割文本信息,然后将词汇单元同一为小写形式。该分析器会去掉数字类型的字符。
Whitespace分词器:仅仅是去除空格,对字符没有lowcase(大小写转换)化,不支持中文;并且不对生成的词汇单元进行其他的标准化处理。
language分词器:特定语言的分词器,不支持中文;
查看es分词结果
大数据
2018-09-18 09:33:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
最近开始学习es,想把学习过程(踩过的坑)记录下来,方便大家参考;
声明:参考自https://www.jianshu.com/p/a57053a11e32,推荐大家去看看 下载head 访问https://github.com/mobz/elasticsearch-head,
下载对应es版本的head插件zip包,解压; 安装node.js
现在新版本安装head必须安装node.js,尽量下载最新版本的node,不需要安装npm,配npm环境变量什么的
node地址: https://nodejs.org/zh-cn/,
安装很简单,完成之后输入 node -v
查看是否安装成功; 安装grant
grunt是一个很方便的构建工具,可以进行打包压缩、测试、执行等等的工作 # 在 head 插件目录中执行 npm install -g grunt-cli # 安装完使用下面查看版本 grunt -version
由于 npm 是国外的源,下载速度比较慢,推荐使用国内淘宝镜像执行完上面的命令后就可以使用 cnpm 来代替上面的 npm 命令,
(之前一直没配置这个东西,下载很慢,慢的我怀疑人生。。。) npm install -g cnpm --registry=https://registry.npm.taobao.org
修改 elasticsearch 的配置,这样 head 插件才可以访问 es(解决跨域问题) 在 elasticsearch.yml中追加下面内容,注意每一行前面空一格 http.cors.enabled: true http.cors.allow-origin: "*" 运行head
运行 head 插件 # 在 head 插件目录中执行 cnpm install grunt server
再运行es
然后在浏览器访问 http://192.168.0.117:9100/, 访问成功!!!
大数据
2018-09-17 17:28:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
大数据Hadoop之 YARN认识 2
Yarn是一个分布式的资源管理系统,用以提高分布式的集群环境下的资源利用率,这些资源包括内存、IO、网络、磁盘等。其产生的原因是为了解决原MapReduce框架的不足。
Yarn是一个分布式的资源管理系统,用以提高分布式的集群环境下的资源利用率,这些资源包括内存、IO、网络、磁盘等。其产生的原因是为了解决原MapReduce框架的不足。
最初MapReduce的committer们还可以周期性的在已有的代码上进行修改,可是随着代码的增加以及原MapReduce框架设计的不足,在原MapReduce框架上进行修改变得越来越困难,
所以MapReduce的committer们决定从架构上重新设计MapReduce,使下一代的MapReduce(MRv2/Yarn)框架具有更好的扩展性、可用性、可靠性、向后兼容性和更高的资源利用率以及能支持除了MapReduce计算框架外的更多的计算框架。
1、MapReduce框架的不足
现在比较流行的说法是jobtracker的问题,比如单点故障,任务过重。但除了Jobtracker,同时还有一个TaskTracker。我们看下图:


JobTacker概述
JobTacker其承担的任务有:接受任务、计算资源、分配资源、与DataNode进行交流。
在hadoop中每个应用程序被表示成一个作业,每个作业又被分成多个任务,JobTracker的作业控制模块则负责作业的分解和状态监控。
*最重要的是状态监控:主要包括TaskTracker状态监控、作业状态监控和任务状态监控。主要作用:容错和为任务调度提供决策依据。
TaskTracker概述
TaskTracker是JobTracker和Task之间的桥梁:一方面,从JobTracker接收并执行各种命令:运行任务、提交任务、杀死任务等;另一方面,将本地节点上各个任务的状态通过心跳周期性汇报给JobTracker。TaskTracker与JobTracker和Task之间采用了RPC协议进行通信
资源slot概述
slot不是CPU的Core,也不是memory chip,它是一个逻辑概念,一个节点的slot的数量用来表示某个节点的资源的容量或者说是能力的大小,因而slot是 Hadoop的资源单位。
hadoop中什么是slots
http://www.aboutyun.com/forum.php?mod=viewthread&tid=7562
所以JobTracker需要完成的任务太多,既要维护job的状态又要维护job的task的状态,造成过多的资源消耗
在taskTracker端,用map/reduce task作为资源的表示过于简单,没有考虑到CPU、内存等资源情况,当把两个需要消耗大内存的task调度到一起,很容易出现OOM
把资源强制划分为map/reduce slot,当只有map task时,reduce slot不能用;当只有reduce task时,map slot不能用,容易造成资源利用不足。
2、Yarn
首先让我们看一看Yarn的架构


1.ResourceManager概述
是全局的,负责对于系统中的所有资源有最高的支配权。ResourceManager作为资源的协调者有两个主要的组件:Scheduler和ApplicationsManager(AsM)。
Scheduler负责分配最少但满足application运行所需的资源量给Application。Scheduler只是基于资源的使用情况进行调度,并不负责监视/跟踪application的状态,当然也不会处理失败的task。
ApplicationsManager负责处理client提交的job以及协商第一个container以供applicationMaster运行,并且在applicationMaster失败的时候会重新启动applicationMaster。
2.NodeManager概述
NM主要负责启动RM分配给AM的container以及代表AM的container,并且会监视container的运行情况。
在启动container的时候,NM会设置一些必要的环境变量以及将container运行所需的jar包、文件等从hdfs下载到本地,也就是所谓的资源本地化;当所有准备工作做好后,才会启动代表该container的脚本将程序启动起来。
启动起来后,NM会周期性的监视该container运行占用的资源情况,若是超过了该container所声明的资源量,则会kill掉该container所代表的进程。
3.ApplicationMaster概述
由于NodeManager 执行和监控任务需要资源,所以通过ApplicationMaster与ResourceManager沟通,获取资源。换句话说,ApplicationMaster起着中间人的作用。
转换为更专业的术语:AM负责向ResourceManager索要NodeManager执行任务所需要的资源容器,更具体来讲是ApplicationMaster负责从Scheduler申请资源,以及跟踪这些资源的使用情况以及任务进度的监控。
所以我们看到JobTracker的功能被分散到各个进程中包括ResourceManager和NodeManager:
比如监控功能,分给了NodeManager,和Application Master。
ResourceManager里面又分为了两个组件:调度器及应用程序管理器。
也就是说Yarn重构后,JobTracker的功能,被分散到了各个进程中。同时由于这些进程可以被单独部署所以这样就大大减轻了单点故障,及压力。
最后要提醒在yarn上写应用程序并不同于我们熟知的MapReduce应用程序,必须牢记yarn只是一个资源管理的框架,并不是一个计算框架,计算框架可以运行在yarn上。我们所能做的就是向RM申请container,然后配合NM一起来启动container。
大数据
2018-09-17 16:45:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
1. 新一代的框架介绍
YARN的职能就是将资源调度和任务调度分开。资源管理器ResourceManager全局管理所有应用程序计算资源的分配,每一个job的ApplicationMaster负责相应任务的调度和协调。 ResourceManager做的事情是负责协调集群上计算资源的分配。调度、启动每一个 Job 所属的 ApplicationMaster、另外监控 ApplicationMaster 的存在情况。 NodeManager 功能比较专一,根据要求启动和监视集群中机器的计算容器container。负责 Container 状态的维护,并向 RM 保持心跳汇报该节点资源使用情况。 ApplicationMaster 负责一个 Job 生命周期内的所有工作。注意每一个Job都有一个 ApplicationMaster。它和MapReduce任务一样在容器中运行。AM通过与RM交互获取资源,然后然后通过与NM交互,启动计算任务。 容器是由ResourceManager进行统一管理和分配的。有两类container:一类是AM运行需要的container;另一类是AP为执行任务向RM申请的。 YARN的作用:资源调度。
ResourceManager------NodeManager
主节点 ---------- 从节点 ApplicationMaster作用:任务调度
MRAppMaster ------ yarnchild
动态产生 ------ 动态产生(可以是Map,可以是Reduce)
YARN中提交job的详细流程
不是完全正确,下面是一些解释和更正: RunJar里面的Conf的配置引用决定了是在本地还是集群运行。是提交到集群yarn_provider还是本地运行local_provider。配置conf决定了是访问远程rpc还是本地rpc。 步骤2中的staging_dir存放的是作业Jar、配置信息和分片信息;这个staging_dir默认是在HDFS上。 步骤5是ResourceManager将任务添加到任务队列中。然后,ResourceManager将随机挑选一个NodeManager管理下的Container分配给ApplicationMaster进程,作为MRAppMaster任务调度中心。 MRAppMaster会对作业初始化,接受任务的进度和完成报告;接受HDFS中存放的客户端计算的输入分片信息,对每一个分片创建一个map任务对象和由mapreduce.job.reduces确定的reduce对象。 ApplicationMaster会为该作业所有的map和reduce任务向ResourceManager请求容器(包括内存资源和CPU资源);附着心跳信息的请求包括map任务的本地化信息,如输入分片所在的主机和机架信息。ResourceManager根据这些信息完成分配决策,理想情况会将任务分配给数据本地化的节点。 ResourceManager为任务分配了容器后,ApplicationMaster就通过节点间通信来启动NodeManager中的容器,任务由容器中的YarnChild应用程序执行。在任务执行前,容器将任务需要的资源本地化,包括staging_dir中的作业Jar、配置和文件资源。 ApplicationMaster负责启动map和reduce任务,监控。并在所有任务完成后,向ResourceManager注销自己,清理工作状态。 在实际运行中,NodeManager节点会随机被指定MRAppMaster进程,然后在任务节点出现yarnChild进程。yarnChild进程执行完map或reduce任务后会消失,MRAppMaster进程执行完这个job后会消失。
2. YARN框架的通用性
资源管理框架ResourceManager可以为MapReduce、Spark、Storm等计算框架实现资源调度。但是这些计算框架需要实现一个接口,AppMaster;资源管理器才能启动这个AppMaster执行计算任务。
比如只需要MR实现MRAppMaster,Spark也需要实现SparkAppMaster
3. YARN提交job的源码流程
4. YARN的HA
Yarn的Ha只能保证,在一个节点失效时,另一台能提供服务。但是不能像HDFS一样智能。Application在执行一半时ResourceManager宕机,另一个ResourceManager不能继续提供任务的执行服务,因为中间数据太多,Hadoop未实现这种任务调度的切换。而HDFS的HA可以保证杀掉active状态的NameNode,文件依然能够上传成功。
参考《Hadoop权威指南》和博客《 http://dongxicheng.org/mapreduce-nextgen/nodemanager-container-launch-process/ 》
初接触,记下学习笔记,还有很多问题,望指导,谢谢。
大数据
2018-09-17 16:52:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
一、Yarn简介
Yarn是Hadoop集群的资源管理系统。Hadoop2.0对MapReduce框架做了彻底的设计重构,我们称Hadoop2.0中的MapReduce为MRv2或者Yarn。在介绍Yarn之前,我们先回头看一下Hadoop1.x对MapReduce job的调度管理方式(可参考: Hadoop核心之MapReduce架构设计 ),它主要包括两部分功能: 1. ResourceManagement 资源管理 2. JobScheduling/JobMonitoring 任务调度监控
到了Hadoop2.x也就是Yarn,它的目标是将这两部分功能分开,也就是分别用两个进程来管理这两个任务: 1. ResourceManger 2. ApplicationMaster
需要注意的是,在Yarn中我们把job的概念换成了 application ,因为在新的Hadoop2.x中,运行的应用不只是MapReduce了,还有可能是其它应用如一个DAG(有向无环图Directed Acyclic Graph,例如storm应用)。Yarn的另一个目标就是拓展Hadoop,使得它不仅仅可以支持MapReduce计算,还能很方便的管理诸如Hive、Hbase、Pig、Spark/Shark等应用。这种新的架构设计能够使得各种类型的应用运行在Hadoop上面,并通过Yarn从系统层面进行统一的管理,也就是说,有了Yarn,各种应用就可以互不干扰的运行在同一个Hadoop系统中,共享整个集群资源,如下图所示:
二、Yarn的组件及架构
Yarn主要由以下几个组件组成: 1. ResourceManager:Global(全局)的进程 2. NodeManager:运行在每个节点上的进程 3. ApplicationMaster:Application-specific(应用级别)的进程 - *Scheduler:是ResourceManager的一个组件* - *Container:节点上一组CPU和内存资源*
Container 是Yarn对计算机计算资源的抽象,它其实就是 一组CPU和内存资源 ,所有的应用都会运行在Container中。 ApplicationMaster 是对运行在Yarn中某个应用的抽象,它其实就是某个类型应用的实例,ApplicationMaster是应用级别的,它的主要功能就是向 ResourceManager (全局的)申请计算资源(Containers)并且和NodeManager交互来执行和监控具体的task。 Scheduler 是ResourceManager专门进行资源管理的一个组件,负责分配NodeManager上的Container资源, NodeManager 也会不断发送自己Container使用情况给ResourceManager。
ResourceManager和NodeManager两个进程主要负责系统管理方面的任务。ResourceManager有一个Scheduler,负责各个集群中应用的资源分配。对于每种类型的每个应用,都会对应一个ApplicationMaster实例,ApplicationMaster通过和ResourceManager沟通获得Container资源来运行具体的job,并跟踪这个job的运行状态、监控运行进度。
下面我们看一下整个Yarn的架构图:
三、Yarn的组件详解
3.1 Container
Container 是Yarn框架的计算单元,是具体执行应用task(如map task、reduce task)的基本单位。Container和集群节点的关系是:一个节点会运行多个Container,但一个Container不会跨节点。
一个Container就是一组分配的系统资源,现阶段只包含两种系统资源(之后可能会增加磁盘、网络等资源): 1. CPU core 2. Memory in MB
既然一个Container指的是具体节点上的计算资源,这就意味着Container中必定含有计算资源的位置信息:计算资源位于哪个机架的哪台机器上。所以我们在请求某个Container时,其实是向某台机器发起的请求,请求的是这台机器上的CPU和内存资源。
任何一个job或application必须运行在一个或多个Container中,在Yarn框架中,ResourceManager只负责告诉ApplicationMaster哪些Containers可以用,ApplicationMaster还需要去找NodeManager请求分配具体的Container。
3.2 Node Manager
NodeManager 进程运行在集群中的节点上,每个节点都会有自己的NodeManager。NodeManager是一个slave服务:它负责接收ResourceManager的资源分配请求,分配具体的Container给应用。同时,它还负责监控并报告Container使用信息给ResourceManager。通过和ResourceManager配合,NodeManager负责整个Hadoop集群中的资源分配工作。ResourceManager是一个全局的进程,而NodeManager只是每个节点上的进程,管理这个节点上的资源分配和监控运行节点的健康状态。下面是NodeManager的具体任务列表: - 接收ResourceManager的请求,分配Container给应用的某个任务 - 和ResourceManager交换信息以确保整个集群平稳运行。ResourceManager就是通过收集每个NodeManager的报告信息来追踪整个集群健康状态的,而NodeManager负责监控自身的健康状态。 - 管理每个Container的生命周期 - 管理每个节点上的日志 - 执行Yarn上面应用的一些额外的服务,比如MapReduce的shuffle过程
当一个节点启动时,它会向ResourceManager进行注册并告知ResourceManager自己有多少资源可用。在运行期,通过NodeManager和ResourceManager协同工作,这些信息会不断被更新并保障整个集群发挥出最佳状态。
NodeManager只负责管理自身的Container,它并不知道运行在它上面应用的信息。负责管理应用信息的组件是ApplicationMaster,在后面会讲到。
3.3 Resource Manager
ResourceManager主要有两个组件:Scheduler和ApplicationManager。
Scheduler是一个资源调度器,它主要负责协调集群中各个应用的资源分配,保障整个集群的运行效率。Scheduler的角色是一个纯调度器,它只负责调度Containers,不会关心应用程序监控及其运行状态等信息。同样,它也不能重启因应用失败或者硬件错误而运行失败的任务
Scheduler是一个可插拔的插件,它可以调度集群中的各种队列、应用等。在Hadoop的MapReduce框架中主要有两种Scheduler:Capacity Scheduler和Fair Scheduler,关于这两个调度器后面会详细介绍。
另一个组件ApplicationManager主要负责接收job的提交请求,为应用分配第一个Container来运行ApplicationMaster,还有就是负责监控ApplicationMaster,在遇到失败时重启ApplicationMaster运行的Container。
3.4 Application Master
ApplicationMaster的主要作用是向ResourceManager申请资源并和NodeManager协同工作来运行应用的各个任务然后跟踪它们状态及监控各个任务的执行,遇到失败的任务还负责重启它。
在MR1中,JobTracker即负责job的监控,又负责系统资源的分配。而在MR2中,资源的调度分配由ResourceManager专门进行管理,而每个job或应用的管理、监控交由相应的分布在集群中的ApplicationMaster,如果某个ApplicationMaster失败,ResourceManager还可以重启它,这大大提高了集群的拓展性。
在MR1中,Hadoop架构只支持MapReduce类型的job,所以它不是一个通用的框架,因为Hadoop的JobTracker和TaskTracker组件都是专门针对MapReduce开发的,它们之间是深度耦合的。Yarn的出现解决了这个问题,关于Job或应用的管理都是由ApplicationMaster进程负责的,Yarn允许我们自己开发ApplicationMaster,我们可以为自己的应用开发自己的ApplicationMaster。这样每一个类型的应用都会对应一个ApplicationMaster,一个ApplicationMaster其实就是一个类库。这里要区分ApplicationMaster*类库 和ApplicationMaster 实例*,一个ApplicationMaster类库何以对应多个实例,就行java语言中的类和类的实例关系一样。总结来说就是,每种类型的应用都会对应着一个ApplicationMaster,每个类型的应用都可以启动多个ApplicationMaster实例。所以,在yarn中,是每个job都会对应一个ApplicationMaster而不是每类。
Yarn 框架相对于老的 MapReduce 框架什么优势呢? - 这个设计大大减小了 ResourceManager 的资源消耗,并且让监测每一个 Job 子任务 (tasks) 状态的程序分布式化了,更安全、更优美。 - 在新的 Yarn 中,ApplicationMaster 是一个可变更的部分,用户可以对不同的编程模型写自己的 AppMst,让更多类型的编程模型能够跑在 Hadoop 集群中,可以参考 hadoop Yarn 官方配置模板中的 ``mapred-site.xml`` 配置。 - 对于资源的表示以内存为单位 ( 在目前版本的 Yarn 中,没有考虑 cpu 的占用 ),比之前以剩余 slot 数目更合理。 - 老的框架中,JobTracker 一个很大的负担就是监控 job 下的 tasks 的运行状况,现在,这个部分就扔给 ApplicationMaster 做了,而 ResourceManager 中有一个模块叫做 ApplicationsManager,它是监测 ApplicationMaster 的运行状况,如果出问题,会将其在其他机器上重启。 - Container 是 Yarn 为了将来作资源隔离而提出的一个框架。这一点应该借鉴了 Mesos 的工作,目前是一个框架,仅仅提供 java 虚拟机内存的隔离 ,hadoop 团队的设计思路应该后续能支持更多的资源调度和控制 , 既然资源表示成内存量,那就没有了之前的 map slot/reduce slot 分开造成集群资源闲置的尴尬情况。
四、Yarn request分析
4.1 应用提交过程分析
了解了上面介绍的这些概念,我们有必要看一下Application在Yarn中的执行过程,整个执行过程可以总结为三步: 1. 应用程序提交 2. 启动应用的ApplicationMaster实例 3. ApplicationMaster实例管理应用程序的执行
下面这幅图展示了应用程序的整个执行过程:
客户端程序向ResourceManager提交应用并请求一个ApplicationMaster实例 ResourceManager找到可以运行一个Container的NodeManager,并在这个Container中启动ApplicationMaster实例 ApplicationMaster向ResourceManager进行注册,注册之后客户端就可以查询ResourceManager获得自己ApplicationMaster的详细信息,以后就可以和自己的ApplicationMaster直接交互了 在平常的操作过程中,ApplicationMaster根据 resource-request协议 向ResourceManager发送resource-request请求 当Container被成功分配之后,ApplicationMaster通过向NodeManager发送 container-launch-specification 信息来启动Container, container-launch-specification信息包含了能够让Container和ApplicationMaster交流所需要的资料 应用程序的代码在启动的Container中运行,并把运行的进度、状态等信息通过 application-specific协议 发送给ApplicationMaster 在应用程序运行期间,提交应用的客户端主动和ApplicationMaster交流获得应用的运行状态、进度更新等信息,交流的协议也是 application-specific协议 一但应用程序执行完成并且所有相关工作也已经完成,ApplicationMaster向ResourceManager取消注册然后关闭,用到所有的Container也归还给系统
4.2 Resource Request和Container
Yarn的设计目标就是允许我们的各种应用以共享、安全、多租户的形式使用整个集群。并且,为了保证集群资源调度和数据访问的高效性,Yarn还必须能够感知整个集群拓扑结构。为了实现这些目标,ResourceManager的调度器Scheduler为应用程序的资源请求定义了一些灵活的协议,通过它就可以对运行在集群中的各个应用做更好的调度,因此,这就诞生了 Resource Request 和 Container 。
具体来讲,一个应用先向ApplicationMaster发送一个满足自己需求的资源请求,然后ApplicationMaster把这个资源请求以 resource-request 的形式发送给ResourceManager的Scheduler,Scheduler再在这个原始的 resource-request 中返回分配到的资源描述Container。每个ResourceRequest可看做一个可序列化Java对象,包含的字段信息如下: resource-name:资源名称,现阶段指的是资源所在的host和rack,后期可能还会支持虚拟机或者更复杂的网络结构 priority:资源的优先级 resource-requirement:资源的具体需求,现阶段指内存和cpu需求的数量 number-of-containers:满足需求的Container的集合
number-of-containers 中的Containers就是ResourceManager给ApplicationMaster分配资源的结果。Container就是授权给应用程序可以使用某个节点机器上CPU和内存的数量。
ApplicationMaster在得到这些Containers后,还需要与分配Container所在机器上的NodeManager交互来启动Container并运行相关任务。当然Container的分配是需要认证的,以防止ApplicationMaster自己去请求集群资源。
大数据
2018-09-17 16:28:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
9月13日,第十届ESE天翼智能生态博览会在广州广交会展馆正式拉开帷幕。作为全球最重要的通信展会之一,此次博览会以“共赢智能新时代”为主题,将众人目光聚焦于智能科技、智能生态等领域,促进生态融合与进化,让科技走进人们的生活。
亚洲诚信作为中国电信天翼云的合作伙伴受邀参会,并重点展示了亚洲诚信安全解决方案,助力智能安全新生态。

本届博览会上,亚洲诚信在 9.2号智慧城市馆【D40】 展位重点展示了 MySSL企业版、HTTPS全站加密解决方案、MPKI证书管理、Apple ATS 等四大领先技术解决方案。吸引了天翼展现场观众的驻足,也聚焦起各行业对信息安全的关注。

方案一:MySSL企业版
随着企业用户安全防范意识的提高以及对网络安全法、等级保护的高度重视,越来越多企业选择部署HTTPS传输加密为平台数据保驾护航,但部署HTTPS保障用户的传输安全不是一件容易和一劳永逸的事情,MySSL.com数据表明,还有39.14% 的HTTPS站点为“不安全”(安全评级低于A-),其服务端配置仍存在安全漏洞。
海量证书管理,私钥安全存放隐患,无法及时发现到期失效证书,更换麻烦等成为了众多运维者们工作中的痛点。
MySSL企业版是MySSL.com专为企业定做的SSL安全评估系统管理展示平台,提供了可视化评级图表和可交互的跨品牌证书管理仪表盘,是一款集多个HTTPS站点安全检测、SSL证书数据、支持HTTP外链报告、证书有效期管理以及异常告警等功能于一体的系统,有效帮助企业用户每天对网站证书部署,SSL配置进行实时监控,以便检查自己部署的HTTPS网站是否真正的安全。

方案二:HTTPS全站加密解决方案
HTTPS全站加密解决方案,开启HTTP/2协议使网站加载速度更快数据更安全;开启全站加密后增加搜索引擎的权重,提升网站搜索排名;有效防止恶意流量劫持和内容篡改,从此不再有“弹窗小广告”。同时,全站加密解决方案让iOS和安卓客户端接口访问更安全!网站的任何数据传输都是加密的,不必再担心数据泄露了。

方案三: MPKI证书管理
MPKI证书生命周期管理系统,降低管理数字证书成本和复杂度,证书申请、颁发、下载、更新,一键完成。
SSL证书智能推荐: 根据实际需求和预算,推荐适合您的SSL证书产品,让您获取性价比更高的产品组合。
快捷申请SSL证书: 申请SSL证书步骤和流程更加简单快捷,尽量大幅度地的节约您的成本和时间,提高您的效率。
分权限证书管理: 可让不同的角色访问不同的功能,实现资源隔离,防止SSL证书信息泄露,保护您的资产安全。
智能数据报表中心: 丰富、智能、直观的数据和图标,可定制化报告服务,助您时刻掌握全局数据和动态。
先进的云平台架构: 基于主流的云平台架构,让您的数据和资源安全可靠,且能自动伸缩和扩展,让您能时刻流畅使用。
可定制管理流程: SSL证书申请、管理等工作流程可按需求定制,轻松获得最顺手的SSL证书申请和管理的平台。

方案四: Apple ATS方案
App Transport Security,简称 ATS,是苹果在 iOS 9 当中首次推出的一项安全功能。在开启 ATS 安全特性之后,它会强制App应用及网页通讯自动通过HTTPS加密传输链接网络服务, 通过加密App及网页通讯来保障用户数据安全。
亚洲诚信Apple ATS方案是一款提供配置检测、部署指导、服务稳定性监控等一站式解决方案,采用ECC算法提升速率,安全且兼容性强的配置,防止数据泄露,助您的应用程序正确快捷的通过苹果商店审核。

当下数据泄露、勒索软件劫持等安全事件频发,面对日益严峻和复杂的网络生态环境,企业管理者越来越重视数据安全的问题。
亚洲诚信希望通过完备可靠的安全解决方案,以贯彻落实《网络安全法》及等级保护相关要求,帮助各行业企业用户成功落地数字化转型。
未来,亚洲诚信将携手天翼云等更多的厂商和安全企业开展广泛深入合作,共同为打造“安全可信的网络生态圈”,为国家网络强国战略持续注入新的力量。

大数据
2018-09-17 16:09:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
Hadoop的三大核心组件之HDFS和YARN
Hadoop集群具体来说包含两个集群:HDFS集群和YARN集群,两者逻辑上分离,但物理上常在一起。
(1)HDFS集群:负责海量数据的存储,集群中的角色主要有 NameNode / DataNode/SecondaryNameNode。
(2)YARN集群:负责海量数据运算时的资源调度,集群中的角色主要有 ResourceManager /NodeManager
(3)MapReduce:它其实是一个应用程序开发包。
一、HDFS
HDFS是一个高度容错性的系统,适合部署在廉价的机器上。HDFS采用master/slave架构。一个HDFS集群是由一个Namenode和一定数目的Datanodes组成。Namenode是一个中心服务器,负责管理文件系统的名字空间(namespace)以及客户端对文件的访问。集群中的Datanode一般是一个节点一个,负责管理它所在节点上的存储。架构如下图:
A、NameNode
NameNode管理着文件系统的命名空间,维护着文件系统树,它不存储真实数据,存储元数据(MetaData)[元数据(FileName、副本数、每一个副本所在的位置...)],NameNode保存在内存中。
元数据信息通过以下文件和过程持久化到磁盘中。
a、fsimage--对元数据定期进行镜像
b、edits--存放一定时间内对HDFS的操作记录
c、checkpoint---检查点
Namenode在内存中保存着整个文件系统的名字空间和文件数据块映射(Blockmap)的映像。这个关键的元数据结构设计得很紧凑,因而一个有4G内存的Namenode足够支撑大量的文件和目录。当Namenode启动时,它从硬盘中读取Editlog和FsImage,将所有Editlog中的事务作用在内存中的FsImage上,并将这个新版本的FsImage从内存中保存到本地磁盘上,然后删除旧的Editlog,因为这个旧的Editlog的事务都已经作用在FsImage上了。这个过程称为一个检查点(checkpoint)。在当前实现中,检查点只发生在Namenode启动时,在不久的将来将实现支持周期性的检查点。
B、DataNode---存储节点,真正存放数据的节点,用于保存数据,保存在磁盘上(在HDFS上保存的数据副本数默认是3个,这个副本数量是可以设置的)。基本单位是块(block),默认128M。
Block块的概念
先不看HDFS的Block,每台机器都有磁盘,机器上的所有持久化数据都是存储在磁盘上的。磁盘是通过块来管理数据的,一个块的数据是该磁盘一次能够读写的最小单位,一般是512个字节,而建立在磁盘之上的文件系统也有块的概念,通常是磁盘块的整数倍,例如几kb。
HDFS作为文件系统,一样有块的概念,对于分布式文件系统,使用文件块将会带来这些好处:
1.一个文件的大小不限制于集群中任意机器的磁盘大小
2.因为块的大小是固定的,相对比不确定大小的文件,块更容易进行管理和计算
3.块同样方便进行备份操作,以提高数据容错性和系统的可靠性
为什么HDFS的块大小会比文件系统的块大那么多呢?
操作数据时,需要先从磁盘上找到指定的数据块然后进行传输,而这就包含两个动作:
1)数据块寻址 :找到该数据块的起始位置
2)数据传输 :读取数据
也就是说,操作数据所花费的时间是由以上两个步骤一起决定的,步骤1所花费的时间一般比步骤2要少很多,那么当操作的数据块越多,寻址所花费的时间在总时间中就越小的可以忽略不计。所以块设置的大,可以最小化磁盘的寻址开销。但是HDFS的Block块也不能设置的太大,会影响到map任务的启动数,并行度降低,任务的执行数据将会变慢。
★名词扩展:心跳机制、宕机、安全模式(zzy至理名言--“自己看网上都有”)
Datanode负责处理文件系统客户端的读写请求。在Namenode的统一调度下进行数据块的创建、删除和复制。集群中单一Namenode的结构大大简化了系统的架构。Namenode是所有HDFS元数据的仲裁者和管理者,这样,用户数据永远不会流过Namenode。
C、SecondaryNameNode---辅助节点,用于同步元数据信息。辅助NameNode对fsimage和edits进行合并(冷备份),下面用SNN代替
NameNode 的元数据信息先往 edits 文件中写,当 edits 文件达到一定的阈值(3600 秒或大小到 64M)的时候,会开启合并的流程。合并流程如下:
①当开始合并的时候,SNN 会把 edits 和 fsimage 拷贝到自己服务器所在内存中,开始合并,合并生成一个名为 fsimage.ckpt 的文件。
②将 fsimage.ckpt 文件拷贝到 NameNode 上,成功后,再删除原有的 fsimage,并将 fsimage.ckpt文件重命名为 fsimage。
③当 SNN 将 edits 和 fsimage 拷贝走之后,NameNode 会立刻生成一个 edits.new 文件,用于记录新来的元数据,当合并完成之后,原有的 edits 文件才会被删除,并将 edits.new 文件重命名为 edits 文件,开启下一轮流程。

二、YARN
A、ResourceManager
B、NodeManager

◆MapReduce 在 YARN 上的执行流程:
①client 提交 job,首先找 ResourceManager(ApplicationsManager)分配资源,同时将 jar 包默认拷贝10 份到 hdfs。
②ResourceManager 指 定 一 个 NodeManager 开 启 一 个 container , 在 Container 中 运 行 一 个ApplicationMaster 来管理这个应用程序。
③ApplicationMaster 会计算此个应用所需资源,向 ResourceManager(ResourceScheduler)申请资源。
④ResourceManager 会分配资源,在 NodeManager上开启不同的 container,在container中来运行 map任务或者 reduce 任务
⑤当所有的 task 都执行完了,ApplicationMaster会将结果反馈给客户端,所有工作执行完成之后,ApplicationMaster 就会自行关闭。
⑥如果某个 map 任务或者 reduce 任务失败,ApplicationMaster会重新申请新的 container 来执行这个task。
大数据
2018-09-17 15:21:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
概览

首先我们来认识一下HDFS, HDFS(Hadoop Distributed File System )Hadoop分布式文件系统。它其实是将一个大文件分成若干块保存在不同服务器的多个节点中。通过联网让用户感觉像是在本地一样查看文件,为了降低文件丢失造成的错误,它会为每个小文件复制多个副本(默认为三个),以此来实现多机器上的多用户分享文件和存储空间。
HDFS特点:
① 保存多个副本,且提供容错机制,副本丢失或宕机自动恢复。默认存3份。
② 运行在廉价的机器上。
③ 适合大数据的处理。因为小文件也占用一个块,小文件越多(1000个1k文件)块越 多,NameNode压力越大。

如:将一个大文件分成三块A、B、C的存储方式

PS :数据复制原则:
除了最后一个块之外的文件中的所有块都是相同的大小。
HDFS 的放置策略:
是将一个副本放在本地机架中的一个节点上,另一个位于不同(远程)机架中的节点上,而最后一个位于不同节点上远程机架。
涉及到的属性:
块大小:Hadoop1版本里默认为64M,Hadoop2版本里默认为128M
复制因子:每个文件加上其文件副本的份数

HDFS 的基本结构


如上图所示,HDFS基本结构分NameNode、SecondaryNameNode、DataNode这几个。
NameNode :是Master节点,有点类似Linux里的根目录。管理数据块映射;处理客户端的读写请求;配置副本策略;管理HDFS的名称空间;
SecondaryNameNode :保存着NameNode的部分信息(不是全部信息NameNode宕掉之后恢复数据用),是NameNode的冷备份;合并fsimage和edits然后再发给namenode。(防止edits过大的一种解决方案)
DataNode :负责存储client发来的数据块block;执行数据块的读写操作。是NameNode的小弟。
热备份:b是a的热备份,如果a坏掉。那么b马上运行代替a的工作。
冷备份:b是a的冷备份,如果a坏掉。那么b不能马上代替a工作。但是b上存储a的一些信息,减少a坏掉之后的损失。
fsimage :元数据镜像文件(文件系统的目录树。)
edits :元数据的操作日志(针对文件系统做的修改操作记录)
namenode 内存中存储的是=fsimage+edits。

NameNode 详解

作用:
Namenode起一个统领的作用,用户通过namenode来实现对其他数据的访问和操作,类似于root根目录的感觉。
Namenode包含:目录与数据块之间的关系(靠fsimage和edits来实现),数据块和节点之间的关系

fsimage 文件与edits文件是Namenode结点上的核心文件。
Namenode中仅仅存储目录树信息,而关于BLOCK的位置信息则是从各个Datanode上传到Namenode上的。
Namenode的 目录树信息就是物理的存储在fsimage这个文件中 的,当Namenode启动的时候会首先读取fsimage这个文件,将目录树信息装载到内存中。
而edits存储的是日志信息,在Namenode启动后 所有对目录结构的增加,删除,修改等操作都会记录到edits文件中,并不会同步的记录在fsimage中。
而当Namenode结点关闭的时候,也不会将fsimage与edits文件进行合并,这个合并的过程实际上是发生在Namenode启动的过程中。
也就是说,当Namenode启动的时候,首先装载fsimage文件,然后在应用edits文件,最后还会将最新的目录树信息更新到新的fsimage文件中,然后启用新的edits文件。
整个流程是没有问题的,但是有个小瑕疵,就是如果Namenode在启动后发生的改变过多,会导致edits文件变得非常大,大得程度与Namenode的更新频率有关系。
那么在下一次Namenode启动的过程中,读取了fsimage文件后,会应用这个无比大的edits文件,导致启动时间变长,并且不可控,可能需要启动几个小时也说不定。
Namenode的edits文件过大的问题,也就是SecondeNamenode要解决的主要问题。
SecondNamenode会按照一定规则被唤醒,然后进行fsimage文件与edits文件的合并,防止edits文件过大,导致Namenode启动时间过长。

DataNode 详解

DataNode在HDFS中真正存储数据。
首先解释块(block)的概念: DataNode在存储数据的时候是按照block为单位读写数据的。block是hdfs读写数据的基本单位。 假设文件大小是100GB,从字节位置0开始,每128MB字节划分为一个block,依此类推,可以划分出很多的block。每个block就是128MB大小。 block本质上是一个 逻辑概念,意味着block里面不会真正的存储数据,只是划分文件的。 block里也会存副本,副本优点是安全,缺点是占空间
SecondaryNode

执行过程:从NameNode上 下载元数据信息(fsimage,edits),然后把二者合并,生成新的fsimage,在本地保存,并将其推送到NameNode,同时重置NameNode的edits.

工作原理(转自“大牛笔记”的博客,由于实现是清晰,受益很大,在此不做改动)

写操作:

有一个文件FileA,100M大小。Client将FileA写入到HDFS上。
HDFS按默认配置。
HDFS分布在三个机架上Rack1,Rack2,Rack3。

a. Client将FileA按64M分块。分成两块,block1和Block2;
b. Client向nameNode发送写数据请求,如图蓝色虚线①------>。
c. NameNode节点,记录block信息。并返回可用的DataNode,如粉色虚线②--------->。
Block1: host2,host1,host3
Block2: host7,host8,host4
原理:
NameNode具有RackAware机架感知功能,这个可以配置。
若client为DataNode节点,那存储block时,规则为:副本1,同client的节点上;副本2,不同机架节点上;副本3,同第二个副本机架的另一个节点上;其他副本随机挑选。
若client不为DataNode节点,那存储block时,规则为:副本1,随机选择一个节点上;副本2,不同副本1,机架上;副本3,同副本2相同的另一个节点上;其他副本随机挑选。
d. client向DataNode发送block1;发送过程是以流式写入。
流式写入过程,
1> 将64M的block1按64k的package划分;
2> 然后将第一个package发送给host2;
3> host2接收完后,将第一个package发送给host1,同时client想host2发送第二个package;
4> host1接收完第一个package后,发送给host3,同时接收host2发来的第二个package。
5> 以此类推,如图红线实线所示,直到将block1发送完毕。
6> host2,host1,host3向NameNode,host2向Client发送通知,说“消息发送完了”。如图粉红颜色实线所示。
7> client收到host2发来的消息后,向namenode发送消息,说我写完了。这样就真完成了。如图黄色粗实线
8> 发送完block1后,再向host7,host8,host4发送block2,如图蓝色实线所示。
9> 发送完block2后,host7,host8,host4向NameNode,host7向Client发送通知,如图浅绿色实线所示。
10> client向NameNode发送消息,说我写完了,如图黄色粗实线。。。这样就完毕了。
分析, 通过写过程,我们可以了解到:
① 写1T文件,我们需要3T的存储,3T的网络流量贷款。
② 在执行读或写的过程中,NameNode和DataNode通过HeartBeat进行保存通信,确定DataNode活着。如果发现DataNode死掉了,就将死掉的DataNode上的数据,放到其他节点去。读取时,要读其他节点去。
③ 挂掉一个节点,没关系,还有其他节点可以备份;甚至,挂掉某一个机架,也没关系;其他机架上,也有备份。

读操作:

读操作就简单一些了,如图所示,client要从datanode上,读取FileA。而FileA由block1和block2组成。

那么,读操作流程为:
a. client向namenode发送读请求。
b. namenode查看Metadata信息,返回fileA的block的位置。
block1:host2,host1,host3
block2:host7,host8,host4
c. block的位置是有先后顺序的,先读block1,再读block2。而且block1去host2上读取;然后block2,去host7上读取;

上面例子中,client位于机架外,那么如果client位于机架内某个DataNode上,例如,client是host6。那么读取的时候,遵循的规律是:
优选读取本机架上的数据 。

运算和存储在同一个服务器中,每一个服务器都可以是本地服务器

补充

元数据
元数据被定义为:描述数据的数据,对数据及信息资源的描述性信息。(类似于Linux中的i节点)
以 “blk_”开头的文件就是 存储数据的block。这里的命名是有规律的,除了block文件外,还有后 缀是“meta”的文件 ,这是block的源数据文件,存放一些元数据信息。

数据复制
NameNode做出关于块复制的所有决定。它周期性地从集群中的每个DataNode接收到一个心跳和一个阻塞报告。收到心跳意味着DataNode正常运行。Blockreport包含DataNode上所有块的列表。

参考文献:
http://www.cnblogs.com/laov/p/3434917.html
https://www.ibm.com/developerworks/cn/opensource/os-cn-hadoop-name-node/
http://www.cnblogs.com/linuxprobe/p/5594431.html
大数据
2018-09-17 14:58:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
云数据库管理与数据迁移认证可以帮助学员掌握云数据库的概念,如何在云端创建数据库、将自建数据库迁移至云数据库MySQL版、数据导入导出,以及云数据库运维的常用操作。
课程链接: 云数据库管理与数据迁移
课程亮点:
场景模拟:体验云端数据库管理与数据迁移场景
案例实操:在线实验提供详尽实验手册以及真实线上环境
举一反三:通过案例掌握云数据库控制台操作,轻松应对更多场景
认证证书:考试通过即可获得证书,证明自己的云数据库管理能力
课时目录: 课程介绍
通过学习,可以了解本课程的主要内容及学习目标。 云数据库简介与使用场景
通过学习,可以了解云数据库是什么,相对传统数据库的优势,以及使用场景。 云数据库MySQL版的基本概念
通过学习,可以掌握云数据库MySQL版的分类,以及实例、白名单、访问模式等基本概念。 创建实例、数据库与账号
通过学习,可以掌握在云数据库MySQL版中创建实例、数据库与账号的步骤与方法。 SQL操作与数据导入导出
通过学习,可以掌握数据库管理服务DMS的使用,以及连接数据库、SQL操作与数据导入导出的方法。 数据库迁移上云
通过学习,可以掌握数据库迁移的工具和步骤,以及从自建数据库迁移至云数据库、云数据库实例间迁移的相关操作。 云数据库运维常用设置
通过学习,可以掌握变更配置、参数设置、迁移可用区、切换主备实例、切换网络访问模式等运维常用的操作。 在线实验1:云数据库初体验
通过实验,可以掌握云数据库的基本概念、创建数据库和数据库账号、导入本地数据、获取诊断报告等操作方法。 在线实验2:实现数据库迁移上云
通过实验,可以掌握建立云数据库,以及将ECS自建数据库迁移到RDS数据库等操作方法。
更多精品课程:
阿里云大学官网( 阿里云大学 - 官方网站,云生态下的创新人才工场 )
大数据
2018-09-17 11:47:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
功能介绍
为了简化开发者和服务工程师维护Kafka集群的工作,yahoo构建了一个叫做Kafka管理器的基于Web工具,叫做 Kafka Manager。这个管理工具可以很容易地发现分布在集群中的哪些topic分布不均匀,或者是分区在整个集群分布不均匀的的情况。它支持管理多个集群、选择副本、副本重新分配以及创建Topic。同时,这个管理工具也是一个非常好的可以快速浏览这个集群的工具,有如下功能: 管理多个kafka集群 便捷的检查kafka集群状态(topics,brokers,备份分布情况,分区分布情况) 选择你要运行的副本 基于当前分区状况进行 可以选择topic配置并创建topic 删除topic(只支持0.8.2以上的版本并且要在broker配置中设置delete.topic.enable=true) Topic list会指明哪些topic被删除 为已存在的topic增加分区 为已存在的topic更新配置 在多个topic上批量重分区 在多个topic上批量重分区(可选partition broker位置)
安装环境要求 java scala sbt
安装步骤 下载最新的kafka-manager的releases中zip版本( https://github.com/yahoo/kafka-manager/releases ), 解压 下载安装kafka-manager要求的java版本,检查系统环境path路径是否添加 下载安装kafka-manager要求scala的window版本对应的msi文件 ( https://www.scala-lang.org/download/ ),双击安装,检查系统环境path路径是否添加 下载安装kafka-manager要求sbt的window版本对应的msi文件( https://www.scala-sbt.org/download.html ), 双击安装,检查系统环境path路径是否添加成功
编译运行 打开命令窗口cmd, 并进入kafka-manager解压目录 在命令窗口输入sbt, 会自动初始化工作目录 工作目录初始化结束后,输入compile,进行编译 编译完成后, 输入run 运行 打开浏览器,输入http://127.0.0.1:9000/ 就可以看到管理界面
大数据
2018-09-17 11:03:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
大数据 时代,搜索无处不在。搜索技术是全栈工程师必备技术之一,如今是开源时代,数不尽的资源供我们利用,如果要自己写一套 搜索引擎 无疑是浪费绳命。本节主要介绍搜索引擎开源项目elasticSearch的安装和使用
请尊重原创,转载请注明来源网站 www.shareditor.com 以及原始链接地址
为什么需要搜索引擎

首先想一下:在一篇文章里找一个关键词怎么找?字符串匹配是最佳答案。
然后再想一下:找到100篇文章里包含某个关键词的文章列表怎么找?依然是关键词匹配
再继续想:找到100000000000(一千亿)篇文章里包含某个关键词的文章怎么找?如果用关键词匹配,以现在的电脑处理速度,从远古时代到人类灭绝这么长时间都处理不完,这时候搜索引擎要发挥作用了

搜索引擎技术有多么高深?

搜索引擎这种技术实际上从古代就有了。想象一个国家存储各类编撰资料的部门,有几个屋子的书,如果想找到某一本书的时候会怎么找呢?对了,有分类目录,先确定要找的书籍是哪个类别的,然后从目录里面找到想要找的书籍位于屋子的什么位置,然后再去拿。搜索引擎其实就是做了生成目录(也就是索引)的事情。那么如今的搜索引擎是怎么生成索引的呢?
要把互联网上的资料生成索引,拢共分三步:第一步,把资料编号;第二步,把每篇资料内容切成词;第三步,把词和资料编号的对应关系处理成“词=》编号列表”的形式
这时候你就可以迅速的找到一千亿篇文章里包含某个关键词的文章了,告诉我关键词是什么,我直接就从索引里找到了这个词对应的文章编号列表了,搞定!把需要数万年才能做完的工作用了不到一秒钟就搞定了,这就是搜索引擎的魅力!
当然,上面说的搜索引擎技术很简单,但百度数万工程师也不都是白吃饭的,如果想做好一个搜索引擎产品需要解决的问题就有很多了:收集网页时要考虑全、快、稳、新、优的问题,建索引时要考虑质量、效率、赋权、周期、时效性、资源消耗等问题,搜索的时候要考虑query分析、排序、筛选、展示、性能、广告、推荐、个性化、统计等问题,整体上要考虑地域性、容灾、国际化、当地法律、反作弊、垂直需求、移动互联网等诸多问题,所以百度大厦彻夜通明也是可以理解的。

开源搜索引擎

既然搜索引擎技术这么复杂,那么我们何必自寻烦恼了,开源社区为我们提供了很多资源,世界很美好。
说到开源搜索引擎一定要用的开源项目就是lucene,它不是搜索引擎产品,而是一个类库,而且是至今开源搜索引擎的最好的类库没有之一,因为只有它一个。lucene是用 Java 语言开发,基本上涵盖了搜索引擎中索引和检索两个核心部分的全部功能,而且抽象的非常好,我后面会单独写数篇文章专门讲lucene的使用。最后强调一遍,它是一个类库,不是搜索引擎,你可以比较容易的基于lucene写一个搜索引擎。
然后要说的一个开源项目是solr,这是一个完整的搜索引擎产品,当然它底层一定是基于lucene的,毫无疑问,因为lucene是最好且唯一的搜索引擎类库。solr使用方法请看我的另一篇文章《 教你一步步搭建和运行完整的开源搜索引擎 》

最后要说的就是elasticSearch,这个开源项目也可以说是一个产品级别的开源项目,当然它底层一定是基于lucene的,毫无疑问,因为lucene是最好且唯一的搜索引擎类库,我承认我是唐僧。它是一种提供了RESTful api的服务,RESTful就是直接通过HTTP协议收发请求和响应,接口比较清晰简单,是一种 架构 规则。话不多说,下面我就说下安装方法和简单使用方法,这样更容易理解,之后我会单独讲解怎么让你的网站利用elasticSearch实现搜索功能

Elasticsearch(简称ES)是一个基于Apache Lucene(TM)的开源 搜索引擎 ,无论在开源还是专有领域,Lucene可以被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库。
Elasticsearch简介
Elasticsearch是什么
Elasticsearch是一个基于Apache Lucene(TM)的开源搜索引擎,无论在开源还是专有领域,Lucene可以被认为是迄今为止最先进、性能最好的、功能最全的搜索引擎库。
但是,Lucene只是一个库。想要发挥其强大的作用,你需使用 Java 并要将其集成到你的应用中。Lucene非常复杂,你需要深入的了解检索相关知识来理解它是如何工作的。
Elasticsearch也是使用Java编写并使用Lucene来建立索引并实现搜索功能,但是它的目的是通过简单连贯的RESTful API让全文搜索变得简单并隐藏Lucene的复杂性。
不过,Elasticsearch不仅仅是Lucene和全文搜索引擎,它还提供: 分布式的实时文件存储,每个字段都被索引并可被搜索 实时分析的分布式搜索引擎 可以扩展到上百台服务器,处理PB级结构化或非结构化数据
而且,所有的这些功能被集成到一台服务器,你的应用可以通过简单的RESTful API、各种语言的客户端甚至命令行与之交互。上手Elasticsearch非常简单,它提供了许多合理的缺省值,并对初学者隐藏了复杂的搜索引擎理论。它开箱即用(安装即可使用),只需很少的学习既可在生产环境中使用。Elasticsearch在Apache 2 license下许可使用,可以免费下载、使用和修改。
随着知识的积累,你可以根据不同的问题领域定制Elasticsearch的高级特性,这一切都是可配置的,并且配置非常灵活。
以上内容来自 [百度百科]
Elasticsearch中涉及到的重要概念
Elasticsearch有几个核心概念。从一开始理解这些概念会对整个学习过程有莫大的帮助。
(1) 接近实时(NRT)
Elasticsearch是一个接近实时的搜索平台。这意味着,从索引一个文档直到这个文档能够被搜索到有一个轻微的延迟(通常是1秒)。
(2) 集群(cluster)
一个集群就是由一个或多个节点组织在一起,它们共同持有你整个的数据,并一起提供索引和搜索功能。一个集群由一个唯一的名字标识,这个名字默认就是“elasticsearch”。这个名字是重要的,因为一个节点只能通过指定某个集群的名字,来加入这个集群。在产品环境中显式地设定这个名字是一个好习惯,但是使用默认值来进行 测试 /开发也是不错的。
(3) 节点(node)
一个节点是你集群中的一个服务器,作为集群的一部分,它存储你的数据,参与集群的索引和搜索功能。和集群类似,一个节点也是由一个名字来标识的,默认情况下,这个名字是一个随机的漫威漫画角色的名字,这个名字会在启动的时候赋予节点。这个名字对于管理工作来说挺重要的,因为在这个管理过程中,你会去确定网络中的哪些服务器对应于Elasticsearch集群中的哪些节点。
一个节点可以通过配置集群名称的方式来加入一个指定的集群。默认情况下,每个节点都会被安排加入到一个叫做“elasticsearch”的集群中,这意味着,如果你在你的网络中启动了若干个节点,并假定它们能够相互发现彼此,它们将会自动地形成并加入到一个叫做“elasticsearch”的集群中。
在一个集群里,只要你想,可以拥有任意多个节点。而且,如果当前你的网络中没有运行任何Elasticsearch节点,这时启动一个节点,会默认创建并加入一个叫做“elasticsearch”的集群。
(4) 索引(index)
一个索引就是一个拥有几分相似特征的文档的集合。比如说,你可以有一个客户数据的索引,另一个产品目录的索引,还有一个订单数据的索引。一个索引由一个名字来标识(必须全部是小写字母的),并且当我们要对对应于这个索引中的文档进行索引、搜索、更新和删除的时候,都要使用到这个名字。索引类似于关系型 数据库 中Database的概念。在一个集群中,如果你想,可以定义任意多的索引。
(5) 类型(type)
在一个索引中,你可以定义一种或多种类型。一个类型是你的索引的一个逻辑上的分类/分区,其语义完全由你来定。通常,会为具有一组共同字段的文档定义一个类型。比如说,我们假设你运营一个博客平台并且将你所有的数据存储到一个索引中。在这个索引中,你可以为用户数据定义一个类型,为博客数据定义另一个类型,当然,也可以为评论数据定义另一个类型。类型类似于关系型数据库中Table的概念。
(6)文档(document)
一个文档是一个可被索引的基础信息单元。比如,你可以拥有某一个客户的文档,某一个产品的一个文档,当然,也可以拥有某个订单的一个文档。文档以JSON( JavaScript Object Notation)格式来表示,而JSON是一个到处存在的互联网数据交互格式。
在一个index/type里面,只要你想,你可以存储任意多的文档。注意,尽管一个文档,物理上存在于一个索引之中,文档必须被索引/赋予一个索引的type。文档类似于关系型数据库中Record的概念。实际上一个文档除了用户定义的数据外,还包括 _index 、 _type 和 _id 字段。
(7) 分片和复制(shards & replicas)
一个索引可以存储超出单个结点硬件限制的大量数据。比如,一个具有10亿文档的索引占据1TB的磁盘空间,而任一节点都没有这样大的磁盘空间;或者单个节点处理搜索请求,响应太慢。
为了解决这个问题,Elasticsearch提供了将索引划分成多份的能力,这些份就叫做分片。当你创建一个索引的时候,你可以指定你想要的分片的数量。每个分片本身也是一个功能完善并且独立的“索引”,这个“索引”可以被放置到集群中的任何节点上。
分片之所以重要,主要有两方面的原因: 允许你水平分割/扩展你的内容容量 允许你在分片(潜在地,位于多个节点上)之上进行分布式的、并行的操作,进而提高性能/吞吐量
至于一个分片怎样分布,它的文档怎样聚合回搜索请求,是完全由Elasticsearch管理的,对于作为用户的你来说,这些都是透明的。
在一个网络/云的环境里,失败随时都可能发生,在某个分片/节点不知怎么的就处于离线状态,或者由于任何原因消失了。这种情况下,有一个故障转移机制是非常有用并且是强烈推荐的。为此目的,Elasticsearch允许你创建分片的一份或多份拷贝,这些拷贝叫做复制分片,或者直接叫复制。复制之所以重要,主要有两方面的原因: 在分片/节点失败的情况下,提供了高可用性。因为这个原因,注意到复制分片从不与原/主要(original/primary)分片置于同一节点上是非常重要的。 扩展你的搜索量/吞吐量,因为搜索可以在所有的复制上并行运行
总之,每个索引可以被分成多个分片。一个索引也可以被复制0次(意思是没有复制)或多次。一旦复制了,每个索引就有了主分片(作为复制源的原来的分片)和复制分片(主分片的拷贝)之别。分片和复制的数量可以在索引创建的时候指定。在索引创建之后,你可以在任何时候动态地改变复制数量,但是不能改变分片的数量。
默认情况下,Elasticsearch中的每个索引被分片5个主分片和1个复制,这意味着,如果你的集群中至少有两个节点,你的索引将会有5个主分片和另外5个复制分片(1个完全拷贝),这样的话每个索引总共就有10个分片。一个索引的多个分片可以存放在集群中的一台主机上,也可以存放在多台主机上,这取决于你的集群机器数量。主分片和复制分片的具体位置是由ES内在的策略所决定的。
以上部分内容转自 Elasticsearch基础教程 ,并对其进行了补充。


elasticSearch安装

从github下载1.7版tag并编译(选择1.7版是因为当前我们的网站的symfony2版本还不支持2.x版本,但请放心的用,1.7版是经过无数人验证过的最稳定版本) wget https://codeload.github.com/elastic/elasticsearch/tar.gz/v1.7.5
解压后进入目录执行 mvn package -DskipTests
这会花费你很长一段时间,你可以去喝喝茶了

编译完成后会在target/releases中生成编译好的压缩包(类似于elasticsearch-1.7.5.zip这样的文件),把这个压缩包解压放到任意目录就安装好了

安装ik插件

ik是一个中文切词插件,elasticSearch自带的中文切词很不专业,ik对中文切词支持的比较好。
在 https://github.com/medcl/elasticsearch-analysis-ik 上找到我们elasticSearch对应的版本,1.7.5对应的ik版本是1.4.1,所以下载https://github.com/medcl/elasticsearch-analysis-ik/releases/tag/v1.4.1
解压出的目录是:
elasticsearch-analysis-ik-1.4.1
进入目录后执行 mvn clean package
编译完后依然是在target/releases生成了类似于elasticsearch-analysis-ik-*.zip的压缩包,把里面的内容解压到elasticsearch安装目录的plugins/ik下
再把elasticsearch-analysis-ik-1.4.1/config/ik目录整体拷贝到elasticsearch安装目录的config下
修改elasticsearch安装目录下的config/elasticsearch.yml,添加: index: analysis: analyzer: ik: alias: [ik_analyzer] type: org.elasticsearch.index.analysis.IkAnalyzerProvider ik_max_word: type: ik use_smart: false ik_smart: type: ik use_smart: true
这样ik就安装好了

启动并试用

直接进入elasticsearch安装目录,执行 ./bin/elasticsearch -d
后台启动完成



elasticSearch是通过HTTP协议收发数据的,所以我们用curl命令来给它发命令,elasticSearch默认监听9200端口

写入一篇文章: curl -XPUT 'http://localhost:9200/myappname/myblog/1?pretty' -d ' { "title": "我的标题", "content": "我的内容" }'
会收到返回信息: { "_index" : "myappname", "_type" : "myblog", "_id" : "1", "_version" : 1, "created" : true }
这说明我们成功把一篇文章发给了elasticSearch,它底层会利用lucene自动帮我们建好搜索用的索引

再写一篇文章: curl -XPUT 'http://localhost:9200/myappname/myblog/2?pretty' -d ' { "title": "这是第二篇标题", "content": "这是第二篇内容" }'
会收到返回信息: { "_index" : "myappname", "_type" : "myblog", "_id" : "2", "_version" : 1, "created" : true }
请尊重原创,转载请注明来源网站 www.shareditor.com 以及原始链接地址
这时我们找到elasticsearch安装目录的data目录下会生成这样的目录和文件: ls data/nodes/0/indices/myappname/ 0 1 2 3 4 _state
不同环境会稍有不同,但是都会生成myappname目录就对了

查看所有文章: curl -XGET 'http://localhost:9200/myappname/myblog/_search?pretty=true' -d ' { "query" : { "match_all" : {} } }'
这时会把我们刚才添加的两篇文章都列出来

搜索关键词“我的”: curl -XGET 'http://localhost:9200/myappname/myblog/_search?pretty=true' -d ' { "query":{ "query_string":{"query":"我的"} } }'
会返回: { "took" : 2, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "failed" : 0 }, "hits" : { "total" : 1, "max_score" : 0.191783, "hits" : [ { "_index" : "myappname", "_type" : "myblog", "_id" : "1", "_score" : 0.191783, "_source": { "title": "我的标题", "content": "我的内容" } } ] } }
搜索关键词“第二篇”: curl -XGET 'http://localhost:9200/myappname/myblog/_search?pretty=true' -d ' { "query":{ "query_string":{"query":"第二篇"} } }'
会返回: { "took" : 2, "timed_out" : false, "_shards" : { "total" : 5, "successful" : 5, "failed" : 0 }, "hits" : { "total" : 1, "max_score" : 0.1879082, "hits" : [ { "_index" : "myappname", "_type" : "myblog", "_id" : "2", "_score" : 0.1879082, "_source": { "title": "这是第二篇标题", "content": "这是第二篇内容" } } ] } }

如果想检查ik的切词效果,可以执行: curl 'http://localhost:9200/myappname/_analyze?analyzer=ik_max_word&pretty=true' -d' { "text":"中华人民共和国国歌" }'
通过返回结果可以看出,ik_max_word切词把中华人民共和国国歌切成了“中华人民共和国”、“中华人民”、“中华”、“华人”、“人民共和国”、“人民”、“共和国”、“共和”、“国”、“国歌”
也就是说我们搜索这些词中的任意一个都能把这句话搜到,如果不安装ik插件的话,那只会切成:“中”、“华”、“人”、“民”、“共”、“和”、“国”、“国”、“歌”,不够 智能 ,搜索也不好进行了

讲解一下
上面几条命令都是json形式,elasticSearch就是这么人性化,没治了。
这里面的myappname是你自己可以改成自己应用的名字,这在elasticSearch数据存储中是完全隔离的,而myblog是我们在同一个app中想要维护的不同的数据,就是你的不同数据,比如文章、用户、评论,他们最好都分开,这样搜索的时候也不会混
pretty参数就是让返回的json有换行和缩进,容易阅读,调试时可以加上,开发到程序里就可以去掉了
analyzer就是切词器,我们指定的ik_max_word在前面配置文件里遇到过,表示最大程度切词,各种切,360度切
返回结果里的hits就是“命中”,total是命中了几条,took是花了几毫秒,_score就是相关性程度,可以用来做排序的依据

elasticSearch有什么用
上面都是json的接口,那么我们怎么用呢?其实你想怎么用就怎么用,煎着吃、炒着吃、炖着吃都行。比如我们的博客网站,当你创建一篇博客的时候可以发送“添加”的json命令,然后你开发一个搜索页面,当你输入关键词点搜索的时候,可以发送查询的命令,这样返回的结果就是你的搜索结果,只不过需要你自己润色一下,让展现更美观。感觉复杂吗?下一节告诉你怎么用symfony2的扩展来实现博客网站的搜索功能


————————————————————————————————————————————————————

linux下elasticsearch 安装、配置及示例

简介
开始学es,我习惯边学边记,总结出现的问题和解决方法。本文是在两台 Linux 虚拟机下,安装了三个节点。本次搭建es同时实践了两种模式——单机模式和分布式模式。条件允许的话,可以在多台机器上配置es节点,如果你机器性能有限,那么可以在一台虚拟机上完成多节点的配置。
如图,是本次3个节点的分布。
虚拟机主机名 IP es节点
master slave
192.168.137.100 192.168.137.101
node1、node3 node2
一、下载及配置
1.几个基本名词
index: es里的index相当于一个 数据库 。
type: 相当于数据库里的一个表。
id: 唯一,相当于主键。
node:节点是es实例,一台机器可以运行多个实例,但是同一台机器上的实例在配置文件中要确保http和tcp端口不同(下面有讲)。
cluster:代表一个集群,集群中有多个节点,其中有一个会被选为主节点,这个主节点是可以通过选举产生的,主从节点是对于集群内部来说的。
shards:代表索引分片,es可以把一个完整的索引分成多个分片,这样的好处是可以把一个大的索引拆分成多个,分布到不同的节点上,构成分布式搜索。分片的数量只能在索引创建前指定,并且索引创建后不能更改。
replicas:代表索引副本,es可以设置多个索引的副本,副本的作用一是提高系统的容错性,当个某个节点某个分片损坏或丢失时可以从副本中恢复。二是提高es的查询效率,es会自动对搜索请求进行负载均衡。
2.下载
名称 版本 下载地址
elasticsearch
1.7.3
elasticsearch-1.7.3.tar.gz
下载后,放到你的目录下并解压. 因为我们要配置包含三个节点的集群,可以先将其重命名为elasticsearch-node1。比如我的是 /home/zkpk/elasticsearch-node1。
3.修改配置文件
(1) 初步修改
打开/home/zkpk/elasticsearch-node1/config目录下的elasticsearch.yml 文件 ,修改以下属性值并取消该行的注释: cluster.name: elasticsearch #这是集群名字,我们 起名为 elasticsearch。es启动后会将具有相同集群名字的节点放到一个集群下。 node.name: "es-node1" #节点名字。 covery.zen.minimum_master_nodes: 2 #指定集群中的节点中有几个有master资格的节点。对于大集群可以写3个以上。 discovery.zen.ping.timeout: 40s #默认是3s,这是设置集群中自动发现其它节点时ping连接超时时间,为避免因为网络差而导致启动报错,我设成了40s。 discovery.zen.ping.multicast.enabled: false #设置是否打开多播发现节点,默认是true。 network.bind_host: 192.168.137.100 #设置绑定的ip地址,这是我的master虚拟机的IP。 network.publish_host: 192.168.137.100 #设置其它节点和该节点交互的ip地址。 network.host: 192.168.137.100 #同时设置bind_host和publish_host上面两个参数。 discovery.zen.ping.unicast.hosts: ["192.168.137.100", "192.168.137.101","192.168.137.100:9301"] #discovery.zen.ping.unicast.hosts:["节点1的 ip","节点2 的ip","节点3的ip"] 指明集群中其它可能为master的节点ip,以防es启动后发现不了集群中的其他节点。第一对引号里是node1,默认端口是9300。第二个是 node2 ,在另外一台机器上。第三个引号里是node3,因为它和node1在一台机器上,所以指定了9301端口。
(2) 进一步修改
拷贝 elasticsearch-node1 整个文件夹,两份,一份elasticsearch-node2,一份elasticsearch-node3.
将elasticsearch-node2 文件夹copy到另外一台IP为192.168.137.101的机器上。而在 192.168.137.100 机器上有 node1和node3.
对于node3: node3和node1在一台机器上,node1的配置文件里端口默认分别是9300和9200,所以要改一下node3配置文件里的端口,elasticsearch.yml 文件修改如下: node.name: "es-node3" transport.tcp.port: 9301 http.port: 9201
对于node2: 对 elasticsearch.yml 修改如下 node.name: "es-node2" network.bind_host: 192.168.137.101 network.publish_host: 192.168.137.101 network.host: 192.168.137.101
注意:
1.对于单机多节点的es集群,一定要注意修改 transport.tcp.port 和http.port 的默认值保证节点间不冲突。
2. 出现找不到同一集群中的其他节点的情况,检查下 discovery.zen.ping.unicast.hosts 是否已设置。
二、运行 & 关闭 elasticsearch
1.运行elasticsearch :
编辑 /home/zkpk/elasticsearch-1.7.3/bin/elasticsearch.in.sh, 设置 ES_MIN_MEM和ES_MAX_MEM,确保二者数值一致,或者可以在启动es时指定, [zkpk @master ~]$ cd ~/elasticsearch-node1/bin [zkpk @master bin]$ ./elasticsearch -Xms512m -Xmx512m 1 2 1 2
若想让es后台运行,则 [zkpk@master bin]$ ./elasticsearch -d -Xms512m -Xmx512m 1 1
2.关闭elasticsearch:
前台运行:可以通过”CTRL+C”组合键来停止运行
后台运行,可以通过”kill -9 进程号”停止.也可以通过REST API接口: curl -XPOST http://主机IP:9200/_cluster/nodes/_shutdown 1 1
来关闭整个集群,通过: curl -XPOST http://主机IP:9200/_cluster/nodes/节点标示符(如es-node1)/_shutdown 1 1
来关闭单个节点.
三、插件及其安装
BigDesk Plugin : 对集群中es状态进行监控。
Elasticsearch Head Plugin: 对ES进行各种操作,如查询、删除、浏览索引等。
1.安装head插件
进入到节点elasticsearch-node1/bin路径,并安装插件。 [zkpk@master bin]$ ./plugin -install mobz/elasticsearch-head 1 1
2. 安装bigdesk
[zkpk @master bin]$ ./plugin -install lukas-vlcek/bigdesk
让我们看下es页面吧~~
打开head浏览,浏览器输入 http://192.168.137.100:9200/_plugin/head/ ,如图,
每个小方块就是索引分片,可以看到每个索引被分成几个分片,每个分片还有它的备份分片,然后存储在三个节点上。粗框的是主分片,细框的是备份分片。
四、添加索引
现在我们来添加一个索引记录吧~
1.可以在命令窗口通过命令来添加 curl -XPUT 'http://主机IP:9200/dept/employee/32' -d '{ "empname": "emp32"}' 1 1
见 http://www.oschina.net/translate/elasticsearch-getting-started?cmp
2.我们可以在页面上通过JSON添加
(1)点击 复合查询[+] ,我们可以在 megacorp 索引 (相当于数据库名)的 employee 类型(相当于表名)下新增一个id为2的人的信息。
点击下方的 提交请求 按钮,页面右方有回馈信息,“created”代表是否为新建。添加成功。
点击 浏览数据 ,在左侧 索引 下选择 megacorp,如图,
可以看到,一条id为2的记录被添加了。
(2)下面我们修改id为2 的人的年龄为15,把about 信息去掉,并且加一项兴趣。
提交后,右侧有反馈信息,“created”为 false,因为我们这次不是新建而是修改。
返回浏览数据,id为2 的记录,年龄、兴趣等均已发生变化。
参考:
http://www.cnblogs.com/huangfox/p/3543351.html
http://www.linuxidc.com/Linux/2015-02/114243.htm
http://my.oschina.net/u/579033/blog/394845?fromerr=Kt60ej6x
大数据
2018-09-17 10:54:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
创建一个索引
Elasticsearch 命令的一般格式是:REST VERBHOST:9200/index/doc-type— 其中 REST VERB 是 PUT、GET 或 DELETE。(使用 cURL -X 动词前缀来明确指定 HTTP 方法。)
要创建一个索引,可在您的 shell 中运行以下命令:
curl -XPUT “ http://localhost:9200/music/ ”
插入一个文档
要在 /music 索引下创建一个类型,可插入一个文档。在第一个示例中,您的文档包含数据(包含一行)“Deck the Halls” 的歌词,这是一首最初由威尔士诗人 John Ceirog Hughes 于 1885 年编写的传统的圣诞歌曲。
要将包含 “Deck the Halls” 的文档插入索引中,可运行以下命令(将该命令和本教程的其他 cURL 命令都键入到一行中): curl -XPUT "http://localhost:9200/music/songs/1" -d '{ "name": "Deck the Halls", "year": 1885, "lyrics": "Fa la la la la" }'
运行以上命令可能出现异常错误:
{“error”:”Content-Type header [application/x-www-form-urlencoded] is not supported”,”status”:406}
这是因为没有指定内容的格式导致 因此需要在命令里面指定header 命令改为: curl -H "Content-Type: application/json" -XPUT "http://localhost:9200/music/songs/1" -d '{"name":"Deck the Halls","year":1885,"lyrics":"Fa la la la la"}'
再次运行 成功 并返回成功信息 {"_index":"music","_type":"songs","_id":"2", "_version":1,"result":"created","_shards":{"total":2,"successful":1,"failed":0},"_seq_no":0,"_primary_term":1}
<—– 注意—–>
这里的music为索引 而songs为类型 一个索引下面只能为一个类型
下面的命令可以列出每个 Index 所包含的 Type curl 'localhost:9200/_mapping?pretty=true'
查看文档
要查看该文档,可使用简单的 GET 命令: curl -XGET "http://localhost:9200/music/songs/1"
Elasticsearch 使用您之前 PUT 进索引中的 JSON 内容作为响应: {"_index":"music","_type":"songs","_id":"1","_version":1, "found":true,"_source":{ "name": "Deck the Halls", "year": 1885, "lyrics": "Fa la la la la" }}
更新文档
es的更新命令和插入命令一致 curl -H "Content-Type: application/json" -XPUT "http://localhost:9200/music/songs/1" -d '{"name":"Deck the Halls","year": 1886,"lyrics":"Fa la la la la" }'
这里指出了需要更新的文档的id因此会返回 更新成功。 {"_index":"music","_type":"songs","_id":"2","_version":2, "result":"updated","_shards":{"total":2,"successful":1,"failed":0},"_seq_no":1,"_primary_term":1}
删除文档##
删除文档使用 -XDELETE curl -XDELETE "http://localhost:9200/music/songs/1"
返回信息: {"_index":"music","_type":"songs","_id":"1","_version":3, "result":"deleted","_shards":{"total":2,"successful":1,"failed":0},"_seq_no":2,"_primary_term":1}
查看索引 curl -X GET 'http://localhost:9200/_cat/indices?v'
常用命令:
http://192.168.30.70:9200/_cat/ //显示命令提示
curl -X POST "http://localhost:9200/music/_open" 打开索引 关闭索引 (_close) curl -X GET 'http://localhost:9200/_cat/indices?v' 查看索引 curl 'localhost:9200/_mapping?pretty=true' 列出每个 Index 所包含的 Type curl 'localhost:9200/accounts/person/_search' 查看某个索引下全部记录
大数据
2018-09-17 10:45:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
es5以上版本安装head需要安装node和grunt(之前的直接用plugin命令即可安装)
安装ElasticSearch6.3.1
一、安装jdk8(jdk7不可以)
二、安装ElasticSearch6.3.1
1、从官方下载中心 ElasticSearch Download 下载ElasticSearch安装包

2,开启ElasticSearch 服务
将zip文件解压到E盘,进入 E:\elasticsearch-6.3.1\bin 目录,双击执行 elasticsearch.bat,该脚本文件执行 ElasticSearch 安装程序,稍等片刻,打开浏览器,输入 http://localhost:9200 ,显式以下画面,说明ES安装成功。

安装ElasticSearch6.3.1的Head插件
一、安装nodejs
从地址: https://nodejs.org/en/download/ 下载相应系统的msi,双击安装。
把NODE_HOME设置到环境变量里(安装包也可以自动加入PATH环境变量)。测试一下node是否生效:


二、安装grunt
grunt构建工具,可以进行打包压缩、测试、执行等等的工作,head插件就是通过grunt启动的。因此需要安装grunt:
注意:路径切到E:\nodejs下。 npm install -g grunt-cli
-g代表全局安装。

把head插件的源码git clone下来: git clone git://github.com/mobz/elasticsearch-head.git
效果如图:

三、修改head源码
由于head的代码还是2.6版本的,直接执行有很多限制,比如无法跨机器访问。因此需要用户修改两个地方:
目录:head/Gruntfile.js: connect: { server: { options: { port: 9100, hostname: '*', base: '.', keepalive: true } } }
增加hostname属性,设置为*

修改连接地址:
目录:head/_site/app.js
修改head的连接地址: this.base_uri = this.config.base_uri || this.prefs.get("app-base_uri") || "http://localhost:9200";
把localhost修改成你es的服务器地址,如: this.base_uri = this.config.base_uri || this.prefs.get("app-base_uri") || "http://10.10.10.10:9200";


四、运行head
修改elasticsearch的参数
修改一下es使用的参数。编辑config/elasticsearch.yml: # 换个集群的名字,免得跟别人的集群混在一起 cluster.name: es-5.0-test # 换个节点名字 node.name: node-101 # 修改一下ES的监听地址,这样别的机器也可以访问 network.host: 0.0.0.0 # 默认的就好 http.port: 9200 # 增加新的参数,这样head插件可以访问es http.cors.enabled: true http.cors.allow-origin: "*"
注意,设置参数的时候:后面要有空格!

启动效果:


然后在head源码目录中,执行npm install 下载的包: npm install
效果如图:

最后,在head源代码目录下启动nodejs: grunt server
效果如图:

五、访问:target:9100
这个时候,访问 http://localhost:9100 就可以访问head插件了:
安装好下次启动方法如图: 再访问http://localhost:9100即可
大数据
2018-09-17 10:43:00
「深度学习福利」大神带你进阶工程师,立即查看>>>
提起机器学习,尤其是深度学习,大家可能会对诸如Tensorflow,Pytorch,Caffee的工具耳熟能详。但其实在实际的机器学习的生命周期中,训练模型(上述工具主要解决的问题)只是整个机器学习生命周期的很小一部分。
数据如何准备?模型训练好了如何部署?如何上云?如何上规模Scale?等等挑战随之而来。随着机器学习的广泛应用,许多工具响应而生,以解决模型部署的问题。例如: Oracle 的 graphpipe Databricks 的 mlflow Google的 kubeflow
我们今天就来看一看Google推出的Kubeflow。Kubeflow,顾名思义,是 Kubernetes + Tensorflow ,是Google为了支持自家的Tensorflow的部署而开发出的开源平台,当然它同时也支持Pytorch和基于Python的SKlearn等其它机器学习的引擎。与其它的产品相比较,因为是基于强大的Kubernetes之上构建,Kubeflow的未来和生态系统更值得看好。
Kukeflow主要提供在生产系统中简单的大规模部署机器学习的模型的功能,利用Kubernetes,它可以做到: 简单,可重复,可移植的部署 利用微服务提供松耦合的部署和管理 按需扩大规模
Kubeflow是基于K8S的机器学习工具集,它提供一系列的脚本和配置,来管理K8S的组件。Kubeflow基于K8s的微服务架构,其核心组件包括: Jupyterhub 多租户Nootbook服务 Tensorflow / Pytorch / MPI / MXnet / Chainer 主要的机器学习引擎 Seldon 提供在K8s上对于机器学习模型的部署 Argo 基于K8s的工作流引擎 Ambassador API Gateway Istio 提供微服务的管理,Telemetry收集 Ksonnet K8s部署工具
基于K8s,扩展其它能力非常方便,Kubeflow提供的其它扩展包括: Pachyderm 基于容器和K8s的数据流水线 (git for data) Weaveworks flux 基于git的配置管理 ... ...
我们可以看出,基于K8s,Kubeflow利用已有的生态系统来构微服务,可以说充分体现了微服务的高度扩展性。
我们下面就来看看Kubeflow是如何整合了这些组件,来提供机器学习模型部署的功能的。
JupyterHub
Jupyter Notebook 是深受数据科学家喜爱的开发工具,它提供出色的交互和实时反馈。JupyterHub提供一个使用Juypter Notebook的多用户使用环境,它包含以下组件: 多用户Hub 可配置的HTTP代理 多个但用户Notebook server
运行以下的命令通过port-forward访问jyputer hub kubectl port-forward tf-hub-0 8000:8000 -n
第一次访问,可以创建一个notebook的实例。创建的实例可以选择不同的镜像,可以实现对GPU的支持。同时需要选择配置资源的参数。
创建好的 jupyterlab (JupyterLab是新一代的Juypter Notebook)的界面如下:
不过我还是比较习惯传统的notebook界面。Lab的优点是可以开Console,这个不错。(Lab也支持打开传统的notebook界面)
Kubeflow在notebook镜像中集成了 Tensorboard ,可以方便的对tensflow的程序进行可视化和调试。
在jyputerlab的Console中,输入下面的命令开启Tensorboard: tensorboard --logdir $ tensorboard --logdir /tmp/logs 2018-09-15 20:30:21.186275: I tensorflow/core/platform/cpu_feature_guard.cc:140] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA W0915 20:30:21.204606 Reloader tf_logging.py:121] Found more than one graph event per run, or there was a metagraph containing a graph_def, as well as one or more graph events. Overwriting the graph with the newest event. W0915 20:30:21.204929 Reloader tf_logging.py:121] Found more than one metagraph event per run. Overwriting the metagraph with the newest event. W0915 20:30:21.205569 Reloader tf_logging.py:121] Found more than one graph event per run, or there was a metagraph containing a graph_def, as well as one or more graph events. Overwriting the graph with the newest event. TensorBoard 1.8.0 at http://jupyter-admin:6006 (Press CTRL+C to quit)
访问tensorboard也需要port-forward,这里user是创建notebook的用户名,kubeflow为为一个实例创建一个Pod。缺省的tensorboard的端口是6006。 kubectl port-forward jupyter- 6006:6006 -n
Tensorflow 训练
为了支持在Kubernete中进行 分布式的Tensorflow的训练 ,Kubeflow开发了K8s的 CDR , TFJob (tf-operater)。
如上图所示,分布式的Tensorflow支持0到多个以下的进程: Chief 负责协调训练任务 Ps Parameter servers,参数服务器,为模型提供分布式的数据存储 Worker 负责实际训练模型的任务. 在某些情况下 worker 0 可以充当Chief的责任. Evaluator 负责在训练过程中进行性能评估
下面的yaml配置是Kubeflow提供的一个 CNN Benchmarks 的例子。 --- apiVersion: kubeflow.org/v1alpha2 kind: TFJob metadata: labels: ksonnet.io/component: mycnnjob name: mycnnjob namespace: kubeflow spec: tfReplicaSpecs: Ps: template: spec: containers: - args: - python - tf_cnn_benchmarks.py - --batch_size=32 - --model=resnet50 - --variable_update=parameter_server - --flush_stdout=true - --num_gpus=1 - --local_parameter_device=cpu - --device=cpu - --data_format=NHWC image: gcr.io/kubeflow/tf-benchmarks-cpu:v20171202-bdab599-dirty-284af3 name: tensorflow workingDir: /opt/tf-benchmarks/scripts/tf_cnn_benchmarks restartPolicy: OnFailure tfReplicaType: PS Worker: replicas: 1 template: spec: containers: - args: - python - tf_cnn_benchmarks.py - --batch_size=32 - --model=resnet50 - --variable_update=parameter_server - --flush_stdout=true - --num_gpus=1 - --local_parameter_device=cpu - --device=cpu - --data_format=NHWC image: gcr.io/kubeflow/tf-benchmarks-cpu:v20171202-bdab599-dirty-284af3 name: tensorflow workingDir: /opt/tf-benchmarks/scripts/tf_cnn_benchmarks restartPolicy: OnFailure
在Kubeflow中运行这个例子,会创建一个TFjob。可以使用Kubectl来管理,监控这个Job的运行。 # 监控当前状态 kubectl get -o yaml tfjobs -n # 查看事件 kubectl describe tfjobs -n # 查看运行日志 kubectl logs mycnnjob-[ps|worker]-0 -n
Tensoflow 服务(Serving)
Serving就是指当模型训练好了以后,提供一个稳定的接口,供用户调用,来应用该模型。
基于 Tensorflow的Serving 功能,Kubeflow提供一个Tensorflow模型服务器(model server)的Ksonnet模块来提供模型服务的功能。
Kukeflow支持使用S3,Google Cloud或者NFS来存贮模型。并支持利用 Istio 来收集Telemetry。
其它机器学习引擎的支持
虽说Tensorflow是自家的机器学习引擎,但是Google的Kubeflow也提供了对其它不同引擎的支持,包含: Pytorch PyTorch是由Facebook的人工智能研究小组开发,基于Torch的开源Python机器学习库。 MXnet Apache MXNet是一个现代化的开源深度学习软件框架,用于训练和部署深度神经网络。它具有可扩展性,允许快速模型培训,并支持灵活的编程模型和多种编程语言 MXNet库是可移植的,可以扩展到多个GPU和多台机器。 Chainer Chainer是一个开源深度学习框架,纯粹用Python编写,基于Numpy和CuPy Python库。 该项目由日本风险投资公司Preferred Networks与IBM,英特尔,微软和Nvidia合作开发。 Chainer因其早期采用“按运行定义”方案以及其在大规模系统上的性能而闻名。Kubeflow对Chainer的支持要到下一个版本。现在还在Beta。 MPI 使用MPI来训练Tensorflow。这部分看到的资料比较少。
这些都是用Kubernetes CDRs的形式来支持的,用户只要利用KS创建对应的组件来管理就好了。
Seldon Serving
既然要支持不同的机器学习引擎,当然也不能只提供基于Tensforflow的模型服务,为了提供其它模型服务的能力,Kubeflow集成了Seldon。
Seldon Core 是基于K8s的开源的机器学习模型部署平台。
机器学习部署面临许多挑战。 Seldon Core希望帮助应对这些挑战。它的高级目标是: 允许数据科学家使用任何机器学习工具包或编程语言创建模型。我们计划最初涵盖以下工具/语言: 基于Python的模型包括 Tensorflow模型 Sklearn模特 Spark模型 H2O模型 R模型 在部署时通过REST和gRPC自动公开机器学习模型,以便轻松集成到需要预测的业务应用程序中。 允许将复杂的运行时推理图部署为微服务。这些图可以包括: 模型 - 可执行机器学习模型的运行时推理 路由器 - 将API请求路由到子图。示例:AB测试,多武装强盗。 组合器 - 结合子图的响应。示例:模型集合 变形器 - 转换请求或响应。示例:转换要素请求。 处理已部署模型的完整生命周期管理: 更新运行时图表,无需停机 缩放 监控 安全
除了提供单模型服务的功能,Seldon还支持AB测试,异常检测等等。
模型部署好了之后,通过API Gateway暴露的endpoint来访问和使用模型。 http:///seldon//api/v0.1/predictions

Argo
argo 是一个开源的基于容器的工作流引擎,并实现为一个K8S的CRD。 用容器实现工作流的每一个步骤 用DAG的形式描述多个任务之间的关系的依赖 支持机器学习和数据处理中的计算密集型任务 无需复杂配置就可以在容器中运行CICD
用容器来实现工作流已经不是什么新鲜事了, codeship 就是用容器来实现CICD的每一步。所以Argo很适合CICD。
下图就是一个Argo工作流的例子:
机器学习同样可以抽象为一个或者多个工作流。Kubeflow继承了Argo来作为其机器学习的工作流引擎。
可以通过Kubectl proxy来访问Kubeflow中的Argo UI。 http://localhost:8001/api/v1/namespaces/kubeflow/services/argo-ui/proxy/workflows
现阶段,并没有实际的Argo工作流来运行机器学习的例子。但是Kubeflow在使用Argo来做自己的 CICD 系统。

Pachyderm
Pychyderm是容器化的数据池,提供像git一样的数据版本系统管理,并提供一个数据流水线,来构建你的数据科学项目。

总结
Kubeflow利用Google自家的两大利器Kubernete和Tensorflow,强强联手,来提供一个数据科学的工具箱和部署平台。我们可以看到他有很多优点: 云优化 - 基于K8s,可以说,所有功能都很容易的在云上扩展。诸如多租户功能,动态扩展,对AWS/GCP的支持等等 利用微服务架构,扩展性强,基于容器,加入心得组件非常容易 出色的DevOps和CICD支持,使用Ksonnet/argo,部署和管理组件和CICD都变得非常轻松 多核心支持,除了我们本文提到的深度学习引擎,Kubeflow很容易扩展新的引擎,例如 Caffe2 正在开发中。 GPU支持
同时我们也可以看到Kubeflow的一些问题: 组件比较多,缺乏协调,更像是一推工具集合。希望能有一个整合流畅的工作流,能统一各个步骤。 文档还需改善
当然,kubeflow的当前版本是0.2.5,我相信,未来Kubeflow会有很好的发展。

参考: kubeflow open mpi Kubeflow: Cloud-native machine learning with Kubernetes Bringing Your Data Pipeline Into The Machine Learning Era Introducing Argo — A Container-Native Workflow Engine for Kubernetes Introducing Seldon Deploy jupyterhub 文档 MPI AND SCALABLE DISTRIBUTED MACHINE LEARNING Chainer 使复杂神经网络变的简单 pachyderm 文档 https://github.com/fnproject/fn-helm/issues/21
大数据
2018-09-17 02:40:00
「深度学习福利」大神带你进阶工程师,立即查看>>> 原文:April 5, 2018 Scaling Uber’s Apache Hadoop Distributed File System for Growth How Uber implemented these improvements to facilitate the continued growth, stability, and reliability of our storage system.
三年前, Uber 工程团队引入 Hadoop 作为大数据分析的存储 (HDFS) 和计算 (YARN) 基础设施。
Uber 使用 Hadoop 进行批量和流式分析, 广泛应用于包括欺诈检测( fraud detection)、机器学习(machine learning)和 ETA 计算(Estimated Time of Arrival)等领域。在过去的几年里, Uber 的业务发展迅猛,数据量和相关的访问负载呈指数级增长 ; 仅在 2017年, 存储在 HDFS 上的数据量就增长了400% 以上。
在扩展基础设施的同时保持高性能可不是一件轻松的事。为了实现这一目标,Uber 数据架构团队通过实施若干新的调整和功能来扩展 HDFS , 包括可视化文件系统(View File System ,ViewFs)、频繁的 HDFS 版本升级、NameNode 垃圾回收调整, 限制通过系统筛选小文件的数量、HDFS 负载管理服务和只读 NameNode 副本。下面将详细介绍如何执行这些改进以促进存储系统的持续增长、稳定性和可靠性。
Challenges
HDFS 被设计为可伸缩的分布式文件系统, 单个群集支持上千个节点。只要有足够的硬件, 在一个集群中可以轻松、快速地扩展实现超过 100 pb 的原始存储容量。
然而对于 Uber 而言, 业务迅速增长使其难以可靠地进行扩展同时而不减慢数据分析的速度。成千上万的用户每周都要执行数以百万计的查询(通过 Hive 或 Presto )。
目前, HDFS 超过一半以上的访问源于 Presto, 并且 90% 的 Presto 查询需要 100 秒以上的时间来处理。如果我们的 HDFS 基础结构超载, 那么在队列中的查询就会堆积起来, 从而导致查询延迟。更为重要的是,对于每个查询而言,我们需要在 HDFS 上尽快地提供数据。
针对原来的存储基础架构, 我们设计了提取(extract)、转换(transform)和加载 (ETL) 机制以便在用户运行查询时减少同一集群中发生的复制延迟。这些群集由于具有双重职责,因而需要生成小文件以适应频繁的写入和更新, 这反而进一步堵塞了队列。
在我们面临的挑战中,首要任务是多个团队需要大量的存储数据, 这就决定了不能采用按照用例或组织进行集群分割的方案, 那样反过来会降低效率的同时增加成本。
造成减速的根源 — 在不影响用户体验的情况下扩展 HDFS 的主要瓶颈是 NameNode 的性能和吞吐量, 它包括系统中所有文件的目录树, 用于跟踪保存数据文件的位置。由于所有元数据都存储在 NameNode 中, 因此客户端对 HDFS 群集的请求必须首先通过它。更复杂的是, NameNode 命名空间上的ReadWriteLock 限制了 NameNode 可以支持的最大吞吐量, 因为任何写入请求都将被独占写锁定, 并强制任何其他请求都在队列中等待。
2016 年晚些时候, 我们开始发现 NameNode RPC 队列时间高的问题。有时, NameNode 队列时间可能超过每个请求 500毫秒 (最慢的队列时间达到接近一秒), 这意味着每一个 HDFS 请求在队列中至少等待半秒 -- 与我们的正常进程时间(10 毫秒以下)相比, 这是明显的减速。
Enabling scaling & improving performance
为了确保 HDFS 高性能运行的同时持续扩展, Uber 并行开发多个解决方案, 以避免在短期内出现停机。这些解决方案使我们建立了一个更可靠和可扩展的系统, 能够支持未来的长期增长。
改进方案概述如下:
Scaling out using ViewFs
Twitter 尝试过类似努力 ,在他们的启发下, 我们利用可视化文件系统 (ViewFs) 将 HDFS 拆分为多个物理命名空间, 并使用 ViewFs 挂载点向用户呈现一个虚拟命名空间。
为了完成这一目标, 我们将 HBase(YARN 和 Presto 操作)从相同的 HDFS 集群分开。该调整不仅大大减少了主集群上的负载, 而且使我们的 HBase 更加稳定, 将 HBase 集群的重启时间从几小时减少到几分钟。
我们还为聚合 YARN 应用日志创建了一个专用的 HDFS 群集。要使日志聚合支持 ViewFs, 需要 YARN-3269 。我们的 Hive 临时目录也被移动到这个群集。增加集群的结果是非常令人满意的 ; 目前, 新群集的服务总写入请求数约占总数的 40%, 而且大多数文件都是小文件, 这也减轻了主群集上的文件计数压力。由于对现有应用程序而言,不需要更改客户端, 因此改转换非常顺利。
最后, 我们在 ViewFs 后端实现了独立的的 HDFS 群集, 而不是基础架构中的 HDFS Federation 。通过这种设置, 可以逐步执行 HDFS 升级, 最大限度地减少大规模停机的风险; 此外, 完全隔离还有助于提高系统的可靠性。然而, 这种修复方案的一个缺点是, 保持单独的 HDFS 群集会导致更高的运营成本。
HDFS upgrades
第二个解决方案是升级 HDFS 以跟上最新版本。我们一年执行了两次主要升级, 首先从 CDH 5.7.2 ( 包含大量 HDFS 2.6.0 补丁) 升级到 Apache 2.7.3, 然后升级到 Apache 2.8.2。为此, 我们还必须重构基于 Puppet 和 Jenkins 之上的部署框架, 以更换第三方群集管理工具。
版本升级带来了关键的可伸缩性改进, 包括 HDFS-9710、HDFS-9198 和 HDFS-9412。例如, 升级到 Apache 2.7.3 后, 增量块报告(incremental block report)的数量明显减少, 从而减轻了 NameNode 的负载。
升级 HDFS 可能会有风险, 因为它可能会导致停机、性能下降或数据丢失。为了解决这些可能的问题, 我们花了几个月的时间来验证 Apache 2.8.2 之后才将其部署到生产环境中。但是, 在升级最大的生产集群时, 仍然有一个 Bug (HDFS-12800) 让我们措手不及。尽管 Bug 引起的问题很晚才发现, 但是凭借独立群集、分阶段升级过程(a staged upgrade process)和应急回滚计划(contingency rollback plans),最后给我们的影响非常有限。
事实证明,在同一台服务器上运行不同版本的 YARN 和 HDFS 的能力对于我们实现扩展至关重要。由于 YARN 和 HDFS 都是 Hadoop 的一部分, 它们通常一起升级。然而, YARN 主线版本的升级需要更长时间的充分验证之后才会推出, 一些生产应用的 YARN 可能需要更新,由于 YARN API 的变化或 YARN 和这些应用的 JAR 依赖冲突。虽然 YARN 的可伸缩性在我们的环境中不是一个问题, 但我们不希望关键的 HDFS 升级被 YARN 升级阻塞。为了防止可能的堵塞, 我们目前运行的 YARN 比 HDFS 的版本更早, 在我们的场景很有效。(但是, 当采用诸如 Erasure Coding 之类的功能时, 由于需要更改客户端, 此策略可能不起作用。)
NameNode Garbage collection
垃圾回收 (Garbage collection , GC) 调优在整个优化方案中也发挥了重要作用。它在扩展存储基础架构的同时,给我们创造了必要的喘息空间。
通过强制使用并发标记扫描收集器 (Concurrent Mark Sweep collectors ,CMS) 防止长时间 GC 暂停, 通过调整 CMS 参数 (如 CMSInitiatingOccupancyFraction、UseCMSInitiatingOccupancyOnly 和 CMSParallelRemarkEnabled ) 来执行更具侵略性的老年代集合(注:CMS 是分代的,新生代和老年代都会发生回收。CMS 尝试通过多线程并发的方式来跟踪对象的可达性,以便减少老生代的收集时间)。虽然会增加 CPU 利用率, 但幸运的是我们有足够的空闲 CPU 来支持此功能。
由于繁重的 RPC 负载, 在新生代中创建了大量短期的对象, 迫使新生代收集器频繁地执行垃圾回收暂停(stop-the-world)。通过将新生代的规模从 1.5GB 增加到 16GB , 并调整 ParGCCardsPerStrideChunk 值 (设置为 32768), 生产环境中 NameNode 在 GC 暂停时所花费的总时间从 13% 减少到 1.7% , 吞吐量增加了 10% 以上。
与 GC 相关的 JVM 参数( NameNode 堆大小 160GB ), 供参考: XX:+UnlockDiagnosticVMOptions XX:ParGCCardsPerStrideChunk=32768 -XX:+UseParNewGC XX:+UseConcMarkSweepGC -XX:+CMSConcurrentMTEnabled XX:CMSInitiatingOccupancyFraction=40 XX:+UseCMSInitiatingOccupancyOnly XX:+CMSParallelRemarkEnabled -XX:+UseCondCardMark XX:+DisableExplicitGC
Uber 还在评估是否将第一垃圾回收器 (Garbage-First Garbage Collector , G1GC) 集成在系统中。虽然在过去使用 G1GC 时没有看到优势, 但 JVM 的新版本带来了额外的垃圾回收器性能改进, 因此重新审视收集器和配置的选择有时是必要的。
Controlling the number of small files
由于 NameNode 将所有文件元数据加载到内存中, 小文件增长会增加 NameNode 的内存压力。此外, 小文件会导致读取 RPC 调用增加, 以便在客户端读取文件时访问相同数量的数据, 以及在生成文件时增加 RPC 调用。为了减少存储中小文件的数量, Uber 主要采取了两种方法:
首先,Uber Hadoop 数据平台团队基于 Hoodie 库建立了新的摄取管道, 生成比原始数据管道创建的更大的文件。不过, 作为一个临时解决方案, 在这些可用之前, 我们还建立了一个工具 (称为 stitcher "订书机"), 将小文件合并成较大的文件(通常大于 1GB )。
其次, 在 Hive 数据库和应用程序目录上设置了严格的命名空间配额。为了贯彻这一目标, 我们为用户创建了一个自助服务工具, 用于管理其组织内的配额。配额的分配比例为每文件 256MB, 以鼓励用户优化其输出文件大小。Hadoop 团队还提供优化指南和文件合并工具以帮助用户采用最佳实践。例如, 在 Hive 上启用自动合并(auto-merge)和调整减速器数量(the number of reducers )可以大大减少由 Hive insert-overwrite 查询生成的文件数。
HDFS load management service
运行大型多租户基础架构 (如 HDFS ) 的最大挑战之一是检测哪些应用程序导致异常大的负载、如何快速采取措施来修复它们。为了实现这一目的,Uber 构建了内置 HDFS 的负载管理服务, 称为 Spotlight 。
在目前的 Spotlight 实现中, 审计日志从活跃的 NameNode 以流的形式送到一个基于 Flink 和 Kafka 的后端实时处理。最后,日志分析结果通过仪表板输出, 并用于自动化处理(例如自动禁用帐户或杀死导致 HDFS 减速的工作流)。
New Feature : Observer NameNode
Uber 正在开发一个新的 HDFS 功能 Observer NameNode (HDFS-12975) 。 Observer NameNode 设计为一个 NameNode 只读副本, 目的是减少在活跃的 NameNode 群集上加载。由于 HDFS RPC 容量和增长的一半以上来自只读的 Presto 查询, Uber 希望借助 Observer NameNodes 的帮助将总体 NameNode 吞吐量扩展到 100% 。Uber 已经完成了这个工具的验证, 并正在将其投入生产环境中。
最佳实践 Layer your solutions: 考虑不同层次的解决方案。实现像 Observer NameNode 那样的工具或将 HDFS 切分到多集群需要付出巨大的努力。短期措施, 如 GC 调整和通过 stitcher 合并较小的文件, 给了我们很多喘息的空间以开发完善长期的解决方案。 Bigger is better: 因为小文件对 HDFS 的威胁, 所以最好及早解决它们, 而不是延后。主动向用户提供工具、文档和培训是帮助实施最佳实践非常有效的方法。 Participate in the community: Hadoop 已经存在超过 10 年了, 其社区比以往任何时候都更加活跃, 几乎每个版本中都引入了可伸缩性和功能改进。通过贡献您自己的发现和工具来参与 Hadoop 社区对于你持续扩展基础架构非常重要。
未来
在不久的将来, Uber 计划将各种新服务集成到存储系统(如 图6 所示)。
接下来重点介绍两个主要项目, 基于路由的 HFDS Federation 和 tiered storage :
Router-based HDFS Federation
Uber 目前使用 ViewFs 扩展 HDFS (当 subclusters 超载时)。此方法的主要问题是, 每次在 ViewFs 上添加或替换新的挂载点时, 都需要更改客户端配置, 而且很难在不影响生产工作流的情况下进行。这种困境是我们目前只拆分不需要大规模更改客户端数据的主要原因之一, 例如 YARN 日志聚合。
Microsoft 的新倡议—基于路由的 HFDS Federation ( HDFS-10467 , HDFS-12615 ),目前包含在 HDFS 2.9 版本中, 是一个基于 ViewFs 的分区联盟的扩展。该联盟添加了一层软件集中管理 HDFS 命名空间。通过提供相同的接口 (RPC 和 WebHDFS 的组合), 它的外层为用户提供了对任何 subclusters 的透明访问, 并让 subclusters 独立地管理其数据。
通过提供再平衡工具( a rebalancing tool ), 联盟层( the federation layer )还将支持跨 subclusters 的透明数据移动, 用于平衡工作负载和实现分层存储。联盟层集中式维护状态存储区中全局命名空间的状态, 并允许多个活跃的路由器将用户请求定向到正确的 subclusters 时启动和运行。
Uber 正在积极地与 Hadoop 社区密切协作,致力于将基于路由的 HDFS Federation 引入到生产环境, 并进一步开源改进, 包括支持 WebHDFS 。
Tiered Storage
随着基础架构的规模增长, 降低存储成本的重要性也同样重要。Uber 技术团队中进行的研究表明, 相较旧数据 (warm data) 用户会更频繁地访问最近的数据 (hot data)。将旧数据移动到一个单独的、占用较少资源的层将大大降低我们的存储成本。HDFS Erasure Coding 、Router-based Federation、高密度 (250TB 以上) 硬件和数据移动服务 (在 "热" 层群集和 "暖" 层群集之间处理移动数据) 是即将进行的分层存储设计的关键组件。Uber 计划在以后的文章中分享在分层存储实现方面的经验。
Apache Hadoop ABC $ hadoop version Hadoop 3.1.0 Source code repository https://github.com/apache/hadoop -r 16b70619a24cdcf5d3b0fcf4b58ca77238ccbe6d Compiled by centos on 2018-03-30T00:00Z Compiled with protoc 2.5.0 From source with checksum 14182d20c972b3e2105580a1ad6990 This command was run using /usr/local/Cellar/hadoop/3.1.0/libexec/share/hadoop/common/hadoop-common-3.1.0.jar # 常见异常:检查 JDK 版本是否过低 $ hadoop version Exception in thread "main" java.lang.UnsupportedClassVersionError: org/apache/hadoop/util/VersionInfo : Unsupported major.minor version 52.0 at java.lang.ClassLoader.defineClass1(Native Method)
Java Garbage Collection Types Serial GC (-XX:+UseSerialGC): Serial GC uses the simple mark-sweep-compact approach for young and old generations garbage collection i.e Minor and Major GC. Serial GC is useful in client-machines such as our simple stand alone applications and machines with smaller CPU. It is good for small applications with low memory footprint. Parallel GC (-XX:+UseParallelGC): Parallel GC is same as Serial GC except that is spawns N threads for young generation garbage collection where N is the number of CPU cores in the system. We can control the number of threads using -XX:ParallelGCThreads=n JVM option. Parallel Garbage Collector is also called throughput collector because it uses multiple CPUs to speed up the GC performance. Parallel GC uses single thread for Old Generation garbage collection. Parallel Old GC (-XX:+UseParallelOldGC): This is same as Parallel GC except that it uses multiple threads for both Young Generation and Old Generation garbage collection. Concurrent Mark Sweep (CMS) Collector (-XX:+UseConcMarkSweepGC): CMS Collector is also referred as concurrent low pause collector. It does the garbage collection for Old generation. CMS collector tries to minimize the pauses due to garbage collection by doing most of the garbage collection work concurrently with the application threads. CMS collector on young generation uses the same algorithm as that of the parallel collector. This garbage collector is suitable for responsive applications where we can’t afford longer pause times. We can limit the number of threads in CMS collector using -XX:ParallelCMSThreads=n JVM option. G1 Garbage Collector (-XX:+UseG1GC): The Garbage First or G1 garbage collector is available from Java 7 and it’s long term goal is to replace the CMS collector. The G1 collector is a parallel, concurrent, and incrementally compacting low-pause garbage collector. Garbage First Collector doesn’t work like other collectors and there is no concept of Young and Old generation space. It divides the heap space into multiple equal-sized heap regions. When a garbage collection is invoked, it first collects the region with lesser live data, hence “Garbage First”. You can find more details about it at Garbage-First Collector Oracle Documentation.
扩展阅读:电子书《Linux Perf Master》 https://riboseyim.gitbook.io/perf https://www.gitbook.com/book/riboseyim/linux-perf-master/details
扩展阅读:开源架构技术漫谈 开源架构技术漫谈:Hadoop 基于Kafka构建事件溯源型微服务 基于Go语言快速构建一个RESTful API服务 数据可视化(三)基于 Graphviz 实现程序化绘图 SDN 技术指南(一): 架构概览 SDN 技术指南(二): OpenFlow 浅谈基于数据分析的网络态势感知 网络数据包的捕获与分析(libpcap、BPF及gopacket) 计算机远程通信协议:从 CORBA 到 gRPC 基于LVS的AAA负载均衡架构实践 基于Ganglia实现服务集群性能态势感知 Stack Overflow:云计算平台的趋势分析 Stack Overflow:2017年最赚钱的编程语言 Stack Overflow: The Architecture & Hardware - 2016 Edition
大数据
2018-09-16 09:59:00