关于java:面试题之java缓存总结从单机缓存到分布式缓存架构

1、缓存定义

高速数据存储层,进步程序性能

2、为什么要用缓存(读多写少,高并发)

1、进步读取吞吐量

2、晋升应用程序性能

3、升高数据库老本

4、缩小后端负载

5、打消数据库热点

6、可预测的性能

3、缓存分类

3.1、单机缓存(localCache)

实现计划

1、基于JSR107标准自研(理解即可):

1、Java Caching定义了5个外围接口,别离是CachingProvider, CacheManager, Cache, Entry 和 Expiry。
2、CachingProvider定义了创立、配置、获取、治理和管制多个CacheManager。一个利用能够在运行期拜访多个CachingProvider。
3、CacheManager定义了创立、配置、获取、治理和管制多个惟一命名的Cache,这些Cache存在于CacheManager的上下文中。一个CacheManager仅被一个CachingProvider所领有。
4、Cache是一个相似Map的数据结构并长期存储以Key为索引的值。一个Cache仅被一个CacheManager所领有。
5、Entry是一个存储在Cache中的key-value对。
每一个存储在Cache中的条目有一个定义的有效期,即Expiry Duration。
一旦超过这个工夫,条目为过期的状态。一旦过期,条目将不可拜访、更新和删除。缓存有效期能够通过ExpiryPolicy设置。

2、基于ConcurrentHashMap实现数据缓存

3.2、分布式缓存(redis、Memcached)

4、单机缓存

1、本人实现一个单机缓存

创立缓存类

/**
 * @author yinfeng
 * @description 本地缓存实现:用map实现一个简略的缓存性能
 * @since 2022/2/8 13:54
 */
public class MapCacheDemo {

    /**
     * 在构造函数中,创立了一个守护程序线程,每5秒扫描一次并清理过期的对象
     */
    private static final int CLEAN_UP_PERIOD_IN_SEC = 5;

    /**
     * ConcurrentHashMap保障线程平安的要求
     * SoftReference <Object>  作为映射值,因为软援用能够保障在抛出OutOfMemory之前,如果短少内存,将删除援用的对象。
     */
    private final ConcurrentHashMap<String, SoftReference<CacheObject>> cache = new ConcurrentHashMap<>();

    public MapCacheDemo() {
        //创立了一个守护程序线程,每5秒扫描一次并清理过期的对象
        Thread cleanerThread = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    Thread.sleep(CLEAN_UP_PERIOD_IN_SEC * 1000);
                    cache.entrySet().removeIf(entry -> Optional.ofNullable(entry.getValue()).map(SoftReference::get).map(CacheObject::isExpired).orElse(false));
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        });
        cleanerThread.setDaemon(true);
        cleanerThread.start();
    }

    public void add(String key, Object value, long periodInMillis) {
        if (key == null) {
            return;
        }
        if (value == null) {
            cache.remove(key);
        } else {
            long expiryTime = System.currentTimeMillis() + periodInMillis;
            cache.put(key, new SoftReference<>(new CacheObject(value, expiryTime)));
        }
    }

    public void remove(String key) {
        cache.remove(key);
    }

    public Object get(String key) {
        return Optional.ofNullable(cache.get(key)).map(SoftReference::get).filter(cacheObject -> !cacheObject.isExpired()).map(CacheObject::getValue).orElse(null);
    }

    public void clear() {
        cache.clear();
    }

    public long size() {
        return cache.entrySet().stream().filter(entry -> Optional.ofNullable(entry.getValue()).map(SoftReference::get).map(cacheObject -> !cacheObject.isExpired()).orElse(false)).count();
    }

    /**
     * 缓存对象value
     */
    private static class CacheObject {
        private Object value;
        private final long expiryTime;

        private CacheObject(Object value, long expiryTime) {
            this.value = value;
            this.expiryTime = expiryTime;
        }

        boolean isExpired() {
            return System.currentTimeMillis() > expiryTime;
        }

        public Object getValue() {
            return value;
        }

        public void setValue(Object value) {
            this.value = value;
        }
    }

  
}

