Zookeeper-Redis-MongoDB

  • Zookeeper: Apache Hadoop项目下的一个子项目; 一个分布式、开源的分布式应用程序的协调服务; 提供的主要功能为: 配置管理, 分布式锁, 集群管理
  • Redis(Remote Dictionary Server): 键值类型的非关系型数据库, value支持多种不同数据结构(文档类型: MongoDB; 列类型: HBase; Graph类型: Neo4j)
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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// 安装Redis, 此处使用的环境为CentOS 7
// Redis是基于C语言编写的, 首先需要安装Redis所需的gcc依赖
yum install -y gcc tcl
// 将官网下载的安装包上传至虚拟机的/usr/local/src目录
// 进入redis-6.2.6目录, 编译并安装
make && make install
// 默认的安装路径为/usr/local/bin, 进入该路径能看到redis相关的文件:
// redis-cli: redis提供的命令行客户端
// redis-server: redis服务器启动脚本, 直接运行即可启动
// redis-sentinel: redis哨兵启动脚本

// 指定配置启动, 需修改redis-6.2.6目录下的redis.conf文件
// 文件备份: cp redis.conf redis.conf.bck
// 修改配置如下:
bind 0.0.0.0 // 127.0.0.1: 只能在本地访问; 0.0.0.0: 可以在任意IP访问
daemonize yes // 守护进程, yes表示可在后台运行
requirepass 123123 // 设置后访问redis需输入密码
port 6379 // 默认的监听端口
dir . // 默认为当前目录, 运行redis-server时, 命令、日志、持久化文件会保存在这个目录
database 1 // 数据库数量, 此处表示只使用1个数据库(默认值为16, 即有16个数据库, 编号为0-15)
maxmemory 512mb // redis能够使用的最大内存
logfile "redis.log" // 日志文件, 默认为空(即不记录日志), 可以指定日志文件名

// 修改完毕后, 执行redis-server redis.conf命令运行

// 配置系统文件
vi /etc/systemd/system/redis.service

[Unit]
Description=redis-server
After=network.target

[Service]
Type=forking
ExecStart=/usr/local/bin/redis-server /usr/local/src/redis-6.2.6/redis.conf
PrivateTmp=true

[Install]
WantedBy=multi-user.target

// 重载系统服务: systemctl daemon-reload // 使配置文件生效
// 启动: systemctl start redis
// 停止: systemctl stop redis
// 重启: systemctl restart redis
// 查看状态: systemctl status redis
// 让redis开机自启: systemctl enable redis

// 命令行客户端
redis-cli
// -h(指定要连接的redis节点的IP地址, 默认为127.0.0.1)
// -p(指定要连接的redis节点的端口, 默认为6379)
// -a(指定redis的访问密码)
redis-cli -h=127.0.0.1 -p=6379 -a=123123
// 也可以先通过redis-cli -h=127.0.0.1 -p=6379连接, 再通过AUTH 123123输入密码

set age 20 // OK
get age // "20"

// Redis图形化界面的客户端
// <https://github.com/lework/RedisDesktopManager-Windows/releases>
// 进入1号库: select 1
// 官方文档: <https://redis.io/commands>

// Redis通用命令
KEYS *
KEYS *a // 查询匹配的key
DEL age // 删除一个指定的key
MSET k1, v1, k2, v2, k3, v3 // 批量插入
EXISTS age // 判断指定的key是否存在
EXPIRE age 20 // 给一个key设置有效期(数值的单位为s), 到期时该key会被自动删除
TTL // 查看一个key的剩余有效期(-2表示已过期, -1表示永久有效)

// String类型
// value是字符串, 根据字符串格式可分为3类: string, int, float
// 常见命令
// SET: 添加或修改键值对 e.g set name zhangsan
// GET: 根据key获取value e.g get name
// MSET: 多次添加或修改键值对 e.g MSET k1, v1, k2, v2, k3, v3
// MGET: 多次根据key获取value e.g MSET k1, k2, k3
// INCR: 使一个整型的自增1 e.g INCR age
// INCRBY: 使一个整型的自增指定步长 e.g INCRBY age 2
// INCRBYFLOAT: 使一个浮点型的自增指定步长 e.g INCRBYFLOAT socre 1.5
// SETNX: 添加一个键值对(前提是key不存在, 否则不执行) e.g set name lisi
// 等价于 set name lisi nx
// SETEX: 添加一个键值对并设置有效期 e.g setex name 10 lisi

