zoukankan      html  css  js  c++  java
  • redis学习笔记

    redis是一个功能强大的内存数据结构存储,具有多种用途,包括数据库,缓存。

    github上有人整理里一份很全面的redis学习文档。

    1. redis特性

    • 读写性能优异
    • 持久化
    • 数据类型丰富
    • 单线程
    • 数据自动过期
    • 发布订阅
    • 分布式

    1.1 高性能适合当做缓存

    缓存是Redis最常见的应用场景,之所有这么使用,主要是因为Redis读写性能优异。而且逐渐有取代memcached,成为首选服务端缓存的组件。而且,Redis内部是支持事务的,在使用时候能有效保证数据的一致性。 作为缓存使用时,一般有两种方式保存数据:

    • 1、读取前,先去读Redis,如果没有数据,读取数据库,将数据拉入Redis。
    • 2、插入数据时,同时写入Redis。

    方案一:实施起来简单,但是有两个需要注意的地方:
    1、避免缓存击穿。(数据库没有就需要命中的数据,导致Redis一直没有数据,而一直命中数据库。)
    2、数据的实时性相对会差一点。

    方案二:数据实时性强,但是开发时不便于统一处理。 。

    当然,两种方式根据实际情况来适用。如:方案一适用于对于数据实时性要求不是特别高的场景。方案二适用于字典表、数据量不大的数据存储

    1.2 丰富的数据格式性能更高,应用场景丰富

    Redis相比其他缓存,有一个非常大的优势,就是支持多种数据类型。

    数据类型说明string字符串,最简单的k-v存储hashhash格式,value为field和value,适合ID-Detail这样的场景。list简单的list,顺序列表,支持首位或者末尾插入数据set无序list,查找速度快,适合交集、并集、差集处理sorted set有序的set

    其实,通过上面的数据类型的特性,基本就能想到合适的应用场景了。

    • string——适合最简单的k-v存储,类似于memcached的存储结构,短信验证码,配置信息等,就用这种类型来存储。
    • hash——一般key为ID或者唯一标示,value对应的就是详情了。如商品详情,个人信息详情,新闻详情等。
    • list——因为list是有序的,比较适合存储一些有序且数据相对固定的数据。如省市区表、字典表等。因为list是有序的,适合根据写入的时间来排序,如:最新的***,消息队列等。
    • set——可以简单的理解为ID-List的模式,如微博中一个人有哪些好友,set最牛的地方在于,可以对两个set提供交集、并集、差集操作。例如:查找两个人共同的好友等。
    • Sorted Set——是set的增强版本,增加了一个score参数,自动会根据score的值进行排序。比较适合类似于top 10等不根据插入的时间来排序的数据。

    如上所述,虽然Redis不像关系数据库那么复杂的数据结构,但是,也能适合很多场景,比一般的缓存数据结构要多。了解每种数据结构适合的业务场景,不仅有利于提升开发效率,也能有效利用Redis的性能。

    1.3 单线程可以作为分布式锁

    谈到Redis和Memcached 的区别,大家更多的是谈到数据结构和持久化这两个特性,其实还有一个比较大的区别就是:

    • Redis 是单线程,多路复用方式提高处理效率。
    • Memcached 是多线程的,通过CPU线程切换来提高处理效率。

    所以Redis单线程的这个特性,其实也是很重要的应用场景,最常用的就是分布式锁。
    应对高并发的系统,都是用多服务器部署,每个技术框架针对数据锁都有很好的处理方式,如 .net 的lock,java 的synchronized,都能通过锁住某个对象来应对线程导致的数据污染问题。但是毕竟,只能控制本服务器的线程,分布式部署以后数据污染问题,就比较难处理了。Redis的单线程这个特性,就非常符合这个需求,伪代码如下:

    //产生锁
    while lock!=1
        //过期时间是为了避免死锁
        now = int(time.time())
        lock_timeout = now + LOCK_TIMEOUT + 1
        lock = redis_client.setnx(lock_key, lock_timeout)
    
    //真正要处理的业务
    doing() 
    
    //释放锁
    now = int(time.time())
    if now < lock_timeout:
        redis_client.delete(lock_key)

    以上是一个只说明流程的伪代码,其实整体的逻辑是很简单的,只要考虑到死锁时的情况,就比较好处理了。Redis作为分布式锁,因为其性能的优势,不会成为瓶颈,一般会产生瓶颈的是真正的业务处理内容,还是尽量缩小锁的范围来确保系统性能。

    1.4 自动过期能有效提升开发效率

    Redis针对数据都可以设置过期时间,这个特点也是大家应用比较多的,过期的数据清理无需使用方去关注,所以开发效率也比较高,当然,性能也比较高。最常见的就是:短信验证码、具有时间性的商品展示等。无需像数据库还要去查时间进行对比。因为使用比较简单,就不赘述了

    1.5 分布式和持久化有效应对海量数据和高并发

    Redis初期的版本官方只是支持单机或者简单的主从,大多应用则都是自己去开发集群的中间件,但是随着应用越来越广泛,用户关于分布式的呼声越来越高,所以Redis 3.0版本时候官方加入了分布式的支持,主要是两个方面:

    • Redis服务器主从热备,确保系统稳定性
    • Redis分片应对海量数据和高并发

    而且Redis虽然是一个内存缓存,数据存在内存,但是Redis支持多种方式将数据持久化,写入硬盘,所有,Redis数据的稳定性也是非常有保障的,结合Redis的集群方案,有的系统已经将Redis当做一种NoSql数据存储来适用。

    1.6 示例:秒杀和Redis的结合

    秒杀是现在互联网系统中常见的营销模式,作为开发者,其实最不愿意这样的活动,因为非技术人员无法理解到其中的技术难度,导致在资源协调上总是有些偏差。秒杀其实经常会出现的问题包括:

    • 并发太高导致程序阻塞。
    • 库存无法有效控制,出现超卖的情况。

    其实解决这些问题基本就两个方案:

    • 数据尽量缓存,阻断用户和数据库的直接交互。
    • 通过锁来控制避免超卖现象。

    现在说明一下,如果现在做一个秒杀,那么,Redis应该如何结合进行使用?

    • 提前预热数据,放入Redis
    • 商品列表放入Redis List
    • 商品的详情数据 Redis hash保存,设置过期时间
    • 商品的库存数据Redis sorted set保存
    • 用户的地址信息Redis set保存
    • 订单产生扣库存通过Redis制造分布式锁,库存同步扣除
    • 订单产生后发货的数据,产生Redis list,通过消息队列处理
    • 秒杀结束后,再把Redis数据和数据库进行同步

    2. 大多数人经常认为它是一个简单的键值存储,但它拥有很多强大的功能。

    2.1 整页缓存

    使用服务器端渲染页面,如果不希望为每个请求重新渲染页面。可以使用 redis 将其缓存起来,可以大大减少请求页面的延迟。

    // Set the page that will last 1 minute
    SET key "<html>...</html>" EX 60
    
    // Get the page
    GET key

    2.2 排行榜

    redis 在内存中可以非常快速和高效地处理递增和递减。比起为每个请求执行一次 SQL 查询它可以给应用节省很多的时间!

    使用 redis 的 sortedset 你可以以毫秒为单位抓取列表中评分最高的项目,而且用起来非常的简单。

    // Add an item to the sorted set
    ZADD sortedSet 1 "one"
    
    // Get all items from the sorted set
    ZRANGE sortedSet 0 -1
    
    // Get all items from the sorted set with their score
    ZRANGE sortedSet 0 -1 WITHSCORES

    2.3 Session 存储

    我们通常会使用 redis 来储存 session,和其他的缓存系统不同(例如Memcache),redis 可以持久化储存 session,这样就算服务器出故障这些 session 也不会丢失。

    // Set session that will last 1 minute
    SET randomHash "{userId}" EX 60
    
    // Get userId
    GET randomHash

    2.4 队列

    一个不太常见但非常有用的是你可以用 redis 创建队列,无论是电子邮件还是应用程序使用的其他数据,都可以使用 redis 来创建一个高效的队列。

    // Add a Message
    HSET messages <id> <message>
    ZADD due <due_timestamp> <id>
    
    // Recieving Message
    ZRANGEBYSCORE due -inf <current_timestamp> LIMIT 0 1
    HGET messages <message_id>
    
    // Delete  Message
    ZREM due <message_id>
    HDEL messages <message_id>

    2.5 Pub/Sub

    Pub/Sub 可以用在很多的地方。你可以用来创建一个实时聊天系统,触发社交网络上的朋友请求通知等等。这个功能是 redis 提供的最被低估的功能之一。

    // Add a message to a channel
    PUBLISH channel message
    
    // Recieve messages from a channel
    SUBSCRIBE channel

     3. redis数据类型及基本操作

     redis共有五种数据类型。

    1).String 可以是字符串、整数或浮点,统称为元素

    string是redis最基本的类型,你可以理解成与Memcached一模一样的类型,一个key对应一个value。

    string类型是二进制安全的。意思是redis的string可以包含任何数据。比如jpg图片或者序列化的对象 。

    string类型是Redis最基本的数据类型,一个键最大能存储512MB。

    redis 127.0.0.1:6379> SET name "runoob"
    OK
    redis 127.0.0.1:6379> GET name
    "runoob"

    2).list 一个序列集合且每个节点都包好了一个元素

    Redis 列表是简单的字符串列表,按照插入顺序排序。你可以添加一个元素到列表的头部(左边)或者尾部(右边)。

    redis 127.0.0.1:6379> lpush runoob redis
    (integer) 1
    redis 127.0.0.1:6379> lpush runoob mongodb
    (integer) 2
    redis 127.0.0.1:6379> lpush runoob rabitmq
    (integer) 3
    redis 127.0.0.1:6379> lrange runoob 0 10
    1) "rabitmq"
    2) "mongodb"
    3) "redis"

    3).Set 各不相同的元素

    Redis的Set是string类型的无序集合。

    集合是通过哈希表实现的,所以添加,删除,查找的复杂度都是O(1)。

    sadd 命令

    sadd key member

    添加一个 string 元素到 key 对应的 set 集合中,成功返回1,如果元素已经在集合中返回 0,如果 key 对应的 set 不存在则返回错误。

    redis 127.0.0.1:6379> sadd runoob redis
    (integer) 1
    redis 127.0.0.1:6379> sadd runoob mongodb
    (integer) 1
    redis 127.0.0.1:6379> sadd runoob rabitmq
    (integer) 1
    redis 127.0.0.1:6379> sadd runoob rabitmq
    (integer) 0
    redis 127.0.0.1:6379> smembers runoob
    
    1) "redis"
    2) "rabitmq"
    3) "mongodb"

    4).Hash 有key-value的散列组,其中key是字符串,value是元素

    Redis hash 是一个键值(key=>value)对集合。

    Redis hash是一个string类型的field和value的映射表,hash特别适合用于存储对象

    redis> HMSET myhash field1 "Hello" field2 "World"
    "OK"
    redis> HGET myhash field1
    "Hello"
    redis> HGET myhash field2
    "World"

    5).zsetSort-Set 带分数的score-value有序集合,其中score为浮点,value为元素

     Redis zset 和 set 一样也是string类型元素的集合,且不允许重复的成员。

    不同的是每个元素都会关联一个double类型的分数。redis正是通过分数来为集合中的成员进行从小到大的排序

    zset的成员是唯一的,但分数(score)却可以重复。

    zadd key score member 

    zadd 命令

    添加元素到集合,元素在集合中存在则更新对应score

    redis 127.0.0.1:6379> zadd runoob 0 redis
    (integer) 1
    redis 127.0.0.1:6379> zadd runoob 0 mongodb
    (integer) 1
    redis 127.0.0.1:6379> zadd runoob 0 rabitmq
    (integer) 1
    redis 127.0.0.1:6379> zadd runoob 0 rabitmq
    (integer) 0
    redis 127.0.0.1:6379> > ZRANGEBYSCORE runoob 0 1000
    1) "mongodb"
    2) "rabitmq"
    3) "redis"
    
    
  • 相关阅读:
    手机号不能为空
    选项卡套选项卡
    可以在一个html的文件当中读取另一个html文件的内容
    价格计算
    v形 加强版
    V形
    生成100个Div
    伪元素::after和::before
    数组中的toString,toLocalString,valueOf方法有什么区别
    JavaScript toLocaleString() 方法
  • 原文地址:https://www.cnblogs.com/miaoxiaonao/p/9046821.html
Copyright © 2011-2022 走看看