写个main办法测试一下

public static void main(String[] args) throws InterruptedException {
        MapCacheDemo mapCacheDemo = new MapCacheDemo();
        mapCacheDemo.add("uid_10001", "{1}", 5 * 1000);
        mapCacheDemo.add("uid_10002", "{2}", 5 * 1000);
        System.out.println("从缓存中取出值:" + mapCacheDemo.get("uid_10001"));
        Thread.sleep(5000L);
        System.out.println("5秒钟过后");
        // 5秒后数据主动革除了
        System.out.println("从缓存中取出值:" + mapCacheDemo.get("uid_10001"));
    }

2、谷歌guava cache缓存框架

2.1、简介

Guava Cache是一个内存缓存模块,用于将数据缓存到jvm内存中,是单个利用运行时的本地缓存,他不将数据放到文件或内部服务器。

2.2 简略应用

/**
 * @author yinfeng
 * @description guava测试,https://github.com/google/guava
 * @since 2022/2/8 14:13
 */
public class GuavaCacheDemo {
    public static void main(String[] args) throws ExecutionException {
        //缓存接口这里是LoadingCache,LoadingCache在缓存项不存在时能够主动加载缓存
        LoadingCache<String, User> userCache
                //CacheBuilder的构造函数是公有的,只能通过其静态方法newBuilder()来取得CacheBuilder的实例
                = CacheBuilder.newBuilder()
                //设置并发级别为8,并发级别是指能够同时写缓存的线程数
                .concurrencyLevel(8)
                //设置写缓存后8秒钟过期
                .expireAfterWrite(8, TimeUnit.SECONDS)
                //设置写缓存后1秒钟刷新
                .refreshAfterWrite(1, TimeUnit.SECONDS)
                //设置缓存容器的初始容量为10
                .initialCapacity(10)
                //设置缓存最大容量为100,超过100之后就会依照LRU最近虽少应用算法来移除缓存项
                .maximumSize(100)
                //设置要统计缓存的命中率
                .recordStats()
                //设置缓存的移除告诉
                .removalListener(notification -> System.out.println(notification.getKey() + " 被移除了,起因: " + notification.getCause()))
                //build办法中能够指定CacheLoader,在缓存不存在时通过CacheLoader的实现主动加载缓存
                .build(
                        new CacheLoader<String, User>() {
                            @Override
                            public User load(String key) {
                                System.out.println("缓存没有时,从数据库加载" + key);
                                // TODO jdbc的代码~~疏忽掉
                                return new User("yinfeng" + key, key);
                            }
                        }
                );
        // 第一次读取
        for (int i = 0; i < 20; i++) {
            User user = userCache.get("uid" + i);
            System.out.println(user);
        }
        // 第二次读取
        for (int i = 0; i < 20; i++) {
            User user = userCache.get("uid" + i);
            System.out.println(user);
        }
        System.out.println("cache stats:");
        //最初打印缓存的命中率等 状况
        System.out.println(userCache.stats().toString());
    }

    @Data
    @AllArgsConstructor
    public static class User implements Serializable {
        private String userName;
        private String userId;
        @Override
        public String toString() {
            return userId + " --- " + userName;
        }
    }
}

5、分布式缓存

5.1 redis

5.1.1 介绍

Redis是一个开源的应用C语言缩写、反对网络、可基于内存亦可长久化的日志型,Key-Value数据库,并提供多种语言的API。

实质是客户端-服务端应用软件程序。

特点是应用简略,性能强悍,性能利用场景丰盛。

5.1.2通用命令

命令 作用
DEL key 用于在key存在是删除key
DUMP key 序列化给定的key,并返回给定的值
EXISTS key 查看给定key是否存在
EXPIRE key seconds 为给定key设置过期工夫,单位秒
TTL key 以秒为单位,返回给定key的残余生存工夫
TYPE key 返回key所存储的值的类型

