缓存的基础知识,你们都了解了吗?

1、什么是缓存?

1.1、定义

存储在计算机上的一个原始数据的复制集,以便于访问。

缓存是介于数据访问者和数据源之间的一种高速存储,当数据需要多次读取的时候,用于监控读取的速度。

缓存是有读操作,多次读取的时候才需要用缓存

缓存所在的领域:CPU缓存、操作系统缓存、数据库缓存、JVM编译缓存、CDN缓存、代理与反向代理缓存、前端缓存、应用程序缓存、分布式对象缓存;

1.2、缓存的数据存储(Hash表)

  • 访问复杂度O(1),以key/value的形式存储;

  • 通过key计算hashcode,比如“abc”.hashcode=101;

  • 根据hashcode计算哈希表的下标索引,通过余模8取值;

  • 数据存储结构是哈希表结构,每个地址的长度是8个字节;

  • 每个数据保存的是值空间的指针;

1.3、关键指标

缓存命中率是说,缓存是否有效依赖于能多少次重用用一个缓存响应业务请求

主要指标:

  • 缓存键集合的大小:缓存中的每一个对象使用缓存键识别,定位一个对象的唯一方式就是对缓存键执行精确匹配,缓存键越少,命中率越高;

  • 缓存可使用内存空间;缓存可使用空间直接决定了缓存对象的平均大小和缓存对象数量;

  • 缓存对象生存时间:缓存对象生存时间TTL(Time To Live),对象缓存的时间越长,缓存对象被重用的可能性越高

1.4、缓存种类

  • 代理服务器:客户端连接到本地代理服务器,获取静态资源,如果缓存未命中则去服务器获取;

  • 反向代理服务缓存:客户端在数据中心访问,请求进来时做缓存代理,未命中则请求资源;

  • 多层反向代理缓存:由多层反向代理服务缓存,RestFul风格特别适合做缓存代理;

  • 内容分发网络:也叫CDN,CDN放在网络提供的数据中心,客户端请求CDN服务数据中心,然后CDN没有名字发至服务器

  • 通读缓存:应用程序连通读缓存,由通读缓存去查找,只能去连接缓存,看不到数据源,一般代理缓存、反向代理缓存、CDN缓存

  • 旁路缓存:客户端会连接缓存服务端,如果没有命中,则由服务端直接去查服务数据,对象缓存就是一种旁路缓存

2、算法

2.1、一致性hash

  • 开始位置0,结束位置2^23-1,hashcode的范围;

  • 每个服务器节点取hash值,三个服务NODE0、NODE1、NODE2;

  • 根据算出来的hash值顺时针查找获取最近的服务节点;

  • 扩容时新增节点只需要变更最近的key值,影响范围较小;

  • hash值是一个随机数,导致数据分布不均匀,负载不均衡;

2.2、基于虚拟节点的一致性Hash算法

  • 服务器字符串的hash值放到环上,节点变成虚拟节点;

  • 一个服务分成多个虚拟节点均匀的分布在环上面;

  • 根据算出来的hash值顺时针查找获取最近的虚拟节点;

  • 影响范围是基本所有虚拟节点都会受到影响,但是影响的数据量相对较少;

3、性能

3.1、为什么缓存能提高性能

缓存数据通常来自于内存,比磁盘上的数据有更快的访问速度;

缓存存储数据的最终结果形态,不需要中间计算,减少CPU资源的消耗;

缓存降低数据库、磁盘、网络的负载压力,是这些I/O设备活动更好的响应特性

缓存一般有几个特点:技术简单、性能提升显著、应用场景多

3.2、合理的使用缓存

使用缓存对提高系统性能有很多好处、但是不合理的使用缓存可能非但不能提高系统的性能,还会成为系统的累赘,甚至风险。实践中,缓存滥用的情景屡见不鲜。

频繁修改的数据,不应该缓存,由于频繁修改,应用还来不及读取就已经失效了,增加系统负担,一般来说,数据的读写比例在2:1,缓存才有意义;

没有热点的访问:缓存使用内存作为存储,内存资源宝贵而有限,不能将所有的数据缓存起来,如果应用系统访问数据没有热点,不遵循二八定律,即大部分数据访问不是集中的小部分数据,name缓存就没有意义;

缓存雪崩:缓存是为了提供数据读取性能,缓存数据丢失或者缓存不可用不会影响到应用程序的作用,他可以直接获取数据库的数据。随着业务的发展,缓存会承受大部分的数据访问压力,进而导致整个网站不可用。

缓存预热:缓存中存放的是热点数据,热点数据又是缓存利用LRU算法对不断访问的数据筛选淘汰处理的,过程时间较长,这段时间对系统的负载不太友好,一般是在系统启动的时候就把热点数据预热好。

缓存穿透:如果不恰当的业务或者恶意攻击持续高并发的请求某个不存在的数据,以为缓存没有报错该数据,所有的请求都会落在数据库上面,会对数据库造成很大的压力甚至奔溃,一个简单的对策是将不存在的数据也缓存起来,并设定一个较短的失效时间。

4、Hash算法实现

4.1、一致性Hash实现

public class HashNodeHandler {


    private List<String> nodes;


    private TreeMap<Integer, String> virtualNodes = new TreeMap<>();


    private TreeMap<String, Integer> serverVisit = new TreeMap<>();


    private int nodeNum;


