Nosql
为什么要用nosql?
NoSQL概念随着web2.0的快速发展,非关系型、分布式数据存储得到了快速的发展,它们不保证关系数据的ACID特性。NoSQL概念在2009年被提了出来。NoSQL最常见的解释是“non-relational”,“Not Only SQL”也被很多人接受。(“NoSQL”一词最早于1998年被用于一个轻量级的关系数据库的名字。)
NoSQL被我们用得最多的当数key-value存储,当然还有其他的文档型的、列存储、图型数据库、xml数据库等。在NoSQL概念提出之前,这些数据库就被用于各种系统当中,但是却很少用于web互联网应用。比如cdb、qdbm、bdb数据库。
什么是nosql
NoSQL(Not only SQL)是对不同于传统的关系数据库的数据库管理系统的统称,即广义地来说可以把所有不是关系型数据库的数据库统称为NoSQL。
NoSQL 数据库专门构建用于特定的数据模型,并且具有灵活的架构来构建现代应用程序。NoSQL 数据库使用各种数据模型来访问和管理数据。这些类型的数据库专门针对需要大数据量、低延迟和灵活数据模型的应用程序进行了优化,这是通过放宽其他数据库的某些数据一致性限制来实现的。
nosql特点
- 方便扩展(数据之间没有关系)
- 大数据量高性能(一秒写8W次,读11W次,nosql的缓存记录级,是一种细粒度的缓存,性能高)
- 数据类型多样性
- string
- hash
- list
- set
- zset
- geospatial
- hyperloglog
- bitmaps
Redis
概述
定义
Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
能做什么
- 内存存储持久化(rdb,aof)
- 效率高 高数缓存
- 发布订阅分析
- 地图信息系统
- 计时器,计数器(浏览量)
- …
测试性能
redis-benchmark是官方自带的压力测试工具
1 | redis-benchmark -h localhost -p 6379 -c 100 -n 1000 #不是在客户端 而是在redis目录下 100并发1000请求 |
基础知识
- redis默认有16个数据库 可以用select切换数据库
- flushdb / flushall 删库跑路
- redis是单线程的,基于内存操作,cpu不是redis的性能瓶颈,而是机器的内存和网络带宽
- QPS 10W+
- redis将所有的数据放在内存中处理,所以用单线程操作最快
Redis 键(key) 命令
命令 | 描述 |
---|---|
Redis Type 命令 | 返回 key 所储存的值的类型。 |
Redis PEXPIREAT 命令 | 设置 key 的过期时间亿以毫秒计。 |
Redis PEXPIREAT 命令 | 设置 key 过期时间的时间戳(unix timestamp) 以毫秒计 |
Redis Rename 命令 | 修改 key 的名称 |
Redis PERSIST 命令 | 移除 key 的过期时间,key 将持久保持。 |
Redis Move 命令 | 将当前数据库的 key 移动到给定的数据库 db 当中。 |
Redis RANDOMKEY 命令 | 从当前数据库中随机返回一个 key 。 |
Redis Dump 命令 | 序列化给定 key ,并返回被序列化的值。 |
Redis TTL 命令 | 以秒为单位,返回给定 key 的剩余生存时间(TTL, time to live)。 |
Redis Expire 命令 | seconds 为给定 key 设置过期时间。 |
Redis DEL 命令 | 该命令用于在 key 存在是删除 key。 |
Redis Pttl 命令 | 以毫秒为单位返回 key 的剩余的过期时间。 |
Redis Renamenx 命令 | 仅当 newkey 不存在时,将 key 改名为 newkey 。 |
Redis EXISTS 命令 | 检查给定 key 是否存在。 |
Redis Expireat 命令 | EXPIREAT 的作用和 EXPIRE 类似,都用于为 key 设置过期时间。 不同在于 EXPIREAT 命令接受的时间参数是 UNIX 时间戳(unix timestamp)。 |
Redis Keys 命令 | 查找所有符合给定模式( pattern)的 key 。 |
Redis 字符串(String) 命令
命令 | 描述 |
---|---|
Redis Setnx 命令 | 只有在 key 不存在时设置 key 的值。 |
Redis Getrange 命令 | 返回 key 中字符串值的子字符 |
Redis Mset 命令 | 同时设置一个或多个 key-value 对。 |
Redis Setex 命令 | 将值 value 关联到 key ,并将 key 的过期时间设为 seconds (以秒为单位)。 |
Redis SET 命令 | 设置指定 key 的值 |
Redis Get 命令 | 获取指定 key 的值。 |
Redis Getbit 命令 | 对 key 所储存的字符串值,获取指定偏移量上的位(bit)。 |
Redis Setbit 命令 | 对 key 所储存的字符串值,设置或清除指定偏移量上的位(bit)。 |
Redis Decr 命令 | 将 key 中储存的数字值减一。 |
Redis Decrby 命令 | key 所储存的值减去给定的减量值(decrement) 。 |
Redis Strlen 命令 | 返回 key 所储存的字符串值的长度。 |
Redis Msetnx 命令 | 同时设置一个或多个 key-value 对,当且仅当所有给定 key 都不存在。 |
Redis Incrby 命令 | 将 key 所储存的值加上给定的增量值(increment) 。 |
Redis Incrbyfloat 命令 | 将 key 所储存的值加上给定的浮点增量值(increment) 。 |
Redis Setrange 命令 | 用 value 参数覆写给定 key 所储存的字符串值,从偏移量 offset 开始。 |
Redis Psetex 命令 | 这个命令和 SETEX 命令相似,但它以毫秒为单位设置 key 的生存时间,而不是像 SETEX 命令那样,以秒为单位。 |
Redis Append 命令 | 如果 key 已经存在并且是一个字符串, APPEND 命令将 value 追加到 key 原来的值的末尾。 |
Redis Getset 命令 | 将给定 key 的值设为 value ,并返回 key 的旧值(old value)。 |
Redis Mget 命令 | 获取所有(一个或多个)给定 key 的值。 |
Redis Incr 命令 | 将 key 中储存的数字值增一。 |
Redis 哈希(Hash) 命令
命令 | 描述 |
---|---|
Redis Hmset 命令 | 同时将多个 field-value (域-值)对设置到哈希表 key 中。 |
Redis Hmget 命令 | 获取所有给定字段的值 |
Redis Hset 命令 | 将哈希表 key 中的字段 field 的值设为 value 。 |
Redis Hgetall 命令 | 获取在哈希表中指定 key 的所有字段和值 |
Redis Hget 命令 | 获取存储在哈希表中指定字段的值/td> |
Redis Hexists 命令 | 查看哈希表 key 中,指定的字段是否存在。 |
Redis Hincrby 命令 | 为哈希表 key 中的指定字段的整数值加上增量 increment 。 |
Redis Hlen 命令 | 获取哈希表中字段的数量 |
Redis Hdel 命令 | 删除一个或多个哈希表字段 |
Redis Hvals 命令 | 获取哈希表中所有值 |
Redis Hincrbyfloat 命令 | 为哈希表 key 中的指定字段的浮点数值加上增量 increment 。 |
Redis Hkeys 命令 | 获取所有哈希表中的字段 |
Redis Hsetnx 命令 | 只有在字段 field 不存在时,设置哈希表字段的值。 |
Redis 列表(List) 命令
命令 | 描述 |
---|---|
Redis Lindex 命令 | 通过索引获取列表中的元素 |
Redis Rpush 命令 | 在列表中添加一个或多个值 |
Redis Lrange 命令 | 获取列表指定范围内的元素 |
Redis Rpoplpush 命令 | 移除列表的最后一个元素,并将该元素添加到另一个列表并返回 |
Redis Blpop 命令 | 移出并获取列表的第一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 |
Redis Brpop 命令 | 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 |
Redis Brpoplpush 命令 | 从列表中弹出一个值,将弹出的元素插入到另外一个列表中并返回它; 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止。 |
Redis Lrem 命令 | 移除列表元素 |
Redis Llen 命令 | 获取列表长度 |
Redis Ltrim 命令 | 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。 |
Redis Lpop 命令 | 移出并获取列表的第一个元素 |
Redis Lpushx 命令 | 将一个或多个值插入到已存在的列表头部 |
Redis Linsert 命令 | 在列表的元素前或者后插入元素 |
Redis Rpop 命令 | 移除并获取列表最后一个元素 |
Redis Lset 命令 | 通过索引设置列表元素的值 |
Redis Lpush 命令 | 将一个或多个值插入到列表头部 |
Redis Rpushx 命令 | 为已存在的列表添加值 |
Redis 集合(Set) 命令
命令 | 描述 |
---|---|
Redis Sunion 命令 | 返回所有给定集合的并集 |
Redis Scard 命令 | 获取集合的成员数 |
Redis Srandmember 命令 | 返回集合中一个或多个随机数 |
Redis Smembers 命令 | 返回集合中的所有成员 |
Redis Sinter 命令 | 返回给定所有集合的交集 |
Redis Srem 命令 | 移除集合中一个或多个成员 |
Redis Smove 命令 | 将 member 元素从 source 集合移动到 destination 集合 |
Redis Sadd 命令 | 向集合添加一个或多个成员 |
Redis Sismember 命令 | 判断 member 元素是否是集合 key 的成员 |
Redis Sdiffstore 命令 | 返回给定所有集合的差集并存储在 destination 中 |
Redis Sdiff 命令 | 返回给定所有集合的差集 |
Redis Sscan 命令 | 迭代集合中的元素 |
Redis Sinterstore 命令 | 返回给定所有集合的交集并存储在 destination 中 |
Redis Sunionstore 命令 | 所有给定集合的并集存储在 destination 集合中 |
Redis Spop 命令 | 移除并返回集合中的一个随机元素 |
Redis 有序集合(sorted set) 命令
命令 | 描述 |
---|---|
Redis Zrevrank 命令 | 返回有序集合中指定成员的排名,有序集成员按分数值递减(从大到小)排序 |
Redis Zlexcount 命令 | 在有序集合中计算指定字典区间内成员数量 |
Redis Zunionstore 命令 | 计算给定的一个或多个有序集的并集,并存储在新的 key 中 |
Redis Zremrangebyrank 命令 | 移除有序集合中给定的排名区间的所有成员 |
Redis Zcard 命令 | 获取有序集合的成员数 |
Redis Zrem 命令 | 移除有序集合中的一个或多个成员 |
Redis Zinterstore 命令 | 计算给定的一个或多个有序集的交集并将结果集存储在新的有序集合 key 中 |
Redis Zrank 命令 | 返回有序集合中指定成员的索引 |
Redis Zincrby 命令 | 有序集合中对指定成员的分数加上增量 increment |
Redis Zrangebyscore 命令 | 通过分数返回有序集合指定区间内的成员 |
Redis Zrangebylex 命令 | 通过字典区间返回有序集合的成员 |
Redis Zscore 命令 | 返回有序集中,成员的分数值 |
Redis Zremrangebyscore 命令 | 移除有序集合中给定的分数区间的所有成员 |
Redis Zscan 命令 | 迭代有序集合中的元素(包括元素成员和元素分值) |
Redis Zrevrangebyscore 命令 | 返回有序集中指定分数区间内的成员,分数从高到低排序 |
Redis Zremrangebylex 命令 | 移除有序集合中给定的字典区间的所有成员 |
Redis Zrevrange 命令 | 返回有序集中指定区间内的成员,通过索引,分数从高到底 |
Redis Zrange 命令 | 通过索引区间返回有序集合成指定区间内的成员 |
Redis Zcount 命令 | 计算在有序集合中指定区间分数的成员数 |
Redis Zadd 命令 | 向有序集合添加一个或多个成员,或者更新已存在成员的分数 |
Redis 连接 命令
命令 | 描述 |
---|---|
Redis Echo 命令 | 打印字符串 |
Redis Select 命令 | 切换到指定的数据库 |
Redis Ping 命令 | 查看服务是否运行 |
Redis Quit 命令 | 关闭当前连接 |
Redis Auth 命令 | 验证密码是否正确 |
Redis 服务器 命令
命令 | 描述 |
---|---|
Redis Client Pause 命令 | 在指定时间内终止运行来自客户端的命令 |
Redis Debug Object 命令 | 获取 key 的调试信息 |
Redis Flushdb 命令 | 删除当前数据库的所有key |
Redis Save 命令 | 异步保存数据到硬盘 |
Redis Showlog 命令 | 管理 redis 的慢日志 |
Redis Lastsave 命令 | 返回最近一次 Redis 成功将数据保存到磁盘上的时间,以 UNIX 时间戳格式表示 |
Redis Config Get 命令 | 获取指定配置参数的值 |
Redis Command 命令 | 获取 Redis 命令详情数组 |
Redis Slaveof 命令 | 将当前服务器转变为指定服务器的从属服务器(slave server) |
Redis Debug Segfault 命令 | 让 Redis 服务崩溃 |
Redis Flushall 命令 | 删除所有数据库的所有key |
Redis Dbsize 命令 | 返回当前数据库的 key 的数量 |
Redis Bgrewriteaof 命令 | 异步执行一个 AOF(AppendOnly File) 文件重写操作 |
Redis Cluster Slots 命令 | 获取集群节点的映射数组 |
Redis Config Set 命令 | 修改 redis 配置参数,无需重启 |
Redis Command Info 命令 | 获取指定 Redis 命令描述的数组 |
Redis Shutdown 命令 | 异步保存数据到硬盘,并关闭服务器 |
Redis Sync 命令 | 用于复制功能(replication)的内部命令 |
Redis Client Kill 命令 | 关闭客户端连接 |
Redis Role 命令 | 返回主从实例所属的角色 |
Redis Monitor 命令 | 实时打印出 Redis 服务器接收到的命令,调试用 |
Redis Command Getkeys 命令 | 获取给定命令的所有键 |
Redis Client Getname 命令 | 获取连接的名称 |
Redis Config Resetstat 命令 | 重置 INFO 命令中的某些统计数据 |
Redis Command Count 命令 | 获取 Redis 命令总数 |
Redis Time 命令 | 返回当前服务器时间 |
Redis Info 命令 | 获取 Redis 服务器的各种信息和统计数值 |
Redis Config rewrite 命令 | 对启动 Redis 服务器时所指定的 redis.conf 配置文件进行改写 |
Redis Client List 命令 | 获取连接到服务器的客户端连接列表 |
Redis Client Setname 命令 | 设置当前连接的名称 |
Redis Bgsave 命令 | 在后台异步保存当前数据库的数据到磁盘 |
Redis 脚本 命令
命令 | 描述 |
---|---|
Redis Script kill 命令 | 杀死当前正在运行的 Lua 脚本。 |
Redis Script Load 命令 | 将脚本 script 添加到脚本缓存中,但并不立即执行这个脚本。 |
Redis Eval 命令 | 执行 Lua 脚本。 |
Redis Evalsha 命令 | 执行 Lua 脚本。 |
Redis Script Exists 命令 | 查看指定的脚本是否已经被保存在缓存当中。 |
Redis Script Flush 命令 | 从脚本缓存中移除所有脚本。 |
Redis 事务 命令
命令 | 描述 |
---|---|
Redis Exec 命令 | 执行所有事务块内的命令。 |
Redis Watch 命令 | 监视一个(或多个) key ,如果在事务执行之前这个(或这些) key 被其他命令所改动,那么事务将被打断。 |
Redis Discard 命令 | 取消事务,放弃执行事务块内的所有命令。 |
Redis Unwatch 命令 | 取消 WATCH 命令对所有 key 的监视。 |
Redis Multi 命令 | 标记一个事务块的开始。 |
Redis HyperLogLog 命令
命令 | 描述 |
---|---|
Redis Pgmerge 命令 | 将多个 HyperLogLog 合并为一个 HyperLogLog |
Redis Pfadd 命令 | 添加指定元素到 HyperLogLog 中。 |
Redis Pfcount 命令 | 返回给定 HyperLogLog 的基数估算值。 |
Redis 发布订阅 命令
命令 | 描述 |
---|---|
Redis Unsubscribe 命令 | 指退订给定的频道。 |
Redis Subscribe 命令 | 订阅给定的一个或多个频道的信息。 |
Redis Pubsub 命令 | 查看订阅与发布系统状态。 |
Redis Punsubscribe 命令 | 退订所有给定模式的频道。 |
Redis Publish 命令 | 将信息发送到指定的频道。 |
Redis Psubscribe 命令 | 订阅一个或多个符合给定模式的频道。 |
Redis 地理位置(geo) 命令
命令 | 描述 |
---|---|
Redis GEOHASH 命令 | 返回一个或多个位置元素的 Geohash 表示 |
Redis GEOPOS 命令 | 从key里返回所有给定位置元素的位置(经度和纬度) |
Redis GEODIST 命令 | 返回两个给定位置之间的距离 |
Redis GEORADIUS 命令 | 以给定的经纬度为中心, 找出某一半径内的元素 |
Redis GEOADD 命令 | 将指定的地理空间位置(纬度、经度、名称)添加到指定的key中 |
Redis GEORADIUSBYMEMBER 命令 | 找出位于指定范围内的元素,中心点是由给定的位置元素决定 |
持久化
RDB
什么是RDB
在指定时间间隔后,将内存中的数据集快照写入数据库 ;在恢复时候,直接读取快照文件,进行数据的恢复 ;
默认情况下, Redis 将数据库快照保存在名字为 dump.rdb的二进制文件中。文件名可以在配置文件中进行自定义。
工作原理
在进行 RDB 的时候,redis 的主线程是不会做 io 操作的,主线程会 fork 一个子线程来完成该操作;
Redis 调用forks。同时拥有父进程和子进程。
子进程将数据集写入到一个临时 RDB 文件中。
当子进程完成对新 RDB 文件的写入时,Redis 用新 RDB 文件替换原来的 RDB 文件,并删除旧的 RDB 文件。
这种工作方式使得 Redis 可以从写时复制(copy-on-write)机制中获益(因为是使用子进程进行写操作,而父进程依然可以接收来自客户端的请求。)
触发机制
- save的规则满足的情况下,会自动触发rdb原则
- 执行flushall命令,也会触发我们的rdb原则
- 退出redis,也会自动产生rdb文件
save
使用 save 命令,会立刻对当前内存中的数据进行持久化 ,但是会阻塞,也就是不接受其他操作了;
由于 save 命令是同步命令,会占用Redis的主进程。若Redis数据非常多时,save命令执行速度会非常慢,阻塞所有客户端的请求。
flushall命令
flushall 命令也会触发持久化 ;
bgsave命令
bgsave 是异步进行,进行持久化的时候,redis 还可以将继续响应客户端请求 ;
优点:
适合大规模的数据恢复
对数据的完整性要求不高
缺点
- 需要一定的时间间隔进行操作,如果redis意外宕机了,这个最后一次修改的数据就没有了。
- fork进程的时候,会占用一定的内容空间。
AOF
什么是AOF
快照功能(RDB)并不是非常耐久(durable): 如果 Redis 因为某些原因而造成故障停机, 那么服务器将丢失最近写入、以及未保存到快照中的那些数据。 从 1.1 版本开始, Redis 增加了一种完全耐久的持久化方式: AOF 持久化。
优点
- 每一次修改都会同步,文件的完整性会更加好
- 每秒同步一次,可能会丢失一秒的数据
- 从不同步,效率最高
缺点
- 相对于数据文件来说,aof远远大于rdb,修复速度比rdb慢!
- Aof运行效率也要比rdb慢,所以我们redis默认的配置就是rdb持久化
Redis主从复制
概念
主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(Master/Leader),后者称为从节点(Slave/Follower), 数据的复制是单向的!只能由主节点复制到从节点(主节点以写为主、从节点以读为主)。
默认情况下,每台Redis服务器都是主节点,一个主节点可以有0个或者多个从节点,但每个从节点只能由一个主节点。
作用
数据冗余:主从复制实现了数据的热备份,是持久化之外的一种数据冗余的方式。
故障恢复:当主节点故障时,从节点可以暂时替代主节点提供服务,是一种服务冗余的方式
负载均衡:在主从复制的基础上,配合读写分离,由主节点进行写操作,从节点进行读操作,分担服务器的负载;尤其是在多读少写的场景下,通过多个从节点分担负载,提高并发量。
高可用基石:主从复制还是哨兵和集群能够实施的基础。
为什么使用集群
单台服务器难以负载大量的请求
单台服务器故障率高,系统崩坏概率大
单台服务器内存容量有限。
缓冲穿透&缓冲击穿&缓冲雪崩
缓冲穿透
概念
在默认情况下,用户请求数据时,会先在缓存(Redis)中查找,若没找到即缓存未命中,再在数据库中进行查找,数量少可能问题不大,可是一旦大量的请求数据(例如秒杀场景)缓存都没有命中的话,就会全部转移到数据库上,造成数据库极大的压力,就有可能导致数据库崩溃。网络安全中也有人恶意使用这种手段进行攻击被称为洪水攻击。
解决方法
- 布隆过滤器
- 缓存空对象
缓冲击穿
概念
相较于缓存穿透,缓存击穿的目的性更强,一个存在的key,在缓存过期的一刻,同时有大量的请求,这些请求都会击穿到DB,造成瞬时DB请求量大、压力骤增。这就是缓存被击穿,只是针对其中某个key的缓存不可用而导致击穿,但是其他的key依然可以使用缓存响应。
比如热搜排行上,一个热点新闻被同时大量访问就可能导致缓存击穿。
解决方法
- 设置热点数据永不过期
- 加互斥锁
缓冲雪崩
概念
大量的key设置了相同的过期时间,导致在缓存在同一时刻全部失效,造成瞬时DB请求量大、压力骤增,引起雪崩。
解决方法
redis高可用
这个思想的含义是,既然redis有可能挂掉,那我多增设几台redis,这样一台挂掉之后其他的还可以继续工作,其实就是搭建的集群
限流降级
这个解决方案的思想是,在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和写缓存,其他线程等待。
数据预热
数据加热的含义就是在正式部署之前,我先把可能的数据先预先访问一遍,这样部分可能大量访问的数据就会加载到缓存中。在即将发生大并发访问前手动触发加载缓存不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。