5.1.3 数据结构

1. String

定义

String数据结构是简略的key-value类型,value其实不仅是String,也能够是数字。

应用场景:微博数,粉丝数(惯例计数)

常用命令

命令 作用
Get 获取指定key的值
Set 设置指定key的值
Incr 将key中贮存的数字值增一
Decr 将key中贮存的数字值减一
Mget 获取所有(一个或多个)给定key的值

2. List

定义

List就是链表,依赖于链表构造

应用场景:微博的关注列表,粉丝列表

常用命令

命令 作用
Lpush 将一个或多个值插入到列表头部
Rpush 在列表中增加一个或多个值
Lpop 移出并获取列表的第一个元素
Rpop 移除列表的最初一个元素,返回值为移除的元素
Lrange 获取所有(一个或多个)给定key的值

3. Set

定义

Set就是一个汇合,汇合的概念就是一堆不反复值的组合。利用Reds提供的Set数据结构,能够存储一些汇合性的数据。

应用场景:实现如独特关注,独特爱好,二度好友

常用命令

命令 作用
Lpush 向汇合中增加一个或多个成员
Rpush 移除并返回汇合中的一个随机元素
Lpop 返回汇合中的所有成员
Rpop 返回所有给定汇合的并集

4. Sorted set

定义

Sorted set的应用场景与set相似,区别是set不是主动有序的,而sorted set能够通过用户额定提供一个优先级(score)的参数来为成员排序,并且是插入有序的,即主动排序。

应用场景:排行榜、依照用户投票和工夫排序

常用命令

命令 作用
Zadd 向有序汇合增加一个或多个成员,或者更新已存在成员的分数
Zrange 通过索引区间返回有序汇合中指定区间内的成员
Zrem 移除有序汇合中的一个或多个成员
Zcard 获取有序汇合的成员数

5. Hash

定义

Hash是一个sting类型的field和value的映射表

应用场景:存储局部变更数据,如用户信息

常用命令

命令 作用
Zadd 获取存储在哈希表中指定字段的值
Zrange 将哈希表key中的字段field的值设为value
Hgetall 获取在哈希表中指定key的所有字段和值

6. GEO

定义

GEO3.2版本开始对GEO(地理位置)的反对

应用场景:LBS利用开发

常用命令

命令 作用
GEOADD 减少地理位置的坐标,能够批量增加地理位置
GEODIST 获取两个地理位置的间隔
GEOHASH 获取某个地理位置的geohash值
GEOPOS 获取指定地位的坐标,能够批量获取多个地理位置的坐标
GEORADIUS 依据给定地理位置坐标获取指定范畴内的地理位置汇合(留神:该命令的中心点由输出的经度和结度决定)
GEORADIUSBYMEMBER 依据给定成员的地位获取指定范畴内的地位信息汇合(留神:该命令的中心点足由给定的地位元素决定)

7. Stream

定义

Stream5.0版本开始的新构造“流”

应用场景:消费者生产者场景(相似MO)

常用命令

命令 作用
XADD 减少地理位置的坐标,能够批量增加地理位置
XLEN stream流中的音讯数量
XDEL 删除流中的音讯
XRANGE 返回流中满足给定ID范畴的音讯
XREAD 从一个或者多个流中读取音讯
XINFO 检索对于流和关联的消费者组的不同的信息

5.1.4 长久化机制

1. 介绍

redis的数据都寄存在内存中,如果没有配置长久化,重启后数据就全失落,于是须要开启redis的长久化性能,将数据保留到磁盘上,当redis重启后,能够从磁盘中复原数据

2. 长久化形式

  1. RDB长久化:RDB长久化形式可能在指定的工夫距离对你的数据进行快照存储
  2. AOF长久化: AOF长久化形式记录每次对服务器写的操作,当服务器重后的时候会从新执行这些命令来复原原始的数据

