关于缓存:DeepRoute-Lab-缓存对多线程程序性能的影响

当咱们的多线程程序遇到性能问题时,通常咱们会下意识地感觉这是因为上下文切换、cpu 迁徙等因素导致的。那么,如何更进一步地剖析到底是哪一部分语句造成了什么样的影响呢?这篇分享将从计算机体系结构的角度,联合十分典型的代码案例,为你解惑。 在进入正题之前,如果对缓存还不理解的读者,能够先看看这篇分享。DeepRoute Lab | 【C++性能】CPU Cache Serial 1 01引子1.1 第一个代码片段(点击查看大图) 1.2 第二个代码片段(点击查看大图) 1.3 转置代码片段一外面,GoodWorker的效率(计算的耗时)是 BadWorker 的 10 倍左右(取决于具体硬件条件和其余相干因素)。在不晓得其余背景常识的前提下,咱们怎么来定位这个问题呢?加耗时的打印?- 不好意思,面对这种曾经只剩大量基本操作的代码,没法做到更细粒度的耗时打印了。看火焰图? (点击查看大图) 能够看到,除了 GoodWorker 在整个 workload 上的占比(83%)比 BadWorker (96%) 略低以外(也不能提供其余进一步的指导意义了), 两个函数在火焰图上都堪称是“层峦叠嶂”,火焰图在这种状况下也失去了指导意义。难道就没有任何方法了吗?开什么玩笑,如果没有方法,这篇文章也就写不上来了!那么答案是什么呢! 02Perf Events 初探2.1 代码片段一的性能数据在具体介绍 perf events 之前,让咱们直观地通过数据来领会一下它在剖析这类问题上的弱小之处。上面所有相似的后果均采纳 perf events 生成。 (点击查看大图) 以上别离是 BadWorker 和 GoodWorker 应用 Perf Events 诊断的后果,能够看到曾经有大量的差别微小的数值和比例了。咱们通过一个表格比照一下几个次要的指标:咱们能够看到,GoodWorker 相较于 BadWorker,外表上除了 backend stall rate 处于劣势以外,其余均全面占优,其中 frontend stall rate 和 LLC load miss 的性能达到了百倍的差距(尽管外表上 LLC miss rate 只有不到两倍,然而数量上大于百倍)。BadWorker 另一个显著的数据 pattern 如下(后文会解释这些数值的意义,不要焦急!) Frontend stall rate 【显著高于】backend stall rateL1-icache miss rate【在数量级上靠近】L1-dcache miss rateLLC miss rate 的【数值也不低】Branch miss rate 【显著升高】(这个与具体代码中是否存在分支无关)并且咱们晓得,在 GoodWorker 的比照下,BadWorker 肯定是一种有问题的实现形式。那么至此,咱们至多对一种问题代码的 perf events 的数据模式有了一个初步的意识。 ...

May 6, 2023 · 3 min · jiezi

关于缓存:cache2kGuava-Cache及Caffeine之外的新选择

序本文次要钻研一下cache2k这款新型缓存 示例Cache<String,String> cache = new Cache2kBuilder<String, String>() {} .eternal(true) .expireAfterWrite(5, TimeUnit.MINUTES) // expire/refresh after 5 minutes .setupWith(UniversalResiliencePolicy::enable, b -> b // enable resilience policy .resilienceDuration(30, TimeUnit.SECONDS) // cope with at most 30 seconds // outage before propagating // exceptions ) .refreshAhead(true) // keep fresh when expiring .loader(k -> expensiveOperation(k)) // auto populating function .build();常见问题的解决方案空值问题JCache标准不反对null,所以cache2k默认也不反对,不过能够通过permitNullValues(true)来开启,这样子缓存就能够存储null值 cache stampede问题又称作cache miss storm,指的是高并发场景缓存同时生效导致大面积回源,cache2k采纳的是block的申请形式,防止对同一个key并发回源 org/cache2k/core/HeapCache.java protected Entry<K, V> getEntryInternal(K key, int hc, int val) { if (loader == null) { return peekEntryInternal(key, hc, val); } Entry<K, V> e; for (;;) { e = lookupOrNewEntry(key, hc, val); if (e.hasFreshData(clock)) { return e; } synchronized (e) { e.waitForProcessing(); if (e.hasFreshData(clock)) { return e; } if (e.isGone()) { metrics.heapHitButNoRead(); metrics.goneSpin(); continue; } e.startProcessing(Entry.ProcessingState.LOAD, null); break; } } boolean finished = false; try { load(e); finished = true; } finally { e.ensureAbort(finished); } if (e.getValueOrException() == null && isRejectNullValues()) { return null; } return e; }同步回源造成的接口稳定性问题cache2k提供了refreshAhead参数,在新数据没有拉取胜利之前,过期数据依然能够拜访,防止申请到来时发现数据过期触发同步回源造成接口延时增大问题。不过具体底层还依赖prefetchExecutor,如果refresh的时候没有足够的线程能够应用则会立马过期,期待下次get登程同步回源 ...

May 6, 2023 · 2 min · jiezi

关于缓存:5个备受Linux运维人员推崇的开源缓存组件

数据缓存对于任何网站或应用程序都是十分重要的,因为它能够在很大水平上帮忙缩小服务器负载。 在本文中,咱们将介绍 5 个备受 Linux 系统管理员推崇的开源缓存工具。 5) Varnish CacheVarnish 是一个风行的 HTTP 加速器,在超过 300 万个网站中应用。 顾名思义,这个缓存 HTTP 反向代理工具将存储一个网站的内容。当你拜访一个网站,下次当您再次拜访该网站时,如果在网页中没有做任何更改,那么您将只从缓存中取得内容,而不是从原网站。 这意味着内容交付速度极快,您不须要期待从服务器下载内容。它是开源的,高度灵便,也是一个多功能工具。它与所有古代 Linux 发行版、Solaris 和 FreeBSD 平台兼容。 长处开源灵活性强性能卓越兼容 OS X, FreeBSD, Linux, Solaris 等反对日志记录毛病原生不反对 SSL/TLS4) Hazelcast IMDGHazelcast IMDG 功能强大,速度快,重量轻,而且可扩大。它的次要亮点之一是它与 Windows、Mac OS X、linux 和所有装置了 Java 的平台兼容。 应用 Hazelcast IMDG 的次要劣势在于其令人难以置信的速度,因为您不须要依赖任何近程存储,并且能够每秒解决数百万个事务。应用 Hazelcast,你的重启速度比 ssd 快 2.5 倍。 您能够轻松地降级集群节点,而不用放心中断服务。它为管理员提供了一个管理中心,能够疾速查看集群流动,同时它也提供 REST API 和可配置水印。 长处快的无可比拟高度可扩大的 IMDG不间断解决无忧降级重启工夫比 ssd 快 5 倍兼容英特尔 Optane DC 长久内存易于应用文档清晰毛病较低的一致性3) Couchbase说到缓存,大多数公司都抉择 Couchbase,因为它是高度牢靠的缓存工具。它带有一个专门为高速缓存设计的内置层,为高速读取和写入数据提供外围性能。Couchbase 服务器与磁盘空间实用程序一起工作,以确保缓存层始终有足够的空间存储缓存的数据。 在 Couchbase 服务器中,缓存的数据以键值格局存储。它与 Linux 以及 Windows 和 Mac OS x 等其余平台高度兼容。它应用了 N1QL,这是一种非常复杂且功能丰富的查询语言,用于从数据库中索引和查问内容。 ...

April 26, 2023 · 1 min · jiezi

关于缓存:缓存与数据库双写一致性几种策略分析

作者:京东批发 于泷 一、背景在高并发场景中,为避免大量申请间接拜访数据库,缓解数据库压力,罕用的形式个别会减少缓存层起到缓冲作用,缩小数据库压力。引入缓存,就会波及到缓存与数据库中数据如何放弃一致性问题,本文将对几种缓存与数据库保证数据一致性的应用形式进行剖析。为保障高并发性能,以下剖析场景不思考执行的原子性及加锁等强一致性要求的场景,仅谋求最终一致性。 二、读取过程 • 读缓存 • 如果缓存里没有值,那就读取数据库的值 • 同时把这个值写进缓存中 三、更新过程更新操作有多种策略,各有优劣,次要针对此场景进行剖析 策略1:先更新db,再删除缓存(罕用的Cache-Aside Pattern旁路缓存) 问题: 1.如果更新db胜利,删缓存失败,将导致数据不统一 2.极其场景,申请A读,B写 1)此时缓存刚好生效 2)A查库失去旧值 3)B更新DB胜利 4)B删除缓存 5)A将查到的旧值更新到缓存中 此场景的产生须要步骤2)查db 始终慢于 3)的更新db,能力导致4)先于5)执行,通常db的查问是要快于写入的,所以此极其场景的产生过于严格,不易产生 策略2:先更新db,再更新缓存 问题: 1.并发更新场景下,更新缓存会导致数据不统一 2.依据读写比,思考是否有必要频繁同步更新缓存,而且,如果结构缓存中数据过于简单,或者数据更新频繁,然而读取并不频繁的状况,还会造成不必要的性能损耗 此种形式不举荐 策略3:先更新缓存,再更新db 同上,不举荐 策略4:先删缓存,再更新db 先删缓存,尽管解决了策略1中,后删缓存如果失败的场景,但也会产生不统一的问题 例如:申请 A 删除缓存,这时申请B来查,就会击穿到数据库,B读取到旧的值后写入缓存,A失常更新db,因为时间差导致数据不统一的状况 策略5:缓存延时双删 该策略兼容了策略1和策略4,解决了先删缓存还是后删缓存的问题,如策略1中,更新db后删缓存失败和策略4中的不统一场景,该策略能够将延时工夫内(比方延时10ms)所造成的缓存脏数据,再次删除。然而,如果延时删缓存失败,策略4中不统一问题还会产生,同时延时的实现,如创立线程,或者引入mq异步,可能会减少零碎复杂度问题。 策略6:变种双删,前置缓存过期工夫 该策略针对策略1中后删缓存失败的场景,前置一层缓存数据过期工夫(具体工夫依据本身零碎自身评估,如可笼罩db读写耗时或一致性容忍度等),更新db后就算删缓存失败,在expire工夫后也能保障缓存中无数据。同时,前置expire失败,或者更新db失败,都不会影响数据统一。 可能解决策略4中的问题:申请 A 删除缓存,这时申请B来查,就会击穿到数据库,B读取到旧的值后写入缓存,A失常更新db,因为时间差导致数据不统一的状况,形容图如下: 本策略中步骤1为expire缓存,不会产生击穿缓存到数据库的状况,数据将间接返回。除非更极其状况,如下图: expire工夫没有覆盖住更新db的耗时,相似策略1中极其场景,此处不赘述 四、总结对于每种计划策略,各有利弊,但一致性问题始终存在(文章结尾排除了原子性和锁),只是产生的几率在一点点缓缓变小了,计划的评估不仅要依据本身零碎的业务场景,如读写比、并发量、一致性容忍度,还要思考零碎复杂度,投入产出比等,寻找最合适的计划。

April 19, 2023 · 1 min · jiezi

关于缓存:建木缓存提升构建速度让你不加班

常常有小伙伴在群里询问和吐槽: maven打包时,拉的依赖有本地缓存吗? 每次都须要去下载jar包,很耗时... 没有缓存速度“感人”... 小伙伴们,你们的需要听到了,两只耳朵都听到了!没有辜负大家的冀望,这个呼声排在Top前列的需要,咱们在v2.7.0实现了!先去更新版本!一边更新一边看教程! 背景之前建木的CI/CD流程执行完,会主动清理工作空间,某些节点:如大家常常提到的maven构建,每次执行时都会从新下载Java我的项目所需的依赖,让小伙伴们“一等再等”。有了缓存之后,依赖包不必反复下载,构建速度也将大大晋升(看群里一位小伙伴的反馈,maven构建从3m51s晋升到了14s)。 如何应用上面将以maven构建和nodejs构建两个节点为例,演示如何增加和查看缓存。 以下三点务必留神⚠️ (1)maven和nodejs节点要应用最新版本,老版本缓存不起作用 (2)缓存目录反对自定义,但要和本地仓库门路统一 (3)以后的cache只反对docker worker,不反对k8s worker 记住这个缓存增加三步走:定义缓存-援用缓存-写缓存目录,上面一起来看看吧。 maven构建增加缓存图形化 1、定义缓存:点击顶部缓存-填写缓存惟一标识maven_repo(缓存惟一标识能够自定义,满足规定即可)。 2、节点中援用缓存:点击maven节点,抉择最新版本 抉择刚刚定义的缓存maven_repo,填写缓存要挂载的目录。挂载目录须要和本地仓库门路统一,不便起见可间接写成 /.m2/repository。如果想自定义挂载目录,记得批改本地仓库门路,放弃两者统一。 DSL在global段落下定义缓存cache,已定义的cache能够在节点maven_build中援用 global: #先定义缓存 cache: maven_repo pipiline: maven_build: # 要用最新的节点版本 type: maven_build:1.4.0-jdk11 # 在节点中援用缓存 cache: # 示意容器中的 /.m2/repository 目录会挂载到缓存maven_repo上 maven_repo: /.m2/repository param: mvn_action: test workspace: ${git_clone.git_path}再叮咛一遍,要应用最新的节点版本,以及填写正确的缓存挂载目录。 nodejs构建增加缓存图形化 1、定义缓存:点击顶部缓存-填写缓存惟一标识node_cache 2、节点中援用缓存:点击nodejs节点,抉择最新版本 抉择刚刚定义的缓存node_cache,填写缓存要挂载的目录/cache DSL 在global段落下定义缓存cache,已定义的cache能够在节点node_build中援用 global: #先定义缓存 cache: node_cachepipiline: node_build: # 要用最新的节点版本 type: _/nodejs_build:1.6.0-node16 # 在节点中援用缓存 cache: # 示意容器中的 /cache 目录会挂载到缓存node_cache上 node_cache: /cache param: workspace: ${git_clone.git_path}/ui registry_url: https://registry.npm.taobao.org记得应用最新的节点版本,以及填写正确的缓存挂载目录。 ...

March 20, 2023 · 1 min · jiezi

关于缓存:GuavaCache与物模型大对象引起的内存暴涨分析设备管理运维类

背景介绍首先对物联网平台的几个概念做下名词解释 总结一下产品是一类设施的汇合,物模型形容了这一类设施的性能,包含属性、事件、服务。 比方创维电视是一个产品,而每户家庭中的一个个创维电视则是具体设施,这些电视(设施)都具备雷同的性能,即在创维电视这个产品上定义的性能。比方以后电视的频道、亮度、音量,这些都是具体的属性;比方如果电视的温度高于50摄氏度,则能够上报报警事件;比方能够通过服务调用的形式,来管制电视的关上和敞开,等等。 从以上的示例中,能够总结出创维电视这款产品的物模型定义,包含属性、事件、服务属性 - 电视状态(开/关)、频道、亮度、音量等等事件 - 电视温度过高事件服务 - 管制电视开/关、调整电视亮度 具体的物模型是非常复杂的,局部简单的产品可能蕴含几百几千个属性、事件、服务,因而残缺的物模型是十分微小的。 对于设施每次上报的属性、事件等,物联网平台都会查问出相应的物模型,对设施上报的数据进行校验。 本文记录线上环境,大量设施上报数据,进行物模型校验引起的一次内存告警剖析以一台单机进行剖析如上图所示,十几分钟的工夫,内存从50%一路飙升到75%,最终稳固在77%左右不再上涨。通过监控剖析,在13:40开始,零碎流量有所增长,且都来自于一个租户该租户是一个测试租户在压测,与相干同学分割后,进行压测,集群重启后内存恢复正常。 问题剖析Dump剖析能够看到,占内存的根本是guava cache,本地缓存导致了内存疯狂上涨。为什么guava cache导致内存上涨? guava cache本地缓存了物模型对象,size=1000,缓存工夫为一分钟。对于物模型本地缓存,曾经上线运行了两周,运行比较稳定,为什么此次忽然呈现内存上涨? 剖析该租户下有1000个产品下的设施同时上报,且继续在上报,一个产品对应一个物模型。本地缓存时,key=产品惟一标识符,value=物模型每个产品的物模型十分大,有130个属性,单是文本大小曾经达到70KB,理论Java对象占用内存更大。理论Java对象到底有多大?shallow heap示意这个对象自身大小retained heap示意这个对象所有援用对象对于一个json或map对象,想计算该对象所援用的所有对象大小,应该关注的是retained heap看上图,一个guava cache的entry占用内存 1508096 B ≈ 1508 KB ≈ 1.5 MB为什么会这么大?有1.5 M开展来看entry外部对象有next、valueReference、key等其中next其实是下一个entry的大小了,图中显示为856512 B ≈ 856 KB,这里不过多关注理论重点关注valueReference援用了一个JSONObject,这是缓存TSL对象的次要内存占用,大小为 651384 B ≈ 651 KB即一个物模型对象在内存中的大小约为651 KB一个物模型对象就如此之大,那么1000个产品的物模型,如果都在本地缓存,势必占用十分大的内存空间。然而即便如此,为什么会造成内存的继续上涨?为什么GC没有回收掉? GC日志剖析查看GC日志,通过肯定解决后如下分水岭能够看到13:40之前,每次YGC后,老年代内存增量平均值为10K左右13:40之后,每次YGC后,老年代内存增量平均值为35000K左右间接增长了3500倍通过下面的GC日志,能够看到,老年代的内存在继续上涨,也就是说,每次YGC后,都有相当一部分对象降职到了老年代。这是导致内存持续增长的根本原因。 线上JVM配置-Xms5334m -Xmx5334m -Xmn2000m-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m-XX:MaxDirectMemorySize=1g -XX:SurvivorRatio=10-Xmn2000m 示意新生代总大小为2000M,从ParNew的GC日志看,新生代总大小理论为1877376K,与2000M有肯定偏差。且eden: survivor1 : survivor2 = 10:1:1按新生代总大小2000M计算,survivor大小约为170M按新生代总大小1877376K计算,survivor大小约为156M 垃圾回收 - 复制算法新生代分为Eden和2个survivor,其中两个survivor别离叫From Survior和To Survior。每次应用Eden和From Survivor。YGC时,将Eden和From Survivor中存活的对象复制到To Survivor空间,最初清理掉Eden和From Survivor空间。YGC后,From Survivor和To Survivor两块区域会调换,也就是原先的To Survivor会变成下次YGC时的From Survivor区,原先的From Survivor区会变成下次YGC时的To Survivor区。图一:初始状态图二:在新生代创建对象图三:YGC,Eden和From Survivor中存活的对象移到To Survivor中,而后回收Eden和From Survivor的空间。图四:转换From Survivor和To Survivor。循环下面的步骤 ...

March 17, 2023 · 1 min · jiezi

关于缓存:聊聊如何基于spring-Cacheable扩展实现缓存自动过期时间以及即将到期自动刷新

前言用过spring cache的敌人应该会晓得,Spring Cache默认是不反对在@Cacheable上增加过期工夫的,尽管能够通过配置缓存容器时对立指定。形如 @Beanpublic CacheManager cacheManager( @SuppressWarnings("rawtypes") RedisTemplate redisTemplate) { RedisCacheManager cacheManager= new RedisCacheManager(redisTemplate); cacheManager.setDefaultExpiration(60); Map<String,Long> expiresMap = new HashMap<>(); expiresMap.put("customUser",30L); cacheManager.setExpires(expiresMap); return cacheManager;}但有时候咱们会更习惯通过注解指定过期工夫。明天咱们就来聊一下如何扩大@Cacheable实现缓存主动过期以及缓存行将到期主动刷新 实现注解缓存过期前置常识SpringCache蕴含两个顶级接口,Cache和CacheManager,通过CacheManager能够去治理一堆Cache。因而咱们要扩大@Cacheable,就脱离不了对Cache和CacheManager进行扩大 其次要实现过期工夫,首先是引入的缓存产品,他自身就要反对过期工夫,比方引入的缓存为ConcurrentHashMap,他本来就是不反对过期工夫,如果要扩大,就要十分消耗精力实现 实现注解缓存过期办法一、通过自定义cacheNames形式形如下 @Cacheable(cacheNames = "customUser#30", key = "#id")通过#分隔,#前面局部代表过期工夫(单位为秒) 实现逻辑步骤为: 1、自定义缓存管理器并继承RedisCacheManager,同时重写createRedisCache办法示例: public class CustomizedRedisCacheManager extends RedisCacheManager { public CustomizedRedisCacheManager(RedisCacheWriter cacheWriter, RedisCacheConfiguration defaultCacheConfiguration) { super(cacheWriter, defaultCacheConfiguration); } @Override protected RedisCache createRedisCache(String name, RedisCacheConfiguration cacheConfig) { String[] array = StringUtils.delimitedListToStringArray(name, "#"); name = array[0]; if (array.length > 1) { long ttl = Long.parseLong(array[1]); cacheConfig = cacheConfig.entryTtl(Duration.ofSeconds(ttl)); } return super.createRedisCache(name, cacheConfig); }}2、将默认的缓存管理器改成咱们自定义的缓存管理器示例: ...

October 11, 2022 · 5 min · jiezi

关于缓存:社区收藏缓存设计重构实战

一、背景社区珍藏业务是一个典型的读多写少的场景,社区各种外围Feeds流都须要依赖用户是否珍藏的数据判断,晚期缓存设计时因为流量不是很大,未体现出显著的问题,近期通过监控平台等相干伎俩发现了相干的一些问题,因而咱们针对这些问题对缓存做了重构设计,以保障珍藏业务的性能和稳定性。 二、问题剖析定位2.1 接口RT偏大通过监控平台查看「判断是否珍藏接口」的RT在最高在8ms左右,该接口的次要作用是判断指定单个用户是否已珍藏一批内容,其实如果缓存命中率高的话,接口RT就应该趋近于Redis的RT程度,也就是1-2ms左右。 (图中有单根尖刺,这个具体问题要具体分析优化,咱们这里次要论述整体程度的优化) 2.2 Redis&MySQL拜访QPS偏高通过监控平台能够看到从上游服务过去的珍藏查问QPS绝对拜访Redis缓存的QPS放大了15倍,并且MySQL查问的最高QPS占上游访问量靠近37%,这阐明缓存并没有很高的命中率,导致回表查问的概率还是很大。 QPS访问量见下图: Redis访问量 MySQL访问量 基于以上剖析咱们当初有了明确的优化切入点,接下来咱们来看下具体的找下起因是什么。接下来咱们来看一下伪代码的实现: //判断用户是否对指定的动静珍藏func IsLightContent(userId uint64,contentIds []uint64){ index := userId%20 cacheKey := key + "_" + fmt.Sprintf("%d", index) pipe := redis.GetClient().Pipeline() for _, item := range contentIds { InitCache(userId, contentId) pipe.SisMember(cacheKey, userId) } pipe.Exec() //......}//缓存初始化判断,不存在则初始化数据缓存func InitCache(userId uint64,contentId uint64){ index := userId%20 cacheKey := key + "_" + fmt.Sprintf("%d", index) ttl,_ := redis.GetClient().TTL(cacheKey) if ttl <= 0{//key不存在或者未设置过期工夫 // query from db // sql := "select userId from trendFav where userId%20 = index and content_id = contentId" // save to redis }else{ redis.GetClient().Expire(cacheKey,time.Hour()*48) }}从下面的伪代码中,咱们可能很清晰的看到,该办法会遍历内容id汇合,而后对每个内容去查问缓存下来的用户汇合,判断该以后用户是否珍藏。也就是说缓存设计是依照内容维度和用户1:N来设计的,将单个动静下所有珍藏过内容的用户id查出来缓存起来。并且基于大Key的思考,代码又将用户汇合分片成20组。这无疑又再次放大了Redis缓存Key的数量。并且每个Key都应用TTL命令来判断是否过期。这样一来Redis的QPS和缓存Key就会被放大很多倍。 ...

August 2, 2022 · 1 min · jiezi

关于缓存:分布式场景下缓存引发的问题及解决方案

在分布式场景下,为应答高流量冲击,加重数据库压力,咱们大都会通过缓存来应答流量冲击,常见的缓存中间件如Redis、Memcache等,缓存也会带来肯定的问题,如下:1.缓存穿透:指缓存中没有数据,数据库中也没有数据。在进行数据的拜访时,通过数据的key读取数据,然而该key对应数据在数据库中没有,在缓存中也没有,造成每次通过该key读取数据都会进行数据库操作,且每次读取都为null的状况。在大型项目中,这种有效的数据库操作会减少数据库的读压力。解决方案:空值缓存、布隆过滤。2.缓存击穿:指定key的数据在数据库中存在,然而缓存中还没有写入该key对应的数据,在高并发场景下,多个线程同时通过该key读取数据时,会因为高并发拜访的起因导致同一个key对应的数据会从数据库被屡次读取。解决方案:上锁、singleflight回源操作。3.缓存雪崩:缓存服务不具备高可用性导致大面积缓存生效的状况。解决方案:集群,服务熔断,降级,预热,距离更新缓存。4.数据一致性:数据进行更新时,如何对数据进行操作能力保障数据库中的数据和缓存中的数据统一的问题。解决方案:先更缓存再更新数据库,先更新数据库再更新缓存,先删除缓存再更新数据库,先更数据库再删缓存,先删缓存再更新数据库再删缓存,串行操作。

July 25, 2022 · 1 min · jiezi

关于缓存:Datenlord-Etcd-客户端缓存实践

简介和背景Etcd 是一个反对强一致性的分布式 KV 存储,次要用于 metadata 的治理、服务发现、分布式锁等场景。DatenLord 应用 etcd 来治理集群的 metadata,DatenLord 的利用会频繁查问 etcd 中的 metadata,然而极少更改,是典型的读多写少的场景。在应用过程中咱们发现一次 etcd 操作带来的网络开销成为了性能瓶颈,所以咱们想到通过实现客户端缓存的形式来省去不必要的网络的开销。具体想法是在客户端缓存查问后果,这样每次须要查问 etcd 的时候,如果缓存命中,则只须要拜访一次本地内存省掉一次网络开销,如果没有命中,再到 etcd 中查问,并将查问后果退出缓存,这极大地升高了频繁查问 etcd 所带来的开销和提早。接下来会具体介绍咱们的实现和遇到的问题以及解决方案。 Etcd Watch 机制在启用缓存之后就会面临本地缓存更新的问题,因为 etcd 是一个分布式的 KV 存储,容许多个客户端并发操作并保障一致性,那么如果其余客户端更新了 etcd 中的数据,那么如何更新本客户端本地缓存中的数据呢?一个计划是定时轮询 etcd 来获取数据更新,然而这个计划有显著弊病,如轮询的距离设定,如果设置过大将无奈及时更新本地缓存,导致长时间拿到旧的数据,如果设置很短,随着本地缓存数据量的减少,逐个轮询会同时减少 etcd 和客户端的累赘。 侥幸的是 etcd 提供了 watch 机制能够克服轮询计划的弊病。etcd 的 watch 机制容许客户端通知 etcd 它要关注的 key,如果该 key 有任何批改,etcd 会告诉客户端。具体实现形式是在客户端和服务器端建设一个长连贯,这个长连贯提供了两个性能,1. 客户端会通过这个长连贯来通知 etcd 它要 watch 的 key,以及不再想 watch 某些 key,即对应WatchCreateRequest和WatchCancelRequest。watch 申请能够针对单个 key 或者 prefix。2. watch 申请胜利后,只有该 key 或者满足 prefix 的 key 有更新,etcd 就会通过这个长连贯以WatchResponse的模式告诉到客户端。须要留神的是所有的 watch 申请都复用这一条长连贯。咱们来看一下WatchCreateRequest,WatchCancelRequest,WatchResponse,Event的 protobuf 定义 ...

July 21, 2022 · 4 min · jiezi

关于缓存:缓存穿透缓存雪崩缓存击穿再也不怕了你随便问吧

