Redis(待更新)

数据库架构设计发展史

单库:随着访问量增加出现性能问题

缓存:通过缓存,缓解数据库压力 优化数据结构和索引

读写分离:数据写入压力增大,主从复制和读写分离进入视野

分库分表:主库写压力过高,开始使用innoDB引擎以及分库分表技术

垂直拆分:按照业务模块功能进行垂直拆分,分别读写独立的数据库

水平拆分:mycat作为数据库中间件,统一连接mycat对外提供的一个地址,联系所有后端的数据库

Nosql初识

Nosql=Non-Relational Sql

优势:易扩展(去掉关系型特性 容易扩展)、大数据高性能(数据结构简单 细粒度的cache)、灵活的数据模型(随时存储自定义的数据格式,不需要事先声明字段)、高可用(可以很方便的实现高可用架构)

CAP定理

一致性Consistency:所有节点在同一时间具有相同数据

可用性Availability:保证每个请求不管成功失败都有响应

分割容忍Partition tolerance:系统中任意信息的丢失或失败不会影响系统的继续运作

CAP核心是:一个分布式系统不可能同时很好的满足这三个需求

CA-单点集群

CP-满足一致性 分区容忍性的系统

AP-满足可用性 分区容忍性的系统

Nosql分类

k-v:Memcache、Redis——支持快速查找,常用于缓存

列族:Hbase——按列存储,方便结构化和压缩

文档:MongoDB——用类似json的格式存储,可以对某些字段建立索引

图:Neo4j——图形关系的解决方案

Redis入门

redis官网CRUG网站 练习网站Try Redis

redis启用命令(linux下)

redis-server 启动服务端 + 指定配置文件

redis-cli -p 6379 启动客户端 6379是redis默认端口 通过-p制定端口号

输入ping 返回pong代表链接ok

set key1 "asd" 设置key1的值是"asd"

get key1 返回key1的值

exit 退出客户端

shutdown 退出服务端

redis-benchmark 压测命令 测试不同指令下 十万次请求多长时间完成

redis操作数据库命令

keys * 查看当前数据库所有的key值

keys ?模糊查询 ?——相当于占位符

select 1 切换到1号数据库

dbsize 展示数据库中key个数

flushdb 删当前库的操作

flushall 删除所有数据库的操作

redis键值操作命令

exists + key 判断键值是否存在

type + key 显示当前键值存储的数据类型

expire + key + seconds 设置key值的有效时间为n秒 过了有效时间 key值被删除

pexpire + key + 毫秒 设置key值的有效时间为n毫秒

ttl + key 查看当前key有效时间剩余多少秒

pttl + key 查看当前key有效时间剩余多少毫秒

当返回-2时 说明此key值不存在

当返回-1时 说明key没有设置有效时间

persist + key 设置数据一直有效(去除有效时间)

del + key 删除某一个key

rename + key1 + key2 给key1重命名为key2

randomkey 随机返回一个key值

move + key +(0~15)把当前数据库的指定key移到指定数据库

批量操作

mget key1 key2 key3··· 批量取值

mset key1 str1 key2 str2···批量设置键值

msetnx 使用方法同上

整合命令

setnx key str 如果键值不存在 则创建

setex key time str 创建字符串的时候 设置其有效时间

getset 进行set命令 返回原来的值

Redis数据类型

String字符串

内部结构类似ArrayList 长度大小<1mb时 直接加倍 ;如果大于1mb 一次只扩1mb 直到512mb最大容量

命令

strlen + key查看字符串的长度

append + key + "" 拼接后缀 返回字符串的长度

getrange key start end 返回key的值 从start到end索引号 类似substring

setrange key start newStr 从start开始 开始替换为新的字符串

当value值是整数时 可以通过命令直接进行数学运算

incr 自增 返回最新的值 decr 自减 返回最新的值

incrby 增加指定的值 decrby 减少指定的值

list列表

底层是快速链表 当元素较少的时候 用连续的内存压缩成压缩列表ziplist;当元素较多时,改成quicklist,也就是将多个ziplist使用双向指针串起来使用,以减少内存的碎片化

存取操作:push pop range

lpush:从左侧存入数据---》栈的结构