    public HashNodeHandler(List<String> nodes,Integer nodeNum){
        this.nodes = nodes;
        this.nodeNum = nodeNum;
    }


    public void calculation(){
        nodes.forEach(s -> {
            serverVisit.put(s, 0);
            for (int i = 0; i < nodeNum; i++) {
                virtualNodes.put(hash(s + "NODE=" + i), s);
            }
        });


    }


    public void put(Object object){
        int hash = hash(object);
        SortedMap<Integer, String> integerStringSortedMap = virtualNodes.tailMap(hash);
        String server = "";
        if (integerStringSortedMap.isEmpty()) {
            // 如果没有比reqHash大的值,则返回第一个虚拟服务器节点
            server = virtualNodes.get(virtualNodes.firstKey());
        } else {
            // greaterMap第一个值就是顺时针下离reqHash最近的虚拟服务器节点
            server = integerStringSortedMap.get(integerStringSortedMap.firstKey());
        }
        serverVisit.put(server, serverVisit.get(server) + 1);
    }


    private int hash(Object key) {
        int h;
        return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
    }


    public double calculationStandard() {
        Integer[] visitData = new Integer[serverVisit.size()];
        serverVisit.values().toArray(visitData);
        double avg = Arrays.stream(visitData).mapToInt(Integer::intValue).average().orElse(0d);
        double avgStd = Arrays.stream(visitData).map(count -> Math.pow(count - avg, 2)).mapToDouble(Double::doubleValue).average().orElse(0d);
        double std = Math.sqrt(avgStd);
        return std;
    }


    public TreeMap<String, Integer> getServerVisit() {
        return serverVisit;
    }


}


4.2、测试类

public class HashTest {
    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("192.168.0.1");
        list.add("192.168.0.2");
        list.add("192.168.0.3");
        list.add("192.168.0.4");
        list.add("192.168.0.5");
        list.add("192.168.0.6");
        list.add("192.168.0.7");
        list.add("192.168.0.8");
        list.add("192.168.0.9");
        list.add("192.168.0.10");
        int num = 2000;
        HashNodeHandler hashNodeHandler = new HashNodeHandler(list, num);
        hashNodeHandler.calculation();
        test1000000(hashNodeHandler);
    }


    private static void test1000000(HashNodeHandler hashNodeHandler) {
        int num = 1000000;
        loop(hashNodeHandler,num);
    }


    private static void loop(HashNodeHandler hashNodeHandler,int num) {
        for (int i = 0; i < num; i++) {
            hashNodeHandler.put(i+"nodeDa");
        }
        System.out.println(hashNodeHandler.getServerVisit());
        System.out.println(hashNodeHandler.calculationStandard());


    }


}


4.2、测试结果

服务器数量:10
虚拟节点数量:2000
测试数据量:1000000
服务器分配情况:{192.168.0.1=185375, 192.168.0.10=88721, 192.168.0.2=136291, 192.168.0.3=67317, 192.168.0.4=141577, 192.168.0.5=84482, 192.168.0.6=75216, 192.168.0.7=83256, 192.168.0.8=69623, 192.168.0.9=68142}
标准差:38213.9756816796


服务器数量:11
虚拟节点数量:2200
测试数据量:1000000
服务器分配情况:{192.168.0.1=185375, 192.168.0.10=88721, 192.168.0.11=30946, 192.168.0.2=136291, 192.168.0.3=66028, 192.168.0.4=141577, 192.168.0.5=81289, 192.168.0.6=75216, 192.168.0.7=56792, 192.168.0.8=69623, 192.168.0.9=68142}
标准差:42899.69760532234




服务器数量:8
虚拟节点数量:1600
测试数据量:1000000
服务器分配情况:{192.168.0.1=185375, 192.168.0.2=197838, 192.168.0.3=123376, 192.168.0.4=141577, 192.168.0.5=84482, 192.168.0.6=108407, 192.168.0.7=83256, 192.168.0.8=75689}
标准差:43759.45812621541
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
是的,WebRTC 缓存问题可能涉及到本地缓存。在 WebRTC 中,本地缓存通常指的是浏览器或应用程序在本地存储媒体数据的临时文件或缓冲区。 当进行音视频通话或媒体流传输时,WebRTC 可能会将接收到的数据暂时存储在本地缓存中,以确保较平滑的播放体验。这可以帮助处理网络延迟、丢包或其他网络不稳定情况。 然而,本地缓存也可能导致一些问题,例如延迟增加、占用过多的存储空间或数据不同步。这些问题可能是由于缓存设置不合理、缓存文件损坏或其他应用程序相关的问题引起的。 如果你遇到 WebRTC 缓存问题并怀疑与本地缓存有关,你可以尝试以下方法: 1. 清除浏览器缓存:清除浏览器的缓存可能会清除一些本地缓存文件。尝试清除浏览器缓存后,重新加载页面并测试是否仍然存在问题。 2. 调整缓存设置:如果你有权限访问 WebRTC 应用程序的设置,可以尝试调整相关的缓存设置。例如,你可以尝试更改本地缓存文件的存储位置或缓存大小。 3. 重启浏览器或应用程序:有时候,重启浏览器或应用程序可以清除一些临时文件或重置缓存设置,从而解决问题。 请注意,具体的解决方法可能会因应用程序、浏览器或操作系统的不同而有所差异。如果以上方法无法解决问题,建议查看相关的开发者文档或寻求社区支持以获取更详细的指导和解决方案。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值