背景在古代软件架构中,缓存的利用曾经十分遍及。缓存的应用在面试和实际中都是避不开的硬技能、硬常识,如果你说还不太熟悉缓存的应用,可能都不好意思说本人是程序员。 在上篇文章《如果不晓得这4种缓存模式,敢说懂缓存吗?》中,咱们介绍了缓存应用的四种策略,如果可能联合不同的场景进行灵活运用,你曾经超过了大多数人。毕竟,那四种策略,很多开发多年的人可能都没听说过。 这篇文章,带大家进一步学习在缓存应用中不得不思考三个非凡场景:缓存穿透、缓存雪崩、缓存击穿。 为什么说不得不思考?因为如果不思考这些非凡的场景,在高并发的状况可能间接导致系统解体。上面以常见的Redis缓存组件为例来解说这三种场景及解决方案。 大前提当咱们应用缓存时,指标通常有两个:第一,晋升响应效率和并发量;第二,加重数据库的压力。 而本文中所提到的这三种场景:缓存穿透、缓存雪崩和缓存击穿的产生,都是因为在某些非凡状况下,缓存失去了预期的性能所致。 当缓存生效或没有抵御住流量,流量间接涌入到数据库,在高并发的状况下,可能间接击垮数据库,导致整个零碎解体。 这就是咱们须要晓得的大前提,而缓存穿透、缓存雪崩和缓存击穿,只不过是在这个大前提下的不同场景的细分场景而已。 缓存穿透大多数状况,缓存能够缩小数据库的查问,晋升零碎性能。 通常流程是:一个申请过去,先查问是否在缓存当中,如果缓存中存在,则间接返回。如果缓存中不存在对应的数据,则检索数据库,如果数据库中存在对应的数据,则更新缓存并返回后果。如果数据库中也不存在对应的数据,则返回空或谬误。 缓存穿透(cache penetration)是用户拜访的数据既不在缓存当中,也不在数据库中。出于容错的思考,如果从底层数据库查问不到数据,则不写入缓存。这就导致每次申请都会到底层数据库进行查问,缓存也失去了意义。当高并发或有人利用不存在的Key频繁攻打时,数据库的压力骤增,甚至解体,这就是缓存穿透问题。 缓存穿透产生的场景个别有两类: 原来数据是存在的,但因为某些起因(误删除、被动清理等)在缓存和数据库层面被删除了,但前端或前置的应用程序仍旧保有这些数据;歹意攻击行为,利用不存在的Key或者歹意尝试导致产生大量不存在的业务数据申请。缓存穿透通常有四种解决方案,咱们逐个介绍剖析。 计划一:缓存空值(null)或默认值剖析业务申请,如果是失常业务申请时产生缓存穿透景象,可针对相应的业务数据,在数据库查问不存在时,将其缓存为空值(null)或默认值。须要留神的是,针对空值的缓存生效工夫不宜过长,个别设置为5分钟之内。当数据库被写入或更新该key的新数据时,缓存必须同时被刷新,防止数据不统一。 计划二:业务逻辑前置校验在业务申请的入口处进行数据合法性校验,查看申请参数是否正当、是否蕴含非法值、是否歹意申请等,提前无效阻断非法申请。比方,依据年龄查问时,申请的年龄为-10岁,这显然是不非法的申请参数,间接在参数校验时进行判断返回。 计划三:应用布隆过滤器申请白名单在写入数据时,应用布隆过滤器进行标记(相当于设置白名单),业务申请发现缓存中无对应数据时,可先通过查问布隆过滤器判断数据是否在白名单内,如果不在白名单内,则间接返回空或失败。 计划四:用户黑名单限度当产生异常情况时,实时监控拜访的对象和数据,剖析用户行为,针对成心申请、爬虫或攻击者,进行特定用户的限度; 当然,可能针对缓存穿透的状况,也有可能是其余的起因引起,能够针对具体情况,采纳对应的措施。 缓存雪崩在应用缓存时,通常会对缓存设置过期工夫,一方面目标是放弃缓存与数据库数据的一致性,另一方面是缩小冷缓存占用过多的内存空间。 但当缓存中大量热点缓存采纳了雷同的实效工夫,就会导致缓存在某一个时刻同时实效,申请全副转发到数据库,从而导致数据库压力骤增,甚至宕机。从而造成一系列的连锁反应,造成零碎解体等状况,这就是缓存雪崩(Cache Avalanche)。 下面讲到的是热点key同时生效的场景,另外就是因为某些起因导致缓存服务宕机、挂掉或不响应,也同样会导致流量间接转移到数据库。 所以,缓存雪崩的场景通常有两个: 大量热点key同时过期;缓存服务故障;缓存雪崩的解决方案: 通常的解决方案是将key的过期工夫前面加上一个随机数(比方随机1-5分钟),让key平均的生效。思考用队列或者锁的形式,保障缓存单线程写,但这种计划可能会影响并发量。热点数据能够思考不生效,后盾异步更新缓存,实用于不严格要求缓存一致性的场景。双key策略,主key设置过期工夫,备key不设置过期工夫,当主key生效时,间接返回备key值。构建缓存高可用集群(针对缓存服务故障状况)。当缓存雪崩产生时,服务熔断、限流、降级等措施保障。缓存击穿缓存雪崩是指只大量热点key同时生效的状况,如果是单个热点key,在不停的扛着大并发,在这个key生效的霎时,继续的大并发申请就会击破缓存,间接申请到数据库,如同蛮力击穿一样。这种状况就是缓存击穿(Cache Breakdown)。 从定义上能够看出,缓存击穿和缓存雪崩很相似,只不过是缓存击穿是一个热点key生效,而缓存雪崩是大量热点key生效。因而,能够将缓存击穿看作是缓存雪崩的一个子集。 缓存击穿的解决方案: 应用互斥锁(Mutex Key),只让一个线程构建缓存,其余线程期待构建缓存执行结束,从新从缓存中获取数据。单机通过synchronized或lock来解决,分布式环境采纳分布式锁。热点数据不设置过期工夫,后盾异步更新缓存,实用于不严格要求缓存一致性的场景。”提前“应用互斥锁(Mutex Key):在value外部设置一个比缓存(Redis)过期工夫短的过期工夫标识,当异步线程发现该值快过期时,马上缩短内置的这个工夫,并从新从数据库加载数据,设置到缓存中去。小结本文介绍了在应用缓存时常常会遇到的三种异常情况:缓存穿透、缓存雪崩和缓存击穿。 三种异常情况从根本上来说都是因为本应该拜访缓存的,然而缓存不存在或服务异样,导致流量间接进入了数据库层面。 其中缓存雪崩和缓存击穿是因为数据不存在(或服务异样获取不到),导致大量申请拜访数据库,从而导致数据库压力骤增,甚至解体。 而缓存穿透则是因为数据自身就不存在,导致缓存没有进行数据缓存,流量进入数据库层。 针对不同的缓存异样场景,可抉择不同的计划来进行解决。当然,除了上述计划,咱们还能够限流、降级、熔断等服务层的措施,也能够思考数据库层是否能够进行横向扩大,当缓存异样产生时,确保数据库可能抗住流量,不至于让整个零碎解体。 博主简介:《SpringBoot技术底细》技术图书作者,热爱钻研技术,写技术干货文章。 公众号:「程序新视界」,博主的公众号,欢送关注~ 技术交换:请分割博主微信号:zhuan2quan

July 11, 2022 · 1 min · jiezi

关于缓存:如果不知道这4种缓存模式敢说懂缓存吗

概述在零碎架构中,缓存堪称提供零碎性能的最简略办法之一,略微有点开发教训的同学必然会与缓存打过交道,最起码也实际过。 如果应用切当,缓存能够缩小响应工夫、缩小数据库负载以及节省成本。但如果缓存使用不当,则可能呈现一些莫名其妙的问题。 在不同的场景下,所应用的缓存策略也是有变动的。如果在你的印象和教训中,缓存还只是简略的查问、更新操作,那么这篇文章真的值得你学习一下。 在这里,为大家系统地解说4种缓存模式以及它们的应用场景、流程以及优缺点。 缓存策略的抉择实质上来讲,缓存策略取决于数据和数据拜访模式。换句话说,数据是如何写和读的。 例如: 零碎是写多读少的吗?(例如,基于工夫的日志)数据是否是只写入一次并被读取屡次?(例如,用户配置文件)返回的数据总是惟一的吗?(例如,搜寻查问)抉择正确的缓存策略才是进步性能的要害。 罕用的缓存策略有以下五种: Cache-Aside Pattern:旁路缓存模式Read Through Cache Pattern:读穿透模式Write Through Cache Pattern:写穿透模式Write Behind Pattern:又叫Write Back,异步缓存写入模式上述缓存策略的划分是基于对数据的读写流程来辨别的,有的缓存策略下是应用程序仅和缓存交互,有的缓存策略下应用程序同时与缓存和数据库进行交互。因为这个是策略划分比拟重要的一个维度,所以在后续流程学习时大家须要特地注意一下。 Cache AsideCache Aside是最常见的缓存模式,应用程序可间接与缓存和数据库对话。Cache Aside可用来读操作和写操作。 读操作的流程图: 读操作的流程: 应用程序接管到数据查问(读)申请;应用程序所需查问的数据是否在缓存上: 如果存在(Cache hit),从缓存上查问出数据,间接返回;如果不存在(Cache miss),则从数据库中检索数据,并存入缓存中,返回后果数据;这里咱们须要注意一个操作的边界,也就是数据库和缓存的操作均由应用程序间接进行操作。 写操作的流程图: 这里的写操作,包含创立、更新和删除。在写操作的时候,Cache Aside模式是先更新数据库(增、删、改),而后间接删除缓存。 Cache Aside模式能够说实用于大多数的场景,通常为了应答不同类型的数据,还能够有两种策略来加载缓存: 应用时加载缓存:当须要应用缓存数据时,从数据库中查问进去,第一次查问之后,后续申请从缓存中取得数据;预加载缓存:在我的项目启动时或启动后通过程序预加载缓存信息,比方”国家信息、货币信息、用户信息,新闻信息“等不是常常变更的数据。Cache Aside实用于读多写少的场景,比方用户信息、新闻报道等,一旦写入缓存,简直不会进行批改。该模式的毛病是可能会呈现缓存和数据库双写不统一的状况。 Cache Aside也是一个规范的模式,像Facebook便是采纳的这种模式。 Read ThroughRead-Through和Cache-Aside很类似,不同点在于程序不须要关注从哪里读取数据(缓存还是数据库),它只须要从缓存中读数据。而缓存中的数据从哪里来是由缓存决定的。 Cache Aside是由调用方负责把数据加载入缓存,而Read Through则用缓存服务本人来加载,从而对利用方是通明的。Read-Through的劣势是让程序代码变得更简洁。 这里就波及到咱们下面所说的应用程序操作边界问题了,间接来看流程图: 在上述流程图中,重点关注一下虚线框内的操作,这部分操作不再由应用程序来解决,而是由缓存本人来解决。也就是说,当利用从缓存中查问某条数据时,如果数据不存在则由缓存来实现数据的加载,最初再由缓存返回数据后果给应用程序。 Write Through在Cache Aside中,应用程序须要保护两个数据存储:一个缓存,一个数据库。这对于应用程序来说,有一些繁琐。 Write-Through模式下,所有的写操作都通过缓存,每次向缓存中写数据时,缓存会把数据长久化到对应的数据库中去,且这两个操作在一个事务中实现。因而,只有两次都写胜利了才是最终写胜利了。害处是有写提早,益处是保障了数据的一致性。 能够了解为,应用程序认为后端就是一个繁多的存储,而存储本身保护本人的Cache。 因为程序只和缓存交互,编码会变得更加简略和整洁,当须要在多处复用雷同逻辑时这点就变得分外显著。 当应用Write-Through时,个别都配合应用Read-Through来应用。Write-Through的潜在应用场景是银行零碎。 Write-Through实用状况有: 须要频繁读取雷同数据不能忍耐数据失落(绝对Write-Behind而言)和数据不统一在应用Write-Through时要特地留神的是缓存的有效性治理,否则会导致大量的缓存占用内存资源。甚至无效的缓存数据被有效的缓存数据给革除掉。 Write-BehindWrite-Behind和Write-Through在”程序只和缓存交互且只能通过缓存写数据“这方面很类似。不同点在于Write-Through会把数据立刻写入数据库中,而Write-Behind会在一段时间之后(或是被其余形式触发)把数据一起写入数据库,这个异步写操作是Write-Behind的最大特点。 数据库写操作能够用不同的形式实现,其中一个形式就是收集所有的写操作并在某一时间点(比方数据库负载低的时候)批量写入。另一种形式就是合并几个写操作成为一个小批次操作,接着缓存收集写操作一起批量写入。 异步写操作极大的升高了申请提早并加重了数据库的累赘。同时也放大了数据不统一的。比方有人此时间接从数据库中查问数据,然而更新的数据还未被写入数据库,此时查问到的数据就不是最新的数据。 小结不同的缓存模式有不同的考量点和特色,依据应用程序需要场景的不同,须要灵便的抉择适配的缓存模式。在实际的过程中往往也是多种模式相结合来应用。 博主简介:《SpringBoot技术底细》技术图书作者,热爱钻研技术,写技术干货文章。 公众号:「程序新视界」,博主的公众号,欢送关注~ 技术交换:请分割博主微信号:zhuan2quan

July 4, 2022 · 1 min · jiezi

关于缓存:缓存更新策略

近段时间在学习缓存相干常识的时候,看到了缓存更新策略,于是就依据本人的了解,写下这篇文章 分类Cache AsideRead / Write ThoughWrite BehindCache Aside步骤 读申请未命中缓存,取数据库数据,并回写缓存写申请先更新数据库,再让缓存生效长处 实现简略,调用者可控制数据长久化的细节毛病 下层须要同时治理缓存与长久化,调用较简单写申请与读申请并发,读申请持续时间比写申请长,可能会笼罩旧数据到缓存中应用场景 容许缓存数据不精确的场景因为并发状况下,可能造成脏数据的状况,所以 QPS 较低场景也能够实用代码示例public class CacheAside<T, K> implements CacheUpdate<T, K>{ private Map<K, T> map; @Override public T getData(K key) { //if cache has data, return return map.get(key); } @Override public boolean updateData(K key, T data) { map.remove(key, data); return true; } @Override public boolean addData(K key, T data) { return Objects.nonNull(map.put(key, data)); } @Override public boolean removeData(K key) { map.remove(key); return true; } public CacheAside() { map = new HashMap<>(); }}调用示例public class CacheAsideClient<T, K> implements CacheUpdateClient<T, K>{ public CacheUpdateFactory<T, K> factory = CacheUpdateFactory.getInstance(); private CacheUpdate<T, K> cacheUpdate; private DatabaseOperation<T, K> databaseOperation; @Override public T getData(K key){ //get data from cache T dataFromCache = cacheUpdate.getData(key); //if cache haven't, get from database and put to cache if(Objects.nonNull(dataFromCache)){ return dataFromCache; } T dataFromDatabase = databaseOperation.getData(key); cacheUpdate.addData(key, dataFromDatabase); return dataFromDatabase; } @Override public boolean updateData(K key, T data){ //update data to database boolean updateToDatabaseRes = databaseOperation.updateData(key, data); if(updateToDatabaseRes){ //invalid cache data return cacheUpdate.removeData(key); } return false; } @Override public boolean addData(K key, T data){ //add data to database return databaseOperation.addData(key, data); } @Override public boolean removeData(K key){ //remove from database boolean removeFromDatabaseRes = databaseOperation.removeData(key); if(removeFromDatabaseRes){ //invalid cache data return cacheUpdate.removeData(key); } return false; } public CacheAsideClient() { cacheUpdate = factory.getObject(CacheUpdateEnum.CACHE_ASIDE); databaseOperation = (DatabaseOperation<T, K>) new MockDatabaseOperation<T>(); }}Read / Write Though步骤 ...

June 6, 2022 · 3 min · jiezi

关于缓存:架构师必备Redis的几种集群方案

论断有以下几种Redis集群计划,先说论断: Redis cluster:该当优先思考应用Redis cluster。codis:旧我的项目如果仍在应用codis,可持续应用,但也举荐迁徙到Redis cluster。twemproxy:不倡议应用,与codis同为proxy计划,但不如codis(twemproxy不能平滑地扩容)。客户端分片:该当禁止应用,因为扩容简单,如果2个服务同时读写,其中一个批改了路由,另一个不批改会有问题。上面重点介绍Redis cluster和codis。 Redis cluster原理架构 是官网反对的Redis集群计划: 去中心化架构,不依赖内部存储,每个节点都有槽位信息、以及一部分数据,各节点之间应用gossip协定交互信息划分为16384个slot槽位,每个key依照分片规定,对key做crc16 % 16384失去slot id每个Redis节点存储了一部分槽位数据,各个Redis节点独特分担16384个slot槽位客户端需恪守Redis cluster标准读写数据,客户端连贯集群时,会失去一份集群的槽位配置信息,客户端本地缓存了slot到node的映射关系,以便间接定位到对应的Redis节点 用key计算出slot通过本地缓存的slot到node映射关系(某个slot范畴映射到某个node),用slot得出node申请对应的node节点,如果key对应的槽位在Redis节点存储的各槽位中,则查问后果如果key对应的槽位不在Redis节点存储的各槽位中(即key所在的槽位不归该节点治理),则返回moved <节点> 提醒客户端再次申请指定的节点,并更新本地映射关系如果申请的key对应槽位正在迁徙,则返回ask <节点> 提醒客户端再次申请指定的节点主库读写,从库用于高可用备份、个别不用来承当读申请:主从同步通过指令流、环形数组来做增量同步,通过RDB来做全量同步长处官网反对的集群计划,能应用最新feature性能好,无多余网络开销无一致性问题,读写申请都走主节点槽位更精密,16384(2^14)相比于codis的1024毛病如果是从旧版不反对集群的Redis降级而来,需做较大革新,把传统的Jedis client需替换成智能客户端来保护key到slot的映射关系,如lettuce官网是最小应用准则,没有易用的扩容、迁徙工具,须要寻找社区提供的易用界面,或自行研发迁徙过程中性能可能受影响,有3次申请:首次get失去ask返回、再次asking确认指定节点是否有槽位、最初getcodis原理架构 是Go语言编写的Redis proxy集群计划: codis-proxy作为下层proxy,负责路由申请至底层的Redis分片。client与proxy交互,能够把proxy当作一般的Redis实例一样,因为codis-proxy实现了Redis协定,API保持一致。Redis分片是一个codis-group,包含了多个codis-server,其中有1个主节点、n个从节点,用来作读写拆散,主节点承当写申请,从节点摊派读申请。各个分片的Redis实例是独立的,互不感知。codis-server与一般Redis实例的区别是,在Redis的根底上扩大实现了slot槽的性能,用于扩容、数据迁徙。分片规定:对key做crc32 % 1024强依赖zookeeper,来存储节点槽位信息。codis-dashboard、codis-fe是集群运维工具。长处客户端无需感知背地细节,应用起来跟Redis单实例无显著区别(除局部命令不反对)平滑扩容,运维操作简略,有易于应用的web界面毛病是在Redis官网未反对集群计划之前的可选计划,目前已进行更新proxy会带来额定的网络开销,申请链路多了一层读写拆散可能呈现不统一的问题,也须要评估申请读写比须要额定保护zookeeper

April 30, 2022 · 1 min · jiezi

关于缓存:聊聊缓存布尔值踩到的坑

前言有这么一个业务场景:部门A服务要应用部门B服务的业务数据,部门A服务应用部门B服务的业务数据前置条件是B部门必须要给A受权。B部门的受权和业务数据分属为不同服务。其申请流程如下 因为A的鉴权信息的申请值是固定的,因而鉴权后果大概率也是固定值。过后B部门的业务服务开发共事,为了提高效率。就加了缓存,即B的业务服务会将A的鉴权后果缓存起来。过后写法形如下 private final LoadingCache<String,Boolean> checkSvcCache = Caffeine .newBuilder().maximumSize(Constants.MAX_SIZE) .expireAfterWrite(Conastants.EXPIRE, TimeUnit.DAYS) .build(key -> loadCache(key)); @Nullable private Boolean loadCache(@NonNull String key) { if(key.contains(Constant.UNDER_LINE)){ try { String[] arr = key.split(Constant.UNDER_LINE); Integer ak = Integer.parseInt(arr[0]); String sk = arr[1]; RPCResult<Boolean> result = authService.checkSvc(ak, sk); if(result.getSuccess()){ Boolean data = result.getData(); return data; } return false; } catch (Exception e) { log.error("{}",e); } } return false; }思考大家看下上述代码块的写法有没有问题?粗看貌似没啥问题,但理论是有点小问题的。当进行近程调用时,如果出现异常,此时布尔值会返回false。这样就可能把正确的后果给覆盖了,比方明明都按约定的 ak,sk传值了,后果返回鉴权失败。 修复那要如何修复?扯一点哲学货色,这个世界不是非黑即白,其实可能还存在灰色地带。布尔值在java的世界中,也不是就只有true或者false,当布尔值为包装类时,他还有一种状态是null。因而能够批改为 @Nullable private Boolean loadCache(@NonNull String key) { if(key.contains(Constant.UNDER_LINE)){ try { String[] arr = key.split(Constant.UNDER_LINE); Integer ak = Integer.parseInt(arr[0]); String sk = arr[1]; RPCResult<Boolean> result = authService.checkSvc(ak, sk); if(result.getSuccess()){ Boolean data = result.getData(); return data; } return false; } catch (Exception e) { log.error("{}",e); } } return null; }但这样改就没问题了吗,其实还是有问题,因为null值也不是正确后果。但咱们能够利用null来额定做一些异样兜底。比方呈现null时,就是有问题了,咱们能够对A进行敌对的提醒,而非返回鉴权失败,也便于提前裸露问题,而下次申请进来时,缓存会因为值为null,再次触发近程调用 ...

April 19, 2022 · 1 min · jiezi

关于缓存:Redis二分布式锁与Redis集群搭建

@[toc] 一、 线程锁与分布式锁线程锁 单体我的项目 单体我的项目 步骤 代码如下 //定义动态全局锁 private readonly static object _lock = new object();// 控制器中增加代码 lock (_lock) { Stock sto = new Stock(); sto = demoDbContext.stock.Where(p => p.ID == 1).FirstOrDefault(); if (sto.count == 0) { Console.WriteLine(Thread.CurrentThread.ManagedThreadId + "---秒杀完结,无库存"); return Ok("秒杀完结,无库存"); } Console.WriteLine(Thread.CurrentThread.ManagedThreadId + "--秒杀胜利;"); //库存减1 sto.count = sto.count - 1; demoDbContext.SaveChanges(); } return Ok("秒杀完结");数据库数量为10如图:用jmeter并发10个线程如图: - 运行后果如下: ![在这里插入图片形容](https://img-blog.csdnimg.cn/74dc100990c0461d9fba106606ccc8aa.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBAQEDnpZ7lhpzlhpnku6PnoIE=,size_20,color_FFFFFF,t_70,g_se,x_16#pic_center)分布式锁 条件 启动两个实例 5000/5001Nginxjmeter步骤 外围代码 public class RedisLock { public readonly ConnectionMultiplexer connectionMultiplexer; private IDatabase database = null; public RedisLock() { connectionMultiplexer = ConnectionMultiplexer.Connect("127.0.0.1:6380"); database = connectionMultiplexer.GetDatabase(0); } /// <summary> /// 加锁 /// </summary> public void Lock() { while (true) // { //redis_lock 锁名称 // Thread.CurrentThread.ManagedThreadId 线程名称 // TimeSpan.FromSeconds(10) 设置过期工夫 避免死锁 bool flag = database.LockTake("redis_lock", Thread.CurrentThread.ManagedThreadId, TimeSpan.FromSeconds(10)); //true :加锁胜利 false:加锁失败 if (flag) { break; } Thread.Sleep(10);//避免死锁 等待时间 开释资源。 } } /// <summary> /// 开释锁 /// </summary> public void UnLock() { database.LockRelease("redis_lock", Thread.CurrentThread.ManagedThreadId); connectionMultiplexer.Close(); } } 控制器中应用 ...

April 2, 2022 · 2 min · jiezi

关于缓存:Mybatis缓存

简介什么是缓存? 存在内存中的长期数据将用户常常查问的数据放在缓存(内存)中,用户去查问数据就不必从磁盘上(关系型数据库数据文件)查问,从缓存中查问,从而进步查问效率,解决了高并发零碎的性能问题。为什么应用缓存? 缩小和数据库的交互次数,缩小零碎开销,进步零碎效率。什么样的数据能应用缓存? 常常查问并且不常常扭转的数据。Mybatis缓存Mybatis蕴含一个十分弱小的查问缓存个性,它能够十分不便地定制和配置缓存。缓存能够极大的晋升查问效率。Mybatis零碎中默认定义了两级缓存:一级缓存和二级缓存 默认状况下,只有一级缓存开启。(SqlSession级别的缓存,也称为本地缓存)二级缓存须要手动开启和配置,他是基于namespace级别的缓存。为了进步扩展性,Mybatis定义了缓存接口Cache。咱们能够通过实现Cache接口来自定义二级缓存一级缓存一级缓存也叫本地缓存:SqlSession 与数据库同一次会话期间查问到的数据会放到本地缓存中。当前如果须要获取雷同的数据,间接从缓存中拿,没必要再去查询数据库;@Testpublic void test(){ SqlSession sqlSession = MybatisUtils.getSqlSession(); UserMapper mapper = sqlSession.getMapper(UserMapper.class); User user = mapper.queryUserById(1); System.out.println(user); System.out.println("===================="); User user2 = mapper.queryUserById(1); System.out.println(user2); System.out.println(user == user2);//true sqlSession.close();}日志: 缓存生效的起因: 查问不同的货色增删改操作,可能会扭转原来的数据,所以必定会刷新缓存!查问不同的Mapper.xml手动革除缓存二级缓存二级缓存也叫全局缓存,一级缓存作用域太低了,所以诞生了二级缓存基于namespace级别的缓存,一个名称空间,对应一个二级缓存工作机制 一个会话查问一条数据,这个数据就会被放在以后会话的一级缓存中;如果以后会话敞开了,这个会话对应的一级缓存就没了;然而咱们想要的是,会话敞开了,一级缓存中的数据被保留到二级缓存中;新的会话查问信息,就能够从二级缓存中获取内容;不同的mapper查出的数据会放在本人对应的缓存中;步骤: 开启全局缓存 <!--显示的开启全局缓存--><setting name="cacheEnabled" value="true"/>在要应用二级缓存的Mapper中开启 <!--在以后Mapper.xml中应用二级缓存--><cache/>也能够自定义参数: <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>小结: 只有开启了二级缓存,在同一个Mapper下就无效所有的数据都会先放在一级缓存中只有当会话提交,或者敞开的时候,才会提交到二级缓存中 自定义缓存-ehcacheEhcache是一种宽泛应用的开源Java分布式缓存。次要面向通用缓存。 导包: <!-- https://mvnrepository.com/artifact/org.mybatis.caches/mybatis-ehcache --><dependency> <groupId>org.mybatis.caches</groupId> <artifactId>mybatis-ehcache</artifactId> <version>1.1.0</version></dependency>在mapper中指定应用ehcache缓存: <!--在以后Mapper.xml中应用二级缓存--><cache type="org.mybatis.caches.ehcache.EhcacheCache"/>ehcache.xml <ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd" updateCheck="false"> <diskStore path="./tmpdir/Tmp_EhCache"/> <defaultCache eternal="false" maxElementsInMemory="10000" overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="1800" timeToLiveSeconds="259200" memoryStoreEvictionPolicy="LRU"/> <cache name="cloud_user" eternal="false" maxElementsInMemory="5000" overflowToDisk="false" diskPersistent="false" timeToIdleSeconds="1800" timeToLiveSeconds="1800" memoryStoreEvictionPolicy="LRU"/></ehcache>

January 30, 2022 · 1 min · jiezi

关于缓存:缓存穿透击穿雪崩

缓存穿透缓存和数据库都没有的数据,eg.订单号-1。量大时会导致数据库压力过大。解决办法: 减少合法性校验。应用布隆过滤器,能够判断出有没有。缓存异样后果 缓存击穿在缓存生效时被申请,如果量大,会导致数据库压力过大解决办法: 热点数据永不过期数据为空时,加互斥锁,只容许一个申请击穿,击穿完缓存就有了(这个锁应该设成无限次自旋) 缓存雪崩大量数据同时过期,申请量大会导致数据库压力过大解决办法: 热点数据永不过期过期工夫加随机值热点数据扩散到不同分片,防止宕机引起雪崩两层缓存

January 23, 2022 · 1 min · jiezi

关于缓存:缓存一致性最佳实践

背景概述最近团队里咱们在密集的探讨Redis缓存一致性相干的问题,电商外围的域如商品、营销、库存、订单等实际上在缓存的抉择上各有特色,那么在这些差别的业务背地,咱们有没有一些最佳实际可供参考呢?本文尝试着来探讨这个问题,并给出一些倡议。在探讨之前,有两个重点咱们须要达成统一: 分布式场景下无奈做到强统一:不同于CPU硬件缓存体系采纳的MESI协定以及硬件的强时钟管制,分布式场景下咱们无奈做到缓存与底层数据库的强统一,即把缓存和数据库的数据变更做成一个原子操作。硬件工程师设计了内存屏障(Memory Barrier)的概念,提供给软件开发者不同的一致性选项在性能与一致性上进行衡量。就算是达到最终一致性也很难:分布式场景下,要做到最终一致性,就要求缓存中存储的是最新版本的数据(或者缓存为空),而且是在数据库更新后很迅速的就要达到这个一致性的状态,要做到是极其艰难的。咱们会面临硬件、软件、通信等等组件十分多的异常情况。CPU的缓存构造* 缓存的一致性问题一般化来说,咱们面临的是这样的一个问题,如下图所示,数据库的数据会有5次更新,产生6个版本,V1~V6,图中每个方框的长度代表这个版本继续的工夫。咱们冀望,在数据库中的数据变动后,缓存层须要尽快的感知到并作出反应,如下图所示,缓存层方框中的距离代表这个时间段缓存数据不存在,V2、V3以及V5版本在缓存中不存在并不会毁坏咱们的最终一致性要求,只有数据库的最终版本和缓存的最终版本是雷同的就能够了。 缓存是如何写入的缓存写入的代码通常状况下都是和缓存应用的代码放在一起的,蕴含4个步骤,如下图所示:W1读取缓存,W2判断缓存是否存在,W3组装缓存数据(这通常须要向数据库进行查问),W4写入缓存。每一个步骤间可能会进展多久是没有方法管制的,尤其是W3、W4之间的进展最为要命,它很可能让咱们将旧版本的数据写入到缓存中。咱们可能会想,W4步的写入,带上W2的假如,即应用WriteIfNotExists语义,会不会有所改善? 思考如下的情景,假如有3个缓存写入的并发执行,因为短时间数据库大量的更新,它们别离组装的是V1、V2、V3版本的数据。应用WriteIfNotExists语义,其中必然有2个执行会失败,哪一个会胜利根本无法保障。咱们无奈简略的做决策,须要再次将缓存读取进去,而后判断是否咱们行将写入的一样,如果一样那就很简略;如果不一样的话,咱们有两种抉择:1)将缓存删除,让后续别的申请来解决写入。2)应用缓存提供的原子操作,仅在咱们的数据是较新版本时写入。 如何感知数据库的变动数据库的数据发生变化后,咱们如何感知到并进行无效的缓存治理呢?通常状况下有如下的3种做法: 应用代码执行流通常咱们会在数据库操作实现后,执行一些缓存操作的代码。这种形式最大的问题是可靠性不高,利用重启、机器意外当机等状况都会导致后续的代码无奈执行。 应用事务音讯作为应用代码执行流的改良,在数据库操作实现后收回事务音讯,而后在音讯的生产逻辑里执行缓存的治理操作。可靠性的问题就解决了,只是业务侧要为此减少事务音讯的逻辑,以及运行老本。 应用数据变更日志数据库产品通常都反对在数据变更后产生变更日志,比方MySQL的binlog。能够让中间件团队写一款产品,在接管到变更后执行缓存的治理操作,比方阿里的精卫。可靠性有保障,同时还能够进行某个时间段变更日志的回放,性能就比拟弱小了。 最佳实际一:数据库变更后生效缓存这是最罕用和简略的形式,应该被作为首选的计划,整体的执行逻辑如下图所示:W4步应用最根本的put语义,这里的假如是写入较晚的申请往往也是携带的最新的数据,这在大多的情景下都是成立的。D1步应用监听DB binlog的形式来删除缓存,即前述应用数据变更日志中介绍的办法。 这个计划的毛病是:在数据库数据存在高并发更新且缓存读取流量较大的状况下,会有小概率存在缓存中存储的是旧版本数据的状况。 通常的解法有四种:1)限度缓存无效工夫:设定缓存的过期工夫,比方15分钟。即示意咱们最多承受缓存在15分钟的工夫范畴内是旧的。2)小概率缓存重加载:依据流量比设定肯定比例的缓存重加载,以保障大流量状况下的缓存数据的一致性。比方1%的比例,这同时还能够帮忙数据库失去充沛的预热。3)联合业务特点:依据业务的特点做一些设计,比方:针对营销的场景:在商品详情页/确认订单页的优惠计算时应用缓存,而在下单时不应用缓存。这能够让极其状况产生时,不产生过大的业务损失。针对库存的场景:读取到旧版本的数据只是会在商品已售罄的状况下让多余的流量进入到下单而已,下单时的库存扣减是操作数据库的,所以不会有业务上的损失。4)两次删除:D1步删除缓存的操作执行两次,且两头有肯定的距离,比方30秒。这两次动作的触发都是由“缓存治理组件”发动的,所以能够由它反对。 最佳实际二:带版本写入针对象商品信息缓存这种更新频率低、数据一致性要求较高且缓存读取流量很高的场景,通常会采纳带版本更新的形式,整体的执行逻辑如下图如示: 和“数据库变更后生效缓存”计划最大的差别在W4步和D1步,须要缓存层提供带版本写入的API,即仅当写入数据版本较新时能够写入胜利,否则写入失败。这同时也要求咱们在数据库减少数据版本的信息。这个计划的最终一致性成果比拟好,仅在极其状况下(新版本写入后数据失落了,后续旧版本的写入就会胜利)存在缓存中存储的是旧版本数据的可能。在D1步应用写入而不是应用删除能够极大水平的防止这个极其状况的呈现,同时因为该计划实用于缓存读取流量很高的场景,还能够防止缓存被删除后W3步短时间大量申请穿透到DB。 总结与瞻望对于缓存与数据库拆散的场景,在联合了业界多家公司的实践经验以及ROI衡量之后,前述的两个最佳实际是被利用的最为宽泛的,尤其是最佳实际一,应该作为咱们日常利用的首选。同时,为了最大限度的防止每个最佳实际背地可能产生的不一致性问题,咱们还须要切合业务的特点,在要害的场景上做一些保障一致性的设计(比方前述的营销在下单时应用数据库读而不是缓存读),这也显得尤为重要(毕竟如“背景”中所述,并不存在完满的技术计划)。 除了缓存与数据库拆散的计划,还有两个业界曾经利用的计划也值得咱们借鉴: 阿里XKV简略来讲就是在数据库上部署一个Memcache的Server,它间接绕过数据库层间接拜访存储引擎层(如:InnoDB),同时应用KV client来进行数据的拜访。它的特点是数据实际上与数据库是强统一的,性能能够比应用SQL拜访数据库晋升5~10倍。毛病也很显著,只能通过主键或者惟一键来拜访数据(这只是绝对SQL来说的,大多数缓存原本也就是KV拜访协定)。 腾讯DCache不必自行保护缓存与数据库两套存储,给开发人员对立的一套数据视图,由DCache在缓存更新后自行长久化数据。毛病是反对的数据结构无限( key-value,k-k-row,list,set,zset ),将来也很难反对形如数据库表一样简单的数据结构。 文/苏木关注得物技术,做最潮技术人!