rpush:从右侧存入数据---》队列结构

lrange:范围内查看数据 lange key start end

lpop:从左侧弹出一个元素

rpop:从右侧弹出一个元素

对集合的操作

llen 查看长度

lindex 获取某一个位置的值 下角标从0开始

lrem 删除n个value的值 lrem key n value

ltrim 截取一部分重新赋值给key ltrim key start end

linsert 在指定值后面插入值 linsert key before/after oldvalue newvalue

lpushx 把数据插入到头部

rpushx 把数据插入到尾部

lset 把指定位置的值改为新值 lset key index value

hash哈希

底层实现结构是数据+链表的二维结构,与hashmap类似。但rehash方式不同 hashmap是一次全部rehash,耗时较高;redis为了优化性能,采取渐进式rehash策略:同时保留新旧两个hash结构,然后逐步搬迁,搬迁后再取而代之。

存取数据

hset map1 key1 value1给map1中增加键值对key-value

hget map1 key1取map1中key为key1 的值

hmset hash1 key2 value2 key3 value3批量存值

hmet hash1 key1 key2 批量取值

hsetnx 如果不存在就set新的key值

遍历数据

hkeys map1 取map1中所有的key

hvals map1 取map1中所有的value

hlen 查看长度

hgetall 返回全部的key-value

hexists 判断是否存在某个key

变更数据

hdel hash1 key1 删除指定容器下的指定key

hincrby 对整数的增加操作 hincrby map key num

set集合

存取操作

sadd set value····

scard key 查看set大小

smembers key 查看集合中所有元素 有序返回

sismember key value 判断value是否存在key中

更新操作

srem key value··· 删除指定value值

srandmember key num 可以在set中随机返回n个元素

spop key num 可以随机弹出num个元素

smove set1 set2 value 把value从一个集合移动到另一个集合

sinter set1 set2 求两个集合的交集

sdiff key1 key2 求key1中存在 但key2中不存在的元素 差集

sunion key1 key2 求并集

zset有序集合

每个元素都会关联一个double类型的分数 通过这些分数来为集合中数据进行升序排列,zset成员是唯一的,但分数可以重复

原理:内部实现是“跳跃列表”的数据结构。通过层级制,将元素分层并串联,每隔几个元素选出一个代表,再将代表使用另外一级指针穿起来,同一个元素在不同层级之间身兼数职,是为“跳跃”。新元素插入时,逐层下潜,直到找到合适的位置。

读取操作

zadd 创建或增加zset元素值 需要包含一个分数 zadd key score1 value1 score2 value2

zrangebyscore key minScore maxScore 指定分数范围内查看元素 后面可以加limit 取结果集的指定范围元素 limit start num 从start开始返回num个

zrem key value 删除指定元素

查看元素

zcard key 查看元素个数

zcount key minScore maxScore 统计指定分数范围内元素个数

zscore key value 查看指定成员分数

zrank key value 返回指定成员的索引位置 因为有序 所以位置代表排名

zrevrank key value 默认从低到高排序 逆序正好代表排名 逆序查看索引位置

zrange key start end 指定范围查看元素 如果要查看分数 需要加上 withscores

zrevrange 逆序查看

geo位置信息

zrange 使用方法和zset一样

geoadd key 经度 维度 member 支持存储多个

geodist key member1 member2 + 距离单位 km ,m

geopos key member 查看某个元素经纬度

geohash key member 查看元素的哈希编码结果

georadius key 经度 维度 半径 [withdist] [withcoord]以某个经纬度的位置为半径,返回集合中在半径内的地址信息

[withdist] 返回距离 [withcoord] 返回经纬度 [withhash] 返回哈希值

bitmap位图

setbit key index 0 / 1 设置key的某个索引上的值为0或1

getbit key index 查看key的某个索引上的值

get key 返回key二进制值所对应的字符串

bitcount key [start] [end]查看start 到 end 索引范围内的二进制数据一共有多少个1

HyperLogLog基数统计

pfadd 增加数据 pfadd key value

pfcount 统计数据 自动去重 pfcount key

stream流

消息的发布与订阅

subscribe + channel 订阅频道的命令 会持续接受消息

