0%

Redis快速入门

Redis介绍

Redis是一个键值数据库,内存数据库,属于AP模型(CAP理论模型)

有四种模式可以部署

  • 单机模式
  • 主从模式
  • 哨兵模式
  • 集群模式

Redis内部使用自己设计的一种文本协议进行客户端与服务端之间的通信-RESP(基于TCP协议实现,采用请求/响应模型)

在集群模式下,Redis会对存储数据进行切片(利用哈希槽进行分片,Redis cluster划分了16384个槽,一个槽对应一个节点,存数据时会先算哈希值,具体来说就是在存取key时,Redis会使用CRC16算法得出一个结果,再对16384取余计算出槽位置)

Redis的优势

  • 基于内存
  • 单线程模型
  • 多路复用IO模型,就是多个线程的IO注册到同一个管道上,这个管道会统一和内核进行交互,当管道中的某一个请求需要的数据准备好之后,进程就把对应的数据拷贝到用户空间中。(分为三种:select、poll、epoll)
  • 高效的数据结构(基本数据结构和高级数据结构)
    • 字符串 String
    • 列表 List
    • 集合 Set
    • 有序集合 Zset
    • 哈希 Hash
    • 流 Stream
    • 位图 Bitmap
    • Geospatial
    • HyperLogLog
  • 多线程的引入(Redis6.0),只是接收网络通信使用了多线程,数据的读写操作还是使用的单线程

Redis安装(Ubuntu)

更新apt

1
2
sudo apt update
sudo apt upgrade

安装Redis

1
sudo apt install redis-server

查看Redis版本

1
redis-cli --version

查看运行状态

1
systemctl status redis

配置远程连接

1
2
3
4
5
sudo nano /etc/redis/redis.conf 
# #取消注释requirepass 启动密码认证,并设置访问密码
requirepass your-pass-word
# 以守护进程运行Redis
daemonize yes

ps:需要注意的是,Redis属于键值对数据库,然后键类型是支持所有二进制序列,但是一般都是使用字符串,空字符串也是一个有效的key值,值的类型就是五种基本数据类型加上高级数据类型

命令行操作

Redis默认为16个库

切换库

1
select db

删除库所有数据

1
flushdb

查看所有key

1
keys *

返回存在的key的数量

1
exists key [key...]

Redis可以给key设置过期时间expire &ttl

1
2
expire key 30
ttl key

返回key存储的value数据类型

1
type key

删除key

1
del key

字符串 String

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 设置
set key value
# 获取
get key
# 对数字类型加1
incr key
# 对数字类型减1
decr key
# 追加
append key value
# 获取value总长度
strlen key
# 截取value
getrange key start end
# 替换value
setrange key offset value
# 获取多个和设置多个
mset key1 value1 key2 value2
mget key1 key2

哈希 Hash,这里可以这么理解,就相当于创建一个哈希表,键key相当于表的名字,field和value表示哈希表的槽位和数据值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 新建
hset key field value
# 获取
hget key field
# 设置多个和获取多个
hmset key field1 value1 field2 value2
hmget key field1 field2
# 获取全部
hgetall key
# 删除 hdel
hdel key field
# 获取所有field域
hkeys key
# 获取所有值
hvals key
# 判断filed是否存在
hexists key field

列表 List

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# 添加 lpush 和rpush
lpush key value[value..]
rpush key value[value]
# 获取lrange, 负数表示倒数
lrange key start stop
# 获取指定index元素
lindex key index
# 获取列表长度 llen
llen key
# 按值移除元素 lrem
lrem key count value
# 修改某个值 lset
lset key index value
# 插入元素到指定值之前或之后 linsert
linsert key BEFORE|AFTER pivot value

集合Set

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# 添加 sadd
sadd key member
# 获取元素 smembers
smembers key
# 判断元素是否存在 sismember
sismember key member
# 获取集合元素个数 scard
scard key
# 删除集合key中的一个或多个元素 srem
srem key member
# 随机删除元素spop
spop key [count]
# 随机取元素 srandmember
srandmember key [count]

有序集合 Zset

1
2
3
4
5
6
7
8
9
10
# 添加zadd
zadd key score member [score member ..]
# 查询 zrange,WITHSCORES表示是否同时返回score和member
zrange key start stop [WITHSCORES]
# 区间查询 zrevrange,返回值按照score从大到小排序
zrevrange key start stop [WITHSCORES]
# 删除元素 zrem
zrem key member [member]
# 获取元素个数zcard
zcard key

Java操作Redis

工具:IDEA

安装依赖,使用jedis操作

1
2
3
4
5
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>

初始化对象

1
2
3
4
5
@Before
public void init() {
this.jedis = new Jedis("192.168.10.129", 6379);
jedis.auth("12345678");
}

然后就可以使用jedis对Redis进行操作了

字符串String

1
2
3
4
5
6
7
8
9
10
@Test
public void setKey() {
jedis.set("test", "test");
System.out.println(jedis.get("test"));
}

@Test
public void deleteKey() {
jedis.del("test");
}

列表List

1
2
3
4
5
6
7
8
9
10
11
@Test
public void testList() {
// 添加数据
List<String> temp = Arrays.asList("1", "2", "3");
Gson gson = new Gson();
String s = gson.toJson(temp);
jedis.rpush("testList", s);
jedis.lpush("testList", "sakura");
List<String> test = jedis.lrange("testList", 0, -1);
System.out.println(test);
}

集合Set

1
2
3
4
5
@Test
public void testSet() {
jedis.sadd("testSet", "1", "2", "2");
System.out.println(jedis.smembers("testSet"));
}

有序集合Zset

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Test
public void testZSet() {
HashMap<String, Double> scoreMap = new HashMap<String, Double>();
scoreMap.put("xiaoming", 70.0);
scoreMap.put("xiaowang", 100.0);
scoreMap.put("xiaohong", 88.0);
scoreMap.put("xiaoli", 60.0);
scoreMap.put("zhangsan", 58.0);
jedis.zadd("math", scoreMap);
// 查看scoreMap的形式
System.out.println("查看scoreMap的形式:" + scoreMap);
// 0 第0个元素,-1最后一个元素
System.out.println("返回math全部元素:" + jedis.zrange("math", 0, -1));
System.out.println("查看key有多少个元素:" + jedis.zcard("math"));
// 移除 xiaoli 这个元素
System.out.println("移除xiaoli 这个元素");
jedis.zrem("math", "xiaoli");
// -inf 负无穷 inf 正无穷,即从小到大排序
System.out.println("按照递增顺序,返回math全部的元素(含成绩):" + jedis.zrangeByScoreWithScores("math", "-inf", "inf"));
System.out.println("统计math集合,成绩在[80,100]之间的元素个数:" + jedis.zcount("math", 80, 100));
}

哈希Hash

1
2
3
4
5
@Test
public void testHash() {
jedis.hset("testHash", "testField", "testValue");
System.out.println(jedis.hget("testHash", "testField"));
}

完整的代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
package com.sakura.test;

import com.google.gson.Gson;
import com.nimbusds.jose.shaded.json.JSONUtil;
import org.junit.Before;
import org.junit.Test;
import redis.clients.jedis.Jedis;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