3.RDB形式

客户端间接通过命令BGSAVE或者SAVE来创立一个内存快照:

  1. BGSAVE调用fork来创立一个子过程,子过程负责将快照写入磁盘,而父过程依然持续解决命令。
  2. SAVE执行SAVE命令过程中,不再响应其余命令。

在redis.conf中调整save配置选项,当在规定的工夫内,redis产生了写操作的个数满足条件会触发BGSAVE命令

#900秒之内至多一次写操作
save 900 1
#300秒之内至多产生10次写操作
save 300 10

优缺点

长处 毛病
对性能影响最小 同步时失落数据
RDB文件进行数据恢复比应用AOF要快很多 如果数据集十分大且CPU不够强(比方单核CPU),Redis在fork子过程时可能会耗费绝对较长的工夫,影响RediS对外提供服务的能力

4. AOF长久化形式

开启AOF长久化

appendonty yes

AOF策略调整

#每次有数据批改产生时都会写入AOF文件
appendfsync always
#每秒钟同步一次,该策略为AOF的默认策略
appendfsync everysec
#从不同步。高效然而数据不会被长久化
appendfsync no

长处

长处 毛病
最平安 文件体积大
容灾 性能耗费比RDB高
易读,可批改 数据恢复速度比RDB慢

5.1.5 内存治理

1、内存调配

不同数据类型的大小限度:

Strings类型:一个Strings类型的Value最大能够存储512M。

Lists类型:list的元素个数最多为2^32-1个

Sets类型:元素个数最多为2^32-1个

Hashes类型:键值对个数最多为2^32-1个

最大内存管制:

maxmemory 最大内存阈值

maxmemory-policy 达到阈值的执行策略

2、内存压缩

#配置字段最多512个
hash-max-zipmap-entries 512
#配置value最大为64字节
hash-max-zipmap-value 64
#配置元素个数最多512个
lst-max-zipmap-entries 512
#配置value最大为64字节
list-max-zipmap-value 64
#配置元素个数最多512个
set-max-zipmap-entries 512

大小超出压缩范畴,溢出后redis将主动将其转换为失常大小

3、过期数据的解决策略

被动解决(redis被动触发检测key足否过期)每秒抗行10次。过程如下:

  1. 从具备相干过期的key汇合中测试20个随机key
  2. 删除找到的所有已过期key
  3. 如果超过25%的key已过期,请从步骤1从新开始

被动解决:

  1. 每次拜访key的时候,发现超时后被动过期,清理掉

数据恢复阶段过期数据的解决策略:

RDB形式:过期的Key不会被长久化到文件中。载入时过期的key,会通过redis的被动和被动形式清理掉。

AOF形式:每次遇到过期的key,redis会追加一条DEL命令到AOF文件,也就是说只有咱们程序载入执行AOF命令文件就会删除过期的key

留神:过期数据的计算和计算机本身的工夫是有间接分割的!

Redis内存回收策略:

配置文件中设置:maxmemory-poIicy noeviction

命令动静调整:config set maxmemory-policy noeviction

回收策略 阐明
noeviction 客户端尝试执行会让更多内存被应用的命令间接报错
allkeys-lru 在所有key里执行LRU算法革除
volatile-lru 在所有曾经过期的key里执行LRU算法革除
allkeys-lfu 在所有key里执行LFU算法革除
volatile-lfu 在所有曾经过期的key里执行LFU算法革除
allkeys-random 在所有key里随机回收
volatile-random 在曾经过期的key里随机回收
volatile-ttl 回收曾经过期的key,并且优先回收存活工夫(TTL)较短的key

4、LRU算法

LRU(最近起码应用):依据数据的历史拜访记录来进行沟汰数据

核心思想:如果数据最近被拜访过,那么未来被拜访的几率也更高。

留神:Redis的LRU算法并非残缺的实现,残缺的LRU实现须要太多的内存。

办法:通过对大量keys进行取样(50%),而后回收其中一个最好的key。