pubscribe + channel + message 在某个频道发布消息

stream命令

xadd 生成消息 返回消息id 时间戳+顺序 (顺序指的是该毫秒下产生的第几条消息) xadd key id(*) msg message

xlen 查看消息列表长度

xrange key - + 查看全部消息

xdel key id 删除某一条消息

xread streams key 0-0 读取指定频道下的所有消息 0-0指的是全部 可以通过id查看指定消息

[block num ]使用block时 不能使用0-0 需要使用$标识等待消息返回

[count num] 返回消息的数量

Redis配置

redis.conf

1.单位的问题 1k/1kb/1m/1mb是不同的 单位大小写不敏感

网络相关

2.bind 127.0.0.1 绑定ip地址 指定能够访问的服务端地址

3.protected-mode yes 开启保护模式 当bind没有配置且登录不需要密码时 保护模式开启(只能被本地访问)

4.port 6379 端口号

5.timeout 0 客户端超时时间 0代表不断掉链接

6.tcp-keepalive 300 每300秒检查一次客户端健康情况 避免服务端阻塞

7.tcp-backlog 511 队列数量 包括未完成和已完成三次握手的

通用配置

8.daemonize no 是否后台运行

9.pidfile /var/run/redis_6379.pid 当守护进程开启时 写入进程id的文件的位置

10.loglevel notice 四种级别 指定日志的级别 notice对应生产

11.logfile ""日志存储的位置

config命令

一种从客户端查看配置项信息的方式,使用config get 属于危险命令,可以限制使用

安全校验配置 requirepass 代表是否设置密码

如果需要设置密码 config set requirepass + password

此时输入命令前 需要先校验 anth + password 然后才能执行其他操作

恢复初始状态,只需要重新设置为空串

危险命令限制

包含config/flushdb/keys/flushall

rename-command + 命令 + 空串 将此命令置为不可用

其他限制

maxclients 10000 客户端并发数的限制

maxmemory 最大内存

maxmemory-policy 缓存淘汰策略 默认noeviction 不删除只报错

其他策略主要分为两种allkeys 所有的键值都可能删除 volatile只删除设置了过期时间的键值

LRU算法

Redis持久化

持久化方式

方式一RDB:在指定时间间隔内对数据进行快照存储,将数据写入临时文件,写入成功时,覆盖原来文件,用二进制压缩存储

方拾二AOF:用日志文本记录每一个数据更改指令,然后通过重放来恢复数据

RDB

Redis DataBase

命令触发:

1.save 会阻塞redis服务器,线上禁止使用

2.bgsave 触发一个子进程,阻塞只发生在子进程

自动触发:

1.save seconds changes 多少秒内更改了多少次才会触发保存

2.主从复制时

3.debug reload时

4.shutdown时 如果没有aof开启 也会触发rdb

恢复方式:将备份文件移动到redis安装目录并启动服务即可

RDB-fork原理

执行RDB时,服务器执行以下操作:

1.redis调用系统函数fork(),创建一个子进程

2.子进程将数据集写入到一个临时RDB文件中

3.当子进程完成对临时RDB文件的写入时,redis用新的临时RDB文件替换原来的RDB文件,并删除旧RDB文件。

执行fork时,操作系统会使用写时复制(copy-on-write)策略,即fork函数发生的一刻父子进程共享同一内存数据,当父进程要更改其中某片数据时(如执行一个写命令),操作系统会将该片数据复制一份以保证子进程的数据不受影响。新的RDB文件存储的是执行fork那一刻的内存数据。

在进行快照的过程中不会修改RDB文件,只有快照结束后才会将旧的文件替换成新的。任何时候RDB文件都是完整的。

RDB性能分析

优点

●通过rdb文件恢复数据比较快。

●rdb文件非常紧凑,适合于数据备份。

●通过RDB进行数据备份,由于使用子进程生成,所以对Redis服务器性能影响较小。

缺点

●采用RDB的方式可能会造成某个时段内数据的丢失,比如还没达到触发条件时服务器死机了,那么这个时间段的数据会丢失。

●使用save命令会造成服务器阻塞,直接数据同步完成才能接收后续请求。

