码迷,mamicode.com
首页 > 其他好文 > 详细

redis介绍

时间:2019-10-17 14:05:04      阅读:50      评论:0      收藏:0      [点我收藏+]

标签:一点   相互   str   失效   cache   数据库   键值   imp   port   

概念
关系型数据库/sql: mysql,oracle

非关系型数据库/nosql: redis(存在内存中),mongodb(存在硬盘上)

1.redis是以key-value形式存储

2.redis支持持久化

redis用途

1.做缓存

2.存储session

3.游戏排行榜

4.对速度要求比较高的数据存储

5.做消息队列

redis 五大数据类型

1. 字符串

格式:set [key] [value]
string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。
string类型是Redis最基本的数据类型,一个键最大能存储512MB。

2. 列表

redis列表是简单的字符串列表,按照插入顺序排序,你可以添加一个元素列表的头部(左边)或者尾部(右边)
格式:lpush [name] [value]  # 在key对应list的尾部添加字符串元素
格式:rpush [name] [value]  # 在key对应list的头部添加字符串元素
格式:lrem [name] [index]   # key对应list中删除count个和value相同的元素
格式:llen [name]           # 返回对应list长度

3. 哈希(字典)

格式: hmset [name]  [key1] [value1] [key2] [value2]
Redis hash 是一个键值(key=>value)对集合。
Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象。

4. 集合(set) 

格式:sadd [name] [value]
redis的Set是string类型的无序集合
集合是通过哈希表实现的,所以添加,删除,查找的复杂度都为O(1)

5. 有序集合(zset)

格式: zadd  name score value
Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。
不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序。
zset的成员是唯一的,但分数(score)却可以重复。

什么是Redis持久化?Redis有哪几种持久化方式?优缺点是什么?

持久化就是把内存的数据写到磁盘中去,防止服务宕机了内存数据丢失 
Redis 提供了两种持久化方式:RDB(默认)?和AOF 

RDB(Redis DataBase):

功能核心函数rdbSave(生成RDB文件)和rdbLoad(从文件加载内存)两个函数 



AOF(Append-only file):



每当执行服务器(定时)任务或者函数时flushAppendOnlyFile 函数都会被调用, 这个函数执行以下两个工作
    aof写入保存:
    WRITE:根据条件,将 aof_buf 中的缓存写入到 AOF 文件
    SAVE:根据条件,调用 fsync 或 fdatasync 函数,将 AOF 文件保存到磁盘中。

比较:

1、aof文件比rdb更新频率高,优先使用aof还原数据。
2、aof比rdb更安全也更大
3、rdb性能比aof好
4、如果两个都配了优先加载AOF

redis有哪些架构,以及特点

单机版

特点:简单
缺点:1、内存容量有限 2、处理能力有限 3、无法高可用。



主从复制 

特点:
    1、master/slave 角色
    2、master/slave 数据相同
    3、降低 master 读压力在转交从库
问题:
    1、无法保证高可用
    2、没有解决 master 写的压力



Redis 的复制(replication)功能允许用户根据一个 Redis 服务器来创建任意多个该服务器的复制品,其中被复制的服务器为主服务器(master),而通过复制创建出来的服务器复制品则为从服务器(slave)。 只要主从服务器之间的网络连接正常,主从服务器两者会具有相同的数据,主服务器就会一直将发生在自己身上的数据更新同步 给从服务器,从而一直保证主从服务器的数据相同。 

哨兵

特点:
    1、保证高可用
    2、监控各个节点
    3、自动故障迁移
缺点:
    主从模式,切换需要时间丢数据
    没有解决 master 写的压力





Redis sentinel 是一个分布式系统中监控 redis 主从服务器,并在主服务器下线时自动进行故障转移。其中三个特性:
监控(Monitoring):   Sentinel  会不断地检查你的主服务器和从服务器是否运作正常。
提醒(Notification): 当被监控的某个 Redis 服务器出现问题时, Sentinel 可以通过 API 向管理员或者其他应                    用程序发送通知。
自动故障迁移(Automatic failover): 当一个主服务器不能正常工作时, Sentinel 会开始一次自动故障迁移操作。