配置形式:maxmemory-samples 5

5、LFU算法

LFU:依据数据的历史拜访频率来沟汰数据

核心思想:如果数据过来被拜访屡次,那么未来被拜访的频率也更高。

启用LFU算法后,能够应用热点数据分析性能。

5.1.6 主从复制

1、介绍

为什么要主从复制

redis-server单点故障

单节点QPS无限

利用场景剖析

读写拆散场景,躲避redis单机瓶颈

故障切换,master出问题后还有slave节点能够应用

2、搭建主从复制

主Redis Server以一般模式启动,次要是启动从服务器的形式

  1. 命令行

    #连贯须要实现从节点的rediS,执行上面的命令
    slaveof [ip] [port]
  1. redis.conf配置文件

    #配置文件中减少
    slaveof [ip] [port]
    #从服务器是否只读(默认yes)
    slave-read-only yes
  2. 退出主从集群的形式

    slaveof no one

3、查看主从复制

#redis客户端执行
info replication

4、主从复制流程

  1. 从服务器通过psync命令发送服务器已有的同步进度(同步源ID,同步进度offset)
  2. master收到申请,同步源为以后master,则依据偏移量增量同步
  3. 同步源非以后master,则进入全量同步:maser生成rdb,传输到slave,加载到slave内存

5、主从复制外围常识

  1. Redis默认应用异步复制,slave和master之间异步地确认解决的数据量
  2. 一个master能够领有多个slave
  3. Slave能够承受其余slave的连贯。slave能够有上级sub slave
  4. 主从同步过程在master侧是非阻塞的
  5. slave首次同步须要删除旧数据,加载新数据,会阻塞到来的连贯申请

6、利用场景

  1. 主从复制能够用来反对读写拆散
  2. slave服务器设定为只读,能够用在数据安全的场景下。
  3. 能够应用主从复制来防止master长久化造成的开销。master敞开长久化,slave设置为不定期保留或开启AOF
  4. 留神:重新启动的master程序将从一个空数据集开始,如果一个slave试图与它同步,那么这个slave也会被清空。

7、注意事项

  1. 读写拆散场景:

    数据复制延时导致读到过期数据或者读不到数据(网络起因,slave阻塞)

    从节点故障(多个client如何迁徙)

  2. 全量复制状况下:

    第一次建设主从关系或者runid不匹配会导致全量复制

    故障转移的时候也会呈现全量复制

  3. 复制风暴:

    master故障重启,如果slave节点过多,所有slave都要复制,对服务器的性能,网络的压力都有很大影响。

    如果一个机器部署了多个master

  4. 写能力无限

    主从复制还是只有一台master,提供的写服务能力无限

  5. master故障状况下:

    如果是mater无长久化,Slave开启长久化来保留数据的场展,倡议不要配置redis主动重启。

    启动redis主动重启,master启动后,无备份数据,可能导致集群数据失落的状况

  6. 带有效期的key:

    Slave不会让key过期,而是期待master让key过期

    在Lua脚本执行期间,不执行任何key过期操作

5.1.7 哨兵模式

1、哨兵(Sentinel)机制核心作用

客户端 ==询问主redis地址==> redis哨兵 ==监控、揭示、故障转移(主从切换)==> 主redis(master) ==主从复制关系==> 从redis(slave)

2、外围运作流程

服务发现和健康检查流程

搭建redis主从集群 ==> 启动哨兵(客户端通过哨兵发现Redis实例信息) ==> 哨兵通过连贯master发现主从集群内的所有实例信息 ==> 哨兵监控redis实例的健康状况

故障切换流程

哨兵一旦发现master不能失常提供服务,则告诉给其余哨兵 ==> 当肯定数量的哨兵都认为master挂了 ==> 选举一个哨兵作为故障转移的执行者 ==> 执行者在slave中选取一个作为新的master ==> 将其余slave从新设定为新master的隶属

3、哨兵如何晓得Redis主从信息