●使用bgsave命令在forks子进程时,如果数据量太大,forks的过程也会发生阻塞,另外,forks子 进程会耗费内存。

AOF

Redis为解决aof中更改操作过多,支持aof文件的重写,合并压缩命令

写入流程:命令写入,追加到aof_buf,再同步到aof磁盘

命令触发:barewriteaof

性能分析

优点

●AOF只是追加日志文件,因此对服务器性能影响较小,速度比RDB要快,消耗的内存较少。

●数据安全性较高。

缺点

aof生成的日志文件太大,即使通过重写,体积仍然很大

恢复数据的速度比rdb慢

aof和rdb混合

当RDB与AOF两种方式都开启时,Redis启动时会优先使用AOF日志来恢复数据,因为AOF保存的文件比RDB文件更完整。I

Redis4.0提供了一个混合持久化的选择,将rdb文件的内容和增量的aof日志存在一起,重启时先加载rdb,再重放aof,以达到最大效率。

AOF原理

在重写期间,由于主进程依然在响应命令,为了保证最终备份的完整性;因此它依然会写入旧的AOF file中,如果重写失败,能够保证数据不丢失。

为了把重写期间响应的写入信息也写入到新的文件中,因此也会为子进程保留一个buf,防止新写的file丢失数据。

重写是直接把当前内存的数据生成对应命令,并不需要读取老的AOF文件进行分析、命令合并。

AOF文件直接采用的文本协议,主要是兼容性好、追加方便、可读性高可认为修改修复。

管道与事务

管道

首先,管道技术是客户端提供的,与服务器无关。服务器始终使用,收到-执行-回复的顺序处理消息。而客户端通过对管道中的指令列表改变读写顺序,而节省大幅IO时间,指令越多,效果越好。管道测试: redis-benchmark (-P)管道可以将多个命令打包,一次性的发送给服务器端处理事务

一个成熟的数据库,一定要支持事务,以保障多个操作的原子性.同时,事务还能保证一个事务中的命令依次执行而不会被其他命令插入。

所有事务的基本用法,都是begin、commlt、 rollback.

redis事务的指令是,multi、 exec、discard,虽然可以使用DISCARD取消事务,但是不支持回滚。

当输入MULTI命令后,服务器返回OK表示事务开始成功,然后依次输入需要在本次事务中执行的所有命令,每次输入一个命令服务器并不会马上执行,而是返回”QUEUED",这表示命令已经被服务器接受并且暂时保存起来,最后输入EXEC命令后,本次事务中的所有命令才会被依次执行。

事务错误处理:

1)语法错误,全不执行。

2)运行错误,出错后仍然继续执行。

事务监测

将其中一条命令的执行结果作为另-条命令的执行参数,如1++, 需要使用watch命令。

WATCH命令可以监控一个或多个键,一 旦其中有 -个键被修改(或删除),之后的事务就不会执行,监控直持续到EXEC命令

执行EXEC命令之后会取消监控使用WATCH命令监控的键,如果不想执行事务中的命令,也可以使用UNWATCH命令来取消监控.

使用方式: watch -> multi -> command -> exec

注意:由于WATCH命令的作用只是当被监控的键被修改后取消之后的事务,并不能保证其他客户端不修改监控的值,所以当EXEC命令执行失败之后需要手动重新执行整个事务。

本质上是一种乐观锁。

Redis分布式

乐观锁与悲观锁

悲观锁(Pessimistic Lock),就是很悲观,每次去拿数据的时候都认为别人会修改。所以每次在拿数据的时候都会上锁。这样别人想拿数据就被挡住,直到悲观锁被释放。

乐观锁(Optimistic Lock),就是很乐观,每次去拿数据的时候都认为别人不会修改。所以不会上锁,不会上锁!但是如果想要更新数据,则会在更新前检查在读取至更新这段时间别人有没有修改过这个数据。如果修改过,则重新读取,再次尝试更新,循环上述步骤直到更新成功。

悲观锁VS乐观锁

1)悲观锁阻塞事务,乐观锁回滚重试。

2)乐观锁适用于写比较少的情况下,即冲突很少发生时,可以省去锁的开销,加大了系统吞吐量。