集群(proxy 型): 

特点:
    1、无中心架构(不存在哪个节点影响性能瓶颈),少了 proxy 层。
    2、数据按照 slot 存储分布在多个节点,节点间数据共享,可动态调整数据分布。
    3、可扩展性,可线性扩展到 1000 个节点,节点可动态添加或删除。
    4、高可用性,部分节点不可用时,集群仍可用。通过增加 Slave 做备份数据副本
    5、实现故障自动 failover,节点之间通过 gossip 协议交换状态信息,用投票机制完成 Slave到 Master 的角色       提升。
缺点:
    1、资源隔离性较差,容易出现相互影响的情况。
    2、数据通过异步复制,不保证数据的强一致性



从redis 3.0之后版本支持redis-cluster集群,Redis-Cluster采用无中心结构,每个节点保存数据和整个集群状态,每个节点都和其他所有节点连接。 

redis常用命令

Keys [pattern]              # 查看keys是否存在,Keys * 表示查看所有key
Exists [key]                # 查看key是否存在,有返回1,无返回0
Set [key] [value]            # 设置键值或修改已有键的值
Get [key]                   # 获取单个值
Setnx [key] [value]          # 有则不变,无则设置
Setex [key] [seconds] [value]    # 添加并设置过期时间
Expire [key] [seconds]       # 设置过期时间
TTL [key]                   # 查看过期时间
Mset [key] [value] [key] [value]...  # 设置多个键值
Getset [key] [value]         # 修改为新值并返回旧值
Mget [key] [key]...          # 获取多个值
Incr [key]                  # 使key的值自增1(注意:值必须为整数),若不存在则设置,并返回增后的值
incrby  [key] [increment]    # 同Incr,可指定自增的值
Decr [key]                  # 使key的值自减1(注意:值必须为整数),若不存在则设置,并返回减后的值
Decrby  [key] [decrement]    # 同Decr,可指定自减的值
Append [key] [value]         # 在已有的值后追加字符串,没有则设置
Strlen [key]                # 返回值的长度
move [key]  [id]            # 将 key及value移至指定库
persist [key]               # 取消过期时间
Select [id]                 # 选择数据库0-15
randomkey                   # 随机返回一个kay
Rename [key]                # 重命名key
Type [key]                  # 返回数据类型

怎么使用redis分布式锁

先拿setnx来争抢锁,抢到之后,再用expire给锁加一个 过期时间,防止锁忘记释放

Redis做异步队列

一般使用list结构作为队列,rpush生产消息,lpop消费消息。当lpop没有消息的时候,要适当sleep一会再重试。

缺点:在消费者下线的情况下,生产的消息会丢失,得使用专业的消息队列如rabbitmq等。

什么是缓存穿透?如何避免?什么是缓存雪崩?何如避免?

缓存穿透
    一般的缓存系统,都是按照key去缓存查询,如果不存在对应的value,就应该去后端系统查找(比如DB)。一些恶意    的请求会故意查询不存在的key,请求量很大,就会对后端系统造成很大的压力。这就叫做缓存穿透。
如何避免?
    1:对查询结果为空的情况也进行缓存,缓存时间设置短一点,或者该key对应的数据insert了之后清理缓存。
    2:对一定不存在的key进行过滤。可以把所有的可能存在的key放到一个大的Bitmap中,查询时通过该bitmap过滤。

缓存雪崩
    当缓存服务器重启或者大量缓存集中在某一个时间段失效,这样在失效的时候,会给后端系统带来很大压力。导致系统    崩溃。
如何避免?
    1:在缓存失效后,通过加锁或者队列来控制读数据库写缓存的线程数量。比如对某个key只允许一个线程查询数据和   写缓存,其他线程等待。
    2:做二级缓存,A1为原始缓存,A2为拷贝缓存,A1失效时,可以访问A2,A1缓存失效时间设置为短期,A2设置为长   期
    3:不同的key,设置不同的过期时间,让缓存失效的时间点尽量均匀。

