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减少地理位置的坐标,能够批量增加地理位置
XLENstream流中的音讯数量
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命令返回信息
serverRedis服务器的个别信息
clients客户端的连贯局部
memory内存耗费相干信息
persistence长久化相干信息
stats个别统计
replication主/从复制信息
cpu统计CPU的耗费
commandstatsRedis命令统计
clusterRedis集群信息
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. 布隆过滤器