哨兵配置文件中,保留着主从集群中master的信息,能够通过info replication命令,进行主从信息主动发现。

4、什么是主观下线(sdown)

主观下线:单个哨兵本身认为redis实例曾经不能提供服务

检测机制:哨兵向redis发送ping申请,+PONG,-LOADING,-MASTERDOWN三种状况视为失常,其余回复均视为有效

对应配置文件的配置项:sentinel down-after-milliseconds mymaster 1000

5、什么是主观下线(odown)

主观下线:肯定数量值的哨兵认为master曾经下线。

检测机制:当哨兵主观认为maser下线后,则会通过SENTINEL is-master-down-by-addr命令询问其余哨兵是否认为master曾经下线,如果达成共识(达到quorum个数),就会认为master节点主观下线,开始故障转移流程

对应配置文件的配置项:sentinel monitor mymaster 1.0.0.1 6380 2

6、哨兵之间如何通信

  1. 哨兵之间的主动发现:公布本人的信息,订阅其余哨兵音讯(pub/sub)
  2. 哨兵之间通过命令进行通信:直连发送命令
  3. 哨兵之间通过订阅公布进行通信:互相订阅指定主题(pub/sub)

7、哨兵领导选举机制

基于Raft算法实现的选举机制,流程简述如下:

  1. 拉票阶段:每个哨兵节点心愿本人成为领导者;
  2. Sentinel节点收到拉票命令后,如果没有收到或批准过其余sentinel节点的申请,就批准该sentinel节点的申请(每个sentinel只持有一个批准票数)
  3. 如果sentinel节点发现自己的票数曾经超过一半的数值,那么它将成为领导者,去执行故障转移
  4. 投票完结后,如果超过failover-timeout的工夫内,没进行理论的故障转移操作,则从新拉票选举。

8、slave选举计划

slave节点状态 > 优先级 > 数据同步状况 > 最小的run id

9、最终主从切换的过程

针对行将成为master的slave节点,将其撒出主从集群,主动执行:slaveof NO ONE

针对其余slave节点,使它们成为新master的隶属,主动执行:slaveof new_master_host new_master_port

10、哨兵服务部署计划

不举荐:一主一从,两个哨兵

举荐:一主两从,三个哨兵

redis集群非强统一:一主两从,网络分区下可能呈现数据不统一或失落。

5.1.8 redis集群分片存储

1、为什么要分片存储

redis的内存需要可能超过机器的最大内存。(一台机器不够用)

2、官网集群计划

redis cluster是redis的分布式集科解决方案,在3.0版本推出后无效地解决了redis分布式分面的需要,实现了数据在多个Redis节点之间主动分片,故障主动转移,扩容机制等性能。

次要基于CRC16(key) % 16384 计算出每个key对应的slot,而后依据redis集群中实例的预设槽slot(16384个)进行对应的操作,slot不存储数据,仅仅用来做片区划分。

#### 3、搭建集群

  1. 筹备6个独立的redis服务
  2. 通过redis-cli工具创立集群
  3. 测验集群
  4. 故障转移测试
  5. 集群扩容
  6. 集群节点删除