public class TestRedis {

public static Jedis jedis;

@Before
public void init() {
this.jedis = new Jedis("192.168.10.129", 6379);
jedis.auth("12345678");
}

@Test
public void setKey() {
jedis.set("test", "test");
System.out.println(jedis.get("test"));
}

@Test
public void deleteKey() {
jedis.del("test");
}

@Test
public void testList() {
// 添加数据
List<String> temp = Arrays.asList("1", "2", "3");
Gson gson = new Gson();
String s = gson.toJson(temp);
jedis.rpush("testList", s);
jedis.lpush("testList", "sakura");
List<String> test = jedis.lrange("testList", 0, -1);
System.out.println(test);
}

@Test
public void testSet() {
jedis.sadd("testSet", "1", "2", "2");
System.out.println(jedis.smembers("testSet"));
}

@Test
public void testZSet() {
HashMap<String, Double> scoreMap = new HashMap<String, Double>();
scoreMap.put("xiaoming", 70.0);
scoreMap.put("xiaowang", 100.0);
scoreMap.put("xiaohong", 88.0);
scoreMap.put("xiaoli", 60.0);
scoreMap.put("zhangsan", 58.0);
jedis.zadd("math", scoreMap);
// 查看scoreMap的形式
System.out.println("查看scoreMap的形式:" + scoreMap);
// 0 第0个元素,-1最后一个元素
System.out.println("返回math全部元素:" + jedis.zrange("math", 0, -1));
System.out.println("查看key有多少个元素:" + jedis.zcard("math"));
// 移除 xiaoli 这个元素
System.out.println("移除xiaoli 这个元素");
jedis.zrem("math", "xiaoli");
// -inf 负无穷 inf 正无穷,即从小到大排序
System.out.println("按照递增顺序,返回math全部的元素(含成绩):" + jedis.zrangeByScoreWithScores("math", "-inf", "inf"));
System.out.println("统计math集合,成绩在[80,100]之间的元素个数:" + jedis.zcount("math", 80, 100));
}

@Test
public void testHash() {
jedis.hset("testHash", "testField", "testValue");
System.out.println(jedis.hget("testHash", "testField"));
}


}

MongoDB快速入门

MongoDB安装(Ubuntu)apt模式安装

1
sudo apt-get install gnupg curl
1
2
3
curl -fsSL https://www.mongodb.org/static/pgp/server-7.0.asc | 
sudo gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg
--dearmor
1
echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.org/apt/ubuntu jammy/mongodb-org/7.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
1
sudo apt-get update
1
sudo apt-get install -y mongodb-org
1
mongod -version
1
2
# 开启mongd
sudo systemctl start mongod
1
2
# 查看mongodb状态 active表示正在运行
sudo systemctl status mongod
1
2
# 设置mongodb可以开机自启动
sudo systemctl enable mongod

停止

1
sudo systemctl stop mongod

重启

1
sudo systemctl restart mongod

为了让外网可以访问到MongoDB,需要修改对应的配置文件

1
2
sudo vim /etc/mongod.conf
# 把bindIP的值修改为0.0.0.0

需要注意的是,这样子的设置会导致非常不安全,如果只是为了学习当然无所谓,不过一般还是建议设置一下密码,(这一步可选)

先在配置文件启动鉴权模式

然后使用mongosh进入命令行模式

然后给对应的数据库创建用户(我这里统一用户名就是root,密码就是sql2008)

1
2
use test
db.createUser({user:"root",pwd:"sql2008",roles:[{role:"readWrite",db:"test"}]})

基本操作方法

在进行实际操作之前,我们需要先了解一下MongoDB的基础数据模型是怎么样的

最基础的部分主要包括:

  • 数据库 database或者db
  • 集合collection(也可以叫做表)
  • 集合的一条记录 document
  • 记录当中的字段 field

可以简单的理解为一个JSON数组,MongoDB存储主要是采用了Bson(Binary JSON)的形式存储

image-20240417143053001

命令行模式

切换到数据库,如果没有则会新建

1
use test

需要注意的是,如果开启了权限校验,就需要先登录(如果没有开启则可以跳过这一步)

1
db.auth("root","sql2008")

默认情况下数据库当中没有任何集合,我们新建一个集合

1
2
show collections
db.createCollection("teacher")

然后在对这个集合插入一条数据或多条

1
2
db.teacher.insertOne({"name":"sakura"})
db.teacher.insertMany([{"name":"sakura"},{"name":"test"}])

查看集合数据

1
db.teacher.find()

需要注意的是MongoDB里面也有主键的概念,就是它默认会给你添加一个”_id”字段,然后生成一个唯一标识符,但是如果在插入时手动的指定了”__id”的值,就必须保证这个值是唯一的不然插入就会失败

更新数据,MongoDB的更新操作可以支持多种形式的更新,比如只更新第一条匹配到的记录,或者更新所有匹配到的记录、如果不存在就当新记录插入集合等,具体实现可以通过参数实现

1
db.teacher.updateOne({"name":"sakura0"},{$set:{"age":10}})

删除 deleteOne、deleteMany(与插入类似)

1
db.teacher.deleteOne({"name":"sakura"})

还有就是删除整个集合

1
dp.teacher.drop()

删除整个数据库

1
db.dropDatabase()

需要注意的是,这里的drop删除,更加准确的理解应该是清除,它只是把记录和数据全都删除了,但是删除对象的本身还是存在的,比如drop删除整个集合,集合里面一条记录都没有了,但这个集合本身还是存在的。

编程模式,以Java为例

开发工具:idea(推荐)

如果不会有idea的话,建议看一下下面这篇文章,快速入门

https://zhuanlan.zhihu.com/p/469563500

首先需要强调的是,MongoDB一定要先保证外网可以访问

为了让外网可以访问到MongoDB,需要修改对应的配置文件

1
2
sudo vim /etc/mongod.conf
# 把bindIP的值修改为0.0.0.0

然后就是新建一个maven项目,导入对应的依赖,

tips:一般maven依赖都可以去中央仓库搜索:https://mvnrepository.com/

1
2
3
4
5
<dependency>
<groupId>org.mongodb</groupId>
<artifactId>mongo-java-driver</artifactId>
<version>3.12.10</version>
</dependency>

这种类型的第三方依赖一般都是会提供给你一个客户端对象,让你可以去操作MongoDB

所以我们要做的就是把配置换成自己的,初始化一个自己的客户端对象,然后进行后续操作

第一步:

初始化客户端对象,这里我写了一个工具类用于统一的管理

为了方便管理对应的数据库配置(比如数据库的IP地址、用户名和密码,要访问的数据库),我这里将其统一写到了配置文件当中,具体做法就是在src/main路径下新建一个resources资源目录,然后新建一个配置文件mongofb.properties

1
2
3
4
5
host=192.168.10.129
port=27017
dbname=test
password=sql2008
username=root

然后读取该配置文件初始化对应的客户端对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public class MongoUtils {
private static Properties properties;
private static MongoDatabase mongoDatabase;
private static InputStream stream;
private static String host;
private static int port;
private static String dbname;
private static String password;
private static String username;

//创建一个静态代码块,用于初始化工具类的静态变量,该静态代码块在类加载过程中的初始化阶段执行,并且只执行一次
static {
//判断properties集合对象是否为空,为空则创建一个集合对象
if (properties == null) {
properties = new Properties();
}
/*
* 由于我们会调用load方法,而load方法低层抛出了一个IOException异常,此异常为编译时期异常所以,
* 我们调用load方法时,需要处理低层抛过来的异常*/
try {
//创建一个InputStream字节输入流对象,用于接收mongodb.properties配置文件中的配置参数
stream = MongoUtils.class.getClassLoader().getResourceAsStream("mongodb.properties");
//properties集合对象调用load()方法,将配置参数加载到properties集合中
properties.load(stream);
} catch (IOException e) {
throw new RuntimeException(e);
}
//根据mongodb.properties配置文件中的key,获取value值
host = properties.getProperty("host");
port = Integer.parseInt(properties.getProperty("port"));
dbname = properties.getProperty("dbname");
password = properties.getProperty("password");
username = properties.getProperty("username");
}

//定义一个getMongoClient()方法,用于获取MOngoDB数据库的连接对象
public static MongoClient getMongoClient() {
String addr = "mongodb://" + username + ":" + password + "@" + host + ":" + port;
MongoClient mongoClient = MongoClients.create(addr);
return mongoClient;
}
public static MongoDatabase getMongoDao() {
String addr = "mongodb://" + username + ":" + password + "@" + host + ":" + port;
MongoClient mongoClient = MongoClients.create(addr);
return mongoClient.getDatabase(dbname);
}
}

然后就是针对基础的API进行使用,在下面我只列出了最基础的实现,增删改查的基础实现,如果有更精细化的要求,建议阅读官方文档:

https://mongodb.github.io/mongo-java-driver/3.0/driver/getting-started/quick-tour/

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
public class TestMongoDB {
private static MongoDatabase mongoDao;
private static MongoClient mongoClient;

@Before
public void init() {
mongoDao = MongoUtils.getMongoDao();
mongoClient = MongoUtils.getMongoClient();
}


/**
* 查看数据库
*/
@Test
public void showDBs() {
MongoIterable<String> strings = mongoClient.listDatabaseNames();
for (String string : strings) {
System.out.println(string);
}
}

/**
* 查看所有集合
*/
@Test
public void listCollections() {
ListCollectionsIterable<Document> documents = mongoDao.listCollections();
for (Document document : documents) {
System.out.println(document);
}
}

/**
* 创建集合
*/
@Test
public void createCollection() {
mongoDao.createCollection("test_collection");
}

/**
* 插入数据到集合
*/
@Test
public void insertOne() {
MongoCollection<Document> test = mongoDao.getCollection("test");
Document one = new Document();
one.put("name", "sakura");
one.put("age", 18);
test.insertOne(one);
}

/**
* 删除
*/
@Test
public void deleteOne() {
MongoCollection<Document> test = mongoDao.getCollection("test");
test.deleteOne(Filters.eq("name", "sakura"));
// 删除所有符合匹配条件的数据
// test.deleteMany(Filters.eq("name", "sakura"));
}

/**
* 修改记录document
*/
@Test
public void update() {
MongoCollection<Document> test = mongoDao.getCollection("test");
test.updateOne(Filters.eq("name", "sakura")
, new Document("$set", new Document("age", 20)));
}

@Test
public void listDocument() {
MongoCollection<Document> test = mongoDao.getCollection("test");
FindIterable<Document> documents = test.find();
for (Document document : documents) {
System.out.println(document);
}
}

}

下载HBASE到/usr/local

1
2
cd /usr/local
wget https://mirrors.tuna.tsinghua.edu.cn/apache/hbase/2.4.17/hbase-2.4.17-bin.tar.gz

解压

1
tar -zxvf hbase-2.x.x-bin.tar.gz

单机配置

修改/usr/local/hbase/conf/hbase-env.sh 添加以下内容

1
2
3
export JAVA_HOME=/usr/lib/jvm/jdk1.8.0_241 # 对应的java路径

export HBASE_MANAGES_ZK=true

编辑完成后使用source使修改生效

1
source hbase-env.sh

编辑/etc/profile

1
2
cd ~
sudo vim /etc/profile

添加以下内容

1
2
export HBASE_HOME=/usr/local/hbase    
export PATH=$PATH:$HBASE_HOME/sbin:$HBASE_HOME/bin

使用source命令生效

1
source /etc/profile

修改/usr/local/hbase/conf/hbase-site.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
<configuration>

<property>

<name>hbase.cluster.distributed</name>

<value>false</value>

</property>

<property>

<name>hbase.tmp.dir</name>

<value>./tmp</value>

</property>

<property>

<name>hbase.unsafe.stream.capability.enforce</name>

<value>false</value>

</property>

<property>

<name>hbase.rootdir</name>

<value>hdfs://192.168.10.129:9000/hbase</value>

</property>

</configuration>

伪分布式配置

修改hbase-env.sh,添加以下内容

1
2
3
4
5
export JAVA_HOME=/usr/lib/jvm/jdk1.8.0_241

export HBASE_CLASSPATH=/usr/local/hbase/conf

export HBASE_MANAGES_ZK=true

编辑完成后使用source使修改生效

1
source hbase-env.sh

修改hbase的配置文件hbase-site.xml

1
2
3
cd /usr/local/hbase/conf

vim hbase-site.xml

添加以下内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
<configuration>

<property>

<name>hbase.cluster.distributed</name>

<value>true</value>

</property>

<property>

<name>hbase.tmp.dir</name>

<value>./tmp</value>

</property>

<property>

<name>hbase.unsafe.stream.capability.enforce</name>

<value>false</value>

</property>

<property>

<name>hbase.rootdir</name>

<value>hdfs://192.168.10.129:9000/hbase</value>

</property>

<property>

<name>hbase.zookeeper.quorum</name> <!-- 表示使用hbase自带的zookeeper -->

<value>192.168.10.129</value>

</property>

<property>

<name>hbase.zookeeper.property.clientPort</name> <!-- zookeeper的端口号 -->

<value>2181</value>

</property>

<property>

<name>hbase.zookeeper.property.dataDir</name> <!-- zookeeper的data保存目录 -->

<value>/usr/local/hbase/zookeeper_data</value>

</property>

</configuration>

即可启动进行测试

先启动hadoop

1
/usr/local/hadoop/sbin/start-dfs.sh

再启动hbase

1
/usr/local/hbase/bin/start-hbase.sh

再输入jps查看进程数,HMaster,HRegionServer,HQuorumPeer即代表Hbase的服务节点

img

此时查看HDFS可以看到有一个hbase文件夹用于存储hbase的数据

img

注意:操作 Hadoop和 HBase的执行顺序是:启动Hadoop—>启动HBase—>关闭HBase—>关闭Hadoop。

同时,hbase还提供了web管理页面

访问IP:16010端口

img

完全分布式式安装

参考文章如下所示:

Centos7下HBase安装与配置(亲测!)_centos按照hbase1.2.0-CSDN博客

Centos下ZooKeeper安装部署配置(集群模式)_grep: /opt/zookeeper/apache-zookeeper-3.8.3-bin/bi-CSDN博客

首先需要在三台机器上安装zookeeper

下载安装包

修改权限

1
chmod u+x zookeeper-3.4.13.tar.gz

解压压缩包

1
tar -zxvf zookeeper-3.4.13.tar.gz

创建软链接

1
ln -s zookeeper-3.4.13 zookeeper

修改配置文件

需要注意的是,要先重命名配置文件,配置文件一般位于zookeeper的conf目录下

1
mv zoo_sample.cfg  zoo.cfg

然后需要创建目录,在zookeeper目录下创建 /tmp/data

然后创建文件myid

输入数字1,然后保存退出(注意,这里的1相当于服务的标识符,每个服务有一个唯一的服务ID)

修改zoo.cfg

1
vim zoo.cfg
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#The number of milliseconds of each tick

tickTime=2000

#The number of ticks that the initial

#synchronization phase can take

initLimit=5

#The number of ticks that can pass between

#sending a request and getting an acknowledgement

syncLimit=2

#the directory where the snapshot is stored.

#do not use /tmp for storage, /tmp here is just

#example sakes.

#**这个地方填写自己的路径**

dataDir=/opt/Hadoop/zookeeper/tmp/data

#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

#服务器名称与地址:集群信息(服务器编号、服务器编号、服务器地址、LF通信端口、选举端口)

server.1=node1:2888:3888

server.2=node2:2888:3888

server.3=node3:2888:3888

然后就是分发文件,把一台主机上的配置分发到其他主机上,使用脚本xsync

然后把myid文件修改一下,比如第二台机器就修改为2,以此类推

然后就是启动zookeeper

1
zkServer.sh start

安装完zookeeper以后就可以开始安装hbase了

上传安装包

修改权限

1
chmod u+x hbase-1.2.0-cdh5.9.3.tar.gz

解压

1
tar -zxvf hbase-1.2.0-cdh5.9.3.tar.gz

建立软链接

1
ln -s hbase-1.2.0-cdh5.9.3 hbase

配置环境变量

1
vim ~/.bashrc
1
2
3
export HBASE_HOME=/opt/Hadoop/hbase

export PATH=$HBASE_HOME/bin:$PATH

然后退出,执行

1
source ~/.bashrc

修改配置文件,配置文件一般位于hbase的conf目录下

1
vim hbase-env.sh
1
2
3
export JAVA_HOME=/opt/Hadoop/jdk1.8.0_162 # 改成自己的jdk路径

export HBASE_MANAGES_ZK=false

然后在hbase目录下创建存放zookeeper数据的文件

1
mkdir zookeeper-data

修改配置文件

1
vim hbase-site.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
<configuration>

<!-- Hbase的数据保存在HDFS对应的目录下 -->

