NoSQL数据库
NOt only sql 不仅仅是sql,非关系型数据库
NoSQL数据库特点
1、方便扩展(数据之间没有关系,好扩展)
2、大数据量高i性能
3、数据类型是多样性的(不需要事先设计数据库!随取随用)
4、传统RDBMS和NOSQL
传统的RDBMS
- 结构化组织
- SQL
- 数据和关系都存在单独的表中
- 操作,是数据定义语言
- 严格的一致性
- 基础的事务
- …
NoSQL
- 不仅仅·是数据
- 没有固定的查询语言
- 键值对存储,列存储,文档存储,图形数据库
- 最终一次性
- CAP定理和BASE
- 高性能,高可见,高可扩
- …
3v+3高
3v
- 海量
- 多样
- 实时
3高
- 高性能
- 高并发
- 高可扩
NOSQL的四大分类
- kv键值对
- 文档型数据库(bson格式和json一样)
-
MongoDB
-
是一个基于分布式文件存储的数据库,C++编写,主要处理大量的文档
-
是介于关系型数据库与非关新型数据库之间的产品!
- 列存储数据库
- 图关系数据库
Redis入门
概述
redis是什么
Redis (Remote Dictionary Server)远程字典服务
是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、key-value数据库,并提供多种语言的
redis会周期性的把更新的数据写入磁盘或者把修改操作西而入追加的记录文件,并且在此基础上实现主从同步。
redis能干嘛
1、内存存储、持久化、内存中是断电即失
2、效率高、可以用于高速缓存
3、发布订阅信息
4、地图信息分析
5、计时器、计数器(浏览量)
6…
特性
1、多样的数据据类型
2、持久化
3、集群
4、事务
…
redise的安装
我是使用docker进行安装的
docker pull redis #下载镜像
# 启动redis容器
docker run -itd --name redis-test -p 6379:6379 redis
# 进入redis容器
[root@iZf8zeb4pvftjcmv58dmy8Z ~]# docker exec -ti 1ee93b679ab1 redis-cli
127.0.0.1:6379>
存入key=“name”, value="painye"的键值对
127.0.0.1:6379> set name painye
OK
127.0.0.1:6379> get name
"painye"
查看redis的进程是否开启
[root@iZf8zeb4pvftjcmv58dmy8Z ~]# ps -ef|grep redis
polkitd 7020 6998 0 15:37 ? 00:00:13 redis-server *:6379
root 21420 5606 0 20:00 pts/0 00:00:00 docker exec -it 1ee93b679ab1 redis-cli
root 21436 6998 0 20:00 pts/0 00:00:00 redis-cli
root 21646 21544 0 20:02 pts/1 00:00:00 grep --color=auto redis
关闭redis服务
127.0.0.1:6379> shutdown
[root@iZf8zeb4pvftjcmv58dmy8Z ~]#
# 查看进程
[root@iZf8zeb4pvftjcmv58dmy8Z ~]# ps -ef|grep redis
root 21793 21544 0 20:04 pts/1 00:00:00 grep --color=auto redis
性能测试
root@1ee93b679ab1:/data# redis-benchmark -h localhost -p 6379 -c 100 -n 100000^C
基础的知识
redis有16个数据库,默认用第0个,使用select切换数据库。但是docker中的数据库似乎不足16个
常用基础命令
DBSIZE 查看数据库内容大小
keys * 查看所有的key
127.0.0.1:6379> keys *
1) "counter:__rand_int__"
2) "myname"
3) "name"
4) "mylist"
5) "myhash"
6) "key:__rand_int__"
127.0.0.1:6379>
flushdb 清除当前数据库
127.0.0.1:6379> flushDB
OK
127.0.0.1:6379>
root@1ee93b679ab1:/usr/local/bin# redis-cli
127.0.0.1:6379> DBSIZE
(integer) 0
127.0.0.1:6379>
清空全部数据库 FLUSHALL
127.0.0.1:6379> DBSIZE
(integer) 0
127.0.0.1:6379> set name 22
OK
127.0.0.1:6379> DBSIZE
(integer) 1
127.0.0.1:6379> select 3
OK
127.0.0.1:6379[3]> FLUSHALL
OK
127.0.0.1:6379[3]> select 0
OK
127.0.0.1:6379> DBSIZE
(integer) 0
Redis是单线程的
Redis是基于内存操作的,CPU不是Redis的性能瓶颈,Redis的瓶颈是机器的内存和网络带宽
Redis是单线程为什么还是这么快
一、内存操作与数据结构优化
- 1 全内存操作: redis的数据存储在内存中,读写速度可达纳秒级。
- 2 高效的数据结构
- 简单动态字符串(SDS):支持预分配内存和惰性释放,减少内存碎片。
- 跳跃表 (Skip List): 实现O(logN)复杂度的有序集合查询
- 压缩列表: 对小规模数据采用紧凑存储,减少内存占用。
二、单线程优势
- 1 避免线程切换开销:多线程系统中频繁的上下文切换会消耗10%-30%的CPU资源。而redis单线程无需切换,可连续利用CPU缓存,提升指令执行效率。
- 2 无锁竞争问题:多线程中需要锁机制保证数据的一致性,但锁的获取与释放会带来性能和损耗。
三、网络I/O复用与非阻塞模型
- 1、I/O多路复用技术
- 2、 非阻塞网络通信
误区:
- 1、高性能的服务器一定是多线程的?
- 2、多线程(上下文切换)一定比单线程效率高?cpu频繁的上下文切换也十分的耗时,所以多线程 不一定比单线程快
redis的五种数据类型
redis-key
判断key是否存在: EXISTS
127.0.0.1:6379> set name painye
OK
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> EXISt name
(error) ERR unknown command `EXISt`, with args beginning with: `name`,
127.0.0.1:6379> EXISTS name
(integer) 1
删除指定key: move key 1 (表示将kv从当前数据库移到1数据库)
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> move name 0
(error) ERR source and destination objects are the same
127.0.0.1:6379> move name 1
(integer) 0
# 给指定key设置过期时间秒为单位
127.0.0.1:6379> EXPIRE name 10
(integer) 1
127.0.0.1:6379> ttl name
(integer) 6
127.0.0.1:6379> ttl name
(integer) 4
127.0.0.1:6379> ttl name
(integer) 2
127.0.0.1:6379> ttl name
(integer) 1
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> keys *
1、 String (字符串)
特点
二进制安全,可存储文本、数字、序列化对象或二进制数据,最大容量为512MB
常用命令
SET (设置)、GET(取值)、INCR(自增)、APPEND(追加)
应用场景
- 缓存:存储会话token、页面静态内容
- 计数器: 统计用户访问量、商品库存
SETNX实现分部式锁的原因
SETNX(set if not exists)是redis的原子性命令,通过其特性可以实现分布式锁的互斥访问
一、SETNX的原子性原理
1、SETNX的原子性原理
SETNX命令在执行时, Redis的单线程模型确保同时一时刻只有一个客户端操作键值对。若多个客户端并发调用SETNX key value,仅第一个客户端会成功(返回1),其余请求均返回失败(0)。
SETNX lock_key "client1" # 成功返回1,获得锁
SETNX lock_key "client2" # 失败返回0,锁已被占用
2、互斥性实现
通过SETNX的“建不存在才设置”的特性,天然实现锁的互斥性。第一个成功的客户端独占锁资源,其他客户端需等待或重试。
二、锁竞争的实现步骤
1、获取锁
客户端调用SETNX尝试设置锁key,若返回1则获取锁,否则视为竞争失败:
SETNX local_key "unique_client_id" #原子操作
2、设置锁过期时间(防死锁)
SETNX需要结合EXPIERE 或者之间使用SET命令的NX(等效SETNX)和EX(过期时间)选项,避免客户端崩溃导致锁无法释放
SET local_key "client1" NX EX 10 #原子性设置锁+10s过期时间
3、释放锁
释放锁时选哟验证持有者身份(如唯一标识client_id),避免误删其他客户端的锁。需通过Lua脚本保证操作的原子性
if redis.call("GET", KEYS[1]) == ARGV[1] then
return redis.call("DEL", KEYS[1])
else
return 0;
end
127.0.0.1:6379> set name painye
OK
127.0.0.1:6379[3]> get name
"painye"
127.0.0.1:6379[3]> append name 222
(integer) 9
127.0.0.1:6379[3]> get name
"painye222"
######################################################################
i++
127.0.0.1:6379[3]> set views 0 # 给views设值为0
OK
127.0.0.1:6379[3]> get views # 自加1
"0"
127.0.0.1:6379[3]> incr views
(integer) 1
127.0.0.1:6379[3]> incr views
(integer) 2
127.0.0.1:6379[3]> incr views
(integer) 3
127.0.0.1:6379[3]> incr views
(integer) 4
127.0.0.1:6379[3]> incr views 3
(error) ERR wrong number of arguments for 'incr' command
127.0.0.1:6379[3]> incrby views 3 # 自加3,后面的数值是步长
(integer) 7
127.0.0.1:6379[3]> incrby views 3
(integer) 10
127.0