4、集群关怀的问题

  1. 减少了slot槽的计算,是不是比单机性能差?

    不是的,为了防止每次都须要服务器计算重定向,优良的Java客户端都实现了本地计算,并且缓存服务器slots调配,有变动时再更新本地内容,从而防止了屡次重定向带来的性能损耗。

  2. redis集群大小,到底能够装多少数据?

    实践是能够做到16384个槽,每个槽对应一个实例,然而redis宫方倡议是最大1000个实例,因为存储曾经足够大了。

  3. 集群节点间是怎么通信的?

    每个Redis群集节点都有一个额定的TCP端口,每个节点应用TCP连贯与每个其余节点连贯。检测和故障转移这些步骤根本和哨兵模式相似。

  4. ask和moved重定向的区别

    重定向包含两种状况

    若确定slot不属于以后节点,redis会返回moved。

    若以后redis节点正在解决slot迁徙,则代表此处申请对应的key临时不在此节点,返回ask,通知客户端本次申请重定向。

  5. 数据歪斜和拜访歪斜的问题

    歪斜导致集群中局部节点数据多,压力大。解决方案分为后期和前期:

    后期是业务层面提前预测,哪些key是热点,在设计的过程中躲避。

    前期是slot迁徙,尽量将压力摊派(slot调整有主动rebalance、reshard和手动)。

  6. slot手动迁徙怎么做?

    1. 在迁徙目标节点执行cluster setslot <slot> IMPORTING <node ID>命令,指明须要迁徙的slot和迁徙源节点。
    2. 在迁徙源节点执行cluster setslot <slot> MIGRATING <node ID>命令,指明须要迁徙的slot和迁徙目标节点。
    3. 在迁徙源节点执行cluster getkeysinslot获取该slot的key列表
    4. 在迁徙源节点执行对每个key执行migrate命令,该命令会同步把该key迁徙到目标节点。
    5. 在迁徙源节点重复执行cluster getkeysinslo命令,直到该slot的列表为空。
    6. 在迁徙源节点和目标节点执行cluster setslot <slot> NODE <node ID>,实现迁徙操作。
  7. 节点之间会替换信息,传递的音讯包含槽的信息,带来带宽耗费。留神:防止应用大的一个集群,能够分多个集群。
  8. Pub/Sub公布订阅机制:对集群内任意的一个节点执行pubish公布音讯,这个音讯会在集群中进行流传,其余节点都接管到公布的音讯。
  9. 读写拆散:

    redis-cluster默认所有从节点上的读写,都会重定向到key对应槽的主节点上。

    能够通过readonly设置以后连贯可读,通过readwrite勾销以后连贯的可读状态。

    留神:主从节点仍然存在数据不统一的问题

5.1.9 redis监控

1、monitor命令

monitor是一个调试命令,返回服务器解决的每个命令。对于发现程序的谬误十分有用。出于平安思考,某些非凡治理命令CONFIG不会记录到MONITOR输入。

留神:运行一个MONITOR命令可能升高50%的吞吐量,运行多个MONITOR命令升高的吞吐量更多。

2、info命令

INFO命令以一种易于了解和浏览的格局,返回对于Redis服务器的各种信息和统计数值。

info命令 返回信息
server Redis服务器的个别信息
clients 客户端的连贯局部
memory 内存耗费相干信息
persistence 长久化相干信息
stats 个别统计
replication 主/从复制信息
cpu 统计CPU的耗费
commandstats Redis命令统计
cluster Redis集群信息
keyspace 数据库的相干统计

能够通过section返回局部信息,如果没有应用任何参数时,默认为detault。

3、图形化监控工具: Redis-Live

5.2 memcached入门

因为memcached缓缓淡出了人们的视线,应用的公司越来越少,所以这里只是做个入门介绍。

1、简介

是一个收费开源的、高性能的、具备分布式内存对象的缓存零碎,它通过加重数据库负载减速动静web利用。

实质上就是一个内存key-Value缓存

协定简略,应用的是基于文本行的协定

不反对数据的长久化,服务器敞开之后数据全副失落

Memcached简洁而弱小,便于疾速开发,上手较为容易

没有平安机制

2、设计理念

  1. 简略的键/值存储:服务器不关怀你的数据是什么样的,只管数据存储
  2. 服务端性能简略,很多逻辑依赖客户端实现

    客户端专一如何抉择读取或写入的服务器,以及无奈分割服务器时要执行的操作。

    服务器专一如何存储和治理何时革除或重用内存

  3. Memcached实例之间没有通信机制
  4. 每个命令的复杂度为0(1):慢速机器上的查问应该在1ms以下运行。高端服务器的吞吐量能够达到每秒数百万
  5. 缓存主动革除机制
  6. 缓存生效机制