<property>

<name>hbase.rootdir</name>
<value>hdfs://node1:8020/hbase</value>

</property>



<!-- 是否是分布式环境 -->

<property>

<name>hbase.cluster.distributed</name>

<value>true</value>

</property>



<!-- 配置ZK的地址,3个节点都启用Zookeeper -->

<property>

<name>hbase.zookeeper.quorum</name>

<value>node1,node2,node3</value>

</property>



<!-- 冗余度 -->

<property>

<name>dfs.replication</name>

<value>2</value>

</property>



<!-- 主节点和从节点允许的最大时间误差 -->

<property>

<name>hbase.master.maxclockskew</name>

<value>180000</value>

</property>



<!-- zookeeper数据目录 -->

<property>

<name>hbase.zookeeper.property.dataDir</name>

<value>/opt/Hadoop/hbase/zookeeper-data</value>

</property>

<!-- 设置网页端口号 -->

<property>

<name>hbase.master.info.port</name>

<value>60010</value>

</property>

</configuration>

再修改regionservers,改成自己的

1
vim regionservers

然后就是使用脚本进行分发

启动三台机器

1
start-hbase.sh

img

Bug提醒

在启动HBASE时可能会报错

1
SLF4J: Class path contains multiple SLF4J bindings.等等

只需要把hadoop或者HBASE目录结构中其中一个日志的jar包删除掉即可,具体位置需要看报错信息

需要注意的是,删除HBASE目录下的slf4j-reloadxxxx以后,建议是把hadoop目录下同名的jar包复制过来,不然后面还会有其他报错

同时建议修改hbase-env.sh

新增

1
export Hbase_Disable_Hadoop_CLASSPATH_LOOKUP=true

Hadoop 安全模式,如果开启了hadoop的安全模式会导致HBASE的命令失效报错

可以使用下述命令查看是否启动安全模式

1
hadoop dfsadmin -safemode get

如果启动了可以使用下述命令关闭

1
hadoop dfsadmin -safemode leave

如果一直无法关闭HBASE,可以使用下述命令

1
2
3
hbase-daemon.sh stop master

stop-hbase.sh

如果没用的话可以先关闭HDFS

一切正常以后就可以进行正常使用,比如命令行的方式使用

使用 hbase shell 进入命令行进行操作

list 查看当前所有的表

img

进行建表的时候也可能会报错

比如:ERROR: org.apache.hadoop.hbase.PleaseHoldException: Master is initializing

解决方法:删除HDFS下的HBASE目录以及zookeeper下的hbase目录

1
hdfs dfs -rm -r /hbase

如果使用的是外置的zookeeper的话,直接使用客户端进入zookeeper删除即可,如果是伪分布式,使用自带的zookeeper的话,就要去配置文件设置的存储文件夹寻找

删除完后正常使用建表语句

1
create ‘student’,’info’

img

插入一条记录

1
put ‘student’,’1001’,’info’,’male’

img

查看表记录scan ‘student’

img

命令行操作:

List:查看所有表

img

创建表

img

插入数据:

img

删除数据

img

删除表 drop 表名,要先禁用

img

Java操作:

加载对应的依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
<dependencies>

<!-- https://mvnrepository.com/artifact/org.apache.hbase/hbase-client -->

<dependency>

<groupId>org.apache.hbase</groupId>

<artifactId>hbase-client</artifactId>

<version>2.4.8</version>

</dependency>

<!-- https://mvnrepository.com/artifact/org.apache.hbase/hbase -->

<dependency>

<groupId>org.apache.hbase</groupId>

<artifactId>hbase</artifactId>

<version>2.4.8</version>

<type>pom</type>

</dependency>

</dependencies>

初始化连接配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
static {

//HBase Master地址,在hbase-site.xml中配置

conf.set("hbase.rootdir", "hdfs://hadoop102:8020/hbase");

//ZooKeeper三个服务器地址

conf.set("hbase.zookeeper.quorum", "hadoop102,hadoop103,hadoop104");



try {
connection = ConnectionFactory.createConnection(conf);

admin = connection.getAdmin();

} catch (IOException e) {

e.printStackTrace();

}

}

测试建表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public void createTable(String tableName) throws IOException {



//通过管理员对象创建表

HTableDescriptor hTableDescriptor = new HTableDescriptor(TableName.valueOf(tableName));

//给表添加列族

HColumnDescriptor f1 = new HColumnDescriptor("f1");

HColumnDescriptor f2 = new HColumnDescriptor("f2");

//将两个列族设置到 创建的表中


hTableDescriptor.addFamily(f2);

//创建表

admin.createTable(hTableDescriptor);
//关闭连接

admin.close();

connection.close();

System.out.println("创建表成功");

}

插入数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public void addData(String tableName) throws IOException {



//获取表对象

Table myuser = connection.getTable(TableName.valueOf(tableName));
Put put = new Put("0001".getBytes());

put.addColumn("f1".getBytes(), "id".getBytes(), Bytes.toBytes(1));

put.addColumn("f1".getBytes(), "name".getBytes(), Bytes.toBytes("小明"));

put.addColumn("f1".getBytes(), "age".getBytes(), Bytes.toBytes(22));

put.addColumn("f2".getBytes(), "sex".getBytes(), Bytes.toBytes("男"));

put.addColumn("f2".getBytes(), "address".getBytes(), Bytes.toBytes("青岛"));

put.addColumn("f2".getBytes(), "phone".getBytes(), Bytes.toBytes("15900000001"));
put.addColumn("f2".getBytes(), "say".getBytes(), Bytes.toBytes("你好"));

myuser.put(put);

//关闭表

myuser.close();

System.out.println("插入数据成功");

}

查看数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
public void scanAllData(String tableName) throws IOException {



//获取表对象

Table myuser = connection.getTable(TableName.valueOf(tableName));

Scan scan = new Scan();

//设置起始和结束的rowkey,扫描结果是:[)类型

scan.setStartRow("0001".getBytes());

scan.setStopRow("0008".getBytes());

ResultScanner scanner = myuser.getScanner(scan);

for (Result result : scanner) {

List<Cell> cells = result.listCells();

for (Cell cell : cells) {

String rowkey = Bytes.toString(cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());

//获取列族的名称

String familyName = Bytes.toString(cell.getFamilyArray(), cell.getFamilyOffset(), cell.getFamilyLength());

//获取列的名称

String columnName = Bytes.toString(cell.getQualifierArray(), cell.getQualifierOffset(), cell.getQualifierLength());

if (familyName.equals("f1") && columnName.equals("id") || columnName.equals("age")) {

int value = Bytes.toInt(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());

System.out.println("列族名: " + familyName + " ,列名: " + columnName + " ,列值:" + value);

} else {

String value = Bytes.toString(cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());

System.out.println("列族名: " + familyName + " ,列名: " + columnName + " ,列值:" + value);

}

}

}

//获取返回结果

myuser.close();

}

结果如下所示

img

安装ifconfig

1
sudo apt install net-tools -y
1
sudo apt install net-tools -y

安装vim:

1
sudo apt-get install vim-gtk

设置静态IP

查看ip地址,子网掩码,网关地址

ifconfig

route -n

设置root权限密码

1
sudo passwd root

新增用户

1
sudo useradd -m hadoop -s /bin/bash

设置密码:

1
sudo passwd hadoop

添加sudo权限

1
sudo adduser hadoop sudo

安装java8

更新apt

1
2
3
sudo apt-get update

sudo apt-get install openjdk-8-jdk

配置环境变量

1
Vim  ~/.bashrc

让配置生效

1
source ~/.bashrc

下载hadoop,使用wget下载

Wget https://mirrors.tuna.tsinghua.edu.cn/apache/hadoop/common/stable/hadoop-3.3.6.tar.gz

然后解压

1
Tar -zxvf hadoop-3.3.6.tar.gz -C /usr/local

修改文件操作权限

1
sudo chown -R hadoop ./hadoop

查看hadoop版本号

img

通过一个案例测试hadoop(查询符合条件的单词个数,结果保留到output文件夹)