January 11, 2022 · 1 min · jiezi

关于缓存:Mybatis源码缓存机制

前言在Mybatis源码-Executor的执行过程中对Mybatis的一次理论执行进行了阐明,在整个执行过程中,没有对缓存相干逻辑进行剖析,这本篇文章中,将联合示例与源码,对Mybatis中的一级缓存和二级缓存进行阐明。 注释一. 一级缓存机制展现在Mybatis中如果屡次执行完全相同的SQL语句时,Mybatis提供了一级缓存机制用于进步查问效率。一级缓存是默认开启的,如果想要手动配置,须要在Mybatis配置文件中退出如下配置。 <settings> <setting name="localCacheScope" value="SESSION"/></settings>其中localCacheScope能够配置为SESSION(默认)或者STATEMENT,含意如下所示。 属性值含意SESSION一级缓存在一个会话中失效。即在一个会话中的所有查问语句,均会共享同一份一级缓存,不同会话中的一级缓存不共享。STATEMENT一级缓存仅针对以后执行的SQL语句失效。以后执行的SQL语句执行结束后,对应的一级缓存会被清空。上面以一个例子对Mybatis的一级缓存机制进行演示和阐明。首先开启日志打印,而后敞开二级缓存,并将一级缓存作用范畴设置为SESSION,配置如下。 <settings> <setting name="logImpl" value="STDOUT_LOGGING" /> <setting name="cacheEnabled" value="false"/> <setting name="localCacheScope" value="SESSION"/></settings>映射接口如下所示。 public interface BookMapper { Book selectBookById(int id);}映射文件如下所示。 <?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"><mapper namespace="com.mybatis.learn.dao.BookMapper"> <resultMap id="bookResultMap" type="com.mybatis.learn.entity.Book"> <result column="b_name" property="bookName"/> <result column="b_price" property="bookPrice"/> </resultMap> <select id="selectBookById" resultMap="bookResultMap"> SELECT b.id, b.b_name, b.b_price FROM book b WHERE b.id=#{id} </select></mapper>Mybatis的执行代码如下所示。 public class MybatisTest { public static void main(String[] args) throws Exception { String resource = "mybatis-config.xml"; SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder() .build(Resources.getResourceAsStream(resource)); SqlSession sqlSession = sqlSessionFactory.openSession(false); BookMapper bookMapper = sqlSession.getMapper(BookMapper.class); System.out.println(bookMapper.selectBookById(1)); System.out.println(bookMapper.selectBookById(1)); System.out.println(bookMapper.selectBookById(1)); }}在执行代码中,间断执行了三次查问操作,看一下日志打印,如下所示。 ...

December 28, 2021 · 9 min · jiezi

关于缓存:Client-Side-Cache-和-Server-Side-Cache-的区别

Cache me outside 缓存是一种优化网页加载工夫并优化其应用的内存量的长久化机制。 Cache 的定义出于篇幅限度,本文重点介绍 Web 缓存。 当您加载网站时,网站数据(如图像、视频和 html 文档)将被保留。 从新加载网站后,它不会调用数据库再次获取该数据。 它只是将数据从内存中读取。 缓存以容量换取速度,缓存通常会临时存储数据的子集,而数据库的数据通常是残缺且长久的。 Client Side Caching客户端缓存通常称为浏览器缓存,只管客户端缓存是一个略微宽泛的术语。其运行原理如下图所示: 一旦浏览器从服务器申请数据,它就会将其存储到浏览器创立的文件夹中。 下次关上网页时,它不会调用服务器获取数据,而是从浏览器缓存文件夹中提取数据。 Server Side Caching服务器端缓存是一个相似的概念,但略微简单一些。 一旦用户向网站发出请求,其数据就会存储在服务器上。 下次用户发出请求时,它只需从服务器取回保留的数据,无需从数据库中提取数据,从而节省时间。 这些缓存由站点管理员实现,充当浏览器和源服务器之间的中介。 它们通常也基于 HTTP 缓存指令。 Remote Caching近程缓存相似于服务器端缓存,但它也能够运行应用程序来序列化和反序列化数据。 不同之处在于您能够管制近程服务器,而不是由其他人操作。 通常通过利用程序代码或应用能够利用内存中数据存储的应用程序框架来检索 Web 内容。 Server-Side vs Remote vs Client Side次要区别在于网站的数据在本地保留在客户端缓存中,而在服务器端缓存中能够分发给所有用户,而在近程中,数据也失去解决。大多数精心设计的网站或应用程序将同时应用服务器端和客户端。 Why caching?通过缩小后端资源的负载和网络拥塞,缓存 Web 内容有助于进步网站的响应能力。 - AWS Downside如果您尝试拜访的网站已更新,则在革除缓存之前您可能看不到更新。 这可能产生在您之前,特地是如果您是一名 Web 开发人员并且您正在尝试更新您网站的设计。 如果缓存存储在您的客户端,解决方案很简略。 这实用于客户端缓存,如果服务器端缓存没有正确处理这种状况,可能会在服务器端缓存上返回谬误。如果您应用近程缓存,它能够解决该谬误并为您革除缓存并为您加载新申请。 简而言之,client side cache: 您的网络浏览器(Chrome、Firefox、Safari 或任何您应用的浏览器)决定记住网页的外观,因而不用再次申请服务器发送网页。 这通过打消简直整个网络通信来节省时间(和带宽)。 然而,如果服务器决定更改网页的外观,您就会遇到麻烦,因为浏览器对它认为页面应该是什么样子的“记忆”当初曾经过期了,它会给您一个旧版本的页面而不是新的。 这就是为什么人们有时会告诉您“革除浏览器缓存” - 这会迫使您的浏览器“遗记”页面的外观。 这迫使它向服务器询问页面的新的、更新的版本。 server side cache: ...

October 13, 2021 · 1 min · jiezi

关于缓存:本地缓存的使用

本地缓存的优缺点应用场景在单利用不须要集群反对或者集群状况下各节点无需相互告诉的场景下应用本地缓存较适合。长处利用和cache是在同一个过程外部,申请缓存十分疾速,没有过多的网络开销等。毛病缓存跟应用程序耦合,多个应用程序无奈间接的共享缓存,各利用或集群的各节点都须要保护本人的独自缓存,对内存是一种节约。本地缓存的几种实现间接编程实现应用动态变量实现本地缓存。 应用场景:单机场景下的小数据量缓存需要,同时对缓存数据的变更无需太敏感感知,如上个别配置管理、根底静态数据等场景。长处:通过动态变量一次获取数据而后缓存在内存中,缩小频繁的I/O读取,动态变量实现类间可共享,过程内可共享。毛病:缓存的实时性稍差,受java堆内存大小的影响,缓存数量无限。改良计划: 应用Zookeeper 的主动发现机制,更新缓存。应用示例: City.java public class City { private int id; private String name; public City(int i, String name) { this.id = i; this.name = name; } public void setId(int id) { this.id = id; } public void setName(String name) { this.name = name; } public int getId() { return id; } public String getName() { return name; } public static List<City> getCitysFromDB() { List<City> cities = new ArrayList<>(); cities.add(new City(1, "江西")); cities.add(new City(2, "上海")); cities.add(new City(3, "北京")); cities.add(new City(4, "天津")); cities.add(new City(5, "河北")); cities.add(new City(6, "湖北")); cities.add(new City(7, "湖南")); cities.add(new City(8, "广东")); cities.add(new City(9, "安徽")); cities.add(new City(10, "...")); return cities; }}CityLocalCacheExample.java ...

August 31, 2021 · 3 min · jiezi

关于缓存:缓存与数据库的双写一致性

这几天瞎逛,不晓得在哪里瞟到了缓存的双写,就忽然想起来这块尽管简略,然而细节上还是有足够多咱们能够去关注的点。这篇文章就来具体聊聊双写一致性。首先咱们晓得,当初将高速缓存利用于业务当中曾经非常常见了,甚至可能跟数据库的频率并驾齐驱。你的用户量如果下来了,间接将一个裸的 MySQL 去扛住所有压力显著是不合理的。 这里的高速缓存,目前业界支流的就是 Redis 了,对于 Redis 相干的文章,之前也有聊过,在此就不赘述,感兴趣的能够看看: Redis 根底数据结构和用法Redis 数据长久化Redis 主从同步Redis Sentinel 高可用Redis Cluster 集群详解额,不列出来我都没感觉对于 Redis 我竟然写了这么多...言归正传。在咱们的业务中,广泛都会须要将一部分罕用的热点数据(或者说不常常变然而又比拟多的数据)放入 Redis 中缓存起来。下次业务来申请查问时,就能够间接将 Redis 中的数据返回,以此来缩小业务零碎和数据库的交互。 这样有两个益处,一个是可能升高数据库的压力,另一个自不必说,对雷同数据来说可能无效的升高 API 的 RT(Response Time)。 后者其实还好,升高数据库的压力显得尤为重要,因为咱们的业务服务尽管可能以较低的老本做到横向扩大,但数据库不能。 这里的不能,其实不是指数据库不能扩大。MySQL 在主从架构下,通过扩大 Slave 节点的数量能够无效的横向扩大读申请。而 Master 节点因为不是无状态的,所以扩大起来很麻烦。 对,是很麻烦,也不是不能横向扩大。然而在那种架构下,我举个例子,主-主架构下,会带来很多动向不到的数据同步问题,并且对整个的架构引入了新的复杂性。 就像我在之前写的MySQL 主从原理中提到过的一样,双主架构更多的意义在于 HA,而不是做负载平衡。 所以,雷同的数据会同时存在 Redis 和 MySQL 中,如果该数据并不会扭转,那就完满的一匹。可事实很骨感,这个数据99.9999%的概率是肯定会变的。 为了保护 Redis 和 MySQL 中数据的一致性,双写的问题的就诞生了。 Cache Aside Pattern其中最经典的计划就是 Cache Aside Pattern ,这套定义了一套缓存和数据库的读写计划,以此来保障缓存和数据库中的数据一致性。 具体计划Cache Aside Pattern 具体又分为两种 Case,别离是读和写。 对于读申请,会先去 Redis 中查问数据,如果命中了就会间接返回数据。而如果没有从缓存中获取到,就会去 DB 中查问,将查问到的数据写回 Redis,而后返回响应。 而更新则绝对简略,然而也是最具备争议。当收到写申请时,会先更新 DB 中的数据,胜利之后再将缓存中的数据删除。 ...

August 23, 2021 · 1 min · jiezi

关于缓存:揭秘阿里云-RTS-SDK-如何实现直播降低延迟和卡顿

简介:这个夏天,没什么可能比一场酣畅淋漓的奥运较量来的过瘾。然而,在视频平台直播观看较量也有痛点:“卡顿” 和 “延时”。受限于不同地区、简单的网络状况、传输速度等起因,当您还在为赛点焦灼的时候,隔壁曾经传来欢呼声,观赛兴致霎时全无。为了打造更加晦涩稳固低延时的直播体验,越来越多企业关注低延时直播技术利用。作者:予涛 途坦 阿里云低延时直播RTS(Real-time Streaming)是在视频直播的根底上,进行全链路延时监控、CDN传输协定革新、UDP等底层技术优化,通过集成直播播放端SDK,反对千万级并发场景下的节点间毫秒级延时直播能力,补救了传统直播3~6秒延时的问题,保障低延时、低卡顿、秒开晦涩的极致直播观看体验。 为了可能升高直播的端到端延时,2020 年阿里云正式推出寰球实时传输网络 GRTN (Global Real Time Network) ,是部署在边缘云节点之上的超低延时、全分布式下沉的通信级流媒体传输网络,用于反对视频会议、视频直播、实时音视频等服务。要应用 GRTN 提供的短提早 / 实时传输服务,客户端能够通过浏览器的 webrtc 能力接入,也能够自行开发客户端协定栈来接入。 RTS NetSDK是什么?低延时直播SDK是由RTS NetSDK、推流 SDK和播放器SDK组成。其中,推流SDK将编码器输入的音视频帧发送给RTS NetSDK,播放器SDK从RTS NetSDK以帧的模式读取音频PCM数据和视频H264/H265数据。 Example: ffmpeg集成RTS NetSDK后拉ARTC流 RTS NetSDK是基于GRTN开发运行在客户端的协定栈。RTS NetSDK通过UDP传输层协定和GRTN上的SFU通信,收发音视频数据。思考网络条件未知性,RTS NetSDK集成了WebRTC的QoS算法来适应网络变动,从而提供优质的音视频传输服务。RTS NetSDK的轻量化设计使其非常容易被诸如ffmpeg,obs一类的开源框架所集成。 RTS客户端形成 RTS NetSDK承当推流拉流对接阿里云RTS服务桥梁,以包体积小、集成简略、对现有业务没有入侵为次要特点,帮忙直播客户简略疾速的降级传统直播到阿里云RTS直播。 RTS NetSDK 反对多平台,Android/iOS/MacOS/linux/Windows/RTOS, 反对多个开源我的项目集成的接入代码,ijkPlayer、obs、FFmpeg,而且阿里云推流SDK和播放器SDK曾经内置了RTS直播推拉流能力。 RTMP是基于TCP传输的,RTS是基于UDP传输的。在网络稳固带宽足够条件下,RTS比照rtmp没有多少劣势,但这种现实状况是比拟难以保障的。传输协定上的差别,使得RTMP对于变动的网络没有太多的QoS伎俩,齐全依赖TCP的拥塞管制。这种拥塞管制不以低提早为指标。阿里云的RTS引入WebRTC的QoS技术,对于网络丢包有更好的容忍度。杰出的带宽预计和拥塞管制,提供了细腻的网络应用策略。 另外,在Adobe Flash Player进行更新,RTMP在网页上曾经无奈再应用。客户要么抉择提早十分大的HLS技术,或抉择WebRTC技术。RTS H5版本实质上是WebRTC,能够在网页上运行。 产品劣势低提早散发计划特点提早HLS反对宽泛,类文件减速,散发技术比拟成熟个别10s以上RTMP多用于推流,国内遍地开花。用于客户端散发并不是支流个别5s以上FLV多用于客户端散发,为目前国内支流计划个别5s以上阿里云RTS直播应用udp传输技术500ms左右(基于实验室数据)HLS 直播因为其TS文件切片--整片读取的机制,其提早至多都在一个gop以上。 RTMP、FLV直播,为了保障客户端的播放顺畅,往往会让客户端放弃5秒以上的缓存。 阿里云RTS直播,基于udp传输技术,全链路针对提早优化,最新v1.8.0版本曾经能够将提早升高到500毫秒左右。 抗弱网阿里云RTS直播是基于UDP传输的,通过利用WebRTC的先进技术(比方BWE、jitter buffer、NetEQ、FEC、NACK等QoS机制)以及自研的抗弱网技术,在简单易变的用户网络环境中,比基于TCP传输的直播有着更好的晦涩度和提早。 包体积小RTS NetSDK领有笨重的包体积,以最新版本Android 和iOS为例: 平台增量大小iOS755 KB(arm64)Android0.9MB(arm64)易集成直播客户大多都曾经有了成型的直播推流和直播拉流能力。RTS NetSDK以库的模式被集成进客户现有的SDK,实现低成本降级,且兼容之前的业务逻辑。阿里云RTS直播曾经反对到传统直播的根本所有个性。 能力类型RTS直播反对状况视频编码h264、h265音频编码aac、opus、g722音频采样率44100、48k、16000 (g722)视频SEI反对公有NAL 拓展即使和rtp定义类型抵触,也做到了反对rtmp推流artc拉流反对artc推流rtmp/hls拉流反对artc推流artc拉流反对加密阿里云KMS加密体系产品利用架构 RTS 直播将反对传统直播的根本全副能力,如直播录制、防盗链、导播台等。 RTS NetSDK 能够被集成进拉流侧的各种产品中去。另外提供了集成到 ffplay、ijkPlayer 的源码,客户能够间接应用或者参照着批改。阿里云播放器 SDK 曾经内置了 RTS NetSDK 的拉流能力。 ...

August 13, 2021 · 1 min · jiezi

关于缓存:云原生体系下serverless弹性探索与实践

简介:弹性是 Serverless 外围能力之一,SAE 在传统弹性能力根底上,提供了多维的监控指标和弹性策略,是利用零革新上云的最佳抉择。Serverless时代的降临 Serverless 顾名思义,是一种“无服务器”架构,因为屏蔽了服务器的各种运维复杂度,让开发人员能够将更多精力用于业务逻辑设计与实现。在serverless架构下,开发者只须要关注于下层应用逻辑的开发,而诸如资源申请,环境搭建,负载平衡,扩缩容等等服务器相干的简单操作都由平台来进行保护。在云原生架构白皮书中,对serverless的个性有以下概括: 全托管的计算服务,客户只须要编写代码构建利用,无需关注同质化的、累赘沉重的基于服务器等基础设施的开发、运维、平安、高可用等工作;通用性,可能撑持云上所有重要类型的利用;主动的弹性伸缩,让用户无需为资源应用提前进行容量布局;按量计费,让企业应用老本得无效升高,无需为闲置资源付费。 回顾整个serverless的倒退历程,咱们能够看到从2012年首次提出serverless概念为终点,再到aws推出lambda云产品的这段时间内,人们对serverless的关注度呈现了爆发式的增长,对无服务器的期待和畅想逐步引爆整个行业,但serverless的推广和生产落地的过程却不容乐观,serverless理念与实操生产的过程中存在gap,挑战着人们固有的应用体验和习惯。阿里云深信serverless将作为云原生之后确定性的倒退方向,相继推出了fc,sae等多款云产品来笼罩不同畛域,不同类型的利用负载来应用serverless技术,并且一直在推动整个serverless理念的遍及与倒退。 就以后serverless整个市场格局而言,阿里云曾经做到了Serverless产品能力中国第一,寰球当先,在去年forrester评测魔力象限中能够显著的看到阿里云在serverless畛域曾经与aws并驾齐驱,于此同时,阿里云 Serverless 用户占比中国第一,在2020年中国云原生用户调研报告中整个阿里云serverless用户占比曾经达到了66%,而在serverless技术采纳状况的调研中表明,曾经有越来越多的开发者和企业用户将serverless技术利用于外围业务或者将要利用于外围业务之中。 Serverless弹性摸索 弹性能力作为云的外围能力之一,所关注的问题是容量布局与理论集群负载间的矛盾,通过两幅图的比照能够看到,如果采纳事后布局的形式进行资源安顿,会因为资源筹备量和资源需求量的不匹配导致资源节约或者资源有余的状况,进而导致老本上的过多开销甚至业务受损,而咱们冀望极致弹性能力,是筹备的资源和理论需要的资源简直匹配,这样使得利用整体的资源利用率较高,老本也随业务的增减和相应的增减,同时不会呈现因容量问题影响利用可用性的状况,这就是弹性的价值。弹性其实现上分为可伸缩性和故障容忍性,可伸缩性意味着底层资源能够参照指标的变动有肯定的自适应能力,而故障容忍性则是通过弹性自愈确保服务中的利用或实例处于衰弱的状态。上述能力带来的价值收益在于降老本的同时晋升利用可用性,一方面,资源使用量贴合利用理论消耗量,另一方面,晋升峰值的利用可用性,进而灵便适应市场的一直倒退与变动。 上面将对以后较为广泛的三种弹性伸缩模式进行论述和剖析。 首先是IaaS弹性伸缩,其代表产品是各云厂商云服务器弹性伸缩,如阿里云ess,能够通过配置云监控的告警规定来触发相应的ecs增减操作,同时反对动静增减slb后端服务器和rds白名单来保障可用性,通过健康检查性能实现弹性自愈能力。ess定义了伸缩组的概念,即弹性伸缩的根本单位,为雷同利用场景的ECS实例的汇合及关联slb,rds,同时反对多种伸缩规定,如简略规定,提高规定,指标追踪规定,预测规定等,用户的应用流程为创立伸缩组和伸缩配置,创立伸缩规定,监控查看弹性执行状况。 kubernetes弹性伸缩,这里次要关注于程度弹性hpa,其代表产品为k8s以及其所对应的托管云产品,如阿里云容器服务,k8s做为面向利用运维的基础设施和Platform for Platform,提供的内置能力次要是围绕着容器级别的治理和编排来开展的,而弹性能力聚焦于对底层pod的动静程度伸缩,k8s hpa通过轮询pod的监控数据并将它与指标期望值比拟进行,通过算法实时计算来产生冀望的正本数,进而对workload的正本数进行增减操作,用户在理论应用上须要创立并配置对应的指标源和弹性规定以及对应的workload,能够通过事件来查看弹性的执行状况。 最初介绍一下利用画像弹性伸缩,其次要用于互联网公司外部,如阿里asi容量平台。容量平台提供容量预测服务和容量变更决策服务,领导底层容量变更组件如AHPA/VPA实现容量弹性伸缩,并依据弹性后果修改容量画像。以画像驱动为主 + 指标驱动为辅实现弹性伸缩能力,通过提前伸缩 + 实时修改来升高弹性伸缩危险。整个弹性伸缩会借助odps和机器学习能力对实例监控等数据进行解决并产生利用画像,如基准画像,弹性画像,大促画像等,并借助容量平台来实现画像注入,变更管控和故障熔断等操作。用户应用流程为利用接入,基于历史数据/教训生成对应的容量画像,实时监控指标修改画像,并监控查看弹性执行状况。 从比照能够看出各产品弹性伸缩性能模式上从形象来讲基本相同,均由触发源,弹性决策和触发动作组成,触发源个别依赖内部监控零碎,对节点指标,利用指标进行采集解决,弹性决策个别基于周期性轮询并算法决策,有局部基于历史数据分析预测以及用户定义的定时策略,而触发动作为对实例进行程度扩缩,并提供变更记录与对外告诉。各个产品在此基础上做场景丰盛度,效率,稳定性的竞争力,并通过可观测能力晋升弹性零碎的透明度,便于问题排查和领导弹性优化,同时晋升用户应用体验与粘性。 各产品弹性伸缩模型也存在这肯定的差别,对于IaaS弹性伸缩,其作为老牌弹性伸缩能力,积淀工夫长,功能强大且丰盛,云厂商间能力趋于同质化。弹性效率相较容器受限,且强绑定各自底层iaas资源。kubernetes作为开源产品,通过社区力量一直优化迭代弹性能力和最佳实际,更合乎绝大部分开发运维人员诉求。对弹性行为和api进行高度形象,但其可扩展性不强,无奈反对自定义需要。而利用画像弹性伸缩具备团体外部特色,依据团体利用现状和弹性诉求进行设计,且更聚焦于资源池估算老本优化,缩容危险,复杂度等痛点。不易拷贝扩大,特地对于内部中小客户不实用。 从终态指标上,能够看出私有云与互联网企业方向的不同: 互联网企业往往因为其外部利用具备显著流量特色,利用启动依赖多,速度慢,且对整体资源池容量水位,库存财务管理,离在线混部有组织上的诸多诉求,因此更多的是以容量画像提前弹性扩容为主,基于metrics计算的容量数据作为实时修改,其指标是容量画像足够精准以至于资源利用率达到预期指标。私有云厂商服务于内部客户,提供更为通用,普适的能力,并通过可拓展性满足不同用户的差异化需要。尤其在serverless场景,更强调利用应答突发流量的能力,其指标在于无需容量布局,通过指标监控配合极致弹性能力实现利用资源的近乎按需应用且整个过程服务可用。Serverless弹性落地 Serverless作为云计算的最佳实际、云原生倒退的方向和将来演进趋势,其外围价值在于疾速交付、智能弹性、更低成本。 在时代背景下,SAE应运而生,SAE是一款面向利用的Serverless PaaS平台,反对 Spring Cloud、Dubbo等支流开发框架,用户能够零代码革新间接将利用部署到 SAE,并且按需应用,按量计费,能够充分发挥serverless的劣势为客户节俭闲置资源老本,同时体验上采纳全托管,免运维的形式,用户只需聚焦于外围业务开发,而利用生命周期治理,微服务治理,日志,监控等性能交由SAE实现。 SAE的技术架构如图所示,下层runtime分为网关路由,利用生命周期治理与商业化,镜像构建,定时工作,集群代理等多个模块。底层infra为多租Kubernetes,应用神龙裸金属平安容器、VK对接ECI两种形式提供集群计算资源。用户在SAE中运行的利用会映射到Kubernetes中相应的资源。其中多租能力是借助零碎隔离、数据隔离、服务隔离和网络隔离实现租户间的隔离。 弹性的竞争力次要在于场景丰盛度,效率,稳定性的竞争力,先讲一下SAE在弹性效率上的优化。 通过对SAE利用的整个生命周期进行数据统计和可视化剖析,其蕴含调度,init container 创立,拉取用户镜像,创立用户容器,启动用户容器&利用这几个阶段,示意图中对其耗时的占比进行了简化。咱们能够看到整个利用生命周期耗时集中于调度,拉取用户镜像,利用冷启动这几个阶段。针对于调度阶段,其耗时次要在于SAE以后会执行买通用户VPC操作,因为该步骤强耦合于调度,自身耗时较长,且存在创立长尾超时,失败重试等状况,导致调度链路整体耗时较长。由此产生的疑难是可否优化调度速度?可否跳过调度阶段 ? 而对于拉取用户镜像,其蕴含拉取镜像与解压镜像的时长,特地是在大容量镜像部署的状况下尤为突出。优化的思路在于拉取镜像是否能够优化应用缓存,解压镜像是否能够优化。而对于利用冷启动,SAE存在大量单体和微服务的JAVA利用,JAVA类型利用往往启动依赖多,加载配置慢,初始化过程长,导致冷启动速往往达到分钟级。优化的方向在于可否防止冷启动流程并使用户尽量无感,利用无革新。 首先SAE采纳了原地降级能力,SAE起初应用了k8s原生的deployment滚动降级策略进行公布流程,会先创立新版本pod,再销毁旧版本pod进行降级,而所谓原地降级,即只更新 Pod 中某一个或多个容器版本、而不影响整个 Pod 对象、其余容器的降级。其原理是通过 K8s patch 能力,实现原地降级 container,通过 K8s readinessGates 能力,实现降级过程中流量无损。原地降级给SAE带来了诸多价值,其中最重要的是防止重调度,防止Sidecar容器(ARMS,SLS,AHAS)重建,使得整个部署耗时从耗费整个Pod生命周期到只须要拉取和创立业务容器,于此同时因为无需调度,能够事后在Node上缓存新镜像,进步弹性效率。SAE采纳阿里开源openkruise我的项目提供的cloneset作为新的利用负载,借助其提供的原地降级能力,使得整个弹性效率晋升42%。 同时SAE采纳了镜像预热能力,其蕴含两种预热模式:调度前预热,SAE会对通用的根底镜像进行全节点缓存,以防止其频繁的从远端进行拉取。与此同时对于分批的场景反对调度中预热,借助cloneset原地降级能力,在降级的过程中能够感知到实例的节点散布状况,这样就能够在第一批部署新版本镜像的同时,对前面批次的实例所在节点进行镜像预拉取,进而实现调度与拉取用户镜像并行。通过这项技术,SAE弹性效率晋升了30%。 方才讲述的优化点在于拉取镜像局部,而对于解压镜像,传统容器运行须要将全量镜像数据下载后再解包,然而容器启动可能仅应用其中局部的内容,导致容器启动耗时长。SAE通过镜像减速技术,将原有规范镜像格局主动转化为反对随机读取的减速镜像,能够实现镜像数据免全量下载和在线解压,大幅晋升利用散发效率,同时利用acree提供的p2p散发能力也能够无效缩小镜像散发的工夫。 对于java利用冷启动较慢的痛点,SAE联结Dragonwell 11 提供了加强的AppCDS 启动减速策略,AppCDS即 Application Class Data Sharing,通过这项技术能够获取利用启动时的 classlist并Dump其中的共享的类文件,当利用再次启动时能够应用共享文件来启动利用,进而无效缩小冷启动耗时。映射到SAE的部署场景,利用启动后会生成对应的缓存文件在共享的NAS中,而在进行下一次公布的过程中就能够应用缓存文件进行启动。整体冷启动效率晋升45%。 ...

