redis相关知识点redis 介绍:
1、redis是内存 no-sql 数据库,相比mysql等硬盘数据库效率高
2、在内存值配置数据库使用,而不直接使用内存,redis存储的数据是可以管理的
3、memcache也是内存数据库,且django默认采用的就是memcache数据库,用redis替
换memcache的路由很简单,后者更强大
redis支持更多的数据类型
redis自带缓存机制,出现数据库系统崩溃数据也是可以有找回的功能
redis可以主动完成数据持久化(自带数据持久化功能)
redis的数据过期时间机制也可以自身完成
2.redis 支持的数据类型:String、Hash、List、Set、Sorted Set
String:存储其他类型不能存的所有数据
Hash:存储 key-value 形式数据,类似于字典
List:存储 一系列有序value 形式数据,列表(数组)
Set:存储 一系列无序value 形式数据,集合
Sorted Set:存储 有排列标号value 形式数据,排行
字符串操作:
set:key value
get:key
mset:k1 v1 k2 v2 ... kn vn
mget:k1 k2 ... kn
setex:key exp valu
哈希操作:
单增:hset key field value
单查:hget key field
所有键值:hgetall key
单删:hdel key field
所有key:hkeys key
所有值:hvals key
列表操作:
右增: rpush key v1 v2 ... vn
左增: lpush key v1 v2 ... vn
修改: lset key index value
左删: lpop key
右删: rpop key
插入:linsert key before|after old_value new_value
区间:lrange key begin_index end_index
集合操作:
增:sadd key v1 v2 ... vn
差集:sdiff key1 key2
并集:sinter key1 key2
交集:sunion key1 key2
查:smembers key
随机删:spop key
有序集合操作:
增:zadd key score1 value1 score2 value2 ... scoren valuen
区间个数:zcount key begin_score end_score
排行低到高:zrange key begin_index end_index
排行高到低:zrevrange key begin_index end_index
redis基础命令:
启动服务器: redis-server &
启动客户端连接redis:
redis-cli -h localhost -p 6379 -n 数据库编号(0~15)
连接成功后切换数据库:
select 数据库编号
3.安装: pip install redis
1.redis直接使用:
import redis
r = redis.Redis(host='127.0.0.1', port=6379)
2.连接池使用:
import redis
pool = redis.ConnectionPool(host='127.0.0.1', port=6379)
r = redis.Redis(connection_pool=pool)
3.缓存使用:
1.将缓存存储位置配置到redis中:settings.py
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
"CONNECTION_POOL_KWARGS": {"max_connections": 100}
}
}
}
2.操作cache模块直接操作缓存:views.py
from django.core.cache import cache # 结合配置文件实现插拔式
# 存放token,可以直接设置过期时间
cache.set('token', 'header.payload.signature', 10)
# 取出token
token = cache.get('token')
1.缓存穿透:是指访问一个数据库肯定不存在的数据,如遇到恶意攻击会对数据库造成极大压力,甚至压垮数据库.
2.缓存雪崩:是指某一时间段,缓存集中过期失效,对数据的查询将全部落入数据库,对数据库造成周期性压力波峰.
3.缓存击穿:是指一个key非常热点,在不停的扛着大并发,大并发集中对一个点进行访问,当这个keyzai失效的一瞬
间,持续的大并发击破缓存,进而直接访问数据库.
redis的两种持久方式
1.rdb: 是指在指定的时间间隔内将内存中的数据集快照写入磁盘,实际操作过程是fork一个子进程,
先将数据集写入临时文件,写入成功后,再替换之前的文件,用二进制压缩存储
优点:1.是一个@非常紧凑的文件件,保存了某个时间点上的数据集,非常适合进行备份
注:遇到问题可以随时将数据集还原到不同版本
2.非常适合灾难恢复,由于@,可以加密后传输到别的数据中心
3.可以最大化redis的性能
4.恢复大数据集是的速度比aof快
缺点:保存整个数据集的状态并不轻松,至少5分钟1次,一旦发生故障会丢失几分钟的数据
2.aof: 是以日志的形式记录服务器执行的所有写操作命令,恢复时是通过重新执行这些命令来还原数据集
优点:1.会让redis非常耐久,发生故障最多丢失1秒钟的数据
缺点:1.对相同数据集来说,aof文件体积 > rdb文件体积,而且aof恢复速度慢与adb
``
mysql相关:
数据库的脏读、不可重复读、幻读都和事务的隔离性有关;
原子性(Atomicity):事务是数据库的逻辑工作单位,它对数据库的修改要么全部执行,要么全部不执行。
一致性(Consistemcy):事务前后,数据库的状态都满足所有的完整性约束。
隔离性(Isolation):并发执行的N个事务是隔离的,一个不影响一个,一个事务在没有commit之前,被修改的数据不可能被其他事务看到;
持久性(Durability):持久性意味着当系统或介质发生故障时,确保已提交事务的更新不能丢失。持久性主要在于DBMS的恢复性能
脏读:脏读又称无效数据读出。一个事务读取另外一个事务还没有提交的数据叫脏读;
eg:事务T1修改了一行数据,但是还没有提交,这时候事务T2读取了被事务T1修改后的数据,
之后事务T1因为某种原因Rollback了,那么事务T2读取的数据就是脏的。
解决办法:把数据库的事务隔离级别调整到READ_COMMITTED
不可重复读:不可重复读是指在同一个事务内,两个相同的查询返回了不同的结果(不可重复读的重点是修改 )
eg:事务T1读取某一数据,事务T2读取并修改了该数据,T1为了对读取值进行检验而再次读取
该数据,便得到了不同的结果。
解决办法:把数据库的事务隔离级别调整到REPEATABLE_READ
幻读:(幻读的重点在于新增或者删除 )
系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,
当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样。这就叫幻读:
解决方案:
四种隔离级别,这四个级别可以逐个解决脏读、不可重复读、幻读这几类问题。
1.Read uncommitted 读未提交 可能出现脏读
eg:公司发工资了,把50000元打到我的账号上,但是该事务并未提交,而我正好去查看账户,发现工资已经到账,是50000元整,
非常高兴。可是不幸的是,领导发现发给的工资金额不对,是2000元,于是迅速回滚了事务,修改金额后,将事务提交,最后我
实际的工资只有2000元,空欢喜一场。
2.Read committed 读提交 避免了脏读,但可能会造成不可重复读
eg:我拿着工资卡去消费,系统读取到卡里确实有2000元,而此时老婆也正好在网上转账,把工资卡的2000元转到她账户,并在我
之前提交了事务,当我扣款时,系统检查到工资卡已经没有钱,扣款失败,十分纳闷,明明卡里有钱,为何......
3.Repeatable read 重复读 可以避免不可重复读,但会造成幻读
eg:当我拿着工资卡去消费时,一旦系统开始读取工资卡信息(即事务开始),我老婆就不可能对该记录进行修改,也就是不能在
此时转账。
4.Serializable 串行化 可避免脏读、不可重复读、幻读的发生
分表:
垂直分表:基于数据库的列进行,某个表的字段比较多,可以新建一张扩展表,将不常用的字段或长度较大的字段拆分出去到扩展表中.
优点:1.通过大表拆小表,便于维护与开发,可避免跨页问题,减少额外的性能开销.
2.数据库以行问单位将数据加载到内存中,这样表中的字段较短且访问频率较高,内存能加载更多数据,命中率更高,减少磁
盘io,从而提高数据库性能.
水平分表:将表中不同数据行按照一定规律分布到不同的数据库表中(表保存在同一个数据库中),从而降低单表数据量,优化性能
方法:通过主键或时间等字段进行hash和取模后拆分
分库:
垂直分库:按照业务模块来划分不同的数据库,而不是将所有数据表放在同一个数据库中.
eg:可以将查询库和系统库分开了,这样如果有大查询也不会影响系统库
查询优化
1.注意事项
1.尽量使用简单的查询,避免使用表连接
2.尽量避免全表查询
3.不要用select *
4.在索引字段上查询尽量不要用数据库函数,不便于缓存查询结果
5.千万不要 order by rand(),性能极低
锁: 用于多用户环境下保证数据库完整性和一致性.
分类:
数据库系统角度分为三种:排他锁、共享锁、更新锁.
从程序员角度分为两种:一种是悲观锁,一种乐观锁。
悲观锁:
定义:
很悲观,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人
拿这个数据就会block(阻塞),直到它拿锁;悲观锁的实现,往往依靠数据库提供的锁机制(也只有
数据库层提供的锁机制才能真正保证数据访问的排他性,否则,即使在本系统中实现了加锁机制,也
无法保证外部系统不会修改数据).
共享锁(share lock):
定义:
S锁,也叫读锁,用于所有的只读数据操作。共享锁是非独占的,允许多个并发事务读取其锁定的资源
性质:
1. 多个事务可封锁同一个共享页;
2. 任何事务都不能修改该页;
3. 通常是该页被读取完毕,S锁立即被释放。
排他锁(Exclusive Lock):
定义:
X锁,也叫写锁,表示对数据进行写操作。如果一个事务对对象加了排他锁,其他事务就不能再给它加任何锁了。
eg:
某个顾客把试衣间从里面反锁了,其他顾客想要使用这个试衣间,就只有等待锁从里面打开了.
性质:
1. 仅允许一个事务封锁此页;
2. 其他任何事务必须等到X锁被释放才能对该页进行访问;
3. X锁一直到事务结束才能被释放
更新锁:
定义:
U锁,在修改操作的初始化阶段用来锁定可能要被修改的资源,这样可以避免使用共享锁造成的死锁现象。
注:
1.首先获得一个共享锁,读取数据,然后将共享锁升级为排他锁,再执行修改操作;
这时,这些事务都不会释放共享锁,而是一直等待对方释放,这样就造成了死锁。
2.一个数据在修改前直接申请更新锁,在数据修改时再升级为排他锁,就可以避免死锁
性质:
1. 用来预定要对此页施加X锁,它允许其他事务读,但不允许再施加U锁或X锁;
2. 当被读取的页要被更新时,则升级为X锁;
3. U锁一直到事务结束时才能被释放
乐观锁:
定义:
很乐观,每次去拿数据的时候都认为别人不会修改,所以,不会上锁。但是在更新的时候
会判断一下在此期间别人有没有更新这个数据,可以使用版本号等机制
使用场景:
乐观锁适用于多读的应用类型,这样可以提高吞吐量,像数据库如果提供类似于write_condition机制的其实都是提供的乐观锁
活锁:
定义:
指的是T1封锁了数据R,T2同时也请求封锁数据R,T3也请求封锁数据R,当T1释放了锁之后,
T3会锁住R,T4也请求封锁R,则T2就会一直等待下去。
解决方法:
采用“先来先服务”策略可以避免。
死锁:
定义:
就是我等你,你又等我,双方就会一直等待下去。
比如:
T1封锁了数据R1,正请求对R2封锁,而T2封住了R2,正请求封锁R1,这样就会导致死锁,
死锁这种没有完全解决的方法,只能尽量预防
预法:
1. 一次封锁法,指的是一次性把所需要的数据全部封锁住,但是这样会扩大了封锁的范围,降低系统的并发度;
2. 顺序封锁法,指的是事先对数据对象指定一个封锁顺序,要对数据进行封锁,只能按照规定的顺序来封锁,
但是这个一般不大可能的。
分布式锁:
定义:
是控制分布式系统之间同步访问共享资源的一种方式。在分布式系统中,常常需要协调他们的动作。
如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往
往需要互斥来防止彼此干扰来保证一致性,在这种情况下,便需要使用到分布式锁。
* primary key * unique key * index key
上面三种key前两种除了有加速查询的效果之外还有额外的约束条件(primary key:非空且唯一,unique key:唯一),
而index key没有任何约束功能只会帮你加速查询
索引:
定义:就是一种数据结构,类似于书的目录。意味着以后再查数据应该先找目录再找数据,而不是用翻页的方式查询数据
本质:通过不断地缩小想要获取数据的范围来筛选出最终想要的结果,同时把随机的事件变成顺序的事件,也就是说,
有了这种索引机制,我们可以总是用同一种查找方式来锁定数据。**
影响:
* 在表中有大量数据的前提下,创建索引速度会很慢
* 在索引创建完毕后,对表的查询性能会大幅度提升,但是写的性能会降低
**聚集索引(primary key)**
**特点:**叶子结点放的一条条完整的记录
**辅助索引(unique,index)
辅助索引:查询数据的时候不可能都是用id作为筛选条件,也可能会用name,password等字段信息,那么这个时候就无法
利用到聚集索引的加速查询效果。就需要给其他字段建立索引,这些索引就叫辅助索引
**特点:**叶子结点存放的是辅助索引字段对应的那条记录的主键的值
(比如:按照name字段创建索引,那么叶子节点存放的是:{name对应的值:name所在的那条记录的主键值})
select name from user where name='jason';
上述语句叫覆盖索引:只在辅助索引的叶子节点中就已经找到了所有我们想要的数据
select age from user where name='jason';
上述语句叫非覆盖索引,虽然查询的时候命中了索引字段name,但是要查的是age字段,所以还需要利用主键才去查找
redis 哨兵,复制与集群的设计原理与区别:
说道高可用,Redis正是利用哨兵与复制来保证Redis的高可用
1.哨兵(Sentinel):可以管理多个Redis服务器,它提供了监控,提醒以及自动的故障转移的功能。
why: 哨兵的出现主要是解决了主从复制出现故障时需要人为干预的问题
主要功能:
1)集群监控:负责监控Redis master和slave进程是否正常工作
2)消息通知:如果某个Redis实例有故障,那么哨兵负责发送消息作为报警通知给管理员
3)故障转移:如果master node挂掉了,会自动转移到slave node上
4)配置中心:如果故障转移发生了,通知client客户端新的master地址
高可用原理: 当主节点出现故障时,由Redis Sentinel自动完成故障发现和转移,并通知应用方,实现高可用性。
2.复制(Replication):则是负责让一个Redis服务器可以配备多个备份的服务器。
why:为了解决单点数据库问题,会把数据复制多个副本部署到其他节点上,通过复制,实现Redis的高可用性,
实现对数据的冗余备份,保证数据和服务的高度可靠性。
数据复制原理:
1>从redis服务器启动并发送sync命令给主redis
2>主redis收到命令后,会将所有的写入命令缓存,并fork一个子进程生成rdb快照
3>rdb持久化完成后,主redis发送 rdb文件和缓存命令给从redis
4>之后主数据库每执行一个写命令,都会将被执行的写命令发送给从数据库
3.集群:
why:为了解决单机Redis容量有限的问题,会将数据按一定的规则分配到多台机器,
内存/QPS不受限于单机,可受益于分布式集群高扩展性。分散压力