1
2
3
hadoop jar ./share/hadoop/mapreduce/hadoop-mapreduce-examples-*.jar grep ./input ./output 'dfs[a-z.]+'


创建一个input文件夹

1
Mkdir input

复制一些文件到input中,然后运行示例,结果保存在output文件夹当中

img

实现伪分布式需要修改的配置文件

1
sudo vim ./etc/hadoop/core-site.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<property>

<name>hadoop.tmp.dir</name>

<value>file:/usr/local/hadoop/tmp</value>

<description>Abase for other

temporary directories.</description>

</property>

<property>

<name>fs.defaultFS</name>

<value>hdfs://localhost:9000</value>

</property>
1
sudo vim ./etc/hadoop/hdfs-site.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<property>

<name>dfs.replication</name>

<value>1</value>

</property>

<property>

<name>dfs.namenode.name.dir</name>

<value>file:/usr/local/hadoop/tmp/dfs/name</value>

</property>

<property>

<name>dfs.datanode.data.dir</name>

<value>file:/usr/local/hadoop/tmp/dfs/data</value>

</property>

启动hdfs的namenode和守护进程

1
2
3
./bin/hdfs namenode -format

./sbin/start-dfs.sh

通过jps命令查看是否启动成功

img

Bug记录:有的时候会无法启动成功,比如jps命令只显示了jps进程

这里记录一下我的解决方案:

首先查看前面的配置文件是否配置成功

检查ssh是否配置成功

方式:ssh localhost

如果还需要输入密码才能登录就代表ssh没有配置成功

解决方案:我是因为密钥的问题而导致的,所以只需要重新生成密钥并保存到指定为止即可解决

1
2
3
ssh-keygen -t rsa -P '' -f ~/.ssh/id_rsa

cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys

还有可能会遇到localhost: Error: JAVA_HOME is not set and could not be found.这种报错

但是Java -version又是正常的情况

这个需要修改hadoop下的一个配置文件来解决

1
sudo vim/usr/local/hadoop/etc/hadoop/hadoop-env.sh

把自己的Java安装路径放进去

1
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64

完成以后就可以在浏览器看到以下界面

img

关闭就是运行sbin目录下的停止脚本

img

环境准备

  • 三台虚拟机(Centos7.6)
  • 固定IP地址
    • hadoop101 192.168.10.101
    • hadoop102 192.168.10.102
    • hadoop103 192.168.10.103

环境搭建

关闭防火墙并关闭自启动

1
2
systemctl stop firewalld
systemctl disable firewalld.service

创建hadoop用户

1
2
useradd hadoop
passwd hadoop

配置hadoop拥有root权限

1
vim /etc/sudoers
1
2
3
4
5
6
## Allow root to run any commands anywhere
root ALL=(ALL) ALL

## Allows people in group wheel to run all commands
%wheel ALL=(ALL) ALL
hadoop ALL=(ALL) NOPASSWD:ALL

在/opt目录下新建module目录和software目录

1
2
mkdir /opt/module
mkdir /opt/software

修改module文件夹和software文件夹的所有者和所属组

1
2
chown hadoop:hadoop /opt/module
chown hadoop:hadoop /opt/software

卸载虚拟机自带的jdk

1
rpm -qa | grep -i java | xargs -n1 rpm -e --nodeps 

重启虚拟机

设置静态IP地址(网关等信息从虚拟机的网络设置中查看)

1
vim /etc/sysconfig/network-scripts/ifcfg-ens33
1
2
3
4
5
6
7
8
9
DEVICE=ens33
TYPE=Ethernet
ONBOOT=yes
BOOTPROTO=static
NAME="ens33"
IPADDR=192.168.10.102
PREFIX=24
GATEWAY=192.168.10.101
DNS1=192.168.10.2

修改主机名称

1
vim /etc/hostname

修改hosts文件

1
vim /etc/hosts

添加对应的域名解析

1
2
3
192.168.10.101 hadoop101
192.168.10.102 hadoop102
192.168.10.103 hadoop103

同理,把三台虚拟机的IP地址和主机名都设置好

修改Windows系统C:\Windows\System32\drivers\etc下的hosts文件,添加对应的dns信息

1
2
3
192.168.10.101 hadoop101
192.168.10.102 hadoop102
192.168.10.103 hadoop103

把jdk上传到/opt/software目录下,然后解压

1
tar -zxvf jdk-8u212-linux-x64.tar.gz -C /opt/module/

配置jdk环境变量

新建/etc/profile.d/my_env.sh文件

1
sudo vim /etc/profile.d/my_env.sh

添加以下内容

1
2
3
#JAVA_HOME
export JAVA_HOME=/opt/module/jdk1.8.0_212
export PATH=$PATH:$JAVA_HOME/bin

使用source让配置生效

1
source /etc/profile

测试是否安装成功

1
java -version

hadoop下载路径:https://archive.apache.org/dist/hadoop/common/hadoop-3.1.3/

上传到/opt/software目录下,然后解压到module目录下

1
tar -zxvf hadoop-3.1.3.tar.gz -C /opt/module/

添加环境变量

1
sudo vim /etc/profile.d/my_env.sh
1
2
3
4
#HADOOP_HOME
export HADOOP_HOME=/opt/module/hadoop-3.1.3
export PATH=$PATH:$HADOOP_HOME/bin
export PATH=$PATH:$HADOOP_HOME/sbin

让配置生效

1
source /etc/profile

测试是否安装成功

1
hadoop version

为了方便管理三台虚拟机,编写分发脚本xsync

在/home/hadoop/bin 目录下新建xsync文件

1
2
3
4
cd /home/hadoop
mkdir bin
cd bin
vim xsync

编写脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/bin/bash

#1. 判断参数个数
if [ $# -lt 1 ]
then
echo Not Enough Arguement!
exit;
fi

#2. 遍历集群所有机器
for host in hadoop101 hadoop102 hadoop103
do
echo ==================== $host ====================
#3. 遍历所有目录,挨个发送

for file in $@
do
#4. 判断文件是否存在
if [ -e $file ]
then
#5. 获取父目录
pdir=$(cd -P $(dirname $file); pwd)

#6. 获取当前文件的名称
fname=$(basename $file)
ssh $host "mkdir -p $pdir"
rsync -av $pdir/$fname $host:$pdir
else
echo $file does not exists!
fi
done
done

修改权限

1
chmod +x xsync

配置ssh免密登录

生成密钥

1
ssh-keygen -t rsa

然后一直敲回车

复制密钥

1
2
3
ssh-copy-id hadoop101
ssh-copy-id hadoop102
ssh-copy-id hadoop103

配置hadoop的文件

配置core-site.xml

1
2
cd $HADOOP_HOME/etc/hadoop
vim core-site.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>

<configuration>
<!-- 指定NameNode的地址 -->
<property>
<name>fs.defaultFS</name>
<value>hdfs://hadoop101:8020</value>
</property>

<!-- 指定hadoop数据的存储目录 -->
<property>
<name>hadoop.tmp.dir</name>
<value>/opt/module/hadoop-3.1.3/data</value>
</property>

<!-- 配置HDFS网页登录使用的静态用户为hadoop -->
<property>
<name>hadoop.http.staticuser.user</name>
<value>hadoop</value>
</property>
</configuration>

配置hdfs-site.xml

1
vim hdfs-site.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>

<configuration>
<!-- nn web端访问地址-->
<property>
<name>dfs.namenode.http-address</name>
<value>hadoop101:9870</value>
</property>
<!-- 2nn web端访问地址-->
<property>
<name>dfs.namenode.secondary.http-address</name>
<value>hadoop103:9868</value>
</property>
</configuration>

配置yarn-site.xml

1
vim yarn-site.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>

<configuration>
<!-- 指定MR走shuffle -->
<property>
<name>yarn.nodemanager.aux-services</name>
<value>mapreduce_shuffle</value>
</property>

<!-- 指定ResourceManager的地址-->
<property>
<name>yarn.resourcemanager.hostname</name>
<value>hadoop102</value>
</property>

<!-- 环境变量的继承 -->
<property>
<name>yarn.nodemanager.env-whitelist</name>
<value>JAVA_HOME,HADOOP_COMMON_HOME,HADOOP_HDFS_HOME,HADOOP_CONF_DIR,CLASSPATH_PREPEND_DISTCACHE,HADOOP_YARN_HOME,HADOOP_MAPRED_HOME</value>
</property>
</configuration>

配置mapred-site.xml

1
vim mapred-site.xml
1
2
3
4
5
6
7
8
9
10
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>

<configuration>
<!-- 指定MapReduce程序运行在Yarn上 -->
<property>
<name>mapreduce.framework.name</name>
<value>yarn</value>
</property>
</configuration>

然后分发配置文件

1
xsync /opt/module/hadoop-3.1.3/etc/hadoop/

三台主机都查看一下配置文件是否正确修改

配置workers

1
vim /opt/module/hadoop-3.1.3/etc/hadoop/workers

新增

1
2
3
hadoop101
hadoop102
hadoop103

然后同步所有主机

1
xsync /opt/module/hadoop-3.1.3/etc

第一次启动需要先格式化hdfs

1
hdfs namenode -format

然后启动hdfs

1
sbin/start-dfs.sh

hadoop102启动yarn

1
sbin/start-yarn.sh

浏览器输入http://hadoop101:9870查看hdfs的NameNode

http://hadoop102:8088 查看yarn

启动/关闭集群

1
2
start-dfs.sh/stop-dfs.sh
start-yarn.sh/stop-yarn.sh

为了方便启动和关闭集群,编写脚本

1
2
cd /home/hadoop/bin
vim myhadoop.sh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#!/bin/bash

if [ $# -lt 1 ]
then
echo "No Args Input..."
exit ;
fi

case $1 in
"start")
echo " =================== 启动 hadoop集群 ==================="

echo " --------------- 启动 hdfs ---------------"
ssh hadoop101 "/opt/module/hadoop-3.1.3/sbin/start-dfs.sh"
echo " --------------- 启动 yarn ---------------"
ssh hadoop102 "/opt/module/hadoop-3.1.3/sbin/start-yarn.sh"
echo " --------------- 启动 historyserver ---------------"
ssh hadoop101 "/opt/module/hadoop-3.1.3/bin/mapred --daemon start historyserver"
;;
"stop")
echo " =================== 关闭 hadoop集群 ==================="