3)悲观锁适用于写比较多的情况下,因为如果乐观锁经常冲突,应用要不断进行重试,反倒降低性能。

CAS算法

Compare-and-Swap,即比较并替换,也有叫做Compare-and-Set的,师比较并设置。

1、比较:读取到了一个值A,在将其更新为B之前,检查原值是否仍为A (未被其他线程改动)

2、设置:如果是,将A更新为B,结束。如果不是,则什么都不做。

允许多个线程同时读取(因为根本没有加锁操作),但是只有一个线程可以成功更新数据,并导致其他要更新数据的线程回滚重试。也叫非阻塞同步 业(Non-blocking Synchronization)

乐观锁策略也被称为无锁编程。换句话说,乐观锁其实不是“锁",它仅仅是一个循环重试CAS的算法而已!

乐观锁的缺点——ABA 问题

如果一个变量V初次读取的时候是A值,并且在准备赋值的时候检查到它仍然是A值,那我们就能说明它的值没有被其他线程修改过了吗?很明显是不能的,因为在这段时间它的值可能被改为其他值,然后又改回A,那CAS操作就会误认为它从来没有被修改过。这个问题被称为CAS操作的”ABA"问题。

分布式锁

在很多场景中,我们为了保证数据的最终一致性, 需要很多的技术方案来支持,比如分布式事务、分布式锁等.有时,我们需要保证个方法在同一时间内只能被同一个线程执行。在单机环境中,Java中其实提供了很多井发处理相关的API,但是这些API在分布式场景中就无能为力了.也就是说单纯的Java Api并不能提供分布式锁的能力。所以针对分布式锁的实现目前有多种方案。

分布式锁是控制分布式系统之间同步访问共享资源的一种方式。

分布式锁一般有三种实现方式: 1.数据库乐观锁; 2. 基于Redis的分布式锁; 3. 基于ZooKeeper的分布式锁。

分布式锁的可靠性需满足以下四个条件:

1.互斥性。在任意时刻,只有一个客户端能持有锁.

2.不会发生死锁。即使有一个客户端在持有锁的期间崩溃而没有主动解锁,也能保证后续其他客户端能加锁。

3.具有容错性。只要大部分的Redis节点正常运行,客户端就可以加锁和解锁。

4.加锁和解锁必须是同一个客户端,客户端自己不能把别人加的锁给解了。

主从模式

为了保证高可用,redis-cluster集群引入了主从模式,一个主节点对应一个或者多个从节点,当主节点宕机的时候,就会启用从节点。当其它主节点ping一个主节点A时,如果半数以上的主节点与A通信超时,那么认为主节点A宕机了。如果主节点A和它的从节点A1都宕机了,那么该集群就无法再提供服务了。

优点

支持主从复制,主机会自动将数据同步到从机,可以进行读写分离

为了分载Master的读操作压力,Slave服务器可以为客户端提供只读操作的服务,写服务仍然必须由Master来完成

Slave同样可以接受其它Slaves的连接和同步请求,这样可以有效的分载Master的同步压力。

缺点

Redis不具备自动容错和恢复功能,主机从机的宕机都会导致前端部分读写请求失败,需要等待机器重启或者手动切换前端的IP才能恢复。

主机宕机,宕机前有部分数据未能及时同步到从机,切换IP后还会引入数据不一致的问题, 降低了系统的可用性。

Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。

主从复制

在Redis中,用户可以通过执行SLAVEOF命令或者设置slaveof选项,让个服务器去复制(repllcate) 另一个服务器,我们称呼被复制的服务器为主服务器(master), 而对主服务器进行复制的服务器则被称为从服务器(slave)。配置的口诀为:配从不配主。

假设现在有两个Redis服务器,地址分别为127.0.0.1:6379和127.0.0.1:12345,如果我们向服务器127.0.0.1:12345发送以下命令:

127.0.0.1:12345> SLAVEOF 127.0.0.16379

那么服务器127.0.0.1:12345将成为127.0.0.1:6379的从服务器,而服务器127.0.0.1:6379则会成为127.0.0.1:12345的主服务器。

如果需要解除主从关系,输入slaveof no one.

新版复制

Redis从2 8版本开始,使用PSYNC命令代替SYNC命令来执行复制时的同步操作。