// key层级结构
// Redis的key允许有多个单词形成层级结构, 单词之间用":"隔开
// e.g 项目名称为test, 有user和product两种不同类型的数据, 则可定义:
// user相关的key为: test:user:1 (1表示id, 此处表示id为1的user的信息)
// product相关的key为: test:product:1 (1表示id, 此处表示id为1的product的信息)
// e.g set test:user:1 '{"id": 1, "name": zhangsan, "age": 20}'
// set test:user:2 '{"id": 2, "name": lisi, "age": 21}'

// Hash类型
// Hash结构可将对象中的每个字段独立存储(field对应key), 从而针对单个字段做CRUD
// HSET e.g hset test:user:3 name lucy
// hset test:user:3 age 21
// HMSET e.g hset test:user:3 name lucy age 21
// HGET e.g hget test:user:3 name
// HMSET e.g hset test:user:3 name age
// HGETALL e.g hgetall test:user:3 // 获取key和value
// HKEYS e.g hkeys test:user:3 // 获取key
// HVALS e.g hvals test:user:3 // 获取value
// HINCRBY e.g hincrby test:user:3 age 2 (注: 2也可以换成-2)
// HSETNX e.g hsetnx test:user:3 score 10 (判断的是field是否存在, 不存在则执行)

// List类型
// Redis中的List类型与与Java中的LinkedList类似, 可看作是一个双向链表结构
// 特点: 有序; 元素可以重复; 插入与删除快; 查询速度一般
// LPUSH key element: 在列表左侧插入一个或多个元素 e.g lpush user 1 2 3 (1, 2, 3为value)
// LPOP key: 移除并返回列表左侧第一个元素, 若没有则返回null e.g lpop user 1
// RPUSH key element: 在列表右侧插入一个或多个元素
// RPOP key: 移除并返回列表右侧第一个元素, 若没有则返回null
// LRANGE key start end: 返回一段范围内的所有元素 e.g lrange user 1 2
// BLPOP和BRPOP: 与LPOP和RPOP类似, 但在没有元素时会等待指定时间, 而不是直接返回null
// e.g blpop user 100 (等待时长为100s)

// Set类型
// Redis中的Set类型与Java中的HashSet类似, 可看作是一个value为null的HashMap
// 特点: 无序, 元素不可重复, 查找速度快, 支持交集、并集、差集
// SADD key member: 在set中插入一个或多个元素
// SREM key member: 移除set中的指定元素
// SCARD key: 返回set中的元素个数
// SISMEMBER key member: 判断一个元素是否在set
// SMEMBERS: 获取set中的所有元素
// SINTER key1 key2: 求key1与key2的交集
// SDIFF key1 key2: 求key1与key2的差集
// SUNION key1 key2: 求key1与key2的并集

// SortedSet类型
// Redis中的SortedSet与Java中的TreeSet类似, 但底层数据结构差别很大
// SortedSet中的每一个元素有一个score属性, 可基于score属性对元素排序
// 特点: 可排序, 元素不可重复; 查询速度快
// ZADD key score member: 添加一个或多个元素到sorted set, 若已存在则更新其score值
// e.g ZADD students 99 Jack 99 Lucy
// ZREM key member: 移除sorted set中的指定元素
// ZSCORE key member: 获取sorted set中的指定元素的score值
// ZRANK key member: 获取sorted set中的指定元素的排名 // 默认升序, ZRERANK表示降序
// e.g ZRANK students Rose
// ZCARD key: 获取sorted set中的元素个数
// ZCOUNT key min max: 获取score值在指定范围内的所有元素个数
// ZINCRBY key increment member: 使sorted set中的指定元素按照指定步长自增
// e.g ZINCRBY students 2 Lucy
// ZRANGE key min max: 按照score排序后, 获取指定排名范围内的所有元素
// e.g ZREVRANGE students 0 2
// ZRANGEBYSCORE key min max: 按照score排序后, 获取指定score范围内的所有元素
// e.g ZRANGEBYSCORE students 0 80
// ZDIFF、ZINTER、ZUNION: 获取差集、交集、并集

单线程, 每个命令具备原子性; 低延迟, 速度快(基于内存, IO多路复用; 良好的编码); 支持数据持久化; 支持主从集群, 分片集群; 支持多语言客户端

  • MongoDB: 文档类型的非关系型数据库; 支持的数据结构非常松散, 是一种类似于JSON的格式, 叫BSON, 可存储比较复杂的数据类型

table→collection, row→document, column→field(数据字段/域)

应用场景: 对数据库高并发读写; 对海量数据高效存储与访问; 对数据库高可扩展性的要求

