【缓存】-缓存中间件

时间:2024-10-14 20:38:33

简介:主要介绍缓存中间件MemCachedRedis

MemCached

1、MemCached介绍
MemCached是一种基于内存的key-value存储,用来存储小块的任意数据(字符串、对象)。它便于快速开发,减轻开发难度,解决了大数据量缓存的很多问题,本质上,它是一个简洁的key-value存储系统

2、MemCached工作原理
主要通过缓存数据库查询结果,减少数据库访问次数,以提高动态Web应用的速度。见下图:
这里写图片描述

Redis

1、Redis简介

Redis 是完全开源免费的,是一个高性能的key-value数据库。

Redis 与其他 key - value 缓存产品有以下三个特点:
(1)Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
(2)Redis支持String、list、set、zset、hash等数据结构的存储。
(3)Redis支持数据的备份,即master-slave模式的数据备份。

2、Linux下安装Redis

下载地址:/download
(1)下载并安装:

$ wget http://download.redis.io/releases/redis-4.0.10.tar.gz
$ tar xzf redis-4.0.10.tar.gz
$ cd redis-4.0.10
$ make
  • 1
  • 2
  • 3
  • 4

(2)启动redis服务

$ cd src
$ ./redis-server
  • 1
  • 2

(3)使用redis客户端

$ cd src
$ ./redis-cli
redis> set companyName G7
OK
redis> get companyName 
"G7"
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

3、Java使用Redis

import ;
import .*;

/**
 * Created by pc on 2018/7/23.
 * Redis数据类型
 */
public class RedisDemo
{
    //String
    public static void redisString(){
        //连接 Redis 服务
        Jedis jedis = new Jedis("172.16.*.**",6379);
        System.out.println("连接成功");
        //查看服务是否运行
        System.out.println("Server is running: " + ());
        //设置 redis 字符串数据
        jedis.set("runoobkey", "");
        // 获取存储的数据并输出
        System.out.println("redis 存储的字符串为: "+ jedis.get("runoobkey"));
    }

    //list
    public static void redisList(){
        //连接 Redis 服务
        Jedis jedis = new Jedis("172.16.*.**",6379);
        System.out.println("连接成功");
        //存储数据到列表中
        ("site-list", "Baidu");
        ("site-list", "Google");
        ("site-list", "Taobao");
        // 获取存储的数据并输出
        List<String> list = ("site-list", 0 ,2);
        for(int i=0; i<(); i++) {
            System.out.println("列表项为: "+list.get(i));
        }
    }

    //set
    public static void redisSet(){
        //连接 Redis 服务
        Jedis jedis = new Jedis("172.16.*.**",6379);
        System.out.println("连接成功");
        //存入set的值
        Long mySet = ("websites", "Baidu", "Taobao", "Google");
        //获取set的值
        Set<String> website = ("websites");
        Iterator<String> it = ();
        while(()){
            System.out.println(());
        }
    }

    //hash
    public static void redisHash(){
        //连接 Redis 服务
        Jedis jedis = new Jedis("172.16.*.**",6379);
        System.out.println("连接成功");
        Map<String, String> hashMap = new HashMap<>();
        ("Baidu","");
        ("Taobao","");
        ("Google","");
        ("website", hashMap);
        System.out.println(("website"));

    }

    public static void main(String[] args) {
        redisString();
//        redisList();
//        redisSet();
//        redisHash();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75

运行后,如下图:
这里写图片描述

4、Redis缓存策略

(1)缓存【失效】:客户端请求数据先从缓存中查询,如果没有再查询数据库,最后将数据放入缓存
(2)缓存【命中】:客户端从缓存中直接取到数据,返回结果
(3)缓存【更新】:客户端写入数据到数据库,成功之后,让缓存失效(下次请求时从缓存中拿不到,则查询数据库,再放入缓存)

5、有问题的几种更新缓存策略

(1)先更新缓存,然后更新DB。见下图:
这里写图片描述

从图中可以看出,两个并发写操作,由于某些原因(io阻塞,cpu时间片分配,协程调度,网络原因等等),导致Thread2的更新DB晚于Thread1的更新DB,但是Redis中此时的数据Thread1的,而DB中的数据时Thread2的,这就出现了不一致的问题,DB中是脏数据

(2)先更新DB,然后更新缓存。见下图:
这里写图片描述

从图中可以看出,两个并发写操作,由于某些原因导致Thread2的更新Redis晚于Thread1的更新Redis ,但是DB中此时的数据Thread1的,而Redis中的数据时Thread2的,这就出现了不一致的问题

(3)先删除缓存,然后再更新数据库。见下图:
这里写图片描述

两个并发操作,一个是更新操作,另一个是查询操作,更新操作删除缓存后,查询操作没有命中缓存,会把老数据读出来后放到缓存中,然后更新操作更新了DB。于是,在缓存中的数据还是老的数据,导致缓存中的数据是脏的

(4)先数据库,成功之后,让缓存失效,下次请求时从缓存中拿不到,则查询数据库,再放入缓存。见下图:
这里写图片描述

这种更新策略是我们实际最常用的,但也可能出现问题。实际上出现问题的概率可能非常低,因为这个条件需要发生在读缓存时缓存失效,而且并发着有一个写操作。而实际上数据库的写操作会比读操作慢得多,而且还要锁表,而读操作必需在写操作前进入数据库操作,而又要晚于写操作更新缓存,所有的这些条件都具备的概率基本并不大。

6、Redis与MemCached的区别

(1)Redis和Memcache都是将数据存放在内存中,都是内存数据库。不过memcache还可用于缓存其他东西,例如图片、视频等等;
(2)Redis不仅仅支持简单的k/v类型的数据,同时还提供list,set,hash等数据结构的存储;
(3)虚拟内存–Redis当物理内存用完时,可以将一些很久没用到的value 交换到磁盘;
(4)分布式集群部署:
a、memcache集群节点间的数据是独立的,不能相互通讯,但可以利用magent开源软件解决 ;
b、Redis高可用的,可以做一主多从,主从之间进行数据同步。 当Master宕机后,通过选举算法(Paxos、Raft)从slave中选举出新Master继续对外提供服务,主机恢复后以slave的身份重新加入
(5)存储数据安全–memcache挂掉后,数据没了;redis可以定期保存到磁盘(持久化);
(6)灾难恢复–memcache挂掉后,数据不可恢复; redis数据丢失后可以通过aof恢复;

……完