比较redis和Memcached

          redis         Memcached

数据类型 字符串,列表,字典,集合,有序集合 字符串
持久化 支持 不支持
线程线程 单线程/单进程,但速度非常快 速度较快

Redis与Mysql双写一致性方案解析

一、前言:一般用redis来缓存的流程为:

    但对于更新完数据,先更新缓存,还是先删除缓存有很大争议,因此,进行以下讨论

二、一致性方案

    1.先更新数据库,再更新缓存

    2.先删除缓存,再更新数据库

    3.先更新数据库,再删除缓存

三、先更新数据库,再更新缓存

    普遍反对,有两种原因:

1.(线程安全角度)同时请求A和请求B进行更新操作,可能会出现
    1、A更新了数据
    2、B更新了数据
    3、线程B更新了缓存
    4、线程A更新了缓存
    *此时缓存中是A的数据
2.业务场景:
    *若业务需求是更新远远大于读取,而每次都要更新缓存,则造成很大的性能浪费
    *若写入的数据不是直接写入缓存,而是要经过一些计算再写入,则也会造成性能浪费。显然,删除缓存更为合适

四、先删除缓存,再跟新数据库

    也会导致不一致的原因:

-假设线程A进行更新操作,B进行查询操作
    1、A要更新数据,先删除缓存
    2、B查询时发现没有缓存
    3、B去数据库拿到旧值,并写入缓存
    4、A将新数据写入数据库
    *此时缓存中依然是旧数据
-解决方案(延时双删策略):
    1.先删除缓存
    2.写入数据库
    3.休息1s,再删除缓存
    问题1:1s的时间怎么确定?
        根据具体的业务情况而定
    问题2:采用了mysql的读写分离架构怎么办?
        1、请求A进行写操作,删除缓存
        2、请求A将数据写入数据库了,
        3、请求B查询缓存发现,缓存没有值
        4、请求B去从库查询,这时,还没有完成主从同步,因此查询到的是旧值
        5、请求B将旧值写入缓存
        数据库完成主从同步,从库变为新值上述情形,就是数据不一致的原因。解决方案依然是延时双删,在1s后再加      几百ms,等待主从同步完成
    问题3:第二次删除如果失败怎么办?
        在下面方案中具体阐述...

五、先更新数据库,再删缓存

常用的是这种,虽然理论上还是有点问题:

-假设线程A进行查询,线程B进行更新
    1.缓存刚好失效
    2.请求A进行查询,查到一个旧值
    3.请求B进行更新数据库
    4.请求B进行删除缓存
    5.请求A将取到的旧值添加到缓存,造成脏数据
-讨论
    这种情况发生的情况几乎不存在,因为查询的速度要远大于写入的速度,因此在2进行后不可能会等3,4执行完了,才执行5。那如果删除缓存失败了怎么办?

为了解决删除缓存失败的问题,可用下面两种方案:

一、如图



二、如图



备注说明:上述的订阅binlog程序在mysql中有现成的中间件叫canal,可以完成订阅binlog日志的功能。另外,重试机制,可采用的是消息队列的方式。如果对一致性要求不是很高,直接在程序中另起一个线程,每隔一段时间去重试即可,这些大家可以灵活自由发挥,只是提供一个思路。 

python操作redis

1.简单使用

import redis
conn = redis.Redis(host='localhost',port=6379)  # 获取reis链接
conn.set('age','18')  # 存入数据(reids里存的都是byte格式数据)
name = conn.get('name')  # 获取数据
print(name)

2. redis连接池

    1.新建一个模块conn_pool.py

import redis
POOL=redis.ConnectionPool(host='localhost',port=6379,max_connections=1000)

    2.使用连接池

from conn_poll import POOL
conn=redis.Redis(connection_pool=POOL)
print(conn.get('name'))

3.需要重点掌握的字符串操作

    get  set  mget  mset  incr  decr  append

redis介绍

标签:一点   相互   str   失效   cache   数据库   键值   imp   port   

原文地址:https://www.cnblogs.com/gyk1030/p/11691343.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!