August 12, 2021 · 1 min · jiezi

关于缓存:Caffeine本地缓存实战

简介Caffeine 是一个高性能Java 缓存库,提供近乎最佳的命中率。 A Cache 相似于ConcurrentMap,但不完全相同。最基本的区别是ConcurrentMap保留所有增加到它的元素,直到它们被显式删除。Cache另一方面,A通常配置为主动驱赶条目,以限度其内存占用。在某些状况下, a LoadingCacheorAsyncLoadingCache可能很有用,即便它不驱赶条目,因为其自动缓存加载 性能Caffeine 提供灵便的结构来创立具备以下性能组合的缓存: 主动将条目加载到缓存中,可选异步当超过基于频率和早先度的最大值时基于大小的驱赶基于工夫的条目过期,自上次访问或上次写入以来测量当条目标第一个古老申请产生时异步刷新键主动包装在弱援用中值主动包装在弱援用或软援用中驱赶(或以其余形式删除)条目标告诉写入流传到内部资源缓存拜访统计的累积 应用1.pom.xml依赖 <!--caffeine 本地缓存--> <dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> <version>2.9.1</version> </dependency>2.初始化缓存你也能够基于以下,做降级,比方做异步操作... /** * @description Caffeine本地缓存 * @author: yx-0173 * @date: 2021-07-15 10:23 **/@Configuration@Slf4jpublic class CacheConfig { @Bean public Cache<String, Object> cache() { return Caffeine.newBuilder() // 设置最初一次写入或拜访后通过固定工夫过期 .expireAfterWrite(60, TimeUnit.SECONDS) // 监听器 .removalListener((String key, Object graph, RemovalCause cause) -> log.info("移除缓存中key为:{},value为:{}的缓存记录", key, graph)) // 初始的缓存空间大小 .initialCapacity(100) // 缓存的最大条数 .maximumSize(1000) .build(); } // api测试,以下代码不要写道这个配置类,可自行整顿 // 查找条目,如果未找到,则为null cache.getIfPresent(key); // 从缓存中查问,如果查问不到则将对应的值放入缓存,如果不可计算,则为null cache.get(key, k - > createExpensiveGraph(key)); // 插入或批改缓存 cache.put(key, graph); // 依据key删除一个缓存 cache.invalidate(key); // 批量获取 cache.getAll(keys); 。。。还有很多,可自行官网,页尾附上官网地址}3.工具类奉献给大家** * @description 本地缓存工具类 * @author: yx-0173 * @date: 2021-07-15 12:51 **/@Componentpublic class CacheUtil<K, V> { @Resource private Cache<K, V> cache; /** * 依据key获取value * * @return Object */ public V get(K key) { return cache.asMap().get(key); } /** * 依据key获取value * * @return Object */ public Map<? extends K, ? extends V> getBatch(List<String> key) { return cache.getAllPresent(key); } /** * 将一个map插入 */ public void putBatch(Map<? extends K, ? extends V> map) { cache.asMap().putAll(map); } public ConcurrentMap<K, V> get() { return cache.asMap(); } /** * 插入缓存 * * @param key key * @param value value */ public void put(K key, V value) { cache.put(key, value); } /** * 插入缓存,如果不存在,则将value放入缓存 * * @param key key * @param value value */ public V getIfNotExist(K key, V value) { return cache.get(key, k -> value); } /** * 是否含有 * * @param key key */ public boolean contains(K key) { return cache.asMap().containsKey(key); } /** * 革除 */ public void deleteAll() { cache.invalidateAll(); } /** * 批量删除 * * @param key key */ public void delete(List<String> key) { cache.invalidateAll(key); } /** * 删除 * * @param key key */ public void delete(K key) { cache.asMap().remove(key); } /** * 更新 * * @param key key * @param value value */ public void update(K key, V value) { cache.put(key, value); }}Caffeine驱赶策略1.基于大小Size-based ...

August 3, 2021 · 2 min · jiezi

关于缓存:一个优雅的-LRU-缓存实现

Golang 的各种组件很灵便也很弱小,但对于高级入门的使用者来说,要用好着实不易。最近,在开发一个能够拿来即用的 golang 库。第一个组件抉择了缓存,次要是因为这个组件十分的要害,但也十分不容易实现好。 第一步:定义 Cache 接口设计一个高扩大的缓存包,就须要利用 里氏替换准则(Liskov Substitution Principle),做好形象,将缓存定义为接口 type Cache interface { ...}第二步:组织包构造而后,实现一个具体的 LRU 缓存,那么此时首先要组织好包构造,如下: |-cache| |-lru| | |-lru.go| | |-segment.go| | |-options.go| | |-expvar.go|-cache.go利用包划分档次,将接口放在根包下,作为所有子包的通用语言: // cache.gopackage edgetype Cache interface { ...}第三步:实现 LRU 缓存为了避免锁竞争导致的性能低下,此处应用分段加锁的形式升高锁粒度以进步缓存性能同时将 segment、newSegment、cache 以小写命名,防止对外裸露实现细节应用 Higher-order function,实现可扩大的配置参数应用 expvar 裸露缓存的状态// lru.gopackage lrutype cache struct { ...}func New(opts ...Opt) (*cache, error) { ...}// segment.gopackage lrutype segment struct { ...}func newSegment(c int) *segment { ...}// options.gotype options struct { ...}type Opt func(*options)func WithConcurrency(c int) Opt { return func(o *options) { o.concurrency = c }}func WithCapacity(c int) Opt { return func(o *options) { o.capacity = c }}// expvar.govar m = struct { Get *expvar.Int Set *expvar.Int Delete *expvar.Int Exists *expvar.Int Hit *expvar.Int Evict *expvar.Int}{ Get: expvar.NewInt("cache.lru.get"), Set: expvar.NewInt("cache.lru.set"), Delete: expvar.NewInt("cache.lru.delete"), Exists: expvar.NewInt("cache.lru.exists"), Hit: expvar.NewInt("cache.lru.hit"), Evict: expvar.NewInt("cache.lru.evict"),}第四步:完结了么?当然没有,从以上能够看到,以下几点: ...

July 27, 2021 · 1 min · jiezi

关于缓存:文件缓存模板缓存

文件缓存(模板缓存)从页面片段缓存到 facebook 的 BigPipe 技术将页面划分成一个个小块利用 ob_flush() 与 flush() 将缓冲区的内容提前输入给浏览器浏览器在一个申请中一直接管并渲染到页面,一一小块显示。 注:JS 局部,不须要立即执行的局部,能够最初再 eval 进来程序执行的流程为: program data -> php buffer -> tcp buffer -> client browers 办法作用解释ob_start()关上输入缓冲区 ob_flush()将 PHP buffer 中的内容,送出到 Tcp buffer 中调用 ob_flush() 之后缓冲区内容将被抛弃。flush()将以后为止 Tcp buffer 中内容发送到用户的浏览器。flush() 函数不会对服务器或客户端浏览器的缓存模式产生影响。因而,必须同时应用 ob_flush() 和 flush() 函数来刷新输入缓冲。ob_get_contents()返回外部缓冲区的内容只是失去输入缓冲区的内容,但不革除它,没有激活,则返回 falseob_end_clean()删除外部缓冲区的内容,并且敞开外部缓冲区。 ob_end_flush()发送外部缓冲区的内容到浏览器,并且敞开输入缓冲区 ob_get_length()返回外部缓冲区的长度 如何应用这门技术?nginx 须要设置sudo vim /etc/nginx/nginx.conf proxy_buffering off;fastcgi_keep_conn on;gzip off; // 默认是开启了压缩,须要敞开php 须要设置sudo vim /etc/php/7.0/fpm/php.ini ;output_buffering = 4096output_buffering = off重启 nginx 和 phpsudo service nginx restartsudo service php7.0-fpm restart模板中应用<?php// 开启缓冲区ob_start();?><?php// 模拟程序执行迟缓sleep(1);// 将 php 执行过的货色发送给 nginx 或者 apacheob_flush();// nginx 或 apache 将内容发送给客户端flush();?><?php// 敞开之前也须要将最初的内容发送给客户端ob_flush();flush();// 清理缓冲区ob_end_clean();?>实现的成果及劣势页面中有很多分块内容的时候,能够将许多个分块内容分批次的刷给客户端,使得客户端不须要期待所有的内容加载结束能力看到内容。并且这种技术只有一次申请,如果采纳 ajax 的话,可能会想到的是,每个分块内容应用 ajax 申请一次,这样的话就会有多个申请。 ...

July 18, 2021 · 1 min · jiezi

关于缓存:服务器应用程序程序缓存

服务器应用程序程序缓存Web Server 服务器之 ApacheApache 的过期模块 mod_expires.so通过配置文件管制 HTTP 的 "Expires:" 和 "Cache-Control:" 头内容 # 启用 expires_module 模块LoadModule expires_module modules/mod_expires.so# 启用有效期管制ExpiresActive On# GIF 有效期为 1 个月,2592000 秒为 1 个月ExpiresByType image/gif A2592000# HTML 文档的有效期是最初批改时刻后的一星期ExpiresByType text/html M604800# 以下的含意相似ExpiresByType text/css "now plus 2 months"ExpiresByType image/jpeg "access plus 2 months"具体解释 ExpiresByType image/jpeg "access plus 2 months" 的含意为: ExpiresByType 示意为:由 mime 决定过期配置 image/jpeg 示意为:具体文件的 mime 类型 access 示意:过期工夫从拜访时开始计算,等同于 now 和 A 参数,还能够设置为 modification 或者 M 参数,示意为,被拜访文件的最初批改工夫开始计算。 months 示意月份,可用的参数有:years 、months 、 weeks 、 days 、hours 、 minutes 、 seconds ...

July 17, 2021 · 2 min · jiezi

关于缓存:浏览器缓存

浏览器缓存浏览器解决网页的形式走到协商缓存会返回 304走到强缓存会返回 200 正当应用浏览器缓存页面连贯的申请毋庸做长时间缓存敏感数据像订单等不宜做缓存动态资源局部,通常会设定一个较长的缓存工夫冷热数据拆散,缩小申请量不要随便批改文件,倡议应用 ?version=** 调用多版本不倡议应用 ETag,尤其是分布式header 字段输入形式html 输入形式<meta http-equiv="Cache-Control" content="max-age=7200">php 输入形式<?phpheader('Cache-Control:max-age=7200');强缓存阶段的 header 字段启用强缓存的状态为 200 (from disk cache) 执行到强缓存的机会为: graph TDA[浏览器] --> B[是否有缓存]B --> C{Yes or No?}C --> |yes| D[是否过期]D --> |no| E[就应用缓存中的内容]Pragma (HTTP 1.0)Expires (HTTP 1.0) (设定的是一个准确的工夫)Cache-control (HTTP 1.1) max-age (缓存最大的秒数)Public \ private (当设置为 public 且采纳 https 协定的时候,也会转换成 private)no-cache \ no-store (不容许寄存在用户的硬盘里) \ must-revalidate (必须申请认证)如果这三个参数同时呈现的话:那么优先程序为,1、Cache-control 2、Pragma 3、Expires协商缓存阶段的 header 字段启用协商缓存的状态为 304 Not Modified Last-Modified:末次更新标记,文件最初一次更新的具体工夫(上行 response)If-Modified-Since :资源上次的批改工夫(上行 request)E-Tag : 实体与标记(上行)If-None-Match :资源内容标识(上行)协商缓存的执行流程如下: ...

July 16, 2021 · 1 min · jiezi

关于缓存:那些年我们一起做过的性能优化

简介:性能优化是一个体系化、整体性的事件,印刻在我的项目开发环节的各个细节中,也是体现技术深度的大的战场。文章以Quick BI的简单零碎为背景,具体介绍性能优化的思路和伎俩,以及体系化的思考。-更多对于数智化转型、数据中台内容请退出阿里云数据中台交换群—数智俱乐部 和关注官网微信公总号(文末扫描二维码或点此退出) -阿里云数据中台官网 https://dp.alibaba.com/index 始终以来,性能都是技术层面不可避开的话题,尤其在中大型简单我的项目中。犹如汽车整车性能,谋求极速的同时,还要保障舒适性和实用性,而在汽车制作的每个环节、整机整合状况、发动机调校等等,都会最终影响用户体感以及商业达成,如下图性能对收益的影响。 性能优化是一个体系化、整体性的事件,印刻在我的项目开发环节的各个细节中,也是体现技术深度的大的战场。上面我将以Quick BI的简单零碎为背景,深扒整个性能优化的思路和伎俩,以及体系化的思考。 如何定位性能问题? 通常来讲,咱们对动画的帧率是比拟敏感的(16ms内),但如果呈现性能问题,咱们的理论体感可能就一个字:“慢”,但这并不能为咱们解决问题提供任何帮忙,由此咱们须要分析这个字背地的整条链路。 上图是浏览器通用的解决流程,联合咱们的场景,我这里形象成以下几个步骤: 能够看出,次要的耗时阶段分为两个: 阶段一:资源包下载(Download Code) 阶段二:执行 & 取数(Script Execution & Fetch Data) 如何深刻这两个阶段,咱们个别会用以下几个次要的工具来剖析: Network首先咱们要应用的一个工具是Chrome的Network,它能帮忙咱们初步定位瓶颈所在的环节: 如图示例,在Network中能够高深莫测看到整个页面的:加载工夫(Finish)、加载资源大小、申请数量、每个申请耗时及耗时点、资源优先级等等。下面示例能够很显著看出:整个页面加载的资源很大,靠近了30MB。 Coverage(代码覆盖率)对于简单的前端工程,其工程构建的产物个别会存在冗余甚至未被应用的状况,这些有效加载的代码能够通过Coverage工具来实时剖析: 如上图示例能够看到:整个页面28.3MB,其中19.5MB都未被应用(执行),其中engine-style.css文件的使用率只有不到0.7% 资源大图方才咱们曾经晓得前端资源的利用率非常低,那么具体是哪些有效代码被引入进来了?这时候咱们要借助webpack-bundle-analyzer来剖析整个的构建产物(产物stats能够通过webpack --profile --json=stats.json输入): 如上例,联合咱们以后业务能够看到构建产物的问题: 第一,初始包过大(common.js) 第二,存在多个反复包(momentjs等) 第三,依赖的第三方包体积过大 模块依赖关系有了资源构建大图,咱们也大略晓得了可优化的点,但在一个零碎中,成千盈百的模块个别都是通过相互援用的形式组织在一起,打包工具再通过依赖关系将其构建在一起(比方打成common.js单个文件),想要间接移除掉某个模块代码或依赖可能并非易事,由此咱们可能须要肯定水平抽丝剥茧,借助工具理清零碎中模块的依赖关系,再通过调整依赖或加载形式来作优化: 上图咱们应用到的是webpack官网的analyse工具(其余工具还有:webpack-xray,Madge),只须要将资源大图stats.json上传即可失去整个依赖关系大图 Performance后面讲到的都是和资源加载相干的工具,那么在剖析 “执行 & 取数” 环节咱们应用什么,Chrome提供了十分弱小的工具:Performance: 如上图示例,咱们能够至多发现几个点:主流程串化、长工作、高频工作。 如何优化性能?联合方才提到的剖析工具,方才提到的 “资源包下载”、“执行 & 取数” 两个大的阶段咱们基本上曾经笼罩到,其基本问题和解法也在一直的剖析中逐渐有了思路,这里我将联合咱们这里的场景,给出一些不错的优化思路和成果 大包按需加载要晓得,前端工程构建打包(如webpack)个别是从entry登程,去寻找整棵依赖树(间接依赖),从而依据这棵树产出多个js和css文件bundle或trunk,而一个模块一旦呈现在依赖树中,那么当页面加载entry的时候,同时也会加载该模块。 所以咱们的思路是突破这种间接依赖,针对末端的模块改用异步依赖形式,如下: 将同步的import { Marker } from '@antv/l7'改为异步,这样在构建时,被依赖的Marker会造成一个chunk,仅在此段代码执行时(按需),该thunk才被加载,从而缩小了首屏包的体积。 然而下面计划会存在一个问题,构建会将整个@antv/l7作为一个chunk,而非Marker局部代码,导致该chunk的TreeShaking生效,体积很大。咱们能够应用构建分片形式解决: 如上,先创立Marker的分片文件,使之具备TreeShaking的能力,再在此基础上作异步引入。 下方是咱们优化后的流程比照后果: 这一步,咱们通过按需拆包,异步加载,节俭了资源下载工夫和局部执行工夫 ...

July 14, 2021 · 1 min · jiezi

关于缓存:WebRTC-传输安全机制深入显出-SRTP-协议

简介:SRTP:平安传输协定(Secure Real-time Transport) 通过 DTLS 协商后,RTC 通信的单方实现 MasterKey 和 MasterSalt 的协商。接下来,咱们持续剖析在 WebRTC 中,如何应用替换的密钥,来对 RTP 和 RTCP 进行加密,实现数据的平安传输。同时,本文会对 libsrtp 应用中,遇到的问题的进行解答,例如,什么是 ROC,ROC 为什么是 32-bits?为什么会返回 error\_code=9, error\_code=10?替换的密钥有生命周期吗,如果有是多长时间呢?浏览本篇之前倡议浏览 DTLS 协商篇,两者联合,成果更佳哦! 作者|进学 审校|泰一 要解决的问题RTP/RTCP 协定并没有对它的负载数据进行任何爱护。因而,如果攻击者通过抓包工具,如 Wireshark,将音视频数据抓取到后,通过该工具就能够间接将音视频流播放进去,这是十分恐怖的事件。 在 WebRTC 中,为了避免这类事件产生,没有间接应用 RTP/RTCP 协定,而是应用了 SRTP/SRTCP 协定 ,即平安的 RTP/RTCP 协定。WebRTC 应用了十分有名的 libsrtp 库将原来的 RTP/RTCP 协定数据转换成 SRTP/SRTCP 协定数据。 SRTP 要解决的问题: ・对 RTP/RTCP 的负载 (payload) 进行加密,保障数据安全; ・保障 RTP/RTCP 包的完整性,同时防重放攻打。 SRTP/SRTCP 构造SRTP 构造 从 SRTP 结构图中能够看到: 1. 加密局部 Encrypted Portion,由 payload, RTP padding 和 RTP pad count 局部组成。也就是咱们通常所说的仅对 RTP 负载数据加密。 ...

June 21, 2021 · 6 min · jiezi

关于缓存:聊聊缓存模式

引言在零碎设计中,为了进步数据的处理速度缓存的应用无处不在。比方为了补救CPU处理速度和数据IO的差距,顺次有寄存器、CPU缓存、内存、硬盘金字塔模式的不同存储介质。而在下层的业务利用中,为了进步申请处理速度,通常会减少一层缓存来存储热点数据。而对于缓存数据的解决形式有如下几种模式。 旁路缓存 Cache-Aside旁路缓存模式是开发中最常应用的一种缓存模式,它的外围思路在于仅当一个对象被申请时才将它退出缓存。该模式下缓存数据的读写流程如下: 数据读取业务侧发动数据查问读取申请解决服务首先尝试从缓存读取加载数据判断缓存中数据是否存在,如果存在则间接返回缓存数据否则,从数据库等主存加载数据,并将数据写入缓存返回最终查问后果数据更新业务侧发动数据写入/更新申请解决服务首先对数据库等主存进行更新写入操作实现后将对应缓存数据删除生效模式分析旁路缓存的设计模式次要实用于对数据的读取频率远大于写入更新频率的场景下,即数据一旦写入后数据不再变换或很少变动的状况,并通过采纳LRU等数据淘汰策略,缓存热点数据。 但该模式下数据的更新操作因为须要解决数据和缓存,且不是原子操作,所以很容易呈现数据不统一的状况。须要依据理论的业务对数据一致性的要求进行解决。具体可参考《一文搞定缓存和数据库一致性》[链接] 通读/通写 Read-Through/Write-Through通读通写模式是将数据的缓存解决操作对立进行了封装解决,减少一个缓存层,对利用屏蔽底层数据处理的细节。在旁路缓存模式中,利用须要自行处理缓存命中或未命中的解决逻辑,减少复杂度。而通过减少缓存层,业务服务仅和缓存打交道,不去关怀具体数据的起源。数据读写流程如下: ======================================= 数据读取数据读取流程和旁路缓存相似,只是将缓存逻辑由缓存层对立解决。 数据更新数据更新时,由缓存层作为一个事务同时更新主存和缓存数据。 模式分析通读/通写模式实用于对雷同数据频繁读写的状况,并且对主存和缓存数据有强一致性要求的状况,例如银行的业务零碎。 缓存回写 Write-Behind缓存回写和Write-Through相似,只是在Write-Though模式下会在解决申请时同时解决主存和缓存的数据,而回写模式只对缓存的数据进行更新,而后采纳异步的形式将缓存中的数据回写到主存中。数据写入更新流程如下: 缓存数据的异步回写能够采纳多种形式,比方:按固定的工夫频率定时回写,或者统计数据更新的次数(或固定大小)并在达到肯定次数(大小)时进行回写。还能够两者联合:工夫或者更新次数任何一个达到指定值则触发回写操作。 在MySQL中对于数据的更新操作即采纳了相似的模式。MySQL将存储的数据依照页的形式读取到内存中,当更新数据时只会更新内存中加载的数据,这时数据的缓存页和磁盘中数据不统一,被更改的数据页称为“脏页”。在脏页被淘汰、或者数据库闲暇、敞开等状况下,触发对脏页的数据回写。 模式分析缓存回写的模式一方面因为业务申请仅须要对换粗数据更新即可实现操作,极大的升高了数据写入的工夫,进步了解决效率;另一方面因为缓存数据和主数据的不统一,会导致呈现读取到老数据的状况。另外因为写入主存储是有延时的,在异常情况下可能呈现数据失落。因而采纳该模式须要能容忍肯定的数据不统一,并且对可能的数据失落能够承受或者弥补。 总结没有任何一种模式是完满的,具体抉择哪一种缓存的策略须要结合实际的业务状况,并针对所选模式的劣势或缺点进行额定的弥补解决。 另外缓存的设计及其他很多设计模式,硬件层面和软件层面会在解决某些问题时呈现一样的计划,所以理解和相熟底层零碎或硬件的优良设计,对于下层利用和当初微服务状况下方案设计有很大的参考意义。

June 14, 2021 · 1 min · jiezi

关于缓存:数据库缓存最终一致性的四种方案

缓存与数据库数据一致性问题,始终是面试官很喜爱问的问题,你晓得有多少计划,每种的优缺点是啥?最终会采纳哪种计划较好,你感觉呢? 我的公众号:MarkerHub,Java网站:https://markerhub.com 更多精选文章请点击:Java笔记大全.md 作者:叶不闻 https://juejin.im/post/5d5c99... 背景缓存是软件开发中一个十分有用的概念,数据库缓存更是在我的项目中必然会遇到的场景。而缓存一致性的保障,更是在面试中被重复问到,这里进行一下总结,针对不同的要求,抉择恰到好处的一致性计划。 缓存是什么存储的速度是有区别的。缓存就是把低速存储的后果,长期保留在高速存储的技术。 如图所示,金字塔更下面的存储,能够作为上面存储的缓存。 咱们本次的探讨,次要针对数据库缓存场景,将以 redis 作为 mysql 的缓存为案例来进行。 为什么须要缓存存储如 mysql 通常反对残缺的 ACID 个性,因为可靠性,持久性等因素,性能广泛不高,高并发的查问会给 mysql 带来压力,造成数据库系统的不稳固。同时也容易产生提早。依据局部性原理,80% 申请会落到 20% 的热点数据上,在读多写少场景,减少一层缓存十分有助晋升零碎吞吐量和健壮性。 存在问题存储的数据随着工夫可能会发生变化,而缓存中的数据就会不统一。具体能容忍的不统一工夫,须要具体业务具体分析,然而通常的业务,都须要做到最终统一。 redis 作为 mysql 缓存通常的开发模式中,都会应用 mysql 作为存储,而 redis 作为缓存,减速和爱护 mysql。然而,当 mysql 数据更新之后,redis 怎么放弃同步呢。 强一致性同步老本太高,如果谋求强统一,那么没必要用缓存了,间接用 mysql 即可。通常思考的,都是最终一致性。 解决方案计划一通过 key 的过期工夫,mysql 更新时,redis 不更新。 这种形式实现简略,但不统一的工夫会很长。如果读申请十分频繁,且过期工夫比拟长,则会产生很多长期的脏数据。 长处: 开发成本低,易于实现;治理成本低,出问题的概率会比拟小。有余 齐全依赖过期工夫,工夫太短容易缓存频繁生效,太长容易有长时间更新提早(不统一)计划二在计划一的根底上扩大,通过 key 的过期工夫兜底,并且,在更新 mysql 时,同时更新 redis。 长处 绝对计划一,更新提早更小。有余 如果更新 mysql 胜利,更新 redis 却失败,就进化到了计划一;在高并发场景,业务 server 须要和 mysql,redis 同时进行连贯。这样是损耗双倍的连贯资源,容易造成连接数过多的问题。计划三针对计划二的同步写 redis 进行优化,减少音讯队列,将 redis 更新操作交给 kafka,由音讯队列保障可靠性,再搭建一个生产服务,来异步更新 redis。 ...

June 6, 2021 · 1 min · jiezi

关于缓存:一文搞定缓存和数据库一致性

引言在现在的零碎开发中,为了进步业务和接口的处理速度,缓存数据曾经变成开发模式的惯例操作。通过引入缓存缩小数据库的查问操作,进步数据的查问速度。但任何一件事件都要从它的两个面去看。引入缓存在带来诸多劣势的同时,也相应的进步了零碎的复杂性,比方:如何保障缓存和数据库的一致性。 缓存策略在理论业务中,咱们常常采纳的一种缓存策略如下: 缓存-数据库读流程用户发动查问申请业务服务首先依据要害参数作为key查问缓存如果数据在缓存中存在cache hit,则间接返回缓存中查问后果。如果数据不在缓存中cache miss,则进行数据库查问操作,将后果缓存并返回查问后果。缓存-数据库写流程用户发动申请,须要写数据。业务服务在实现逻辑解决后,开始更新数据库。数据库更新实现后依据key删除缓存数据(or 更新?)上述这种数据缓存策略被称为旁路缓存策略(Cache-Aside Strategy),其核心思想是:只有当有利用来申请时,才将对应的对象进行缓存。并且这种策略实用于读取频繁然而写入或更新不频繁的场景,即数据一旦写入后次要用于查问展现,根本不会更新。 另外罕用的还有其余两种策略: 读写穿透缓存策略(Read-Through/Write-Through Caching Strategy):读写申请由缓存层对立封装解决,业务服务仅操作缓存。异步写入缓存策略(Write-Behind Caching Strategy):数据读取与Read-Through相似,然而数据写入由独立线程异步批量解决更新数据库。以上为罕用的三种缓存策略,前期再做具体阐明,本文仅针对Cache-Aside进行剖析阐明。 问题引入在Cache-Aside策略下,当呈现数据写入/更新申请解决中有这样两个问题须要抉择: 问题一:对缓存中的老数据进行更新还是删除?问题二:在解决时先更新数据库还是先解决缓存更新 OR 删除假如咱们抉择的是缓存更新,上面来剖析在理论多申请并发的状况下 同时有申请A和B对数据进行更新操作;在各自的业务线程A和B中对申请进行解决;线程A更新数据库为90,线程B更新数据库为80;因线程A、B并发执行,B优先更新了缓存,随后线程A执行缓存更新,导致数据库中值为80,缓存中数据为90,呈现数据库和缓存的不统一。基于这个场景来看,的确抉择删除缓存能够避免出现相似问题,最多会呈现cache miss,触发从数据库查问加载。然而,删除缓存就是完满的吗? 先数据库 OR 先缓存在规范的做法里,咱们抉择的是先实现数据库的更新操作,而后操作缓存。首先业务操作的后果只有在数据库实现长久化,才算是实现的标记,其次咱们来看下先淘汰缓存可能呈现的问题。 同时有申请A进行数据更新和申请B进行查问;线程A先实现缓存删除操作;因为并发的存在,线程B在A删除缓存后执行,因cache miss触发数据库查问加载线程B实现数据库查问,失去旧的数据100,并缓存查问后果。线程A实现数据库更新,数据库中后果为90,导致呈现缓存和数据库的不统一。那如果抉择先更新数据库,肯定能保障一致性吗?不肯定。 场景一:缓存删除失败。在实现数据库的操作后,因为缓存服务等起因导致缓存删除失败,导致数据库和缓存呈现不统一。 场景二:缓存生效通常咱们缓存的数据都会设置肯定的有效期,那么还是回到多申请并发的状况下 同时有申请A进行数据更新和申请B进行查问;线程A进行数据库更新操作;线程B查问申请时缓存数据已过期,触发数据库查问加载(这里等同于先执行了删除)。线程B实现数据库查问拿到老数据100;线程A实现数据库更新为90,而后删除缓存线程B执行缓存操作,设置缓存数据为100。缓存和数据库呈现了不统一。然而这些状况呈现须要几个前提: 一是缓存平台出现异常,概率较低; 二是缓存数据过期,并且是数据库查问操作比更新操作耗时更久,导致后设置缓存,概率能够说是极小。 能保持一致吗?通过下面几种场景的剖析,会发现即便咱们抉择规范的旁路缓存的策略,仍然没方法保障100%的数据统一。到这里,就须要引入分布式系统下外围的CAP实践。基于CAP实践剖析,应用缓存的零碎属于CAP实践中的AP,所以咱们无奈保障强一致性,而只能实现BASE实践中最终的统一,即保障缓存和数据库这个数据最终统一。 最终一致性强调的是零碎中所有的数据正本,在通过一段时间的同步后,最终可能达到一个统一的状态。因而,最终一致性的实质是须要零碎保障最终数据可能达到统一,而不须要实时保证系统数据的强一致性。最终统一计划延时双删计划从名字能够看出计划的实质在于在提早肯定工夫后,再进行一次缓存的删除,来解决并发状况下缓存到老数据的问题,即便先操作缓存后操作数据库也能够保障最终数据的统一。 计划流程 用户发动申请,须要写入更新数据业务服务首先进行删除缓存而后业务服务进行数据库的更新操作在提早肯定工夫T后,再执行一次缓存删除。计划剖析该计划的外围点在于延迟时间T,通常咱们把T设置为雷同业务中一次查问操作耗时+几百毫秒,这样保障了第二次的删除能够革除掉因并发导致的缓存脏数据。 该计划的劣势在于: 须要针对兴许评估延迟时间,并减少二次删除逻辑,代码强耦合,减少了复杂度。二次删除也可能呈现缓存失败。缓存删除重试为了保障缓存删除胜利,须要在缓存失败时减少重试机制。能够借助音讯队列,将删除失败的数据进行异步重试。 用户发动申请,须要写入更新数据业务服务首先进行数据库更新操作而后业务服务进行缓存删除,因某些起因导致失败将删除失败缓存key进入音讯队列生产音讯队列中的音讯,获取须要重试的缓存key重试缓存删除操作计划剖析该计划尽管将重试逻辑拆除独立执行,但须要在失常业务逻辑中退出删除失败解决代码,侵入性很强。上面看借助MySQL BinLog实现缓存删除的计划 BinLog缓存删除计划数据库的BinLog存储了对数据库的更改操作日志记录,通过订阅该日志,来进行缓存的更新,业务代码不再关怀缓存更新操作。 用户发动申请,须要写入更新数据业务服务进行数据库更新操作实现业务申请数据库操作写入BinLog日志通过中间件订阅数据库BinLog日志(如:canel),获取须要更新缓存的key和数据依据解析后果进行缓存删除,如果删除失败则放入音讯队列生产音讯队列中的音讯,获取须要重试的缓存key重试缓存删除操作总结缓存和数据库一致性问题的呈现在于高并发申请下缓存操作和数据库操作不是原子性的导致,尽管能够通过引入诸多的计划来保证数据的最终统一,但无论哪种计划都大大增加了零碎的复杂度,同时引入更多问题。因而须要正当的评估业务,对数据一致性的敏感水平来抉择适合的计划,没必要为了谋求统一而统一。

June 6, 2021 · 1 min · jiezi

关于缓存:Ubuntu-查看缓存文件qbit

前言本文在 Ubuntu 20.04 下测试fincore查看单个文件有多大在缓存中 fincore filename查看目录下所有文件有多大在缓存中 ls ./ | xargs fincorevmtouch查看单个文件有多大在缓存中 vmtouch filename查看目录下所有文件有多大在缓存中 vmtouch ./pcstat未尝试,https://github.com/tobert/pcstathcache未尝试,https://github.com/silenceshe...本文出自 qbit snap

May 31, 2021 · 1 min · jiezi

关于缓存:处理器缓存影响-翻译

翻译自: http://igoro.com/archive/gall... 原文代码是C#的,我改成了golang,原文有些不主观,我加了sleep进展一会,把缓存置出 我的电脑是Mac Pro2018, 例1. 内存拜访性能func TestMem(t *testing.T) { var arr = []int{128 * 1024 * 1024} time.Sleep(time.Second) // Loop 1 tt := time.Now() for i := 0; i < len(arr); i++ { arr[i] *= 3 } fmt.Println("Loop 1", time.Now().Sub(tt)) time.Sleep(time.Second) // Loop 2 tt = time.Now() for i := 0; i < len(arr); i += 16 { arr[i] *= 3 } fmt.Println("Loop 2", time.Now().Sub(tt))}运行后果 Loop 1 417nsLoop 2 523ns很神奇, 第一次运行的工夫反而更少循环破费雷同工夫的起因与内存无关。这些循环的运行工夫取决于对数组的内存拜访,而不是整数乘法。而且,正如我将在示例 2 中解释的那样,硬件将为两个循环执行雷同的主内存拜访。 ...

May 31, 2021 · 1 min · jiezi

关于缓存:缓存中的服务详解SpringBoot中二级缓存服务实现

创立缓存服务创立缓存服务接口我的项目创立myshop-service-redis-api我的项目,该我的项目只负责定义接口创立我的项目的pom.xml: <?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.oxford</groupId> <artifactId>myshop-dependencies</artifactId> <version>1.0.0-SNAPSHOT</version> <relativePath>../myshop-dependencies/pom.xml</relativePath> </parent> <artifactId>myshop-service-redis-api</artifactId> <packaging>jar</packaging></project>定义数据Redis接口RedisService: package com.oxford.myshop.service.redis.apipublic interface RedisService{ void set(String key,Object value); void set(String key,Object value,int seconds); void del(String key); Object get(String key);}创立缓存服务提供者我的项目创立myshop-service-redis-provider我的项目,该我的项目用作缓存服务提供者创立我的项目的pom.xml: <?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>com.oxford</groupId> <artifactId>myshop-dependencies</artifactId> <version>1.0.0-SNAPSHOT</version> <relativePath>../myshop-dependencies/pom.xml</relativePath> </parent> <artifactId>myshop-service-redis-api</artifactId> <packaging>jar</packaging> <dependencies> <!-- Spring Boot Starter Settings--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <!--Common Setting--> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-pool2</artifactId> </dependency> <dependency> <groupId>de.javakaffee</groupId> <artifactId>kryo-serializers</artifactId> </dependency> <!--Project Settings--> <dependency> <groupId>com.oxford</groupId> <artifactId>my-shop-commons-dubbo</artifactId> <version>${Project.parent.version}</version> </dependency> <dependency> <groupId>com.oxford</groupId> <artifactId>my-shop-service-redis-api</artifactId> <version>${Project.parent.version}</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <mainClass>com.oxford.myshop.service.redis.provider.MyshopServiceRedisProviderApplication</mainClass> </configuration> </plugin> </plugins> </build></project>Redis底层实现的Java的lettuce客户端 ...

May 22, 2021 · 4 min · jiezi

关于缓存:缓存篇本地缓存

本地缓存有如下四个经典实现:HashMap, Guava Cache, Caffine, Encache HashMap利用LinkedHashMap实现LRU缓存,示例代码如下: public class LRUCache extends LinkedHashMap { /** * 可重入读写锁,保障并发读写安全性 */ private ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock(); private Lock readLock = readWriteLock.readLock(); private Lock writeLock = readWriteLock.writeLock(); /** * 缓存大小限度 */ private int maxSize; public LRUCache(int maxSize) { super(maxSize + 1, 1.0f, true); this.maxSize = maxSize; } @Override public Object get(Object key) { readLock.lock(); try { return super.get(key); } finally { readLock.unlock(); } } @Override public Object put(Object key, Object value) { writeLock.lock(); try { return super.put(key, value); } finally { writeLock.unlock(); } } // 只须要笼罩LinkedHashMap的removeEldestEntry办法,便可实现LRU淘汰策略 @Override protected boolean removeEldestEntry(Map.Entry eldest) { return this.size() > maxSize; }}Guava Cache特点: ...

May 15, 2021 · 2 min · jiezi

关于缓存:独家对话阿里云函数计算负责人不瞋你所不知道的-Serverless

简介:如果你是一名互联网研发人员,那么极有可能理解并利用过 Serverless 这套技术体系。纵观 Serverless 过来十年,它其实因云而生,也在同时扭转云的计算形式。如果套用技术成熟度曲线来形容的话,那么它曾经走过了萌芽期、认知幻灭期,开始朝着成熟稳固的方向倒退。将来,市场对 Serverless 的接受程度将越来越高。 作者 | 杨丽 起源 | 雷锋网(ID:leiphone-sz) Serverless 其实离咱们并没有那么边远。如果你是一名互联网研发人员,那么极有可能理解并利用过 Serverless 这套技术体系。纵观 Serverless 过来十年,它其实因云而生,也在同时扭转云的计算形式。如果套用技术成熟度曲线来形容的话,那么它曾经走过了萌芽期、认知幻灭期,开始朝着成熟稳固的方向倒退。将来,市场对 Serverless 的接受程度将越来越高。 不要诧异,阿里云团队在真正开始构建 Serverless 产品体系的最开始的一两年里,也曾遭逢外部的一些争议。而今,单从阿里团体外部的很多业务线来看,曾经在朝着 Serverless 化的方向倒退了。 日前,阿里云凭借函数计算产品能力寰球第一的劣势,入选 Forrester 2021 年第一季度 FaaS 平台评估报告,成为比肩亚马逊成为寰球前三的 FaaS 领导者。这也是首次有国内科技公司进入 FaaS 领导者象限。 在与雷锋网的访谈中,阿里云 Serverless 负责人不瞋阐释了 Serverless 的演进历程、引入 Serverless 面临的难点与挑战、以及无关云原生的趋势预判。 “肯定要想明确做这件事的终局是什么,包含产品体系的定位,对开发者、对服务商的价值等等这些问题。这要求咱们一直通过实际和意识的深入,让这些问题的答复可能逐步清晰起来。这也是咱们这么多年实际积攒的贵重教训。”不瞋指出。 只管企业的实际还存在种种纳闷和挑战,但 Serverless 实际上离咱们并没有那么边远。举一个最近的例子,新冠疫情让近程办公、在线教育、在线游戏的利用需要短期内减少。业务规模的爆发式增长,对每一个需要的响应须要更加及时,这对利用架构的弹性,对底层计算的速度,对研发效率的晋升等,都要求业务减速向新技术架构演进。 而不瞋的现实就是,帮忙更宽泛的客户实现向新技术架构的平滑迁徙,让 Serverless 渗透到所有的云利用中。 不瞋作为阿里云 Serverless 产品体系的负责人,也是国内 Serverless 的晚期实践者。以下将出现是对这次访谈的残缺总结。 Serverless 的定义在探讨之前,咱们先明确 Serverless 的定义,确保大家对 Serverless 的认知是统一的。 当初 Serverless 越来越热,无论是工业界还是学术界,都将 Serverless 视为云计算倒退的下一阶段。Serverless 有很多种表述,其中伯克利大学的定义绝对谨严一些。 注:2019 年 2 月,加州大学伯克利分校发表的《Cloud Programming Simplified: A Berkerley View on Serverless Computing》论文,曾在业界引发诸多探讨和关注。大抵来讲,Serverless 理论对应的是一整套的产品体系,而不是独自一两个产品;同时,这些产品/服务之间还具备以下特色:服务之间彼此配合、全托管、用户通过 API 调用就可实现整个性能或利用的开发而无需关注底层基础设施。 ...

April 29, 2021 · 2 min · jiezi

关于缓存:网游云上网络优化方案

简介:网游云上网络优化计划 1. 游戏行业背景1.1 行业详情2019寰球数字游戏营收1094亿美元,其中中国市场328亿美元。国内游戏⽤户数6.5亿;挪动端 (60%)>PC端>主机。移动游戏占⽐逐年增⻓已成为相对的支流。国内公司近3万+,近200上市,Top10:腾讯53%,网易15%,三七,中手游,世纪华通,完满,搜狐畅游、游族、多益,紫龙互娱。 趋势:业务上交融电比赛事/直播往社交化、多元化倒退;技术上通过AR/VR/云游戏等来晋升体验。 政策管控:18年开始趋严,文化部管经营备案;广电总局管版号,19年只有数百个版号。 1.2 业务类型分类维度:终端、题材、美术格调、玩法、架构终端:端游、⼿游、页游、主机玩法:MMORPG、ACG、MOBA、RTS、FPS、SLG格调:武侠、魔幻、写实、⼆次元架构:分辨别服、全区全服、寰球同服2. 游戏技术特色2.1 核心技术逻辑对于任何网络游戏而⾔,同步是⼀定要解决的外围问题,甚至比游戏玩法逻辑自身还重要,什么是同步?同步是网络游戏的根底,通过网络通讯来确保同屏玩家看到的游戏世界中每个游戏单位的地位、世界场景、状态属性都要放弃⼀致。即:客户端的体现要⼀致,同时客户端与服务端的数据要⼀致。业界次要有两种同步形式。 状态同步图1 状态同步玩法逻辑(比方战⽃逻辑)写在服务端,服务端作为逻辑管制层,客户作为⼀个体现层,玩家对象数据在服务端生成并保护,客户端中玩家对象的所有动作都会告诉到服务端,服务端进⾏逻辑计算并将后果同步给所有客户端,客户端执行体现(播放动画、特效并批改玩家对象的属性显示),这种形式下,客户端的数据只能由服务端的指令来批改。 长处:安全性极高,防外挂能力强;断线重连⽐较好实现,无非就是把整个场景和⼈物全副从新⽣成⼀遍发给中途掉线重连上来的客户端去体现即可。 毛病:服务端压力较大(所有动作的计算逻辑须要在服务端上做),网络交互流量大,实现难度大,开发效率低。(通过分区风服来平行扩大);对于格⽃竞技竞速类,玩家动作、位移、⻆度的切换⾮常频繁且快,也须要比拟强的同步校验,这时状态同步无奈解决。 典型游戏:状态同步对网络提早的要求并不高(玩家体现层是不是⼀致没有太大关系,只有后果⼀致就行), ⼀般RPG游戏在200-300ms的提早也能玩上来,如MMORPG,魔兽世界、天龙八部等。 帧同步图2 帧同步也叫指令同步,玩法逻辑写在客户端了(比方战斗逻辑),客户端所有动作生成⼀条指令发给服务端(比方攻打对象B),服务端收到指令后什么也不做,间接转发给所有客户端,客户端收到指令后执⾏逻辑计算并执行体现层(播放动画、特效并批改玩家对象的属性数据)。 长处:服务端压力小(仅仅起到⼀个转发的作⽤),网络流量小,能做到更好的及时反馈及细节反馈的⽤户体 验。 毛病:容易外挂,断线重连会⽐较繁琐,须要在客户端重放每⼀条指令。 典型游戏:RTS、moba等即时对战类游戏,对同步性的要求很高,⼀场战斗的人数是确定的。王者光荣、魔兽争霸3、所有格斗类游戏等。实时性要求十分高,要求RTT小于50ms能力有晦涩的体验。 2.2 典型技术架构分辨别服:典型MMORPGMMORPG 大型多人在线角色扮演,如魔兽世界,剑灵,天龙八部 图3 特点:玩家之间强交互、实时性要求⾼、全⾯的游戏世界零碎。 业务流:特色,交付实时性,次要压力在哪⾥(网络、cpu、内存)。数据流:对数据库的拜访逻辑,压力状况。全区全服:典型MOBA分大量几个大区、分服对用户不可见;或者全局对客户不可见,应⽤层按⼀定算法进行调配。 ACG/SNS:休闲竞技类 MOBA(Multiplayer online battle arena)匹配开房间类,大逃杀吃鸡类(MOBA+FPS)王者光荣、绝地求生;堡垒之夜。 特点:休闲竞技类,匹配玩法,须要大量的可匹配玩家,匹配后生成战斗服。 图4 寰球同服:典型SLG为什么要做寰球同服,是⼀个经营需要还是⼀个技术需要?不是所有的游戏类型都适宜寰球同服。 特点:游戏对象之间弱交互,实时性要求并不高,300ms内的同步提早可承受;卡牌,SLG等,如COC:往往有3种架构: 服务端全集中部署,优化接入网络(加速器、DCDN)。全分布式部署,服务端应⽤+数据都分区域部署,做区域间数据同步。服务端应用层分区域部署,数据集中部署,通过区域缓存+高速通道(专线形式拜访DB)。数据⼀致性问题:⼀个玩家断线,缓存数据还未落地,玩家从新登录被断定到另⼀个区域登录了,可能获取不⼀致的角色数据;须要gamesvr断定上一次登录在哪个区域,通过⼀个全局服务去告诉对方gamesvr下线玩家并回写数据,而后再预取数据。 图5 2.3 技术痛点及诉求游戏业务最次要就是要求服务端逻辑解决的实时性和高并发撑持能力,玩法逻辑和数据都在⼀个过程是最现实的形式,但往往因为性能容量的限度,⽬前支流都是逻辑模块拆分、分布式部署,同时又要管制分布式调⽤的链路和次数来管制提早的目标;对于运行时数据根本都是在内存进行解决(如共享内存),玩家角色的结算/存档数据以固定周期长久化。 图6 基于以上游戏技术特征分析,总体来说对游戏对技术层⾯的诉求优先级是:网络>计算>平安>数据库。 在网络方面外围痛点其实就是如何解决网络提早、丢包、抖动对玩家卡顿、掉线等体验的毁坏,随着服务端技术更新和同屏玩家数量的减少,对游戏服务层的并发拜访、稳定性、⽹络提早也有了越来越高的要求。 3. 游戏网络优化游戏体验的优化是⼀个系统工程,须要多种优化伎俩联结作用,业界很多的精力是放在逻辑层的解决上,纯网络层面的优化只能说是一方面,以下基于云环境的网络优化计划进行论述。 3.1 游戏单服网络能力对于状态同步的MMORPG类游戏,每⼀次网络同步的数据是整个游戏世界场景的所有单位的属性、状态、行为断定等数据,同步量大,网络吞吐要求高,以⼀个单服设计容量1万在线的MMORPG游戏来说,通常⼀次网络同步的包大小在512byte左右,单⽤户评估带宽30kbps,则出网卡吞吐、包量能力须要的值: 以上是出公网的网卡的流量,GameServer还存在内网通信的需要,因而在这种场景⼀般倡议是抉择能⽀持百万级别pps的实例,如: ecs.c6.4xlarge 依靠神⻰架构,将网络虚拟化性能卸载到专用硬件,提供了更⾼的网络io承载能力和稳定性。 同时倡议将网络中断扩散给不同的vCPU解决,晋升网络PPS和带宽性能。即开启网卡多队列性能: 图7 图8 3.2 玩家接⼊网络减速这块次要是玩家到游戏服的公网链路上进行减速。 基于加速器优化玩家接入加速器与游戏是人造关联的两个行业,次要解决玩家与游戏服因物理间隔边远而呈现的提早、丢包等状况对游戏晦涩度的影响,这在国内玩家拜访海内游戏服的场景中很常见(比方某些游戏国内禁止发行而国内玩家只能登陆海内服来体验),玩家能够购买各类加速器产品,或者使⽤游戏客户端⾃集成的减速产品来实现链路优化,在云上要构建这⼀层减速其实曾经⾮常简略,甚⾄间接利⽤云的架构轻松实现⼀个加速器产品。 图9 具体流量门路 在上海VPC和⽇本VPC建⽴高速通道实现两地ECS内网互通。在两端地区ECS之间建设隧道协定,GRE或VXLAN,别离绑定本地地区EIP。国内玩家通过公⽹VPN连贯到上海上车点ECS,通过隧道接⼝路由到日本下车点ECS。⽇本ECS接管到去往游戏服的数据包从日本本地EIP进来,同时回程路由到隧道接口发给上海ECS。基于DCDN动静减速页游对于页游、H5小游戏等产品因为其⾛http协定,轻客户端模式动静逻辑中也蕴含有⼤量动态资源,这类游戏往往是全区全服单地区覆盖全国,网络上的次要痛点是:玩家跨运营商跨地区拜访游戏服,网络传输拥塞的时延、丢包等情况严重影响用户体验,同时客户自行去做动静拆散、动静减速等计划须要大量的工夫、老本投入。 图10 全站减速(DCDN)通过动静拆散、边缘缓存、智能路由、压缩传输等技术,解决跨运营商、网络不稳 定、复线源站、突发流量、网络拥塞等诸多因素导致的响应慢、丢包、服务不稳固的问题,晋升动动态混合、纯动静站点或App的减速性能和拜访体验;这种比拟适宜如三七页游、抖⾳小游戏等,其实对于⼀些重度游戏的全局⾮战斗模块、周边零碎等也能接入DCDN来进行全局减速。 基于CEN减速特定地区玩家国内地区⼴阔,游戏服虽是尽量做本地笼罩,但出于老本因素对于有些偏远地区还是笼罩不全,这部分玩家波及跨运营商跨地区的近程拜访游戏服,游戏掉线、卡登时有发⽣,⽐如对于新疆、⻄藏、宁夏、⻘海等地区,游戏服在部署上根本不会做本地笼罩,如果拉近游戏服与玩家的间隔?⽬前基于阿⾥云有种可行的计划是:SLB+CEN+游戏服(跨地区)。 图11 该⽅案对于没有POP点、anycast⽀持的地区比拟适合,相当于SLB挂载跨地区的ECS(白名单凋谢),拉近游戏服到用户侧间隔。 3.3 寰球同服⽹络构建这块次要是基于专线的减速计划,在寰球同服游戏相似中,数据传输须要跨运营商、跨多国通信,这对⽹络品质提出更高的要求,当然⽬前能实现真正意义上的寰球同服游戏其实没有,次要还是对即时性体验要求不高的SLG、卡牌等类型,游戏对象之间弱交互,实时性要求并不高。 ...

April 27, 2021 · 1 min · jiezi

关于缓存:数据弹性的隐形的翅膀

简介:弹性伸缩作为Kubernetes的外围能力之一,但它始终是围绕这无状态的利用负载开展。而Fluid提供了分布式缓存的弹性伸缩能力,能够灵便裁减和膨胀数据缓存。 它基于Runtime提供了缓存空间、现有缓存比例等性能指标, 联合本身对于Runtime资源的扩缩容能力,提供数据缓存按需伸缩能力。作者| 车漾 Fluid社区Commiter 作者| 谢远东 Fluid社区Commiter 背景随着越来越多的大数据和AI等数据密集利用开始部署和运行在Kubernetes环境下,数据密集型利用计算框架的设计理念和云原生灵便的利用编排的一致,导致了数据拜访和计算瓶颈。云原生数据编排引擎Fluid通过数据集的形象,利用分布式缓存技术,联合调度器,为利用提供了数据拜访减速的能力。 弹性伸缩作为Kubernetes的外围能力之一,但它始终是围绕这无状态的利用负载开展。而Fluid提供了分布式缓存的弹性伸缩能力,能够灵便裁减和膨胀数据缓存。 它基于Runtime提供了缓存空间、现有缓存比例等性能指标, 联合本身对于Runtime资源的扩缩容能力,提供数据缓存按需伸缩能力。 这个能力对于互联网场景下大数据利用十分重要,因为少数的大数据利用都是通过端到端流水线来实现的。而这个流水线蕴含以下几个步骤: 数据提取,利用Spark,MapReduce等大数据技术对于原始数据进行预处理模型训练,利用第一阶段生成特色数据进行机器学习模型训练,并且生成相应的模型模型评估,通过测试集或者验证集对于第二阶段生成模型进行评估和测试模型推理,第三阶段验证后的模型最终推送到线上为业务提供推理服务 能够看到端到端的流水线会蕴含多种不同类型的计算工作,针对每一个计算工作,实际中会有适合的业余零碎来解决(TensorFlow,PyTorch,Spark, Presto);然而这些零碎彼此独立,通常要借助内部文件系统来实现把数据从一个阶段传递到下一个阶段。然而频繁的应用文件系统实现数据交换,会带来大量的 I/O 开销,常常会成为整个工作流的瓶颈。 而Fluid对于这个场景非常适合,用户能够创立一个Dataset对象,这个对象有能力将数据扩散缓存到Kubernetes计算节点中,作为数据交换的介质,这样防止了数据的近程写入和读取,晋升了数据应用的效率。然而这里的问题是长期数据缓存的资源预估和预留。因为在数据生产生产之前,准确的数据量预估是比拟难满足,过高的预估会导致资源预留节约,过低的预估会导致数据写入失败可能性增高。还是按需扩缩容对于使用者更加敌对。咱们心愿可能达成相似page cache的应用成果,对于最终用户来说这一层是通明的然而它带来的缓存减速成果是实实在在的。 咱们通过自定义HPA机制,通过Fluid引入了缓存弹性伸缩能力。弹性伸缩的条件是当已有缓存数据量达到肯定比例时,就会触发弹性扩容,扩容缓存空间。例如将触发条件设置为缓存空间占比超过75%,此时总的缓存空间为10G,当数据曾经占满到8G缓存空间的时候,就会触发扩容机制。 上面咱们通过一个例子帮忙您体验Fluid的主动扩缩容能力。 前提条件举荐应用Kubernetes 1.18以上,因为在1.18之前,HPA是无奈自定义扩缩容策略的,都是通过硬编码实现的。而在1.18后,用户能够自定义扩缩容策略的,比方能够定义一次扩容后的冷却工夫。 具体步骤1.装置jq工具不便解析json,在本例子中咱们应用操作系统是centos,能够通过yum装置jq yum install -y jq2.下载、装置Fluid最新版 git clone https://github.com/fluid-cloudnative/fluid.gitcd fluid/chartskubectl create ns fluid-systemhelm install fluid fluid3.部署或配置 Prometheus 这里通过Prometheus对于AlluxioRuntime的缓存引擎裸露的 Metrics 进行收集,如果集群内无 prometheus: $ cd fluid$ kubectl apply -f integration/prometheus/prometheus.yaml如集群内有 prometheus,可将以下配置写到 prometheus 配置文件中: scrape_configs: - job_name: 'alluxio runtime' metrics_path: /metrics/prometheus kubernetes_sd_configs: - role: endpoints relabel_configs: - source_labels: [__meta_kubernetes_service_label_monitor] regex: alluxio_runtime_metrics action: keep - source_labels: [__meta_kubernetes_endpoint_port_name] regex: web action: keep - source_labels: [__meta_kubernetes_namespace] target_label: namespace replacement: $1 action: replace - source_labels: [__meta_kubernetes_service_label_release] target_label: fluid_runtime replacement: $1 action: replace - source_labels: [__meta_kubernetes_endpoint_address_target_name] target_label: pod replacement: $1 action: replace4.验证 Prometheus 装置胜利 ...

April 21, 2021 · 4 min · jiezi

关于缓存:mPaaS-月度小报-3月发生的大事件

简介:mPaaS 月度小报 Mar. 本月亮点速览 Easyconfig 辞别白屏期待:客户端从天而降的“白屏”期待应该如何排查?行业资讯: 货运物流数字化降级行业交流会:如何针对货运物流行业,打造性能晦涩、用户沉闷、终端平安的挪动利用? 安卓 WebView 致利用间断闪退 mPaaS 动静: CodeHub#4 荷小鱼:在线教育利用的开发实际 全新地区——中国(香港)正式开服:助力 App 实现动态化更新与公布 扫码组件上架 APICloud、CSDN,立刻 get 支付宝同款 Easyconfig白屏期待问题如何排查开发者在接入 mPaaS 容器后,配合挪动公布服务,能够让客户端不便地从本地加载业务包,极大地晋升了利用的加载效率。但在接入过程中一些轻微的谬误,可能会导致离线机制生效,以致利用在网络好的状况下会有一个短暂的“白屏”等待时间,在网络较差的状况下,甚至齐全无奈实现页面的加载。 因为 mPaaS 容器存在 fallback 机制,所以即便“离线”失败,容器也是能够“失常”加载业务包的内容的,开发阶段开发者往往容易疏忽掉“离线”对性能层面的影响。 所以倡议开发者在联调和上线的过程中,对于离线机制的工作状况予以检查和确认,能够通过抓包的伎俩从内部确认没有额定的、非必要的 fallback 申请产生,最终的目标是施展离线包的性能劣势。 理解更多:问题排查 | 客户端从天而降的“白屏”期待 行业资讯货运物流数字化降级行业交流会来自上海大学古代物流钻研核心主任的储雪俭传授示意:“明天探讨智慧物流,相对不是欲速不达的,销售渠道下沉造成物流日益碎片化。面对以后业务碎片化,咱们须要思考的是在业务碎片化的情景下,怎么通过平台做整合,建设你的专业化运维池?” 在整个货运物流行业的经营模型里,挪动端目前对用户来说是不可或缺的力量。如何针对货运物流行业,打造一个性能晦涩、用户沉闷、终端平安的挪动利用呢? 理解更多:货运物流挪动端解决方案:为货运物流行业打造高性能、高粘性的“双端”触点 WebView 致安卓利用间断闪退据外媒 9to5 Google 报道,大量安卓用户突遇利用间断闪退的状况,有用户发现通过卸载安卓零碎 WebView 后能够进行闪退。目前,谷歌曾经公布了利用解体问题的永恒修复:波及更新 Android System WebView 和 Chrome 浏览器 89.0.4389.105 版本升级。 实际上,Android 碎片化问题自其诞生之初业已存在,而且目前看上去并没有好的解决方案。不同零碎、不同厂商中的浏览器内核同样存在差别,导致层出不穷的兼容性问题令泛滥安卓开发同学头疼不已。 为了彻底解决并且掌控这些问题,mPaaS 集成独立的 UC 浏览器内核,同时继承了支付宝深度利用的容器及离线包:围绕 WebView 所产生的任何平安问题,开发者能够通过 mPaaS 能够在第一工夫修复并公布 理解更多:技术干货 | 深度解构 Android 利用面临紧急发版时的救星计划:mPaaS 热修复——DexPatch ...

April 20, 2021 · 1 min · jiezi

关于缓存:荷小鱼-x-mPaaS-借助-H5-容器改善-App-白屏浏览器兼容等问题

简介:弱网环境无影响、版本升级无感知 随着5G、大数据、人工智能技术的利用,各类传统行业纷纷鼎力推动数字化转型降级。 而受疫情的影响,教育行业也在大幅减速线上化转型过程,各类在线教育利用也在借助各种力量拓张本人的挪动端市场畛域。 「荷小鱼」作为一款学科启蒙在线学习利用,同样也在这条赛道上,思考如何能力在林立的竞对竞争中拔得头筹,取得更多用户的青眼? 这个问题的解法有很多,但第一步必定是晋升用户体验、优化利用性能。 「荷小鱼」亟待解决的问题原 App 内的局部页面,是通过 WebView 关上 H5 的形式来进行展现的,所以在关上一些重型页面时会呈现以下的一些问题: 1. 网络问题导致白屏; 2. 浏览器兼容性问题; 3. 无离线下发性能; 4. 无奈及时更新资源。 作为启蒙教育利用,「荷小鱼」的 App 页面除了须要嵌入根底框架代码和页面逻辑代码外,还须要嵌入多个字体库和多个音视频文件。 资源的多而大,导致页面非常容易收到网络的影响:网络不稳固时容易文件失落、白屏加载资源工夫长、造成网络线程阻塞等。 同时,也让 App 更新资源变得艰难了很多:无奈实时更新下发最新资源、缓存生效等。为技术团队在更新版本和调修 Bug 上造成了很大的妨碍。 “H5 容器+动静公布”通过了多方调研,「荷小鱼」最终抉择应用 mPaaS“H5 容器 + 动静公布服务”作为技术选型,用来解决 App 现阶段须要解决的难题。 .png") 首先,通过 mPaaS H5 容器中自带的 UC 内核浏览器,能够从根本上解决浏览器兼容性问题。 此外,mPaaS H5 容器反对离线包拜访。 离线包是将包含 HTML、JavaScript、CSS 等页面内动态资源打包到一个压缩包内。事后下载该离线包到本地,而后通过客户端关上,间接从本地加载离线包,从而最大水平地解脱网络环境对 H5 页面的影响。 通过离线包的形式把页面内动态资源嵌入到利用中并公布,当用户第一次开启利用的时候,就无需依赖网络环境下载该资源,而是马上开始应用该利用。 最初,配合动静公布服务能力,在推出新版本或是紧急公布的时候,开发者能够把批改的资源放入离线包,通过更新配置让利用主动下载更新。因而,开发者无需通过利用商店审核,就能让用户及早接管更新。对页面资源进行动静更新, 利用的开发调试和公布部署感激来自「荷小鱼」的前端工程师雷文伟,通过实操演示,展现如何接入 mPaaS 以及如何实现利用公布。 点击浏览原文,观看残缺视频。 弱网环境无影响、版本升级无感知用户体验,是每一个利用都须要面临的生死题。尤其是在雨后春笋般的在线教育利用市场中,利用的性能对用户的留存成果显得更是尤为重要。 挪动利用开发者从 DevOps 开始,到开发、性能监控、性能网络优化解决,在这一整套闭环流程中,通过借助 mPaaS 具备的开发测试、日志剖析、卡顿剖析、问题修复模式、热修复等各项能力,即可获取弱网环境无影响、版本升级无感知的用户体验。 E · N · D ...

April 14, 2021 · 1 min · jiezi

关于缓存:Elasticsearch-段合并qbit

前言本文对 Elasticsearch 7.10 实用节点角度查看节点 segment 状况(官网文档) GET _cat/nodes?v&s=name&h=name,sc,sm索引角度查看索引 index segment 状况(官网文档) GET my_index/_segments查看索引 cat segment 状况(官网文档) GET _cat/segments/my_index?v&h=index,shard,prirep,segment段合并(官网文档) POST my_index/_forcemerge状况索引缓存(官网文档) POST my_index/_cache/clear本文出自 qbit snap

April 13, 2021 · 1 min · jiezi

关于缓存:Python-函数缓存qbit

前言本文的 Python 3.8 实用LRU: least recently used,最近起码应用functools.lru_cache官网规范库: functools.lru_cache给 lru_cache 减少生命周期治理: https://stackoverflow.com/que...cachetoolspypi: https://pypi.org/project/cach...github: https://github.com/tkem/cache...文档: https://cachetools.readthedoc...cachetools v4.2.1 已实现缓存机制 FIFO: First In First Out,先进先出LFU: Least Frequently Used,最小频率应用,淘汰一段时间内应用次数起码的LRU: Least Recently Used,最近起码应用,淘汰最长工夫没有被应用的MRU: Most Recently Used,(淘汰)最近最多应用RR: Random Replacement,随机替换TTL: time-to-live,每个条目按生存工夫淘汰qbit snap

April 12, 2021 · 1 min · jiezi

关于缓存:Java应用全链路启动速度提升至15s阿里云SAE能力再升级

简介:Java 作为一门面向对象编程语言,在性能方面的卓越体现自成一家。但在高性能的背地,Java 的启动性能差也令人印象粗浅,大家印象中的 Java 轻便、迟缓的印象也大多来源于此,高性能和快启动速度仿佛有一些相悖。【云原生利用减速发布会】传送门:https://yqh.aliyun.com/live/detail/22720 点击查看详情:https://yqh.aliyun.com/live/cloudnative\_release Java 作为一门面向对象编程语言,在性能方面的卓越体现自成一家。但在高性能的背地,Java 的启动性能差也令人印象粗浅,大家印象中的 Java 轻便、迟缓的印象也大多来源于此,高性能和快启动速度仿佛有一些相悖。 近日,阿里云Serverless利用引擎(SAE)重磅公布 Java 利用启动减速性能,首度将 Alibaba Dragonwell(阿里巴巴开源的 Open JDK 长期反对版本)的冷启动减速技术、多线程运行减速技术和 SAE 本身的原地降级策略、镜像预热策略相结合,实现了 Java 利用的端到端启动速度晋升至仅15s,多线程性能晋升30%,再加上其本身的0代码革新劣势,已成为企业享受 Serverless 价值的最短门路。 难点剖析家喻户晓,微服务的用户在利用启动层面面临着一些难题: • 软件包大:几百 MB 甚至 GB 级别 • 依赖包多:上百个依赖包,几千个 Class • 加载耗时:从磁盘加载依赖包,再到 Class 按需加载,最高可占启动耗时的一半 借助 Dragonwell 疾速启动和多线程运行减速能力,SAE 为 Serverless Java 利用提供了一套,让利用尽可能减速启动的最佳实际,让开发者更专一于业务开发: • Java 环境 + JAR/WAR 软件包部署:集成 Dragonwell 11 ,提供减速启动环境 • JVM 快捷设置:反对一键开启疾速启动,简化操作 • NAS 网盘:反对跨实例减速,在新包部署时,减速新启动实例/分批公布启动速度 减速成果咱们抉择一些微服务、简单依赖的业务场景典型 Demo 或外部利用,测试启动成果,发现利用广泛能升高 5%~45% 的启动耗时。若利用启动,存在下列场景,会有显著减速成果: • 类加载多(spring-petclinic 启动加载约 12000+ classes) • 依赖内部数据越少 ...

April 7, 2021 · 1 min · jiezi

关于缓存:Fluid-05-版本开启数据集缓存在线弹性扩缩容之路

简介:为了解决大数据、AI 等数据密集型利用在云原生场景下,面临的异构数据源拜访简单、存算拆散 I/O 速度慢、场景感知弱调度低效等痛点问题,南京大学PASALab、阿里巴巴、Alluxio 在 2020 年 6 月份联结发动了开源我的项目 Fluid。 作者 | 顾荣  南京大学PASALab, Fluid我的项目co-founder 起源 | 阿里巴巴云原生公众号 导读:为了解决大数据、AI 等数据密集型利用在云原生场景下,面临的异构数据源拜访简单、存算拆散 I/O 速度慢、场景感知弱调度低效等痛点问题,南京大学PASALab、阿里巴巴、Alluxio 在 2020 年 6 月份联结发动了开源我的项目 Fluid。Fluid 是云原生环境下数据密集型利用的高效撑持平台,我的项目自开源公布以来吸引了泛滥相干方向领域专家和工程师的关注,在大家的踊跃反馈下社区一直演进。近期 Fluid 0.5 版本正式公布,在该版本中,Fluid 次要新增改善以下三个方面内容: 丰盛数据集的操作性能,反对在线弹性扩缩容、元数据备份和复原。反对多样环境配置部署,满足用户的个性化部署配置需要。新增数据缓存引擎实现,减少用户在私有云上的引擎抉择。Fluid 开源我的项目地址:https://github.com/fluid-cloudnative/fluid 这三大次要性能的开发需要来自泛滥社区用户的理论生产反馈,此外 Fluid v0.5 还进行了一些 bug 修复和文档更新,欢送应用体验 Fluid v0.5! Fluidv0.5 下载链接:https://github.com/fluid-cloudnative/fluid/releases 下文是本次新版本公布性能的进一步介绍。 丰盛数据集的操作性能在本版本中 Fluid 重点丰盛了外围形象对象 —— Dataset(数据集)的相干操作性能,从而使数据密集型利用可能更好地利用云原生提供的弹性、可观测性等根底性能,并加强了用户对数据集治理的灵活性。 1. 数据集在线弹性缓存扩缩容这是社区用户始终期待的性能!在 Fluid v0.5 之前,如果用户想要调整数据集的缓存能力,须要以全副卸载缓存引擎再重部署的形式实现。这种形式耗时耗力,还必须思考数据缓存全副失落的昂扬代价。因而,在新版本中,咱们为数据集提供了对缓存弹性扩缩容的反对,用户能够依据本人的场景需要,以不停机形式 on-the-fly 地按需减少某数据集的缓存容量以减速数据拜访(扩容)或缩小某个不频繁应用的数据集的缓存容量(缩容),从而实现更加精密的弹性资源分配,进步资源利用率。Fluid 内置的控制器会依据策略抉择适合的扩缩容节点,例如在缩容时会联合节点上运行工作状况和节点缓存比例作为筛选条件。 执行弹性数据集的缓存能力弹性扩缩容,用户只需运行如下命令: kubectl scale alluxioruntimes.data.fluid.io {datasetName} --replicas={num}其中 datasetName 对应于数据集的名称,replicas 指定缓存节点的数目。 无关数据集手动扩缩容及其成果的演示视频:http://cloud.video.taobao.com/play/u/2987821887/p/1/e/6/t/1/302459823704.mp4 ...

April 6, 2021 · 2 min · jiezi

关于缓存:Midway-Serverless-20一体化让前端研发再次提效

简介:2021 年 3 月,Midway Serverless 推出了第二个大版本。就像两年前说的一样,开源只是开始,终态远没有到来。Midway 体系心愿可能在以后的十字路口,一直向前演进,让前端能够去倒退,朝着利用工程师后退。 作者 | 张挺 起源 | Serverless 公众号 自去年 Midway Serverless 1.0 公布之后,许多业务开始尝试其中,并利用 Serverless 容器的弹性能力,缩小了大量研发人员对基础设施和运维的关注。对前端开发者而言,他们只需写几个函数即可实现后端业务逻辑,推动业务疾速上线。正如去年所说,应用了 Serverless 架构,能够让整个前端研发效力晋升。 2021 年 3 月,Midway Serverless 推出了第二个大版本。就像两年前说的一样,开源只是开始,终态远没有到来。Midway 体系心愿可能在以后的十字路口,一直向前演进,让前端能够去倒退,朝着利用工程师后退。 Midway Serverless 2.0 的外部代号是 “Hercules”,是希腊神话以及漫威中的大力士,藉由半神半人的出世,初步迈向成神之路。而藉由用户在 v1.0 的应用状况,咱们看到了不少问题,这一次 v2.0 的迭代重构,咱们心愿去解决这些问题,让用户体验和开发效率更进一步。 Github:https://github.com/midwayjs/midway欢送到 Github 帮 v2.0 点个 Star~一、Midway Serverless 的演进Midway Serverless 是 Midway 产出的一套面向 Serverless 云平台的开发计划。其内容次要包含函数框架 @midwayjs/faas ,以及一系列跟平台配套的工具链、启动器等。 在 2020 年初公布之后,同年 6 月,又公布了前后端一体化计划,能够不便地在前端代码间接调用函数端代码,一体化计划利用到团体的中后盾我的项目后,效果显著。 同年 9 月,Midway Serverless 公布了全新的 Midway 利用框架的第二个版本,引入了组件生态,之后 swagger、typeorm、mongo、gRPC 等组件一直地孵化,大大裁减了 Midway 的能力。 ...

March 22, 2021 · 2 min · jiezi

关于storage:常用前端缓存-springboot实战电商项目mall4j

罕用前端缓存Mall4j开源商城我的项目 1. LocalStorage本地持久性的缓存,保留之后,不通过手动革除的话,将会始终保留在浏览器中。localStorage 中的键值对总是以字符串的模式存储,这意味着某些数据类型会产生扭转。所以在保留或取出数据时,常常应用到JSON.stringify 或JSON.parse 将数据在对象和字符串间互相转化 2. SessionStorage会话级别的本地存储,它和 localStorage 很类似。最大区别在于:当浏览器被敞开时,sessionStorage的存储内容将全副失落。 localStorage 和 sessionStorage 常见APIlocalStorage.length // 取得storage中的个数localStorage.key(n) // 取得storage中第n个元素对的键值(第一个元素是0)localStorage.getItem(key) // 获取键值key对应的值localStorage.key // 获取键值key对应的值localStorage.setItem(key, value) // 增加数据,键值为key,值为valuelocalStorage.removeItem(key) // 移除键值为key的数据localStorage.clear() // 革除所有数据localStorage 和 sessionStorage 都有同源策略限度,大小均在5MB左右 3. CookieHTTP协定自身是无状态的。Cookie实际上是一小段的文本信息(key-value格局)。客户端向服务器发动申请,如果服务器须要记录该用户状态,就应用response向客户端浏览器颁发一个Cookie。客户端浏览器会把Cookie保存起来。当浏览器再申请该网站时,浏览器把申请的网址连同该Cookie一起提交给服务器。服务器查看该Cookie,以此来识别用户状态。 Cookie的局部属性 属性属性含意NAME=VALUE键值对,保留的名字和存储的值Expires过期工夫Path该 Cookie 是在以后的哪个门路下生成的,如 path=/index/Cookie原生的API不迭Storage敌对,更多时候都应用 npm 的 js-cookie js-cookie 的APIimport Cookies from 'js-cookie'Cookies.set('name', 'value') // 创立简略的cookieCookies.set('name', 'value', { expires: 7 }) // 创立有效期为7天的cookieCookies.set('name', 'value', { expires: 7, path: '' }) // 为当前页创立有效期7天的cookieCookies.get('name'); // => 'value'Cookies.get('nothing'); // => undefined//获取所有cookieCookies.get(); // => { name: 'value' }Cookies.remove('name') // 删除指定Cookie小结localStorage 和 sessionStorage 的相同点 ...

March 16, 2021 · 1 min · jiezi

关于缓存:缓存淘汰算法

缓存淘汰策略的实现从实质上来说,缓存算法并没有好坏之分,只有是否实用以后的业务场景。因而依据不同的业务场景设置不同的缓存算法会使缓存命中率更高。一、FIFOFIFO(First in First out)先进先出。能够了解为是一种相似队列的算法实现 实现概念:最先进来的数据,被认为在将来被拜访的概率也是最低的,因而,当规定空间用尽且须要放入新数据的时候,会优先淘汰最早进来的数据。 长处:没什么长处 毛病:算法逻辑设计所实现的缓存的命中率是比拟低,没有任何额定逻辑可能尽可能的保障罕用数据不被淘汰掉。 二、LRULRU(The Least Recently Used)最近最久未应用算法 实现概念:如果一个数据最近很少被拜访到,那么被认为在将来被拜访的概率也是最低的,当规定空间用尽且须要放入新数据的时候,会优先淘汰最久未被拜访的数据。 长处:LRU很好的应答了针对于突发流量涌入的状况 毛病:对于周期性、偶发性的拜访数据,有大概率可能造成缓存净化,置换进来了热点数据,把这些偶发性数据留下了,从而导致LRU的数据命中率急剧下降。 例如:当一个新剧热播,流量涌入,此剧的相干缓存登顶。但当新剧热度升高趋势变得平缓,其余周期性播出的综艺类节目涌入后将新剧缓存挤出, 这是我又拜访新剧,则不得不又将新剧退出缓存,这显然不合时宜,因为新剧我曾经拜访过很屡次了。 三、LFULFU(The Least Frequently Used)最近很少应用算法,与LRU的区别在于LRU是以工夫掂量,LFU是以时间段内的次数 实现概念:如果一个数据在肯定工夫内被拜访的次数很低,那么被认为在将来被拜访的概率也是最低的,当规定空间用尽且须要放入新数据的时候,会优先淘汰时间段内拜访次数最低的数据。 针对以上的实现概念能够看出,它相较于LRU其多出了拜访次数的概念,能够了解为当有缓存命中时其对应该缓存的计数器会+1。 长处:LFU无效的爱护了缓存,因为是以次数为基准所以更加精确,针对于拜访概率差不多时,缓存命中率较高。 毛病:LFU须要额定的空间来存储计数器来记录拜访频次。针对于一个数据的洪峰。起初又瘦弱,因为其频率过高导致其缓存很难生效。 例如:当一个新剧热播,流量涌入,此剧的相干缓存登顶。但当新剧热度升高趋势变得平缓,然而因为其缓存命中次数过高,导致其缓存始终处于缓存队列中,始终不会生效,直到残余所有缓存计数都超过了此缓存才将其排出。 四、W-TinyLFUW-TinyLFU(Window Tiny Least Frequently Used)是对LFU的的优化和增强 实现概念:当一个数据进来的时候,会进行筛选比拟,进入W-LRU窗口队列,以此应答流量突增,通过淘汰后进入过滤器,通过拜访拜访频率裁决是否进入缓存。如果一个数据最近被拜访的次数很低,那么被认为在将来被拜访的概率也是最低的,当规定空间用尽的时候,会优先淘汰最近拜访次数很低的数据 它也存储一个次数,但它为什么是对LFU的优化呢,因为其存储的值为Count-Min Sketch,Count-Min Sketch是一个hash操作,它扩增为多个hash,在多个hash地址上记录缓存命中次数。这样多个hash会导致原来hash抵触的概率升高,当查问数据时,且从当多个hash获得数据,取出多个hash数据中取其中的最小值,来定义为此缓存的命中次数。也就是Count Min的含意所在。 当某一个key的的计数器大于触发值(k),则整体计数器会除以2,这样解决了LFU的缓存难生效问题。 这样我就能够应用申请固定的空间大小来存储缓存计数,就算是hash抵触也没关系,因为从概率上来说我获取的最小值是最精确的。 其相似于布隆过滤器的实现,能够将布隆过滤器看成一种概率性数据结构,实质是高效的插入和查问。相比于传统的List、Map其更高效、占用空间更少。其实现是当有变量退出布隆过滤器时,通过K个映射函数将变量映射为位图中的K个点,将K个点的值由0置为1.当有新的元素退出时候持续映射,就算是点位反复也没关系,该点位仍旧为1.当查问时,元素交于K个点。 1、若k个地位有一个为0,则该元素必定不在汇合中 2、若K个地位全副为1,则该元素有可能存在汇合中 长处:在空间和工夫维度上领有微小劣势。 毛病:误差率的存在,利用较少,只有Caffine应用此算法。

March 11, 2021 · 1 min · jiezi

关于缓存:CPU高速缓存与极性代码设计

摘要:CPU内置大量的高速缓存的重要性显而易见,在体积、老本、效率等因素下产生了当今用到的计算机的存储构造。1. 介 绍 2. CPU缓存的构造 3. 缓存的存取与统一 4. 代码设计的考量 5. 最 后 CPU频率太快,其处理速度远快于存储介质的读写。因而,导致CPU资源的节约,须要无效解决IO速度和CPU运算速度之间的不匹配问题。芯片级高速缓存可大大减少之间的解决提早。CPU制作工艺的提高使得在比以前更小的空间中装置数十亿个晶体管,如此可为缓存留出更多空间,使其尽可能地凑近外围。 CPU内置大量的高速缓存的重要性显而易见,在体积、老本、效率等因素下产生了当今用到的计算机的存储构造。 介 绍计算机的内存具备基于速度的层次结构,CPU高速缓存位于该层次结构的顶部,是介于CPU内核和物理内存(动态内存DRAM)之间的若干块动态内存,是最快的。它也是最靠近中央处理的中央,是CPU自身的一部分,个别间接跟CPU芯片集成。 CPU计算:程序被设计为一组指令,最终由CPU运行。 装载程序和数据,先从最近的一级缓存读取,如有就间接返回,逐层读取,直至从内存及其它内部存储中加载,并将加载的数据顺次放入缓存。 高速缓存中的数据写回主存并非立刻执行,写回主存的机会: 1.缓存满了,采纳先进先出或最久未应用的程序写回; 2.#Lock信号,缓存一致性协定,明确要求数据计算实现后要立马同步回主存。 CPU缓存的构造古代的CPU缓存构造被分为多解决、多核、多级的档次。 2.1 多级缓存构造 分为三个次要级别,即L1,L2和L3。离CPU越近的缓存,读取效率越高,存储容量越小,造价越高。 L1高速缓存是零碎中存在的最快的内存。就优先级而言,L1缓存具备CPU在实现特定工作时最可能须要的数据,大小通常可达256KB,一些功能强大的CPU占用近1MB。某些服务器芯片组(如Intel高端Xeon CPU)具备1-2MB。L1缓存通常又分为指令缓存和数据缓存。指令缓存解决无关CPU必须执行的操作的信息,数据缓存则保留要在其上执行操作的数据。如此,缩小了争用Cache所造成的抵触,进步了处理器效力。 L2级缓存比L1慢,但大小更大,通常在256KB到8MB之间,功能强大的CPU往往会超过此大小。L2高速缓存保留下一步可能由CPU拜访的数据。大多数CPU中,L1和L2高速缓存位于CPU内核自身,每个内核都有本人的高速缓存。 L3级高速缓存是最大的高速存储单元,也是最慢的。大小从4MB到50MB以上。古代CPU在CPU裸片上具备用于L3高速缓存的专用空间,且占用了很大一部分空间。 2.2 多处理器缓存构造 计算机早已进入多核时代,软件也运行在多核环境。一个处理器对应一个物理插槽、蕴含多个核(一个核蕴含寄存器、L1 Cache、L2 Cache),多核间共享L3 Cache,多处理器间通过QPI总线相连。 L1 和 L2 缓存为CPU单个外围公有的缓存,L3 缓存是同插槽的所有外围都共享的缓存。 L1缓存被分成独立的32K数据缓存和32K指令缓存,L2缓存被设计为L1与共享的L3缓存之间的缓冲。大小为256K,次要作为L1和L3之间的高效内存拜访队列,同时蕴含数据和指令。L3缓存包含了在同一个槽上的所有L1和L2缓存中的数据。这种设计耗费了空间,但可拦挡对L1和L2缓存的申请,加重了各个外围公有的L1和L2缓存的累赘。 2.3 Cache Line Cache存储数据以固定大小为单位,称为Cache Line/Block。给定容量和Cache Line size,则就固定了存储的条目个数。对于X86,Cache Line大小与DDR一次访存能失去的数据大小统一,即64B。旧的ARM架构的Cache Line是32B,因而常常是一次填两个Cache Line。CPU从Cache获取数据的最小单位为字节,Cache从Memory获取的最小单位是Cache Line,Memory从磁盘获取数据通常最小是4K。 Cache分成多个组,每组分成多个Cache Line行,大抵如下图: Linux零碎下应用以下命令查看Cache信息,lscpu命令也可。 缓存的存取与统一上面表格形容了不同存储介质的存取信息,供参考。 存取速度:寄存器 > cache(L1~L3) > RAM > Flash > 硬盘 > 网络存储 ...

February 24, 2021 · 3 min · jiezi

关于缓存:京淘项目Day15

cgb2010-京淘我的项目Day15 1.Redis集群具体参见笔记 1.1 Redis集群宕机条件宕机条件: Redis中的主机缺失时,并且没有从机替补,Redis内存数据失落.这时Redis集群解体了. 问题1: 6台redis 3主3从(1主1从分为3组). 至多Redis宕机几台集群解体. 至多2台 集群解体.问题2: 9台redis 3主6从(1主2从分为3组). 至多宕机几台Redis集群解体. 至多5台 集群解体 集群宕机的条件: 当主机的数量不能保障时集群解体.特点:集群中如果主机宕机,那么从机能够持续提供服务,当主机中没有从机时,则向其它主机借用多余的从机.持续提供服务.如果主机宕机时没有从机可用,则集群解体.答案:9个redis节点,节点宕机5-7次时集群才解体. 1.2 Redis分区算法1.2.1 集群测试入门案例 1.2.2 hash槽算法Hash槽算法 分区算法.阐明: RedisCluster采纳此分区,所有的键依据哈希函数(CRC16[key]%16384)映射到0-16383槽内,共16384个槽位,每个节点保护局部槽及槽所映射的键值数据.依据主节点的个数,平衡划分区间.算法:哈希函数: Hash()=CRC16[key]%16384当向redis集群中插入数据时,首先将key进行计算.之后将计算结果匹配到具体的某一个槽的区间内,之后再将数据set到治理该槽的节点中. 1.3 对于算法面试题1.3.1 对于集群/分片算法阐明问题:一个数据很大.一个槽位不够存怎么办??? 谬误?? A 逻辑谬误 B. 有情理解答:1.一致性hash算法 hash(key) 43亿 依照顺时针方向找到最近的节点 进行set操作.2.Hash槽算法 crc16(key)%16384 (0-16383) 计算的后果归哪个节点治理,则将数据保留到节点中.外围常识: 一致性hash算法/hash槽算法 都是用来确定 数据归谁治理的问题. 最终的数据都会存储到node节点中. 1.3.2 面试题1问: Redis集群中一共能够存储16384个数据? A 对 B 错 为什么???小明猜测: 因为redis中共有16384个槽位,所以每个槽位存储一个key.那么不就是16384个key吗??答案: 谬误起因: Redis集群中的确有16384个槽位.然而这些槽位是用来划分数据归谁治理的.不是用来存储数据的. 并且依据hash计算的规定肯能呈现碰撞的问题.比方hash(key1)%16384=3000hash(key2)%16384=3000 `阐明key1和key2归同一个node治理. node.set(key1,value1); node.set(key2,value2); 因为槽位只是用来辨别数据,数据到底能存储多少个实现由redis内存决定.` 1.3.3 面试题2问题: 为Redis集群中最多有多少台主机?? 16384台主机 1.4 缓存相干面试题1.4.1 缓存穿透阐明: 用户高并发环境下,频繁拜访数据库中不存在的数据.导致用户申请间接拜访数据库.重大时导致数据库服务器宕机.解决方案: ...

February 5, 2021 · 2 min · jiezi

关于缓存:万字长文聊缓存下-应用级缓存

深刻解析SpringMVC外围原理:从手写简易版MVC框架开始(SmartMvc) : https://github.com/silently9527/SmartMvcIDEA多线程文件下载插件: https://github.com/silently9527/FastDownloadIdeaPlugin 公众号:贝塔学JAVA 摘要在上一篇文章 万字长文聊缓存(上)中,咱们次要如何围绕着Http做缓存优化,在后端服务器的应用层同样有很多中央能够做缓存,进步服务的效率;本篇咱们就来持续聊聊利用级的缓存。 缓存的命中率缓存的命中率是指从缓存中获取到数据的次数和总读取次数的比率,命中率越高证实缓存的成果越好。这是一个很重要的指标,应该通过监控这个指标来判断咱们的缓存是否设置的正当。 缓存的回收策略基于工夫存活期:在设置缓存的同时设置该缓存能够存活多久,不管在存活期内被拜访了多少次,工夫到了都会过期闲暇期:是指缓存的数据多久没有被拜访就过期基于空间设置缓存的存储空间,比方:设置缓存的空间是 1G,当达到了1G之后就会依照肯定的策略将局部数据移除 基于缓存数量设置缓存的最大条目数,当达到了设置的最大条目数之后依照肯定的策略将旧的数据移除 基于Java对象援用弱援用:当垃圾回收器开始回收内存的时候,如果发现了弱援用,它将立刻被回收。软援用:当垃圾回收器发现内存已有余的状况下会回收软援用的对象,从而腾出一下空间,避免产生内存溢出。软援用适宜用来做堆缓存缓存的回收算法FIFO 先进先出算法LRU 最近起码应用算法LFU 最不罕用算法Java缓存的类型堆缓存堆缓存是指把数据缓存在JVM的堆内存中,应用堆缓存的益处是没有序列化和反序列化的操作,是最快的缓存。如果缓存的数据量很大,为了防止造成OOM通常状况下应用的时软援用来存储缓存对象;堆缓存的毛病是缓存的空间无限,并且垃圾回收器暂停的工夫会变长。 Gauva Cache实现堆缓存Cache<String, String> cache = CacheBuilder.newBuilder() .build();通过CacheBuilder构建缓存对象 Gauva Cache的次要配置和办法 put : 向缓存中设置key-valueV get(K key, Callable<? extends V> loader) : 获取一个缓存值,如果缓存中没有,那么就调用loader获取一个而后放入到缓存expireAfterWrite : 设置缓存的存活期,写入数据后指定工夫之后生效expireAfterAccess : 设置缓存的闲暇期,在给定的工夫内没有被拜访就会被回收maximumSize : 设置缓存的最大条目数weakKeys/weakValues : 设置弱援用缓存softValues : 设置软援用缓存invalidate/invalidateAll: 被动生效指定key的缓存数据recordStats : 启动记录统计信息,能够查看到命中率removalListener : 当缓存被删除的时候会调用此监听器,能够用于查看为什么缓存会被删除Caffeine实现堆缓存Caffeine是应用Java8对Guava缓存的重写版本,高性能Java本地缓存组件,也是Spring举荐的堆缓存的实现,与spring的集成能够查看文档https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#cache-store-configuration-caffeine。 因为是对Guava缓存的重写版本,所以很多的配置参数都是和Guava缓存统一: initialCapacity: 初始的缓存空间大小maximumSize: 缓存的最大条数maximumWeight: 缓存的最大权重expireAfterAccess: 最初一次写入或拜访后通过固定工夫过期expireAfterWrite: 最初一次写入后通过固定工夫过期expireAfter : 自定义过期策略refreshAfterWrite: 创立缓存或者最近一次更新缓存后通过固定的工夫距离,刷新缓存weakKeys: 关上key的弱援用weakValues:关上value的弱援用softValues:关上value的软援用recordStats:开启统计性能Caffeine的官网文档:https://github.com/ben-manes/caffeine/wiki pom.xml中增加依赖<dependency> <groupId>com.github.ben-manes.caffeine</groupId> <artifactId>caffeine</artifactId> <version>2.8.4</version></dependency>Caffeine Cache提供了三种缓存填充策略:手动、同步加载和异步加载。手动加载:在每次get key的时候指定一个同步的函数,如果key不存在就调用这个函数生成一个值public Object manual(String key) { Cache<String, Object> cache = Caffeine.newBuilder() .expireAfterAccess(1, TimeUnit.SECONDS) //设置闲暇期时长 .maximumSize(10) .build(); return cache.get(key, t -> setValue(key).apply(key));}public Function<String, Object> setValue(String key){ return t -> "https://silently9527.cn";}同步加载:结构Cache时候,build办法传入一个CacheLoader实现类。实现load办法,通过key加载value。public Object sync(String key){ LoadingCache<String, Object> cache = Caffeine.newBuilder() .maximumSize(100) .expireAfterWrite(1, TimeUnit.MINUTES) //设置存活期时长 .build(k -> setValue(key).apply(key)); return cache.get(key);}public Function<String, Object> setValue(String key){ return t -> "https://silently9527.cn";}异步加载:AsyncLoadingCache是继承自LoadingCache类的,异步加载应用Executor去调用办法并返回一个CompletableFuturepublic CompletableFuture async(String key) { AsyncLoadingCache<String, Object> cache = Caffeine.newBuilder() .maximumSize(100) .expireAfterWrite(1, TimeUnit.MINUTES) .buildAsync(k -> setAsyncValue().get()); return cache.get(key);}public CompletableFuture<Object> setAsyncValue() { return CompletableFuture.supplyAsync(() -> "公众号:贝塔学JAVA");}监听缓存被清理的事件public void removeListener() { Cache<String, Object> cache = Caffeine.newBuilder() .removalListener((String key, Object value, RemovalCause cause) -> { System.out.println("remove lisitener"); System.out.println("remove Key:" + key); System.out.println("remove Value:" + value); }) .build(); cache.put("name", "silently9527"); cache.invalidate("name");}统计public void recordStats() { Cache<String, Object> cache = Caffeine.newBuilder() .maximumSize(10000) .recordStats() .build(); cache.put("公众号", "贝塔学JAVA"); cache.get("公众号", (t) -> ""); cache.get("name", (t) -> "silently9527"); CacheStats stats = cache.stats(); System.out.println(stats);}通过 Cache.stats() 获取到CacheStats。CacheStats提供以下统计办法: ...

January 5, 2021 · 4 min · jiezi

关于缓存:前端面试每日-31-第603天

明天的知识点 (2020.12.09) —— 第603天 (我也要出题)[html] 如何解决微信浏览器视频点击主动全屏的问题?[css] css3的属性transfrom的值preserve-3d和perspective有什么区别?[js] 请说说你对内置对象和宿主对象的了解[软技能] 说说你对前端缓存策略的了解《论语》,曾子曰:“吾日三省吾身”(我每天屡次检查本人)。前端面试每日3+1题,以面试题来驱动学习,每天提高一点!让致力成为一种习惯,让奋斗成为一种享受!置信 保持 的力量!!!欢送在 Issues 和敌人们一起探讨学习! 我的项目地址:前端面试每日3+1【举荐】欢送跟 jsliang 一起折腾前端,零碎整顿前端常识,目前正在折腾 LeetCode,打算买通算法与数据结构的任督二脉。GitHub 地址 微信公众号欢送大家前来探讨,如果感觉对你的学习有肯定的帮忙,欢送点个Star, 同时欢送微信扫码关注 前端剑解 公众号,并退出 “前端学习每日3+1” 微信群互相交换(点击公众号的菜单:交换)。 学习不打烊,充电加油只为遇到更好的本人,365天无节假日,每天早上5点纯手工公布面试题(死磕本人,愉悦大家)。心愿大家在这虚夸的前端圈里,放弃沉着,保持每天花20分钟来学习与思考。在这变幻无穷,类库层出不穷的前端,倡议大家不要等到找工作时,才狂刷题,提倡每日学习!(不忘初心,html、css、javascript才是基石!)欢送大家到Issues交换,激励PR,感激Star,大家有啥好的倡议能够加我微信一起交换探讨!心愿大家每日去学习与思考,这才达到来这里的目标!!!(不要为了谁而来,要为本人而来!)交换探讨欢送大家前来探讨,如果感觉对你的学习有肯定的帮忙,欢送点个[Star]

December 10, 2020 · 1 min · jiezi

关于缓存:一文教你看懂缓存击穿穿透雪崩降级等

对于缓存,大家必定都不生疏,不论是前端还是服务端开发,缓存简直都是必不可少的优化形式之一。在理论生产环境中,缓存的应用标准也是始终备受器重的,如果应用的不好,很容易就遇到缓存击穿、雪崩等重大异样情景,从而给零碎带来难以预料的灾祸。 为了防止缓存使用不当带来的损失,咱们有必要理解每种异样产生的起因和解决办法,从而做出更好的预防措施。 缓存穿透而缓存穿透是指缓存和数据库中都没有的数据,这样每次申请都会去查库,不会查缓存,如果同一时间有大量申请进来的话,就会给数据库造成微小的查问压力,甚至击垮db零碎。 比如说查问id为-1的商品,这样的id在商品表里必定不存在,如果没做非凡解决的话,攻击者很容易能够让零碎奔溃,那咱们该如何防止这种状况产生呢? 一般来说,缓存穿透罕用的解决方案大略有两种: 一、缓存空对象 当缓存和数据都查不到对应key的数据时,能够将返回的空对象写到缓存中,这样下次申请该key时间接从缓存中查问返回空对象,就不必走db了。当然,为了防止存储过多空对象,通常会给空对象设置一个比拟短的过期工夫,就比方像这样给key设置30秒的过期工夫: redisTemplate.opsForValue().set(key, null, 30, TimeUnit.SECONDS);这种办法会存在两个问题: 如果有大量的key穿透,缓存空对象会占用贵重的内存空间。空对象的key设置了过期工夫,这段时间内可能数据库刚好有了该key的数据,从而导致数据不统一的状况。这种状况下,咱们能够用更好的解决方案,也就是布隆过滤器 二、Bloom Filter 布隆过滤器(Bloom Filter)是1970年由一个叫布隆的小伙子提出的,是一种由一个很长的二进制向量和一系列随机映射函数形成的概率型数据结构,这种数据结构的空间效率十分高,能够用于检索汇合中是否存在特定的元素。 设计思维 布隆过滤器由一个长度为m比特的位数组(bit array)与k个哈希函数(hash function)组成的数据结构。原理是当一个元素被退出汇合时,通过K个散列函数将这个元素映射成一个位数组中的K个点,把它们置为1。检索时,咱们只有看看这些点是不是都是1就大概晓得汇合中有没有它了,也就是说,如果这些点有任何一个0,则被检元素肯定不在;如果都是1,则被检元素很可能在。 至于说为什么都是1的状况只是可能存在检索元素,这是因为不同的元素计算的哈希值有可能一样,会呈现哈希碰撞,导致一个不存在的元素有可能对应的比特位为1。 举个例子:下图是一个布隆过滤器,共有18个比特位,3个哈希函数。当查问某个元素w时,通过三个哈希函数计算,发现有一个比特位的值为0,能够必定认为该元素不在汇合中。 优缺点 长处: 节俭空间:不须要存储数据自身,只须要存储数据对应hash比特位工夫复杂度低:基于哈希算法来查找元素,插入和查找的工夫复杂度都为O(k),k为哈希函数的个数毛病: 准确率有误:布隆过滤器判断存在,可能呈现元素不在汇合中;判断准确率取决于哈希函数的个数不能删除元素:如果一个元素被删除,然而却不能从布隆过滤器中删除,这样进一步导致了不存在的元素也会显示1的状况。实用场景 爬虫零碎url去重垃圾邮件过滤黑名单缓存击穿缓存击穿从字面上看很容易让人跟穿透搞混,这也是很多面试官喜爱埋坑的中央,当然,只有咱们对知识点了然于心的话,面试的时候也不会那么被糊弄 简略来说,缓存击穿是指一个key十分热点,在不停的扛着大并发,大并发集中对这一个点进行拜访,当这个key在生效的霎时,继续的大并发就穿破缓存,间接申请数据库,就如同堤坝忽然破了一个口,大量洪水汹涌而入。 当产生缓存击穿的时候,数据库的查问压力会倍增,导致大量的申请阻塞。 解决办法也不难,既然是热点key,那么阐明该key会始终被拜访,既然如此,咱们就不对这个key设置生效工夫了,如果数据须要更新的话,咱们能够后盾开启一个异步线程,发现过期的key间接重写缓存即可。 当然,这种解决方案只实用于不要求数据严格一致性的状况,因为当后盾线程在构建缓存的时候,其余的线程很有可能也在读取数据,这样就会拜访到旧数据了。 如果要严格保证数据统一的话,能够用互斥锁 互斥锁 互斥锁就是说,当key生效的时候,让一个线程读取数据并构建到缓存中,其余线程就先期待,直到缓存构建完后从新读取缓存即可。 如果是单机零碎,用JDK自身的同步工具Synchronized或ReentrantLock就能够实现,但一般来说,都达到避免缓存击穿的流量了谁还搞什么单机零碎,必定是分布式高大上点啊,这种状况咱们就能够用分布式锁来做互斥成果。 为了你们能更懂流程,作为暖男的我还是判若两人的给你们筹备了伪代码啦: public String getData(String key){ String data = redisTemplate.opsForValue().get(key); if (StringUtils.isNotEmpty(data)){ return data; } String lockKey = this.getClass().getName() + ":" + key; RLock lock = redissonClient.getLock(lockKey); try { boolean boo = lock.tryLock(5, 5, TimeUnit.SECONDS); if (!boo) { // 休眠一会儿,而后再申请 Thread.sleep(200L); data = getData(key); } // 读取数据库的数据 data = getDataByDB(key); if (StringUtils.isNotEmpty(data)){ // 把数据构建到缓存中 setDataToRedis(key,data); } } catch (InterruptedException e) { // 异样解决,记录日志或者抛异样什么的 }finally { if (lock != null && lock.isLocked()){ lock.unlock(); } } return data;}当然,采纳互斥锁的计划也是有缺点的,当缓存生效的时候,同一时间只有一个线程读数据库而后回写缓存,其余线程都处于阻塞状态。如果是高并发场景,大量线程阻塞势必会升高吞吐量。这种状况该如何解决呢?我只能说没什么设计是完满的,你又想数据统一,又想保障吞吐量,哪有那么好的事,为了零碎能更加健全,必要的时候就义下性能也是能够采取的措施,两者之间怎么取舍要依据理论业务场景来决定,万能的技术计划什么的基本不存在。 ...

December 9, 2020 · 1 min · jiezi

关于缓存:缓存的数据一致性

写缓存和写数据,因为不是原子性的,所以会造成数据的不统一。那咱们是先写数据库还是先操作缓存呢,缓存操作是更新还是删除呢?任何脱离业务的设计都是耍流氓。咱们试想一个场景,A服务更新缓存后,很长一段时间内没有人拜访,B服务也更新了缓存,那A更新的缓存不就做了无用功了?更甚的是,如果这个缓存的计算,是极其简单的、耗时的、耗资源的,多来几个操作数据库的操作,这个开销就很大了。所以咱们选的是做删除,只有用到的时候,才去计算缓存,没有用到缓存的时候,不做计算,毛病就是第一次拜访可能会比较慢。那当初剩下两种状况: 先写数据库,再删除缓存。先删除缓存,再写数据库。另外,咱们也从并发和故障两种状况来思考。 先数据库并发如下图所示: 服务A更新数据,把100更改为99,而后删除缓存。服务B读取缓存,此时缓存为空,从数据库读取99。服务C更新数据,把99更改为98,而后删除缓存。服务B赋值缓存为99。此时,数据库为98,然而缓存为99,数据不统一。 故障如下图所示: 服务A更新数据,把100更改为99。服务A删除缓存失败。服务B读取缓存,为100。此时缓存数据和数据库数据不统一 先缓存并发如下图所示: 服务A删除缓存。服务B读取缓存。服务B读取不到缓存,就读取数据库,此时为100。服务A更新数据库。此时缓存数据和数据库数据不统一 故障如下图所示: 服务A更新缓存。服务A更新数据库失败。服务B读取缓存。服务B读取数据库。因为数据库未做更改,所以缓存数据和数据库数据统一。 解决方案业务任何脱离业务的设计都是耍流氓。如果业务能够承受这种不统一,那就采纳Cache Aside Pattern。如果业务上不承受,那能够让强一致性需要的业务间接读数据库,然而这个性能就会很差,所以咱们有以下的串行计划。 串行在java中,多线程会有数据安全问题,咱们能够用synchronized和cas来解决,次要的思路就是把并行改串行。思路一:通过音讯队列把所有的申请压入队列,因为申请的key太多,能够依照hash取模的形式,把key扩散到无限的队列中。比方有3个队列,hash(key)=0,存入第一个队列。存入的是读、读、写、读、读、写,那执行的时候,跟存入的程序是一样的,因为对同一个key的操作是串行的,所以保障了的数据的一致性。思路二:通过分布式锁在下面的计划中,如果队列太多,则不好治理,如果队列太少,则那么多的key在排队影响了性能,所以咱们能够采纳分布式锁来做。此时的办法相似于synchronized和cas,只有获取到了锁,才能够操作,这样也能够保证数据的一致性。当然不论采纳哪种形式,数据的一致性和性能的关系是正比的。数据的一致性要求高,性能就会降落;数据的一致性要求不高,性能就会回升。

November 9, 2020 · 1 min · jiezi

关于缓存:缓存穿透

缓存穿透就是申请了大量本来就不存在的数据,比方申请A数据,此时缓存没有数据,则从数据库查问,然而数据库也没有值,所以返回空的时候,缓存仍然没有数据。这类的申请一大,数据库要始终解决这些数据,很容易导致解体。以下办法也实用于缓存个体生效的缓存雪崩。 保留空值如果数据库没有数据,则在redis中也赋值相应的key(比方A)为空。这样每次下次再发送A过去,间接从redis中获取,就不必再查数据库了。流程如下:毛病:1、如果A在以后没有数据,过几秒有数据,所以上述办法中还要加一个过期工夫。然而这样数据的一致性也很难保障,比方在过期工夫内,A有了数据,然而redis里还是空值。2、如果申请的数据是随机的,那缓存的数据A被命中的概率也是很低的,这种状况下,还是会到数据库,而且节约了大量内存空间。 互斥锁保留空值的另外一个毛病就是,比方三个申请同时拜访A时,此时缓存是没有数据的,则他们会一起申请数据库,针对这个状况,咱们就能够应用互斥锁来做了,也就是用redis的setnx办法,流程是这样的:获取锁和设置生效工夫两个对redis操作的步骤不是原子性的,也就是说,如果setnx胜利了,expire不肯定胜利,所以能够用lua来做。不过新版本能够将这两个操作以原子性的模式操作。这个办法同样也没方法解决随机的数据的。 布隆过滤器布隆过滤器(Bloom Filter)是1970年由布隆提出的。它实际上是一个很长的二进制向量和一系列随机映射函数。布隆过滤器能够用于检索一个元素是否在一个汇合中。它的长处是空间效率和查问工夫都比个别的算法要好的多,毛病是有肯定的误识别率和删除艰难。误判率和数组的长度无关,数组长度越长,误判率越低,然而所须要的内存越高。比方咱们定义一个8个bit的布隆过滤器:hash(A)=1后存入hash(B)=3后存入hash(C)=3后存入,此时还是3,则3地位的值还是1。这个就是很难删除的起因,因为删除3的地位,会连带着B、C都影响。如果hash(D)也等于3,此时隆过滤器会感觉他存在的,这个就是误判率。联合缓存应用的时候,流程是这样的:在4中,只管有误判的key,然而概率曾经很小了,对数据库不会有太大的影响。另外一个毛病就是咱们要晓得哪些key要放入布隆过滤器。 异步构建缓存这种办法,在缓存不存在的时候,并没有间接读取数据库,而是放入队列里,让队列去更新缓存。当队列解决完后,前面的申请就有值了。毛病就是数据不够实时。流程如下:

November 5, 2020 · 1 min · jiezi

关于缓存:缓存雪崩

引入缓存的时候,咱们失常是这样做的,先判断缓存是否有数据,如果有数据,从缓存返回数据,如果没有数据,则从数据库查问。流程如下:通过缓存,咱们的零碎能够反对大量的并发,然而如果产生了一下事件,则会发送缓存雪崩:1、同一时间,大量的缓存生效工夫到期。2、缓存不可用。3、热点问题。此时缓存是没有数据或者不可用,则大量的申请间接到数据库,数据库撑不住这么大的并发,间接解体。只管始终重启数据库,还是撑不住要解体。针对1的问题,咱们能够对key设置一个随机值的过期工夫,扩散他们的过期工夫。针对2的问题,咱们次要是要保障缓存的可用性,比方redis的主从,redis的哨兵,redis的集群。同时,还要保障redis的长久化,这样重启后可能疾速复原缓存里的内容。如果没有做长久化,那启动reids的时候,大量的申请是没有缓存间接申请数据库,一样会让数据库解体。针对热点问题,即使redis做了分片,然而热点的key还是只能达到指定的redis服务器,此时redis服务器如果撑不住了,就会让申请拜访数据库,导致数据库解体。解决方案如下:先查本地缓存,再查redis,最初查数据库。此时数据的一致性没方法做保障的,比方redis和本地缓存的不统一。本地缓存的过期工夫要小于redis的过期工夫,这样尽量放大不统一的工夫。流程如下:本地缓存是存在于利用中的,利用是能够扩容的,而单点的redis是没法比扩容的,所以把压力分担到利用中,来解决热点问题

November 5, 2020 · 1 min · jiezi

关于缓存:搞定秒杀只需要这几步

灵魂拷问秒杀这种大并发的写场景,间接分库分表开干?应答秒杀流动的流量顶峰很难吗?不要拿淘宝级别的秒杀忽悠我秒杀流动特点我敢说但凡做过电商的同学,都会遇到经营开展的秒杀,限时购等“高并发”的流动。市面上也有不少针对秒杀的解决方案,什么分库分表,缓存,音讯队列呀,凡是能想到的技术“靓点”都根本会写上一段。我感觉应答秒杀这样的带有流量峰值的业务,还是要仔细分析业务的个性,以及依据本人零碎的业务量来确定须要采纳哪些技术“靓点”,如果:一个日活10万的零碎,采纳了分库分表,缓存,音讯队列,限流,降级等等技术手段,尽管性能上达到了预期,然而其实资源上可能会有些节约,技术上兴许只须要一个限流伎俩就足够了。说这些不是想表白什么,我只是想说,那些上来就分库分表等“大手笔”的“优化”伎俩肯定要依据理论业务去考查是否须要施行。 言归正传,秒杀这种业务场景其实特点很显著: 带有短期流量峰值个性,即:短时间内会有大量的申请涌入申请的数据带有热点性,即:大量的申请同一数据申请的胜利有效率低,即:大量的申请中可能只有大量申请会胜利解决业务申请的流量峰值产生在下单之前,即:付款阶段很少存在流量峰值动态资源动态资源是指商品的图片,视频,音频,html页面等简直不会变动的资源,这些资源的解决形式和缓存相似,尽量放在离用户最近的中央,比方:浏览器的本地缓存,当缓存过期的时候,优先举荐从CDN中获取,CDN是应答动态资源拜访顶峰的最简略粗犷,也是最无效的解决方案,如果没有CDN怎么办?那起码要把申请这些动态资源的服务器和后盾业务服务器物理上拆散,防止因为动态资源而影响失常的业务。比方:很早之前,我就喜爱每个我的项目独自一个寄存图片,css,js的网站,这个网站的劣势是无状态,能够做到傻瓜式横向扩大。 至于动态资源的缓存更新,我想你能够百度一下会有很多答案。 业务退让如果负责秒杀流动的产品经理是一个优良的产品经理的话,就不会设计出:用户点击秒杀马上给予是否下单胜利,这样的零碎。相熟分布式的同学必定会想到,想保障这样的数据一致性,在可用性上必然会有所就义。尤其是秒杀这样的业务,我感觉可用性要比一致性优先级要高,所以简直所有的秒杀零碎都会采纳BASE实践来设计零碎,一致性上采纳最终一致性。在用户看来,点击秒杀按钮之后会弹出一个期待的提醒,在技术上咱们称之为:异步解决。异步解决对于用户最显著的感知就是不会马上失去后果,而是要期待一段时间。其实这样的设计也是在技术和业务之间的一个衡量,算是业务作出的退让。 至于秒杀之前须要输出验证码或者某些题的答案等伎俩,其实也能够算是业务上作出的一些退让。为什么说是退让呢?对于用户来说,最现实的秒杀场景是:一点秒杀按钮,马上给予后果,然而技术上难度太大了,所以嘛,相互让一步,大家都好过,对不对? 技术第一招:限流对于秒杀呈现的流量峰值,限流是最间接的削峰伎俩,被限度的申请能够间接返回,客户端提醒申请中提醒。可想而知,当10000/S的申请量被削成100/S的量,预计零碎略微优化一下就能抗住,至于限流的策略依据业务会有很多不同的形式,比方: 针对同一个用户的申请次数限流,例如:每个用户每10秒只容许申请一次针对同一个IP的申请次数限流,例如:每个IP每10秒只容许申请一次至于限流的算法,之前写过一篇文章来介绍,而且性能还不错哦 高并发优雅的做限流 第二招:音讯队列说到音讯队列,每个程序员都不生疏,它相当于一个疾速的数据容器,能够作为一个缓冲层来应答流量顶峰。如果从它的应用场景上来看,它能够算是低速设施和高速设施之间的均衡者,应用音讯队列来进行削峰是一个很显著的异步流程。 利用到秒杀的场景下,大量的申请会先进入音讯队列,它不仅削平了流量的峰值,而且把秒杀下单的这个流程异步化,只有把申请都暂存入队列,生产端缓缓生产即可,然而这里要留神,如果生产的速度远远慢于音讯的投递速度,可能会影响整个零碎性能。 除了削峰之外,我始终认为音讯队列的最大作用是零碎解耦,它把下单和领取解耦,下单和领取业务能够随着本身零碎的承载量来独自扩容。 第三招:缓存为什么要退出缓存这个选项呢?别忘了,除了大量的用户下单这个写操作之外,还有更大量的用户申请下单后果这个读操作。当用户点击秒杀按钮之后,零碎会弹出期待的提示框,很多零碎是不停的去轮训用户的下单后果,我之前也写过缓存的文章,已经提到过缓存最大的作用是提供读操作的疾速响应。整个秒杀零碎能够这样做: 用户点击下单按钮,申请通过限流组件,如果胜利,则进入下单环节(这里能够进入音讯队列,异步下单)服务端无论是采纳redis缓存,还是其余缓存组件,寄存着下单胜利的用户信息(也能够包含订单信息)客户端采纳轮训的形式去查问缓存,如果查问到信息阐明下单胜利,进入领取环节,未查问到则阐明下单还未胜利服务端下单胜利,往缓存中写入数据,当用户下次再次查问的时候会提醒下单胜利。尽管过程很简略,然而其实整个过程中有很多细节须要留神,比方:缓存的过期工夫怎么设置?是否引入下单中的状态?怎么保障缓存数据和数据库数据的一致性? 谈了千百遍的缓存数据的一致性问题 除了以上的信息数据缓存,商品的信息数据也能够放在缓存中,因为读的申请量比拟大,能够思考采纳缓存正本的形式来进步整体的吞吐量。 写在最初其实很多零碎利用上音讯队列+限流之后,针对秒杀业务曾经足够了,其余的分库分表等计划能够依据本人的业务量来确定。每个零碎在满足功能性的需要下,也在满足非功能性需要的前提下越简略越好,不是每个零碎都须要淘宝的架构。 更多精彩文章 分布式大并发系列架构设计系列趣学算法和数据结构系列设计模式系列

November 3, 2020 · 1 min · jiezi

关于缓存:缓存架构不够好系统容易瘫痪

灵魂拷问缓存能大幅度提高零碎性能,也能大幅度提高零碎瘫痪几率怎么样避免缓存零碎被穿透?缓存的雪崩是不是能够完全避免?前几篇文章咱们介绍了缓存的劣势以及数据一致性的问题,在一个面临高并发零碎中,缓存简直成了每个架构师应答高流量的首冲解决方案,然而,一个好的缓存零碎,除了和数据库一致性问题之外,还存在着其余问题,给整体的零碎设计引入了额定的复杂性。而这些复杂性问题的解决方案也间接了影响零碎的稳定性,最常见的比方缓存的命中率问题,在一个高并发零碎中,外围性能的缓存命中率个别要放弃在90%以上甚至更高,如果低于这个命中率,整个零碎可能就面临着随时被峰值流量击垮的可能,这个时候咱们就须要优化缓存的应用形式了。 据说你还不会缓存? 谈了千百遍的缓存数据的一致性问题 如果依照传统的缓存和DB的流程,一个申请到来的时候,首先会查问缓存中是否存在,如果缓存中不存在则去查问对应的数据库。如果零碎每秒的申请量为10000,而缓存的命中率为60%,则每秒穿透到数据库的申请数为4000,对于关系型数据库mysql来说,每秒4000的申请量对于分了一主三从的Mysql数据库架构来说也曾经足够大了,再加上主从的同步提早等诸多因素,这个时候你的mysql曾经行走在down机边缘了。 缓存的最终目标,是在保障申请低提早的状况下,尽最大努力提高零碎的吞吐量那缓存零碎可能会影响零碎解体的起因有那些呢? 缓存穿透缓存穿透是指:当一个申请到来的时候,在缓存中没有查找到对应的数据(缓存未命中),业务零碎不得不从数据库(这里其实能够抽象的成为后端系统)中加载数据 产生缓存穿透的起因依据场景分为两种: 申请的数据在缓存和数据中都不存在当数据在缓存和数据库都不存在的时候,如果依照个别的缓存设计,每次申请都会到数据库查问一次,而后返回不存在,这种场景下,缓存零碎简直没有起任何作用。在失常的业务零碎中,产生这种状况的概率比拟小,就算偶然产生,也不会对数据库造成基本上的压力。 最可怕的是呈现一些异常情况,比方零碎中有死循环的查问或者被黑客攻击的时候,尤其是后者,他会成心伪造大量的申请来读取不存在的数据而造成数据库的down机,最典型的场景为:如果零碎的用户id是间断递增的int型,黑客很容易伪造用户id来模仿大量的申请。 申请的数据在缓存中不存在,在数据库中存在这种场景个别属于业务的失常需要,因为缓存零碎的容量个别是有限度的,比方咱们最罕用的Redis做为缓存,就受到服务器内存大小的限度,所以所有的业务数据不可能都放入缓存零碎中,依据互联网数据的二八规定,咱们能够优先把拜访最频繁的热点数据放入缓存零碎,这样就能利用缓存的劣势来抗住次要的流量起源,而残余的非热点数据,就算是有穿透数据库的可能性,也不会对数据库造成致命压力。 换句话说,每个零碎产生缓存穿透是不可避免的,而咱们须要做的是尽量避免大量的申请产生穿透,那怎么解决缓存穿透问题呢?解决缓存的穿透问题实质上是要解决怎么样拦挡申请的问题,个别状况下会有以下几种计划: 回写空值当申请的数据在数据库中不存在的时候,缓存零碎能够把对应的key写入一个空值,这样当下次同样的申请就不会间接穿透数据库,而间接返回缓存中的空值了。这种计划是最简略粗犷的,然而要留神几点: 当有大量的空值被写入缓存零碎中,同样会占用内存,不过实践上不会太多,齐全取决于key的数量。而且依据缓存淘汰策略,可能会淘汰失常的数据缓存项空值的过期工夫应该短一些,比方失常的数据缓存过期工夫可能为2小时,能够思考空值的过期工夫为10分钟,这样做一是为了尽快开释服务器的内存空间,二是如果业务产生相应的实在数据,能够让缓存的空值疾速生效,尽快做到缓存和数据库统一。//获取用户信息 public static UserInfo GetUserInfo(int userId) { //从缓存读取用户信息 var userInfo = GetUserInfoFromCache(userId); if (userInfo == null) { //回写空值到缓存,并设置缓存过期工夫为10分钟 CacheSystem.Set(userId, null,10); } return userInfo; }布隆过滤器布隆过滤器:将所有可能存在的数据哈希到一个足够大的 bitmap 中,一个肯定不存在的数据会被这个bitmap拦挡掉,从而防止了对底层存储系统的查问压力布隆过滤器有几个很大的劣势 占用内存十分小对于判断一个数据不存在百分百正确具体能够参见之前的文章或者百度脑补一下布隆过滤器: 优雅疾速的统计千万级别uv 因为布隆过滤器基于hash算法,所以在工夫复杂度上是O(1),在应答高并发的场景下十分适合,不过应用布隆过滤器要求零碎在产生数据的时候须要在布隆过滤器同时也写入数据,而且布隆过滤器也不反对删除数据,因为多个数据可能会重用同一个地位。 缓存雪崩缓存雪崩是指缓存中数据大批量同时过期,造成查询数据库数据量微小,引起数据库压力过大导致系统解体。与缓存穿透景象不同,缓存穿透是指缓存中不存在数据而造成会对数据库造成大量查问,而缓存雪崩是因为缓存中存在数据,然而同时大量过期造成。然而实质上是一样的,都是对数据库造成了大量的申请。 无论是穿透还是雪崩都面临着同样的数据会有多个线程同时申请,同时查询数据库,同时回写缓存的一致性问题。举例来说,当多个线程同时申请用户id为1的用户,这个时候缓存正好生效,那这多个线程同时会查询数据库,而后同时会回写缓存,最可怕的是,这个回写的过程中,另外一个线程更新了数据库,就造成了数据不统一,这个问题在之前的文章中着重讲过,大家肯定要留神。 同样的数据会被多个线程产生多个申请是产生雪崩的一个起因,针对这种状况的解决方案是把多个线程的申请程序化,使其只有一个线程会产生对数据库的查问操作,比方最常见的锁机制(分布式锁机制),当初最常见的分布式锁是用redis来实现,然而redis实现分布式锁也有肯定的坑,能够参见之前的文章(如果应用的是Actor模型的话会在无锁的模式下更优雅的实现申请程序化) redis做分布式锁可能不那么简略 多个缓存key同时生效的场景是产生雪崩的次要起因,针对这样的场景个别能够利用以下几种计划来解决 设置不同过期工夫给缓存的每个key设置不同的过期工夫是最简略的避免缓存雪崩的伎俩,整体思路是给每个缓存的key在零碎设置的过期工夫之上加一个随机值,或者罗唆是间接随机一个值,无效的均衡key批量过期时间段,消掉单位之间内过期key数量的峰值。 public static int SetUserInfo(int userId) { //读取用户信息 var userInfo = GetUserInfoFromDB(userId); if (userInfo != null) { //回写到缓存,并设置缓存过期工夫为随机工夫 var cacheExpire = new Random().Next(1, 100); CacheSystem.Set(userId, userInfo, cacheExpire); return cacheExpire; } return 0; }后盾独自线程更新这种场景下,能够把缓存设置为永不过期,缓存的更新不是由业务线程来更新,而是由专门的线程去负责。当缓存的key有更新时候,业务方向mq发送一个音讯,更新缓存的线程会监听这个mq来实时响应以便更新缓存中对应的数据。不过这种形式要思考到缓存淘汰的场景,当一个缓存的key被淘汰之后,其实也能够向mq发送一个音讯,以达到更新线程从新回写key的操作。 ...

October 26, 2020 · 1 min · jiezi

关于缓存:缓存穿透缓存雪崩缓存击穿的区别以及解决方法

缓存穿透缓存和数据库均不存在(申请打到缓存,未查问到,接着查询数据库,也没有查到)时,大量并发会对数据库造成极大压力。 解决方案设置一个key-null的缓存,并将生效工夫能够设置短一点(比方30s), 这样雷同申请就不会间接打到数据库。应用BloomFilter,相当于在查问缓存之前先在汇合中查问key是否存在,如果不存在就间接返回*缓存雪崩同一时刻大量缓存生效,导致申请全部打到数据库。 解决方案缓存数据的过期工夫设置随机,避免同一时间大量数据过期景象产生如果缓存数据库是分布式部署,将热点数据均匀分布在不同搞得缓存数据库中设置热点数据永不过期*缓存击穿缓存雪崩的一种,雪崩是多个key生效,击穿是指某个key生效,同一时刻,大量的雷同申请会间接打到数据库。 解决方案设置热点数据永不过期。采纳互斥锁static Lock reenLock = new ReentrantLock();public List<String> getData() throws InterruptedException { List<String> result = new ArrayList<String>(); // 从缓存读取数据 result = getDataFromCache(); if (result.isEmpty()) { if (reenLock.tryLock()) { try { System.out.println("我拿到锁了,从DB获取数据库后写入缓存"); // 从数据库查问数据 result = getDataFromDB(); // 将查问到的数据写入缓存 setDataToCache(result); } finally { reenLock.unlock();// 开释锁 } } else { result = getDataFromCache();// 先查一下缓存 if (result.isEmpty()) { System.out.println("我没拿到锁,缓存也没数据,先小憩一下"); Thread.sleep(100);// 小憩一会儿 return getData();// 重试 } } } return result;}

October 10, 2020 · 1 min · jiezi

关于缓存:前端面试每日-31-第536天

明天的知识点 (2020.10.03) —— 第536天 (我也要出题)[html] 制作一个页面时,须要兼容PC端和手机端,你是要别离做两个页面还是只做一个页面自适应?为什么?说说你的理由[css] 解释下1px、1rem、1em、1vh代表的含意别离是什么?[js] js如何实现函数缓存?函数缓存有什么使用场景?[软技能] 说说你对serverless的了解,它对前端有什么影响?《论语》,曾子曰:“吾日三省吾身”(我每天屡次检查本人)。前端面试每日3+1题,以面试题来驱动学习,每天提高一点!让致力成为一种习惯,让奋斗成为一种享受!置信 保持 的力量!!!欢送在 Issues 和敌人们一起探讨学习! 我的项目地址:前端面试每日3+1【举荐】欢送跟 jsliang 一起折腾前端,零碎整顿前端常识,目前正在折腾 LeetCode,打算买通算法与数据结构的任督二脉。GitHub 地址 微信公众号欢送大家前来探讨,如果感觉对你的学习有肯定的帮忙,欢送点个Star, 同时欢送微信扫码关注 前端剑解 公众号,并退出 “前端学习每日3+1” 微信群互相交换(点击公众号的菜单:交换)。 学习不打烊,充电加油只为遇到更好的本人,365天无节假日,每天早上5点纯手工公布面试题(死磕本人,愉悦大家)。心愿大家在这虚夸的前端圈里,放弃沉着,保持每天花20分钟来学习与思考。在这变幻无穷,类库层出不穷的前端,倡议大家不要等到找工作时,才狂刷题,提倡每日学习!(不忘初心,html、css、javascript才是基石!)欢送大家到Issues交换,激励PR,感激Star,大家有啥好的倡议能够加我微信一起交换探讨!心愿大家每日去学习与思考,这才达到来这里的目标!!!(不要为了谁而来,要为本人而来!)交换探讨欢送大家前来探讨,如果感觉对你的学习有肯定的帮忙,欢送点个[Star]

October 3, 2020 · 1 min · jiezi

关于缓存:从零开始手写-redis四监听器的实现

前言java从零手写实现redis(一)如何实现固定大小的缓存? java从零手写实现redis(三)redis expire 过期原理 java从零手写实现redis(三)内存数据如何重启不失落? 本节,让咱们来一起学习一下如何实现相似 guava-cache 中的 removeListener 删除监听器,和相似 redis 中的慢日志监控的 slowListener。 删除监听器阐明咱们在两种场景下删除数据是对用户通明的: (1)size 满了之后,进行数据淘汰。 (2)expire 过期时,革除数据。 这两个个性对用户原本应该是无感的,不过用户如果关怀的话,也能够通过增加删除监听器来获取到相干的变更信息。 实现思路为了实现删除的监听,咱们须要找到删除的地位,而后调用监听器即可。 evict 驱除的场景每次 put 数据时,都会校验 size 是否达到最大的限度,如果达到,则进行 evict 淘汰。 expire 过期的场景用户指定 expire 工夫之后,回后盾异步执行刷新。 也存在惰性删除的场景。 接口定义为了对立,咱们将所有的删除都定义对立的接口: /** * 删除监听器接口 * * @author binbin.hou * @since 0.0.6 * @param <K> key * @param <V> value */public interface ICacheRemoveListener<K,V> { /** * 监听 * @param context 上下文 * @since 0.0.6 */ void listen(final ICacheRemoveListenerContext<K,V> context);}内置实现零碎内置的实现如下: ...

September 30, 2020 · 2 min · jiezi

关于缓存:从零开始手写缓存框架二redis-expire-过期原理及实现

前言咱们在 从零手写 cache 框架(一)实现固定大小的缓存 中曾经初步实现了咱们的 cache。 本节,让咱们来一起学习一下如何实现相似 redis 中的 expire 过期性能。 过期是一个十分有用的个性,比方我心愿登录信息放到 redis 中,30min 之后生效;或者单日的累计信息放在 redis 中,在每天的凌晨主动清空。 代码实现接口咱们首先来定义一下接口。 次要有两个:一个是多久之后过期,一个是在什么时候过期。 public interface ICache<K, V> extends Map<K, V> { /** * 设置过期工夫 * (1)如果 key 不存在,则什么都不做。 * (2)临时不提供新建 key 指定过期工夫的形式,会毁坏原来的办法。 * * 会做什么: * 相似于 redis * (1)惰性删除。 * 在执行上面的办法时,如果过期则进行删除。 * {@link ICache#get(Object)} 获取 * {@link ICache#values()} 获取所有值 * {@link ICache#entrySet()} 获取所有明细 * * 【数据的不一致性】 * 调用其余办法,可能失去的不是使用者的预期后果,因为此时的 expire 信息可能没有被及时更新。 * 比方 * {@link ICache#isEmpty()} 是否为空 * {@link ICache#size()} 以后大小 * 同时会导致以 size() 作为过期条件的问题。 * * 解决方案:思考增加 refresh 等办法,临时不做一致性的思考。 * 对于理论的应用,咱们更关怀 K/V 的信息。 * * (2)定时删除 * 启动一个定时工作。每次随机抉择指定大小的 key 进行是否过期判断。 * 相似于 redis,为了简化,能够思考设定超时工夫,频率与超时工夫成反比。 * * 其余拓展性思考: * 前期思考提供原子性操作,保障事务性。临时不做思考。 * 此处默认应用 TTL 作为比拟的基准,临时不想反对 LastAccessTime 的淘汰策略。会减少复杂度。 * 如果减少 lastAccessTime 过期,本办法能够不做批改。 * * @param key key * @param timeInMills 毫秒工夫之后过期 * @return this * @since 0.0.3 */ ICache<K, V> expire(final K key, final long timeInMills); /** * 在指定的工夫过期 * @param key key * @param timeInMills 工夫戳 * @return this * @since 0.0.3 */ ICache<K, V> expireAt(final K key, final long timeInMills);}代码实现为了便于解决,咱们将多久之后过期,进行计算。将两个问题变成同一个问题,在什么时候过期的问题。 ...

September 28, 2020 · 4 min · jiezi

关于缓存:前端面试每日-31-第523天

明天的知识点 (2020.09.20) —— 第523天 (我也要出题)[html] 微信H5页面如何更新缓存?[css] 应用了float的标签,如何防止左侧贴边重叠?[js] 把对象转换到字符串类型是如何转换的?[软技能] 说说你理解的前端代码评审Checklist有哪些项?《论语》,曾子曰:“吾日三省吾身”(我每天屡次检查本人)。前端面试每日3+1题,以面试题来驱动学习,每天提高一点!让致力成为一种习惯,让奋斗成为一种享受!置信 保持 的力量!!!欢送在 Issues 和敌人们一起探讨学习! 我的项目地址:前端面试每日3+1【举荐】欢送跟 jsliang 一起折腾前端,零碎整顿前端常识,目前正在折腾 LeetCode,打算买通算法与数据结构的任督二脉。GitHub 地址 微信公众号欢送大家前来探讨,如果感觉对你的学习有肯定的帮忙,欢送点个Star, 同时欢送微信扫码关注 前端剑解 公众号,并退出 “前端学习每日3+1” 微信群互相交换(点击公众号的菜单:交换)。 学习不打烊,充电加油只为遇到更好的本人,365天无节假日,每天早上5点纯手工公布面试题(死磕本人,愉悦大家)。心愿大家在这虚夸的前端圈里,放弃沉着,保持每天花20分钟来学习与思考。在这变幻无穷,类库层出不穷的前端,倡议大家不要等到找工作时,才狂刷题,提倡每日学习!(不忘初心,html、css、javascript才是基石!)欢送大家到Issues交换,激励PR,感激Star,大家有啥好的倡议能够加我微信一起交换探讨!心愿大家每日去学习与思考,这才达到来这里的目标!!!(不要为了谁而来,要为本人而来!)交换探讨欢送大家前来探讨,如果感觉对你的学习有肯定的帮忙,欢送点个[Star]

September 20, 2020 · 1 min · jiezi

关于缓存:前端面试每日-31-第515天

明天的知识点 (2020.09.12) —— 第515天 (我也要出题)[html] [const nums1 = [1, 2, 2, 1], nums2 = [2] 交加是什么?](https://github.com/haizlin/fe...[css] Fixed定位如果脱离Viewport会产生什么样的bug?如何解决?[js] js的申请个别状况下在哪些地方会有缓存的解决?[软技能] 作为管理者,你是如何解决组织外部的矛盾?《论语》,曾子曰:“吾日三省吾身”(我每天屡次检查本人)。前端面试每日3+1题,以面试题来驱动学习,每天提高一点!让致力成为一种习惯,让奋斗成为一种享受!置信 保持 的力量!!!欢送在 Issues 和敌人们一起探讨学习! 我的项目地址:前端面试每日3+1【举荐】欢送跟 jsliang 一起折腾前端,零碎整顿前端常识,目前正在折腾 LeetCode,打算买通算法与数据结构的任督二脉。GitHub 地址 微信公众号欢送大家前来探讨,如果感觉对你的学习有肯定的帮忙,欢送点个Star, 同时欢送微信扫码关注 前端剑解 公众号,并退出 “前端学习每日3+1” 微信群互相交换(点击公众号的菜单:交换)。 学习不打烊,充电加油只为遇到更好的本人,365天无节假日,每天早上5点纯手工公布面试题(死磕本人,愉悦大家)。心愿大家在这虚夸的前端圈里,放弃沉着,保持每天花20分钟来学习与思考。在这变幻无穷,类库层出不穷的前端,倡议大家不要等到找工作时,才狂刷题,提倡每日学习!(不忘初心,html、css、javascript才是基石!)欢送大家到Issues交换,激励PR,感激Star,大家有啥好的倡议能够加我微信一起交换探讨!心愿大家每日去学习与思考,这才达到来这里的目标!!!(不要为了谁而来,要为本人而来!)交换探讨欢送大家前来探讨,如果感觉对你的学习有肯定的帮忙,欢送点个[Star]

September 12, 2020 · 1 min · jiezi

关于缓存:如何保证缓存与数据库的双写一致性

作者:你是我的海啸起源:https://blog.csdn.net/chang38...分布式缓存是当初很多分布式应用中必不可少的组件,然而用到了分布式缓存,就可能会波及到缓存与数据库双存储双写,你只有是双写,就肯定会有数据一致性的问题,那么你如何解决一致性问题? Cache Aside Pattern最经典的缓存+数据库读写的模式,就是 Cache Aside Pattern。读的时候,先读缓存,缓存没有的话,就读数据库,而后取出数据后放入缓存,同时返回响应。 更新的时候,先更新数据库,而后再删除缓存。 为什么是删除缓存,而不是更新缓存?起因很简略,很多时候,在简单点的缓存场景,缓存不单单是数据库中间接取出来的值。 比方可能更新了某个表的一个字段,而后其对应的缓存,是须要查问另外两个表的数据并进行运算,能力计算出缓存最新的值的。 另外更新缓存的代价有时候是很高的。是不是说,每次批改数据库的时候,都肯定要将其对应的缓存更新一份?兴许有的场景是这样,然而对于比较复杂的缓存数据计算的场景,就不是这样了。如果你频繁批改一个缓存波及的多个表,缓存也频繁更新。然而问题在于,这个缓存到底会不会被频繁拜访到? 举个栗子,一个缓存波及的表的字段,在 1 分钟内就批改了 20 次,或者是 100 次,那么缓存更新 20 次、100 次;然而这个缓存在 1 分钟内只被读取了 1 次,有大量的冷数据。实际上,如果你只是删除缓存的话,那么在 1 分钟内,这个缓存不过就从新计算一次而已,开销大幅度降低,用到缓存才去算缓存。 其实删除缓存,而不是更新缓存,就是一个 lazy 计算的思维,不要每次都从新做简单的计算,不论它会不会用到,而是让它到须要被应用的时候再从新计算。像 mybatis,hibernate,都有懒加载思维。查问一个部门,部门带了一个员工的 list,没有必要说每次查问部门,都外面的 1000 个员工的数据也同时查出来啊。80% 的状况,查这个部门,就只是要拜访这个部门的信息就能够了。先查部门,同时要拜访外面的员工,那么这个时候只有在你要拜访外面的员工的时候,才会去数据库外面查问 1000 个员工。 最高级的缓存不统一问题及解决方案问题:先批改数据库,再删除缓存。如果删除缓存失败了,那么会导致数据库中是新数据,缓存中是旧数据,数据就呈现了不统一。 解决思路:先删除缓存,再批改数据库。如果数据库批改失败了,那么数据库中是旧数据,缓存中是空的,那么数据不会不统一。因为读的时候缓存没有,则读数据库中旧数据,而后更新到缓存中。 比较复杂的数据不统一问题剖析数据产生了变更,先删除了缓存,而后要去批改数据库,此时还没批改。一个申请过去,去读缓存,发现缓存空了,去查询数据库,查到了批改前的旧数据,放到了缓存中。随后数据变更的程序实现了数据库的批改。 完了,数据库和缓存中的数据不一样了。。。 为什么上亿流量高并发场景下,缓存会呈现这个问题? 只有在对一个数据在并发的进行读写的时候,才可能会呈现这种问题。其实如果说你的并发量很低的话,特地是读并发很低,每天访问量就 1 万次,那么很少的状况下,会呈现方才形容的那种不统一的场景。然而问题是,如果每天的是上亿的流量,每秒并发读是几万,每秒只有有数据更新的申请,就可能会呈现上述的数据库+缓存不统一的状况。 解决方案如下:更新数据的时候,依据数据的惟一标识,将操作路由之后,发送到一个 jvm 外部队列中。读取数据的时候,如果发现数据不在缓存中,那么将从新读取数据+更新缓存的操作,依据惟一标识路由之后,也发送同一个 jvm 外部队列中。 一个队列对应一个工作线程,每个工作线程串行拿到对应的操作,而后一条一条的执行。这样的话,一个数据变更的操作,先删除缓存,而后再去更新数据库,然而还没实现更新。此时如果一个读申请过去,读到了空的缓存,那么能够先将缓存更新的申请发送到队列中,此时会在队列中积压,而后同步期待缓存更新实现。 这里有一个优化点,一个队列中,其实多个更新缓存申请串在一起是没意义的,因而能够做过滤,如果发现队列中曾经有一个更新缓存的申请了,那么就不必再放个更新申请操作进去了,间接期待后面的更新操作申请实现即可。 待那个队列对应的工作线程实现了上一个操作的数据库的批改之后,才会去执行下一个操作,也就是缓存更新的操作,此时会从数据库中读取最新的值,而后写入缓存中。 如果申请还在等待时间范畴内,一直轮询发现能够取到值了,那么就间接返回;如果申请期待的工夫超过肯定时长,那么这一次间接从数据库中读取以后的旧值。 高并发的场景下,该解决方案要留神的问题: 1、读申请长时阻塞因为读申请进行了十分轻度的异步化,所以肯定要留神读超时的问题,每个读申请必须在超时工夫范畴内返回。 该解决方案,最大的危险点在于说,可能数据更新很频繁,导致队列中积压了大量更新操作在外面,而后读申请会产生大量的超时,最初导致大量的申请间接走数据库。务必通过一些模仿实在的测试,看看更新数据的频率是怎么的。 另外一点,因为一个队列中,可能会积压针对多个数据项的更新操作,因而须要依据本人的业务状况进行测试,可能须要部署多个服务,每个服务摊派一些数据的更新操作。如果一个内存队列里竟然会挤压 100 个商品的库存批改操作,每隔库存批改操作要消耗 10ms 去实现,那么最初一个商品的读申请,可能期待 10 * 100 = 1000ms = 1s 后,能力失去数据,这个时候就导致读申请的长时阻塞。 ...

August 24, 2020 · 1 min · jiezi

关于缓存:前端面试每日-31-第496天

明天的知识点 (2020.08.24) —— 第496天 (我也要出题)[html] html的哪个标签能够预渲染?[css] 当你遗记某个css时,你是如何解决的?[js] 应用js如何创立一个private办法?[软技能] web缓存须要后盾或者运维怎么配合呢?《论语》,曾子曰:“吾日三省吾身”(我每天屡次检查本人)。前端面试每日3+1题,以面试题来驱动学习,每天提高一点!让致力成为一种习惯,让奋斗成为一种享受!置信 保持 的力量!!!欢送在 Issues 和敌人们一起探讨学习! 我的项目地址:前端面试每日3+1【举荐】欢送跟 jsliang 一起折腾前端,零碎整顿前端常识,目前正在折腾 LeetCode,打算买通算法与数据结构的任督二脉。GitHub 地址 微信公众号欢送大家前来探讨,如果感觉对你的学习有肯定的帮忙,欢送点个Star, 同时欢送微信扫码关注 前端剑解 公众号,并退出 “前端学习每日3+1” 微信群互相交换(点击公众号的菜单:交换)。 学习不打烊,充电加油只为遇到更好的本人,365天无节假日,每天早上5点纯手工公布面试题(死磕本人,愉悦大家)。心愿大家在这虚夸的前端圈里,放弃沉着,保持每天花20分钟来学习与思考。在这变幻无穷,类库层出不穷的前端,倡议大家不要等到找工作时,才狂刷题,提倡每日学习!(不忘初心,html、css、javascript才是基石!)欢送大家到Issues交换,激励PR,感激Star,大家有啥好的倡议能够加我微信一起交换探讨!心愿大家每日去学习与思考,这才达到来这里的目标!!!(不要为了谁而来,要为本人而来!)交换探讨欢送大家前来探讨,如果感觉对你的学习有肯定的帮忙,欢送点个[Star]

August 24, 2020 · 1 min · jiezi

关于缓存:浏览器缓存总结

前几天某人问我了个问题,说了个大略,回头我又查阅材料,理解网上大牛们的文章后进行一下小总结。 start常常拜访某网站页面,有的页面加载快,有的跟蜗牛一样慢,为什么同一个网站会有如此大的差异呢,咱们排除网络因素来剖析下,拜访页面无非就是申请服务器返回特定资源,如果本地有了资源,必定比拜访服务器的要快,本地的这个资源能够了解为:缓存。上图形象的展示了缓存拜访机制。关上控制台,实际操作一下,再看一下拜访的页面: 缓存是浏览器一个进步页面交互体验的重要工具之一,依据其存储地位不一样大略分为这么几种: Service Worker [https://serviceworke.rs/]Memory CacheDisk CachePush Cache这四种都是缓存策略,且是按程序拜访并执行,来具体看下细节。 一、Service Workerservice work是什么?它是一段运行在浏览器后盾过程里的脚本,独立于以后页面。service work有什么作用?1.网络代理,转发申请,伪造响应2.离线缓存3.音讯推送4.后盾消息传递如何查看service work?1.通过命令 chrome://serviceworker-internals 能够查看;2.通过devtools-Application查看。成果一样,界面不同,如下图:形式一: 形式二: Service Worker(仅简略说跟缓存相干)的应用是有限度的,必须运行在htts协定下,因为它波及到申请拦挡,所以通过https协定保障其安全性。Service Worker的缓存与浏览器内建的缓存策略不同,它能够让咱们自在管制缓存哪些文件、如何匹配缓存、如何读取缓存,并且缓存是持续性的。下图显示了可用的Service Worker事件的摘要 Service Worker实现缓存分为三个步骤: 1.首先注册 Service Workerif ('serviceWorker' in navigator) { navigator.serviceWorker.register('./sw-test/sw.js', {scope: './sw-test/'}) .then((reg) => { // registration worked console.log('Registration succeeded. Scope is ' + reg.scope); }).catch((error) => { // registration failed console.log('Registration failed with ' + error); });}2.注册后,减少工夫侦听self.addEventListener('install', (event) => { event.waitUntil( caches.open('v1').then((cache) => { return cache.addAll([ './sw-test/', './sw-test/index.html', './sw-test/style.css', './sw-test/app.js', './sw-test/image-list.js', './sw-test/star-wars-logo.jpg', './sw-test/gallery/', './sw-test/gallery/bountyHunters.jpg', './sw-test/gallery/myLittleVader.jpg', './sw-test/gallery/snowTroopers.jpg' ]); }) );});监听到 install 事件当前就能够缓存须要的文件,如上图的目录及动态资源。在下次用户拜访的时候就能够通过拦挡申请的形式查问是否存在缓存,存在缓存的话就能够间接读取缓存文件。 ...

August 4, 2020 · 2 min · jiezi

关于缓存:在了解Cache缓存原理之前你只是个普通的程序员

作者丨smcdef起源丨http://www.wowotech.net/memory_management/458.html 明天探索的主题是cache。咱们围绕几个问题开展。为什么须要cache?如何判断一个数据在cache中是否命中?cache的品种有哪些,区别是什么? 对于没有接触过底层技术的敌人来说,或者从未据说过cache。毕竟cache的存在对程序员来说是通明的。在接触cache之前,先为你筹备段code剖析。 int arr[10][128]; for (i = 0; i < 10; i++) for (j = 0; j < 128; j++); arr[i][j] = 1; 如果你已经学习过C/C++语言,这段code天然不会生疏。如此简略的将arr数组所有元素置1。你有没有想过这段code还有上面的一种写法。 int arr[10][128]; for (i = 0; i < 128; i++) for (j = 0; j < 10; j++); arr[j][i] = 1; 性能齐全一样,然而咱们始终在反复着第一种写法(或者很多的书中也是倡议这么编码),你是否想过这其中的原因?文章的配角是cache,所以你肯定猜到了答案。那么cache是如何影响这2段code的呢? 为什么须要cache memory 在思考cache是什么之前咱们首先先来思考第一个问题:咱们的程序是如何运行起来的? 咱们应该晓得程序是运行在 RAM之中,RAM 就是咱们常说的DDR(例如 DDR3、DDR4等)。咱们称之为main memory(主存)当咱们须要运行一个过程的时候,首先会从Flash设施(例如,eMMC、UFS等)中将可执行程序load到main memory中,而后开始执行。在CPU外部存在一堆的通用寄存器(register)。如果CPU须要将一个变量(假如地址是A)加1,个别分为以下3个步骤: CPU 从主存中读取地址A的数据到外部通用寄存器 x0(ARM64架构的通用寄存器之一)。通用寄存器 x0 加1。CPU 将通用寄存器 x0 的值写入主存。咱们将这个过程能够示意如下: 其实事实中,CPU通用寄存器的速度和主存之间存在着太大的差别。两者之间的速度大抵如下关系: ...

July 30, 2020 · 2 min · jiezi

关于缓存:在了解Cache缓存原理之前你只是个普通的程序员

作者丨smcdef起源丨http://www.wowotech.net/memory_management/458.html 明天探索的主题是cache。咱们围绕几个问题开展。为什么须要cache?如何判断一个数据在cache中是否命中?cache的品种有哪些,区别是什么? 对于没有接触过底层技术的敌人来说,或者从未据说过cache。毕竟cache的存在对程序员来说是通明的。在接触cache之前,先为你筹备段code剖析。 int arr[10][128]; for (i = 0; i < 10; i++) for (j = 0; j < 128; j++); arr[i][j] = 1; 如果你已经学习过C/C++语言,这段code天然不会生疏。如此简略的将arr数组所有元素置1。你有没有想过这段code还有上面的一种写法。 int arr[10][128]; for (i = 0; i < 128; i++) for (j = 0; j < 10; j++); arr[j][i] = 1; 性能齐全一样,然而咱们始终在反复着第一种写法(或者很多的书中也是倡议这么编码),你是否想过这其中的原因?文章的配角是cache,所以你肯定猜到了答案。那么cache是如何影响这2段code的呢? 为什么须要cache memory 在思考cache是什么之前咱们首先先来思考第一个问题:咱们的程序是如何运行起来的? 咱们应该晓得程序是运行在 RAM之中,RAM 就是咱们常说的DDR(例如 DDR3、DDR4等)。咱们称之为main memory(主存)当咱们须要运行一个过程的时候,首先会从Flash设施(例如,eMMC、UFS等)中将可执行程序load到main memory中,而后开始执行。在CPU外部存在一堆的通用寄存器(register)。如果CPU须要将一个变量(假如地址是A)加1,个别分为以下3个步骤: CPU 从主存中读取地址A的数据到外部通用寄存器 x0(ARM64架构的通用寄存器之一)。通用寄存器 x0 加1。CPU 将通用寄存器 x0 的值写入主存。咱们将这个过程能够示意如下: 其实事实中,CPU通用寄存器的速度和主存之间存在着太大的差别。两者之间的速度大抵如下关系: ...

July 30, 2020 · 2 min · jiezi

关于缓存:案例解读深入理解浏览器的缓存机制

摘要:缓存能够缩小网络 IO 耗费,进步访问速度。浏览器缓存是一种操作简略、效果显著的前端性能优化伎俩。前言浏览器缓存是前端性能优化的重要一环,对于前端效率晋升的重要性,显而易见。 之前对于浏览器缓存也是只知其一;不知其二,这次借着H5页面缓存优化的东风整顿了一下本地浏览器端的缓存机制,如强制缓存、协商缓存等,并且而后联合门户域各部件(官网、云社区、云市场、集体核心、APP)以后的缓存机制进一步合成,旨在出现下以后华为云官网的缓存策略,供大家参考。 1 浏览器缓存1.1 浏览器缓存缓存是一种本地保留远端资源的机制,不论是在客户端、还是在服务端存储着,用雷同的URL进行数据申请,能够间接从缓存中申请资源而不再拜访源服务器。 Web前端缓存大抵能够分为:数据库缓存、服务器端缓存(代理服务器缓存、CDN缓存)、浏览器缓存。 浏览器缓存也蕴含很多内容:HTTP 缓存、indexDB、cookie、localstorage 等等。这里咱们只探讨 HTTP 缓存相干内容。 1.2 浏览器缓存的意义:浏览器在本地对用户对最近申请过的文档进行存储,当用户再次拜访同一页面时,浏览器就能够间接从本地磁盘加载文件。浏览器缓存的意义次要在: a. 防止了冗余的数据传输,节俭流量; b. 放慢了用户拜访网页的速度; c. 减小了服务器的压力。 2 缓存类型2.1 第一次申请数据浏览器第一次申请数据时,浏览器缓存中没有对应的缓存数据,此时须要申请服务器,浏览器返回数据后,会把申请的数据存储至缓存数据库中。 当浏览器中存在缓存数据后,能够依据是否须要向服务器发送申请,将缓存类型分为:强制缓存和协商缓存。 2.2 强制缓存用户申请数据,如果命中强缓存,则不向服务器申请,而间接从本地资源获取,返回200状态码,并提醒from disk cache或from memory cache(比从disk快)。 2.3 协商缓存在用户申请资源时,浏览器间接向服务器发送申请,协商比照服务端和本地的资源,验证本地资源是否生效。 2.4 强制缓存和协商缓存的关系强制缓存和协商缓存命中缓存资源后,都是从本地读取资源。如果强制缓存失效,则不须要再向服务器发出请求;而协商缓存,不论是否应用缓存,必须向服务器发送一个申请来协商。 两类缓存规定能够同时存在,强制缓存优先级高于协商缓存,也就是说,当执行强制缓存的规定时,如果缓存失效,间接应用缓存,不再执行协商缓存规定。如果强制缓存规定不失效,则须要进行协商缓存判断。 3 缓存相干header上文介绍了强制缓存与协商缓存的流程,那么在浏览器中,浏览器如何断定缓存数据是否生效呢?如何确认是否应用缓存数据呢? 3.1 强制缓存强制缓存的response header中会有两个字段来表明生效规定(Expires/Cache-Control) 1. Expires:Expires的值为服务端返回的到期工夫,即下一次申请时,申请工夫小于服务端返回的到期工夫,间接应用缓存数据。不过Expires 是HTTP 1.0的货色,当初默认浏览器均默认应用HTTP 1.1,所以它的作用根本疏忽。另一个问题是,到期工夫是由服务端生成的,然而客户端工夫可能跟服务端工夫有误差,这就会导致缓存命中的误差。 所以HTTP 1.1 的版本,应用Cache-Control代替。 2. Cache-Control:Cache-Control 是最重要的规定。常见的取值有private、public、no-cache、max-age, Expires和Cache-Control的关系: a. 相同点:两者都是强缓存。 b. 不同点: Expires是http1.0规定的,而Cache-Control是http1.1规定的。Expires的过期工夫采纳的是相对工夫,容易造成过错; 而Cache-Control的过期工夫采纳的时绝对工夫,在缓存上不会呈现问题。两者能够同时存在于一次申请中,然而不会同时在一次申请中起作用。 在HTTP1.0的环境下,Cache-Control不起作用,Expires起作用; 在HTTP1.1的环境之下, Expires不起作用,而Cache-Control起作用。以后个别都是http1.1的状况,所以Expires是作为一种向下兼容的模式而存在的。Cache-Control的抉择更多,性能更为弱小,举荐应用。 Expires作为强缓存,性能繁多,不举荐应用。例如:下图(华为云官网首页)中,文件global.js的Cache-Control指定的缓存生效工夫max-age为86400s(1天): ...

July 28, 2020 · 1 min · jiezi