echo " --------------- 关闭 historyserver ---------------"
ssh hadoop101 "/opt/module/hadoop-3.1.3/bin/mapred --daemon stop historyserver"
echo " --------------- 关闭 yarn ---------------"
ssh hadoop102 "/opt/module/hadoop-3.1.3/sbin/stop-yarn.sh"
echo " --------------- 关闭 hdfs ---------------"
ssh hadoop101 "/opt/module/hadoop-3.1.3/sbin/stop-dfs.sh"
;;
*)
echo "Input Args Error..."
;;
esac

修改权限

1
chmod +x myhadoop.sh

同理编写查看集群进程的脚本

1
2
cd /home/hadoop/bin
vim jpsall
1
2
3
4
5
6
7
#!/bin/bash

for host in hadoop101 hadoop102 hadoop103
do
echo =============== $host ===============
ssh $host jps
done

Linux学习笔记

三种网络连接方式:

- 桥接模式:同一个网段建立连接,容易产生IP冲突
- NAT模式:网络地址转换,生成虚拟的网络地址,通过代理地址访问外网
- 主机模式:独立的系统,不与外界发生联系

安装vmtool,可以创建Windows和Linux共享文件夹

Linux的文件结构

​ Linux中,一切皆是文件,Linux文件系统是采用级层式的树状目录结构,在此结构中的最上层是根目录”/“,然后在此目录下再创建其他的目录。

  • /bin [常用] 是Binary的缩写,这个目录存放着最经常使用的命令

  • /sbin s就是Super User的意思,这里存放的是系统管理员使用的系统管理程序

  • /home [常用] 存放普通用户的主目录,在Linux中每个用户都有一个自己的目录,一般该目录名是以用户的账号命名

  • /root [常用] 该目录为系统管理员,也称作超级权限者的用户主目录

  • /lib 系统开机所需要最基本的动态连接共享池,其作用类似于windows里的DLL文件,几乎所有的应用程序都需要用到这些共享库

  • /lost+found 一般为空,当系统非法关机后,这里就存放了一些文件

  • /etc [常用] 所有的系统管理所需要的配置文件和子目录 ,比如安装mysql数据库 my.conf

  • /usr [常用] 十分重要的目录,用户的很多应用程序和文件都放在这个目录下,类似与windows下的program files目录

  • /boot [常用] 存放的是启动Linux时使用的一些核心文件,包括一些连接文件以及镜像文件

  • /prov [不能动] 这个目录是一个虚拟的目录,它是系统内存的映射,访问这个目录来获取系统信息

  • /srv [不能动] service的缩写,该目录存放一些服务启动之后需要提取的数据

  • /sys [不能动] 这是Linux2.6内核的一个很大的变化,该目录下安装了2.6内核中新出现的一个文件系统sysfs

  • /tmp 这个目录是用来存放一些临时文件的

  • /dev 类似于windows的设备管理器,把所有的硬件用文件的形式存储

  • /media [常用] Linux系统会自动识别一些设备,例如U盘,光驱等等,当识别后,Linux会把识别的设备挂载到这个目录下

  • /mnt [常用] 系统提供该目录是为了让用户临时挂载别的文件系统的,我们可以将外部的存储挂载在/mnt上,然后进入该目录就可以查看里的内容了

  • /opt 这是给主机额外安装软件所摆放的目录.如安装ORACLE数据库就可以放到该目录下.默认为空

  • /usr/local [常用] 这是另一个给主机额外安装软件所安装的目录,一般是通过编译源码方式安装的程序

  • /var [常用] 这个目录中存放着在不断扩充着的东西,习惯将经常被修改的目录放在这个目录下.包括各种日志文件

  • /selinux [security-enhanced linux] SELinux是一种安全子系统,它能控制程序只能访问特定文件,有三种工作模式,可以自行设置.

Linux远程登录

两个常用工具:Xshell(远程登录)、Xftp(远程文件传输)

Linux_Vi和Vim

三种模式

  • 正常模式,即默认的模式
  • 插入模式,按下i,I,o,O,a,A,r,R等任何一个字母即可进入编辑模式
  • 命令行模式 输入esc ,再输入: 即可进入 ,提供相关指令,完成读取,存盘,替换,离开vim,显示行号等的动作

常用的快捷键

对应的键盘图

Linux开机、重启、用户登录注销

Linux用户管理

查询当前用户信息 who am I

Linux使用指令

Linux运行级别

Linux文件目录指令

Linux组

Linux中,每个用户都有组,文件有三个概念(所有者、所在组、其它组)

41

42

43

44

45

46

47

48

49

50

51

定时任务调度

53

54

55

57

58

59

60

61

62

63

64

65

66

67

68

69

70

https://img1.imgtp.com/2023/09/17/WVCRQgxx.png

https://img1.imgtp.com/2023/09/17/MV0qnvTN.png

https://img1.imgtp.com/2023/09/17/9HQS1wts.png

https://img1.imgtp.com/2023/09/17/xky1TwC6.png

https://img1.imgtp.com/2023/09/17/aBUwGeEj.png

https://img1.imgtp.com/2023/09/17/TWC9DAjH.png

https://img1.imgtp.com/2023/09/17/DiqGQyIH.png

https://img1.imgtp.com/2023/09/17/4RwfaMmN.png

https://img1.imgtp.com/2023/09/17/k315ZK6T.png

https://img1.imgtp.com/2023/09/17/bdJ2rgOY.png

https://img1.imgtp.com/2023/09/17/ajycZ3b8.png

https://img1.imgtp.com/2023/09/17/zg8zSxE5.png

Linux服务管理

https://img1.imgtp.com/2023/09/17/Ofn7JZ5U.png

https://img1.imgtp.com/2023/09/17/dlrLIgrn.png