PSYNC命令具有完整重同步(full resynchronization)和部分重同步(partial resynchronization)两种模式:

完整重同步用于处理初次复制情况:完整重同步的执行步骤和SYNC命令的执行步骤基本一样,它们都是通过让主服务器创建并发送RDB文件,以及向从服务器发送保存在缓冲区里面的写命令来进行同步;

部分重同步则用于处理断线后重复制情况:当从服务器在断线后重新连接主服务器时,如果条件允许,主服务器可以将主从服务器连接断开期间执行的写命令发送给从服务器,从服务器只要接收并执行这些写命令,就可以将数据库更新至主服务器当前所处的状态。

部分重同步的实现,由以下三个部分构成:

1)主服务器的复制偏移量(replication offset)和从服务器的复制偏移量;

2)主服务器的复制积压缓冲区(replication backlog);

3)服务器的运行ID (run 1D)。

哨兵模式

当主服务器中断服务后,可以将一个从服务器升级为主服务器,以便继续提供服务,但是这个过程需要人工手动来操作。为此,Redis 2.8中提供了哨兵工具来实现自动化的系统监控和故障恢复功能。

哨兵的作用就是监控Redls系统的运行状况。它的功能包括以下两个。(1)监控主服务器和从服务器是否正常运行。

(2)主服务器出现故障时自动将从服务器转换为主服务器。

哨兵模式的优缺点

优点:哨兵模式是基于主从模式的,所有主从的优点,哨兵模式都具有。主从可以自动切换,系统更健壮,可用性更高。

缺点: Redis较难支持在线扩容,在集群容量达到上限时在线扩容会变得很复杂。

Redis客户端

jedis--引入maven依赖

使用方法参考官网

面试相关

Redis Vs Memcached

总的来说,可以把Redis理解为是对Memcached的拓展,是更加重量级的实现,提供了更多更强大的功能。具体来说:

1.性能上:

性能上都很出色,具体到细节,由于Redis只使用单核,而Memcached可以使用多核,所以平均每一个核上Redis在存储小数据时比

Memcached性能更高。而在100k以上的数据中,Memcached性能要高于Redis,虽然Redis最近也在存储大数据的性能上进行优化,但是比起Memcached,还是稍有逊色。

2.内存空间和数据量大小:

MemCached可以修改最大内存,采用LRU算法。Redis增加了VM的特性,突破了物理内存的限制。

3.操作便利上:

MemCached数据结构单一,仅用来缓存数据,而Redis支持更加丰富的数据类型,也可以在服务器端直接对数据进行丰富的操作,这样可以减少网络10次数和数据体积。

4.可靠性上:

MemCached不支持数据持久化,断电或重启后数据消失,但其稳定性是有保证的。Redis支持数据持久化和数据恢复,允许单点故障,但是同时也会付出性能的代价。

常见面试题

Redis有哪几种数据淘汰策略?

什么是Redis持久化? Redis有哪几种持久化方式?优缺点是什么?Redis有哪些架构模式?讲讲各自的特点?

什么是一致性哈希算法?什么是哈希槽?

使用过Redis分布式锁吗,它是怎么实现的?

使用过Redis做异步队列吗,你是怎么用的?有什么缺点?什么是缓存穿透?如何避免?什么是缓存雪崩?何如避免?

缓存穿透:

访问一个不存在的key,缓存不起作用,请求会穿透到DB,流量大时DB会挂掉。

解决方案:采用布隆过滤器,使用一个足够大的bitmap,用于存储可能访问的key,不存在的key直接被过滤。

缓存雪崩:

大量的key设置了相同的过期时间,导致在缓存在同时刻全部失效,造成瞬时DB请求量大、压力骤增,引起雪崩。

解决方案:给缓存设置过期时间时加上一个随机值时间,使得每个key的过期时间分布开来,不会集中在同一时刻失效。

缓存击穿:

-个存在的key,在缓存过期的一刻,同时有大量的请求,这些请求都会击穿到DB,造成瞬时DB请求量大、压力骤增。

解决方案:在访问key之前,采用SETNX (setif not exists)来设置另个短期key来锁住当前key的访问,访问结束再删除该短期key。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值