下载的package: MSI: 需要安装; ZIP: 解压缩即可

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
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
// 在Windows系统
// 命令行启动
mongod --dbpath=..\\data\\db // 此处data\\db为存储数据库的目录
// 配置文件启动
// 在解压目录下新建config文件夹, 文件夹中新建配置文件mongod.conf:
storage:
dbPath:..\\data\\db // 此处需改写为绝对路径
// 启动
mongod -f ../config/mongod.conf
// 或 mongod --config ../config/mongod.conf
// 此处mongod对应的应该是该目录下的mongod.exe文件

// 启动后, 连接MongoDB数据库(注意此时启动的cmd窗口不能关, 需新开一个cmd窗口)
// 连接本地的MongoDB数据库
mongo // 或 mongo --host=127.0.0.1 --port=27017
// 连接成功后测试: show dbs 或 show databases

// 也可通过Compass(MongoDB的图形化界面)进行连接等操作
<https://www.mongodb.com/zh-cn/products/tools/compass>

// 在Linux系统
// 配置文件启动
// 新建数据存储目录
mkdir -p mongodb/single/data/db
// 新建日志存储目录
mkdir -p mongodb/single/log
// 新建并修改配置文件
vi mongodb/single/mongod.conf
systemLog:
destination: file // 日志输出的目标指定为文件
path: "mongodb/single/log/mongod.log"
logAppend: true // 将新条目添加到现有日志文件的末尾
storage:
dbPath: "mongodb/single/data/db"
journal:
enabled: true // 启用持久性日志以确保数据文件的可恢复
processManagement:
fork: true // 启用在后台运行mongod进程的守护进程模式
net:
bindIp: localhost, ... // 服务实例绑定的IP
// 对于远程连接, 绑定的不是远程主机的IP, 而是云服务器所在局域网的IP
// 查看所在局域网的IP: ifconfig命令, 第二行
port: 27017

// 启动后查看进程
ps -ef // 显示系统中所有正在运行的进程的详细信息
ps -ef | grep mongod // 显示系统中所有与mongod相关的正在运行的进程

// 若连接不上, 可能是防火墙未关闭
systemctl status firewalld // 查看防火墙状态
systemctl stop firewalld // 临时关闭防火墙
systemctl disabled firewalld // 禁止启动防火墙

// 关闭
// 方式1: 直接kill进程
// 方式2: 标准关闭方式, 数据不容易出错
mongo --port=27017 // 客户端登录, 通过localhost
use admin // 切换到admin库
db.shutdownServer() // 关闭服务
// 创建/切换数据库, 新建的数据库位于内存而不是磁盘(持久化)
use ...
// 查看当前数据库
db

// 有特殊作用的数据库
admin: "root"数据库, 若将一个用户添加到这个数据库, 这个用户可以继承所有数据库的权限
// 一些特定的服务器端命令也只能在这个服务器端运行
local: 用来存储限于本地单台服务器的任意集合, 永远不会被复制
config: 当Mongo用于分片设置时, config数据库在内部使用, 用于保存分片的相关信息

db.dropDatabase() // 删除数据库
// 创建集合
db.createCollection("mycollection") // 显式
// 查询集合
show collections
// 删除集合
db.mycollection.drop() // db.集合名称.drop()
// 文档插入
db.mycomment.insert(
{"name": "zhangsan", "userid": "10", "datetime": new Date(),
"likenum": NumberInt(5), "state": null}
)
// 若mycomment集合不存在, 则会隐式创建
// mongo中的数字默认为double, 若要存储整型则需使用NumberInt(...)
// 当前日期: new Date()
// 若插入数据没有指定_id, 则会自动生成主键值

// 查询文档
db.comment.find()
// 多条文档插入
db.mycomment.insert(
[{"name": "zhangsan", "userid": "10", "datetime": new Date(),
"likenum": NumberInt(1), "state": null},
{"name": "zhangsan1", "userid": "10", "datetime": new Date(),
"likenum": NumberInt(2), "state": null},
{"name": "zhangsan2", "userid": "11", "datetime": new Date(),
"likenum": NumberInt(3), "state": null}]
)
db.mycomment.find({userid: "10"})
db.mycomment.findOne({userid: "10"})
// 查询结果只显示name, userid
db.mycomment.find({userid: "10"}, {name: 1, userid: 1})

SQL(关系型数据库): 结构化; 关联的; 标准的SQL查询; 存储在磁盘

NoSQL(非关系型数据库): 非结构化(key-value; document; graph); 非关联的(关联需要自己定义); 非SQL查询; 存储在内存