3、常用命令

分组 命令 形容
存储命令 set 用于将value存储在指定的key中。key曾经存在,更新该key所对应的原来的数据。
add 用于将value存储在指定的key中,存在则不更新。
replace 替换已存在的key的Value,不存在,则替换失败。
append 用于向已存在key的value前面追加数据
prepend 向已存在key的value后面追加数据
cas 比拟和替换,比对后,没有被其余客户端批改的状况下能力写入。
检索命令 get 获取存储在key中的value,不存在,则返回空。
gets 获取带有CAS令牌存的value,若key不存在,则返回为空
删除 delete 删除已存在的key
计算 incr/decr 对已存在的key的数字值进行自增或自减操作
统计 stats 返回统计信息如PID(过程号)、版本号、连接数等
stats items 显示各个slab中item的数目和存储时长(最初一次拜访间隔当初的秒数)
stats slabs 显示各个slab的信息,包含chunk的大小、数目、应用状况等。
stats sizes 显示所有item的大小和个数
革除 flush_all 革除所有内容

4、客户端应用

客户端反对的个性:集群下多服务器抉择,节点权重配置,失败/故障转移,数据压缩,连贯治理

5、服务端配置

  1. 命令行参数

    查看memcached-h或man memcached获取最新文档

  2. init脚本

    如果通过yum利用商店装置,能够应用/etc/sysconfig/memcached文件进行参数配置

  3. 查看运行配置

    stats settings查看运行中的memcached的配置

6、memcached性能

Memcached性能的要害是硬件,外部实现是hash表,读写操作都是0(1)。硬件好,几百万的OPS都是没问题的。

最大连接数限度:外部基于事件机制(相似JAVA NIO)所以这个限度和nio相似,只有内存,操作系统参数进行调整,轻松几十万。

集群节点数量限度:实践是没限度的,然而节点越多,客户端须要建设的连贯就会越多。

留神:memcached服务端没有分布式的性能,所以不论是集群还是主从备份,都须要第三方产品反对。

7、服务器硬件须要

CPU要求:CPU占用率低,默认为4个工作线程

内存要求

memcached内容存在内存外面,所有内存使用率高。

倡议memcached实例独占服务器,而不是混用。

倡议每个memcached实例内存大小都足统一的,如果不统一则须要进行权重调整

网络要求

依据我的项目传输的内容来定,网络越大越好,尽管通常10M就够用了

倡议:我的项目往memcached传输的内容放弃尽可能的小

8、Memcached利用场景

  1. 数据查问缓存:将数据库中的数据加载到memcached,提供程序的访问速度
  2. 计数器的场景:通过incr/decr命令实现评论数量、点击数统计,操作次数等等场景。
  3. 乐观锁实现:例如打算工作多实例部暑的场景下,通过CAS实现不反复执行
  4. 避免反复解决:CAS命令

5.3 互联网高并发缓存架构

5.3.1 缓存架构剖析图

5.3.2 缓存雪崩

定义:因为缓存服务挂掉或者热点缓存生效,从而导致所有申请都去查数据库,导致数据库连贯不够用或者数据库解决不过去,从而导致整个零碎不可用。

罕用解决方案

  1. 缓存数据的过期工夫设置随机,避免同一时间大量数据过期景象产生。
  2. 缓存降级,间接返回错误码;
  3. 加锁实现避免大量申请堆到数据库。
  4. 设置热点数据永远不过期,避免了主动生效的状况,通过其余后盾检查程序,避免缓存数据和数据库长期不同步

5.3.2 缓存击穿

定义:查问必然不存在的数据,申请透过Redis,直击数据库。

罕用解决方案

  1. 用户内容预生成。
  2. 拜访频率限度。
  3. 缓存中无数据,也不查询数据库,间接返回错误码。
  4. 布隆过滤器

评论

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

这个站点使用 Akismet 来减少垃圾评论。了解你的评论数据如何被处理