https://img1.imgtp.com/2023/09/17/5YUm7NhH.png

https://img1.imgtp.com/2023/09/17/068T0EXV.png

https://img1.imgtp.com/2023/09/17/aXdbnSDi.png

https://img1.imgtp.com/2023/09/17/3gmzdCoi.png

https://img1.imgtp.com/2023/09/17/1EDJ6DJ9.png

https://img1.imgtp.com/2023/09/17/4lOiKiut.png

https://img1.imgtp.com/2023/09/17/By8Z0Za8.png

https://img1.imgtp.com/2023/09/17/dvTRVqbT.png

https://img1.imgtp.com/2023/09/17/x0uw4zaX.png

https://img1.imgtp.com/2023/09/17/fMYyu93G.png

https://img1.imgtp.com/2023/09/17/kqdskMJF.png

Linux的Shell编程

https://img1.imgtp.com/2023/09/17/dG6EmWa6.png

https://img1.imgtp.com/2023/09/17/V4EBHVSe.png

https://img1.imgtp.com/2023/09/17/sERUjXA1.png

https://img1.imgtp.com/2023/09/17/dQA5NgPj.png

https://img1.imgtp.com/2023/09/17/SMRRThRz.png

https://img1.imgtp.com/2023/09/17/BXzcZvkl.png

https://img1.imgtp.com/2023/09/17/d9aERet8.png

一、虚拟机的设置

​ 这里我采用的是使用虚拟机构建大数据集群,如果有钱也可以采用云平台进行大数据集群的构建。

​ 在VMware的虚拟网络编辑器中,将VMnet8虚拟网卡的:

​ 网段设置为192.168.88.0

​ 网关设置为:192.168.88.2

​ 下载CentOs7.6的镜像文件,然后创建新的虚拟机,选择标准安装,全自动化安装。等待安装完成以后,再进行克隆,克隆完整的系统,这里克隆三个,分别命名为node1、node2、node3,设置node1的内存为4GB、node2和node3的内存为2GB。

​ 然后打开node1,修改主机名,并修改固定IP为:192.168.88.101,node2和node3分别为102和103

1
2
3
4
5
6
7
# 修改主机名
hostnamectl set-hostname node1
# 修改IP地址
vim /etc/sysconfig/network-scripts/ifcfg-ens33
IPADDR="192.168.88.101"
# 重启网卡
systemctl restart network

在windows系统中修改hosts文件,新增以下内容

1
2
3
192.168.88.101 node1
192.168.88.102 node2
192.168.88.103 node3

在3台Linux的/etc/hosts中,新增以下内容:

1
2
3
192.168.88.101 node1
192.168.88.102 node2
192.168.88.103 node3

配置SSH免密登录(每台都要执行一遍)

1
2
3
4
ssh-keygen -t rsa -b 4096
ssh-copy-id node1
ssh-copy-id node2
ssh-copy-id node3

新增hadoop普通用户.然后重复上诉的SSH操作:

1
2
3
4
5
6
# 新增普通用户
useradd hadoop
# 设置密码
passwd hadoop
# 切换用户
su - hadoop

下载JDK

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 新建文件夹存储jdk
mkdir -p /export/server
# 解压文件
tar -zxvf jdk-8u351-linux-x64.tar.gz -C /export/server
# 配置jdk的软链接
ln -s /export/server/jdk1.8.0_351 jdk
# 配置环境变量(编辑/etc/profile文件)
export JAVA_HOME=/export/server/jdk
export PATH=$PATH:$JAVA_HOME/bin
# 生效环境变量
source /etc/profile
# 配置java执行程序的软链接(先删除自带的java,再添加下载的)
rm -f /usr/bin/java
ln -s /export/server/jdk/bin/java /usr/bin/java
# 验证
java -version
javac -version

为了防止防火墙干扰大数据的软件,将防火墙关闭

1
2
3
4
5
6
7
# 每一台都执行
systemctl stop firewalld
systemctl disable firewalld
# 关闭SELinux
vim /etc/sysconfig/selinux
# 修改
SELINUX=disabled

调整每个服务器的时区为中国东八区的时区(校验时间)

1
2
3
4
5
6
7
8
9
10
# 安装ntp软件
yum install -y ntp
# 更新时区
rm -f /etc/localtime
sudo ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# 同步时间
ntpdate -u ntp.aliyun.com
# 开启ntp服务并设置开机自启动
systemctl start ntpd
systemctl enable ntpd

二、Hadoop的部署

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# 上传文件到node1
# 解压
tar -zxvf hadoop-3.3.4.tar.gz -C /export/server
# 构建软链接
ln -s /export/server/hadoop-3.3.4 hadoop
# 先cd /export/server/hadoop,然后再cd etc/hadoop
vim workers
# 填入
node1
node2
node3
# 然后配置hadoop-env.sh文件,同样使用vim hadoop-env.sh
export JAVA_HOME=/export/server/jdk
export HADOOP_HOME=/export/server/hadoop
export HADOOP_CONF_DIR=$HADOOP_HOME/etc/hadoop
export HADOOP_LOG_DIR=$HADOOP_HOME/logs
# 配置core-site.xml
<configuration>
<property>
<name>fs.defaultFS</name>
<value>hdfs://node1:8020</value>
</property>
<property>
<name>io.file.buffer.size</name>
<value>131072</value>
</property>
</configuration>
# 配置hdfs-site.xml
<configuration>
<property>
<name>dfs.datanode.data.dir.perm</name>
<value>700</value>
</property>
<property>
<name>dfs.namenode.name.dir</name>
<value>/data/nn</value>
</property>
<property>
<name>dfs.namenode.hosts</name>
<value>node1,node2,node3</value>
</property>
<property>
<name>dfs.blocksize</name>
<value>268435456</value>
</property>
<property>
<name>dfs.namenode.handler.count</name>
<value>100</value>
</property>
<property>
<name>dfs.datanode.data.dir</name>
<value>/data/dn</value>
</property>
</configuration>
# node1节点
mkdir -p /data/nn
mkdir -p /data/dn
# node2和node3
mkdir -p /data/dn
# 复制hadoop到node2和node3
cd /export/server
scp -r hadoop-3.3.4 node2:`pwd`/
scp -r hadoop-3.3.4 node3:`pwd`/
# 在node2和node3分别建立软链接
ln -s /export/server/hadoop-3.3.4 /export/server/hadoop
# 配置环境变量 vim /etc/profile (退回顶级目录执行)
export HADOOP_HOME=/export/server/hadoop
export PATH=$PATH:$HADOOP_HOME/bin:$HADOOP_HOME/sbin
# source /etc/profile 生效环境变量
# 使用root身份,将权限给普通用户,三台服务器都要
chown -R hadoop:hadoop /data
chown -R hadoop:hadoop /export
# 格式化namenode
su - hadoop # 切换为hadoop普通用户
hadoop namenode -format # 格式化
# 启动HDFS集群
start-dfs.sh
# 关闭HDFS集群
stop-dfs.sh

1.ES6

1.let 和var的区别

作用域不同,var是全局变量而let是根据为位置决定

2.const定义常量,防止变量标识符的重新分配

3.防止对象被改变:Object.freeze(obj)

4.箭头函数代替function关键字:const myFun=(attribute)=>{}

设置默认参数const myFun=(attribute=value)=>{}

5.rest操作符: …args等同于将args数组展开

6.解构赋值:

(1)对象的解构赋值:

1
const user = { name: 'John Doe', age: 34 };
1
const { name, age } = user;//将user的name和age的值赋值给了name和age变量
1
const { name: userName, age: userAge } = user;//将user.name和user.age的值分配给了新变量
1
2
3
4
5
6
const user = {
johnDoe: {
age: 34,
email: 'johnDoe@freeCodeCamp.com'
}
};

嵌套对象的解构赋值:

1
const { johnDoe: { age, email }} = user;//这是解构对象的属性值赋值给具有相同名字的变量:
1
const { johnDoe: { age: userAge, email: userEmail }} = user;//这是将对象的属性值赋值给具有不同名字的变量:

(2)数组的解构赋值:

1
const [a, b] = [1, 2, 3, 4, 5, 6];
1
const [a, b,,, c] = [1, 2, 3, 4, 5, 6];

例:交换变量的值:let a=10; let b=20; [a,b]=[b,a];

1
const [a, b, ...arr] = [1, 2, 3, 4, 5, 7];

arr就是新的数组[3,4,5,7];

(3)模板字面量:

1
2
3
4
5
6
const person = {
name: "Zodiac Hasbro",
age: 56
};
const greeting = `Hello, my name is ${person.name}!
I am ${person.age} years old.`;//占位符${}
1
2
3
4
5
6
const getMousePosition = (x, y) => ({
x: x,
y: y
});//等同于
const getMousePosition = (x, y) => ({ x, y });

1
2
3
4
5
6
const person = {
name: "Taylor",
sayHello: function() {
return `Hello! My name is ${this.name}.`;
}
};
1
2
3
4
5
6
const person = {
name: "Taylor",
sayHello() {
return `Hello! My name is ${this.name}.`;
}
};//简洁的函数声明

构造函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var SpaceShuttle = function(targetPlanet){
this.targetPlanet = targetPlanet;
}
class SpaceShuttle {
constructor(targetPlanet) {
this.targetPlanet = targetPlanet;
}
}
class Book {
constructor(author) {
this._author = author;
}
// getter 定义时的赋值
get writer() {
return this._author;
}
// setter 改变writer属性值的时候
set writer(updatedAuthor) {
this._author = updatedAuthor;
}
}
const novel = new Book('anonymous');
console.log(novel.writer);
novel.writer = 'newAuthor';
console.log(novel.writer);

7.导入模块js文件:

1
<script type="module" src="filename.js"></script>

export导出js的模块:

1
2
3
export const add = (x, y) => {
return x + y;
}
1
2
3
4
5
const add = (x, y) => {
return x + y;
}

export { add };//可以一次导出多个变量或函数

import导入js模块:

1
import { add, subtract } from './math_functions.js'; 

全部导入:

1
import * as myMathModule from "./math_functions.js";

上面的 import 语句会创建一个叫作 myMathModule 的对象。 这只是一个变量名,可以随便命名。 对象包含 math_functions.js 文件里的所有导出,可以像访问对象的属性那样访问里面的函数。 下面是使用导入的 addsubtract 函数的例子:

1
2
myMathModule.add(2,3);
myMathModule.subtract(5,3);

还需要了解另外一种被称为默认导出的 export 的语法。 在文件中只有一个值需要导出的时候,通常会使用这种语法。 它也常常用于给文件或者模块创建返回值。

1
2
3
4
5
6
7
export default function add(x, y) {
return x + y;
}

export default function(x, y) {
return x + y;
}

第一个是命名函数,第二个是匿名函数。

export default 用于为模块或文件声明一个返回值,在每个文件或者模块中应当只默认导出一个值。 此外,你不能将 export defaultvarletconst 同时使用。

还需要一种 import 的语法来导入默认的导出。 在下面的例子里,addmath_functions.js 文件的默认导出。 以下是如何导入它:

1
import add from "./math_functions.js";

这个语法有一处特别的地方, 被导入的 add 值没有被花括号({})所包围。 add 只是一个变量的名字,对应 math_functions.js 文件的任何默认导出值。 在导入默认导出时,可以使用任何名字。

8.Promise:

Promise 是异步编程的一种解决方案 - 它在未来的某时会生成一个值。 任务完成,分执行成功和执行失败两种情况。 Promise 是构造器函数,需要通过 new 关键字来创建。 构造器参数是一个函数,该函数有两个参数 - resolvereject。 通过它们来判断 promise 的执行结果。 用法如下:

1
2
3
const myPromise = new Promise((resolve, reject) => {

});

通过 resolve 和 reject 完成 Promise

Promise 有三个状态:pendingfulfilledrejected。 上一个挑战里创建的 promise 一直阻塞在 pending 状态里,因为没有调用 promise 的完成方法。 Promise 提供的 resolvereject 参数就是用来结束 promise 的。 Promise 成功时调用 resolve,promise 执行失败时调用 reject, 如下文所述,这些方法需要有一个参数。

1
2
3
4
5
6
7
const myPromise = new Promise((resolve, reject) => {
if(condition here) {
resolve("Promise was fulfilled");
} else {
reject("Promise was rejected");
}
});

上面的示例使用字符串作为这些函数的参数,但参数实际上可以是任何格式。 通常,它可能是一个包含数据的对象,你可以将它放在网站或其他地方。

用 then 处理 Promise 完成的情况

当程序需要花费未知的时间才能完成时(比如一些异步操作),一般是服务器请求,promise 很有用。 服务器请求会花费一些时间,当结束时,需要根据服务器的响应执行一些操作。 这可以用 then 方法来实现, 当 promise 完成 resolve 时会触发 then 方法。 例子如下:

1
2
3
myPromise.then(result => {

});//result 即传入 resolve 方法的参数

使用 catch 处理 Promise 失败的情况

当 promise 失败时会调用 catch 方法。 当 promise 的 reject 方法执行时会直接调用。 用法如下:

1
2
3
myPromise.catch(error => {

});//error 是传入 reject 方法的参数。

2.ES7

includes:数组方法,判断是否数组含有某元素,返回布尔值

**:表示幂运算的运算符

1
2
3
const books=["tom","sakura"];
console.log(books.includes("tom"));
console.log(2**10);

async和await:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//async函数返回值为promise对象
//promise对象的结果由async函数执行的返回值决定
function getData(url) {
return new Promise((resolved, reject) => {
let xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.send();
xhr.onreadystatechange = () => {
if (xhr.readyState === 4) {
if (xhr.status >= 200 && xhr.status < 300) {
resolved(xhr.response);
} else {
reject(xhr.status);
}
}
};
});
}
async function get(){
let result=getData("http:///localhost:8000");
console.log(result);
}

3.ES8 对象方法的扩展:

1
2
3
4
//Object.keys(obj) 获取对象的键
//Object.values(obj) 获取对象的值
//Object.entries(obj) 获取对象的二维数组形式
//Object.getOwnPropertyDescriptors(obj) 获取对象的描述对象

4.ES9 正则扩展:

1
2
3
4
5
6
7
8
9
10
//命名捕获分组
let str="<a href='http:www.baidu.com'></a>";
const reg=/<a href="(.*)">(.*)<\/a>/;
const result=reg.exec(str);
console.log(result[1]);
const reg1=/<a href="(?<url>.*)">(?<text>.*)<\/a>/;
const result1=reg1.exec(str);
console.log(result.groups.name);
//反向断言 (?<=啊)
//dotAll 新增s修饰符 写在//s

5.ES10:

1
2
3
//Object.fromEntries() 利用传入的二维数组创建一个对象
//flat和flatMap 将数组降维 flat接收数字参数决定降的维度 flatMap将map和flat结合
//Symbol.prototype.description

6.ES11:

1
2
3
4
5
6
7
8
9
//私有属性
class Person{
name;
#age;//私有属性,以#开头
constructor(name,age){
this.name=name;
this.#age=age;
}
}
1
2
//Promise.allSettled([]) 接收数组 每个元素是个Promise对象 始终成功
//Promise.all([]) 接收参数一样 状态取决于参数是否都成功 否则失败
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//String.prototype.matchAll 返回一个可迭代的对象
let str = `
<ul>
<li>
<a>你好</a>
<p>世界</p>
</li>
<li>
<a>Hello World</a>
<p>sakura</p>
</li>
</ul>
`;
const reg = /<li>.*?<a>(.*?)<\/a>.*?<p>(.*?)<\/p>/gs;
const result = str.exec(reg);
for (let v of result) {
console.log(v);
}
1
2
//可选链操作符 ?. 在使用对象的属性之前判断对象是否存在
//动态import import("").then(module=>{module.method()});

BigInt类型:大整形

1
2
3
//大数值的运算
let n=123;
let m=BigInt(n);

globalThis:始终指向全局对象