1 NoSQL概述:
1.1 为什么要用Nosql
1.1.1 单机年代
数据量太大,一台机器放不下
数据的索引(B+tree),一个服务器承受不了
数据库访问量太大(读写混合)
1.1.2 Memcached + 垂直同步 + 读写分离
image.png发展过程:
优化数据结构和索引-->文件缓存(IO)-->Memcached(当时最热门的技术)
1.1.3 分库分表 + 水平拆分 + MySQL集群
早些年MyISAM:表锁,查用户,会把整个表锁住
InnoDb:行锁
分库分表来解决写的压力
1.1.4 NoSQL
图形 BSON(二进制的JSON)
数据量大,文件图片很多,数据库的表很大。效率低。
目前一个基本互联网项目的基本架构
image.png
1.1.5 为啥要用NoSQL
用户的个人信息,,社交网络,地理位置。用户自己产生的数据,用户日志呈爆发式增长,NoSQL可以很好的处理以上情况。
1.2 什么是Nosql
NoSQL(Not Only SQL),意思是"不仅仅是 SQL",指的是非关系型数据库,是对不同于传统的关系型数据库的数据库管理系统的统称。
NoSQL 用于超大规模数据的存储。这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展。
image.png
1.3 NoSQL的四大分类
image.png- KV键值对:Redis
- 文档数据类型:
- MongoDB
- MongoDB是基于分布式文件存储的数据库,主要用来处理大量的文档
- MongoDB是介于关系型数据库和菲关系新数据库之间的数据库。
- 列存储数据库:
- HBase
- 分布式文件系统
- 图关系数据库:
- Neo4J, InfoGrid, Infinite Graph
2. Redis入门:
Redis是什么:Remote Dictionary Server,远程字典服务,Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。
2.1 windows Redis 安装
这里我选择的是x64-3.2.100,下载的时候下载msi(不要下载zip的压缩包)
如果你是和我一样通过msi文件的安装,你可以在计算机管理→服务与应用程序→服务 看到Redis正在运行
image你也可以将它停止,(不停止会出现错误代码为18012的错误,表示本机端口6379被占用)
然后在cmd窗口进入Redis的安装路径的根目录 (C:\Program Files\Redis\)
输入命令redis-server.exe redis.windows.conf,出现下图证明Redis服务启动成功
image2.1.1 使用redis客户端来连接redis server
image.png2.2 Linux Redis 安装
2020最新Linux系统发行版ContOS7演示安装Redis
2.3 Benchmark 测试 redis 性能
./redis-benchmark -h localhost -p 6379 -c 100 -n 100000
image.png
2.4 Redis 基本知识
Redis 启动server:
cd /usr/local/bin
./redis-server conf/redis.conf
Redis启动客户端:
[root@localhost bin] ./redis-cli -p 6379
127.0.0.1:6379> ping
PONG
127.0.0.1:6379>
选择数据库和清空数据库
- flushdb 清空当前数据库
- flushall 清空所有16个数据库
127.0.0.1:6379> select 3
OK
127.0.0.1:6379[3]> DBSIZE
(integer) 0
127.0.0.1:6379> keys *
1) "myhash:{tag}"
2) "name"
3) "key:{tag}:__rand_int__"
4) "mylist:{tag}"
5) "counter:{tag}:__rand_int__"
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> DBSIZE
(integer) 0
127.0.0.1:6379> keys *
(empty array)
Redis是单线程的!
Redis是基于内存操作的,CPU不是redis的性能瓶颈,Redis的瓶颈是根据机器的内存和网络带宽决定的
为什么是单线程还这么快。
Redis是C语言写的,每秒的QPS为100000+,不必Memecache差。
核心:redis是将所有的数据全部放在内存里,所以说使用单线程去操作效率就是最高的,多线程的CPU是上下文会切换,耗时的操作,对内存系统来说,没有上下文切换的效率就是最高的,多次读写都是在一个CPU上的,这就是内存系统的最佳方案。
3 Redis 数据类型:
3.1 String类型
- key操作:
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> set name 123
OK
127.0.0.1:6379[1]> set age 12
OK
127.0.0.1:6379[1]> keys *
1) "age"
2) "name"
127.0.0.1:6379[1]> EXISTS name
(integer) 1
127.0.0.1:6379[1]> EXISTS name1
(integer) 0
127.0.0.1:6379[1]> move name 2
(integer) 1
127.0.0.1:6379[1]> keys
(error) ERR wrong number of arguments for 'keys' command
127.0.0.1:6379[1]> keys *
1) "age"
- 设置过期时间
127.0.0.1:6379[1]> keys *
1) "age"
2) "name"
127.0.0.1:6379[1]> EXPIRE name 12
(integer) 1
127.0.0.1:6379[1]> ttl name
(integer) 8
127.0.0.1:6379[1]> ttl name
(integer) 6
127.0.0.1:6379[1]> type age #查看类型
string
- 计算长度
[root@VM-0-6-centos bin]# ./redis-cli -p 6379
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> keys *
1) "age"
127.0.0.1:6379[1]> append age index #append value, key不存在就set key
(integer) 7
127.0.0.1:6379[1]> keys *
1) "age"
127.0.0.1:6379[1]> get age
"12index"
127.0.0.1:6379[1]> STRLEN age #计算长度
- 增加 减少 数值
[root@VM-0-6-centos bin]# ./redis-cli -p 6379
127.0.0.1:6379> set age 1
OK
127.0.0.1:6379> incr age
\(integer) 2
127.0.0.1:6379> incr age
(integer) 3
127.0.0.1:6379> decr age
(integer) 2
127.0.0.1:6379[1]> INCRBY name 10
(integer) 10
127.0.0.1:6379[1]> INCRBY name 10
(integer) 20
- 字符串截取和替换
127.0.0.1:6379> set name "hello.syf niubi"
OK
127.0.0.1:6379> get name
"hello.syf niubi"
127.0.0.1:6379> GETRANGE name 1 12
"ello.syf niu"
127.0.0.1:6379> GETRANGE name 0 -1 # 获取整个字符串
"hello.syf niubi"
127.0.0.1:6379> SETRANGE name 1 123456
(integer) 15
127.0.0.1:6379> get name
"h123456yf niubi"
- setex : 将值 value 关联到 key ,并将 key 的生存时间设为 seconds (以秒为单位)。如果 key 已经存在, SETEX 命令将覆写旧值。
- setnx : 只在键 key 不存在的情况下, 将键 key 的值设置为 value 。若键 key 已经存在, 则 SETNX 命令不做任何动作。在分布式锁中将常常使用。
127.0.0.1:6379> set key3 60
OK
127.0.0.1:6379> setex key3 30 hello
OK
127.0.0.1:6379> get key3
"hello"
127.0.0.1:6379> setnx mykey "redis"
(integer) 1
127.0.0.1:6379> get mykey
"redis"
127.0.0.1:6379> setnx mykey "mongoDB" #只在键 key 不存在的情况下, 将键 key 的值设置为 value 。若键 key 已经存在, 则 SETNX 命令不做任何动作。
(integer) 0
127.0.0.1:6379> get mykey
"redis"
- mset
- msetnx
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3
OK
127.0.0.1:6379> keys *
1) "k2"
2) "k3"
3) "name"
4) "mykey"
5) "k1"
127.0.0.1:6379> msetnx k1 v1 k4 v4 # 原子性 要么一起成功 要么一起失败
(integer) 0
127.0.0.1:6379> keys *
1) "k2"
2) "k3"
3) "name"
4) "mykey"
保存对象:
Redis Getset 命令:Redis Getset 命令用于设置指定 key 的值,并返回 key 的旧值。
3.2 list(列表)
- 基本操作
127.0.0.1:6379> LPUSH list one #List里面塞值
(integer) 1
127.0.0.1:6379> LPUSH list two
(integer) 2
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
2) "one"
127.0.0.1:6379> lpop list #移除列表的第一个元素
"two"
127.0.0.1:6379> LRANGE list 0 -1
1) "one"
127.0.0.1:6379> LPUSH list two
(integer) 2
127.0.0.1:6379> rpop list #移除列表的最后个元素
"one"
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
- lindex 通过下标获取某个值
- llen 返回列表的长度
- LREM key count value: 根据参数 count 的值,移除列表中与参数 value 相等的元素。
127.0.0.1:6379> lindex list 0
127.0.0.1:6379> llen list
(integer) 1
redis> LREM greet 2 morning # 移除从表头到表尾,最先发现的两个 morning
(integer) 2 # 两个元素被移除
- rpoplpush: 移除列表的最后一个元素,并将它添加到另一个list的最左边
127.0.0.1:6379> rpush list a
(integer) 2
127.0.0.1:6379> rpush list b
(integer) 3
127.0.0.1:6379> rpush list c
(integer) 4
127.0.0.1:6379> rpoplpush list mylist
-
LSET key index value
将列表 key 下标为 index 的元素的值设置为 value 。
当 index 参数超出范围,或对一个空列表( key 不存在)进行 LSET 时,返回一个错误。 -
LINSERT key BEFORE|AFTER pivot value
将值 value 插入到列表 key 当中,位于值 pivot 之前或之后。
当 pivot 不存在于列表 key 时,不执行任何操作。
当 key 不存在时, key 被视为空列表,不执行任何操作。
如果 key 不是列表类型,返回一个错误。
总结
- 消息队列:Lpush Rpop
- 栈:Lpush Lpop
3.3 Set对象
3.2.1 基本操作
127.0.0.1:6379> sadd myset "hello" # 添加set成员
(integer) 1
127.0.0.1:6379> sadd myset "syf"
(integer) 1
127.0.0.1:6379> sadd myset "xule"
(integer) 1
127.0.0.1:6379> smembers myset
1) "xule"
2) "hello"
3) "syf"
127.0.0.1:6379> sadd myset "xule"
(integer) 0
127.0.0.1:6379> smembers myset # 查看指定set的所有值
1) "xule"
2) "hello"
3) "syf"
127.0.0.1:6379> sismember myset syf # 查看是否包含某个元素
(integer) 1
127.0.0.1:6379> sismember myset syf1
(integer) 0
127.0.0.1:6379> scard myset # 获取个数
127.0.0.1:6379> srem myset xule # 移除某一个元素
127.0.0.1:6379> srandmember myset # 随机抽选出一个元素
127.0.0.1:6379> srandmember myset 2 # 随机抽选出指定个数的个元素
127.0.0.1:6379> spop myset 1 # 随机抽移除指定个数的个元素
127.0.0.1:6379> smove myset myset2 haha # 移动到另外一个集合
(integer) 1
127.0.0.1:6379> smembers myset2
1) "haha"
3.2.2 数字集合类
- 差集
- 交集
- 并集
127.0.0.1:6379> sadd key1 a
(integer) 1
127.0.0.1:6379> sadd key1 b
(integer) 1
127.0.0.1:6379> sadd key1 c
(integer) 1
127.0.0.1:6379> sadd key2 c
(integer) 1
127.0.0.1:6379> sadd key2 b
(integer) 1
127.0.0.1:6379> sadd key2 a
(integer) 1
127.0.0.1:6379> sadd key2 d
(integer) 1
127.0.0.1:6379> sadd key1 e
(integer) 1
127.0.0.1:6379> sdiff key1 key2 # Redis Sdiff 命令返回第一个集合与其他集合之间的差异,也可以认为说第一个集合中独有的元素。
1) "e"
127.0.0.1:6379> sinter key1 key2
1) "c"
2) "a"
3) "b"
127.0.0.1:6379> sunion key1 key2
1) "c"
2) "a"
3) "e"
4) "b"
5) "d"
127.0.0.1:6379> sdiff key1 key2
1) "e"
127.0.0.1:6379> smembers key1
1) "c"
2) "a"
3) "e"
4) "b"
127.0.0.1:6379> smembers key2
1) "a"
2) "c"
3) "b"
3.4 Hash对象
127.0.0.1:6379> hset myhash key1 value1
(integer) 1
127.0.0.1:6379> hget myhash key1
"value1"
127.0.0.1:6379> hset myhash key1 value2
(integer) 0
127.0.0.1:6379> hget myhash key1
"value2"
127.0.0.1:6379> hgetall myhash
1) "key1"
2) "value2"
127.0.0.1:6379> hdel myhash key1
(integer) 1
127.0.0.1:6379> hgetall myhash
(empty array)
127.0.0.1:6379> hlen myhash1 #获取长度
1
127.0.0.1:6379> hset myhash key1 v1 key2 v2 key3 v3 #多个值同时set
(integer) 3
127.0.0.1:6379> hgetall myhash
1) "key1"
2) "v1"
3) "key2"
4) "v2"
5) "key3"
6) "v3"
127.0.0.1:6379> hlen myhash
(integer) 3
127.0.0.1:6379> hexists myhash key2 #判断指定字段是否存在
127.0.0.1:6379> hvals myhash
1) "v1"
2) "v2"
3) "v3"
网友评论