郑州网站关键词推广cms网站建站流程

当前位置: 首页 > news >正文

郑州网站关键词推广,cms网站建站流程,建设的基本流程网站,wordpress商城 中文站作者#xff1a;秦怀 1 缓存前世今生 1.1 故事从硬件开始 Cache 一词来源于 1967 年的一篇电子工程期刊论文。其作者将法语词“cache”赋予“safekeeping storage”的涵义#xff0c;用于电脑工程领域。当时没有 Cache#xff0c;CPU 和内存都很慢#xff0c;CPU 直接访…作者秦怀 1 缓存前世今生 1.1 故事从硬件开始 Cache 一词来源于 1967 年的一篇电子工程期刊论文。其作者将法语词“cache”赋予“safekeeping storage”的涵义用于电脑工程领域。当时没有 CacheCPU 和内存都很慢CPU 直接访问内存。 Intel 80386芯片组增加了对可选的 Cache 的支持高级主板带有 64KB甚至高端的 128KB Write-Through Cache。Intel 80486 CPU 里面加入了 8KB 的 L1 Unified Cache当时也叫做内部 Cache不分代码和数据都存在一起芯片组中的 Cache变成了 L2也被叫做外部 Cache从 128KB 到 256KB 不等增加了 Write-back 的 Cache 属性。Pentium 奔腾 CPU 的 L1 Cache 分为 Code 和 data各自 8KBL2 还被放在主板上。Pentium Pro奔腾 的 L2 被放入到 CPU 的 Package 上。Pentium 3奔腾 开始L2 Cache 被放入了 CPU 的 Die 中。从 Intel Core CPU 开始L2 Cache 为多核共享。 当 CPU 处理数据时它会先到 Cache 中去寻找如果数据因之前的操作已经读取而被暂存其中就不需要再从 随机存取存储器Main memory中读取数据——由于 CPU 的运行速度一般比主内存的读取速度快主存储器周期访问主存储器所需要的时间为数个时钟周期。因此若要访问主内存的话就必须等待数个 CPU 周期从而造成浪费。 提供“缓存”的目的是为了让数据访问的速度适应 CPU 的处理速度其基于的原理是内存中“程序执行与数据访问的局域性行为”即一定程序执行时间和空间内被访问的代码集中于一部分。为了充分发挥缓存的作用不仅依靠“暂存刚刚访问过的数据”还要使用硬件实现的指令预测与数据预取 技术——尽可能把将要使用的数据预先从内存中取到缓存里。 CPU 的缓存曾经是用在超级计算机上的一种高级技术, 不过现今电脑上使用的的 AMD 或 Intel 微处理器都在芯片内部集成了大小不等的数据缓存和指令缓存, 通称为 L1 缓存 (L1 Cache 即 Level 1 On-die Cache, 第一级片上高速缓冲存储器); 而比 L1 更大容量的 L2 缓存曾经被放在 CPU 外部 (主板或者 CPU 接口卡上), 但是现在已经成为 CPU 内部的标准组件; 更昂贵的 CPU 会配备比 L2 缓存还要大的 L3 缓存 (level 3 On-die Cache 第三级高速缓冲存储器) 1.2 概念的扩展 如今缓存的概念已被扩充, 不仅在 CPU 和主内存之间有 Cache, 而且在内存和硬盘之间也有 Cache (磁盘缓存), 乃至在硬盘与网络之间也有某种意义上的 Cache 称为 Internet 临时文件夹或网络内容缓存等凡是位于速度相差较大的两种硬件之间, 用于协调两者数据传输速度差异的结构, 均可称之为 Cache。 现在我们软件开发中常说的缓存是指磁盘和 CPU 之间的协调两者传输速度的结构。 2 缓存的特征 2.1 主要特征 命中率命中率返回正确结果数/请求缓存次数命中率越高表明缓存的使用率也就越高。吞吐量缓存的吞吐量使用 OPS 值每秒操作数Operations per Secondops/s来衡量反映了对缓存进行并发读、写操作的效率即缓存本身的工作效率高低。缓存淘汰策略 FIFO (first in first out)先进先出策略最先进入缓存的数据在缓存空间不够的情况下超出最大元素限制会被优先被清除掉以腾出新的空间接受新的数据。LFU (less frequently used)最少使用策略无论是否过期根据元素的被使用次数判断清除使用次数较少的元素释放空间。LRU (least recently used)最近最少使用策略无论是否过期根据元素最后一次被使用的时间戳清除最远使用时间戳的元素释放空间。
2.2 是否适合缓存的考虑 不是所有数据都适合缓存我们使用缓存是想用较小的成本换取较大的收益在决定是否缓存之前可以考虑以下的问题 是否有一致性的要求缓存和底层存储是否需要强一致性缓存是不是高效的命中率大概怎么样缓存多久是否需要设置 TTL数据结构是否适合缓存计算后缓存亦或是缓存之后计算 2.3 惊群效益 如果许多不同的应用程序进程同时请求一个缓存键但出现缓存未命中随后所有应用程序进程都并行执行相同的数据库查询此时就会发生惊群效应也称作叠罗汉效应。此查询的代价越高对数据库的影响就越大。一般可以通过缓存预热、缓存不存在的空值来减少。 3 缓存的分类 根据应用的耦合度一般分为本地缓存和分布式缓存 本地缓存在应用中的缓存组件应用和 Cache 是在同一个进程内请求特别快没有网络开销。分布式缓存与应用分离的缓存组件可以认为是独立的服务和应用分开多个应用之间可以共享但是会存在网络请求。 4 分布式缓存存在的必要性 先聊缓存的必要性计算机的世界里倘若有无法解决不了的问题一般都可以再加一层来解决而缓存从被提出开始就是那个加了的一层。CPU的速度很快数据库操作很慢怎么办CPU缓存很小很贵很快但是数据库的磁盘很慢很大很便宜怎么办内存来解决 可以提前将一些比较耗时的数据结果暂存到内存如果有持久化也会同时存储在磁盘中中如果有相同请求可以直接返回如果数据变更更新或者删除再处理掉缓存。大家平日里接触最多的可能就是浏览器的缓存有时候多次访问有些数据根本不会再去请求会优先使用浏览器的本地缓存。 除此之外微博也是如此 单机的缓存可以满足大部分的场景但是单节点的最大容量不能超过整个系统的内存而且像 memcached 这种存储断电内容就会彻底丢失Redis 则有持久化的能力只是通电之后需要花点时间从磁盘将数据 load 回内存中。 现在几乎应用服务器都是分布式的如果只做单机缓存意味着每个服务器的缓存都存了一份极大概率存在不一致的情况比如 一个用户第一次请求命中机器 A有缓存第二次命中机器 B 又没缓存只能重新缓存了一份在机器 B 上。 5 分布式缓存设计可能需要考虑的几个问题 站在巨人Redis的肩膀上, 我们可以学到很多优秀的设计、理念设计一个功能比较全面的分布式缓存到底需要考虑哪些问题 下面聊聊几点比较常见的 5.1 、断电了怎么办持久化 必须支持 持久化可以异步的将数据刷盘落到磁盘中重新启动的时候能够加载已有的数据。那刷盘的时机是怎么样的只要改一个数据就刷一次盘么还是修改数据到达某个阈值才进行刷盘这些都是策略最好是可以支持配置这些规则其实我们都可以从 Redis 这些优秀的缓存中间件中学习到。 当然如果在一定场景下能接受数据完全丢失不需要持久化那么可以设置为关闭可以节约性能开销。 5.2 2、内存不足怎么办缓存淘汰策略 单机内存不足可以删除一些数据。但是到底删除哪些数据这必须有一个决策的算法这就是缓存淘汰策略。 常见的缓存淘汰策略有以下几种 FIFO先进先出First InFirst Out如同队列新数据在尾部加入内存不足的时候淘汰的数据从队列头部移除。LFU最低频率使用淘汰算法Least Frequently Used也称为最近最不常使用将使用频率最低的数据淘汰。LRU最近时间未使用Least Recently used也称为最近最少使用内存不足的时候总是淘汰最长时间未被使用得数据。 5.3 3、需不需要自定义协议 一个稳定的分布式缓存系统还需要一套序列化协议怎么设计一个简单而又高效的协议是个值得思考的问题。 比如 Redis 使用得就是 RESP(REdis Serialization Protocol) 协议这是专门为 Redis 设计的属于应用层的通信协议本质上和 HTTP 是同一层级而 Redis 的传输层使用的是 TCP。如果是服务器接收请求的场景那么服务端从 TCPsocket 缓存区里面读取数据然后经过了 RESP 协议解码知乎会得到我们所需的指令。 简单讲一下RESP 主要就是 想用更少的数据表达所需的更丰富的内容也就是压缩数据量增加信息量。 比如第一个字节决定了数据类型 简单字符串 Simple Strings第一个字节响应 错误Errors第一个字节响应 -整型Integers第一个字节响应 :批量字符串Bulk Strings第一个字节响应 $数组Arrays第一个字节响应 * 5.4 4、一台机器存储不够怎么办可拓展 不能一直增加单台机器的容量抛开成本不讲单机大容量网络带宽磁盘 IO计算资源等都可能成为较大的瓶颈肯定需要支持横向拓展水平拓展比如 Redis 集群模式。与横向拓展对应的是垂直拓展也就是增加单个节点的容量性能。互联网发展的这些年已经证明了分布式系统是一个更优的选项。 5.5 5、如果有一台机器宕机了怎么办高可用 如果多台机器中有机器宕机怎么办从事前、事中、事后来看 事前需要可监控需要有监控节点比如 Redis 中的哨兵并且有可以切换的节点从节点。事中怎么切换哪一个机器作为“主持人“角色进行切换切换哪一个机器都是需要抉择的。事后切换之后下线机器怎么处理。 5.6 6、是否支持并发高并发 并发写入怎么办Redis 采取的是队列的方式内部不允许并发执行也就不需要加锁解锁的操作如果考虑使用锁来实现需要同时考虑上下文切换的成本而我们简单的版本可以使用加锁的方式来实现。 6 使用分布式缓存可能会遇到的几个问题 6.1 1、一致性问题 如何保证缓存和数据库的一致性问题是一个比较大的话题我们除了保证数据库和缓存一致分布式缓存的 master 和 slave 也需要保持一致。一般一致性分为以下几种 强一致性数据库更新操作与缓存更新操作是原子性的缓存与数据库的数据在任何时刻都是一致的很难实现。弱一致性当数据更新后缓存中的数据可能是更新前的值也可能是更新后的值这种更新是异步的。最终一致性一种特殊的弱一致性在一定时间后数据会达到一致的状态。最终一致性是弱一致性的理想状态也是分布式系统的数据一致性解决方案上比较推崇的。 根据 CAP 原理分布式系统在可用性、一致性和分区容错性上无法兼得通常由于分区容错无法避免所以一致性和可用性难以同时成立。 这里的几种方案就不展开讲了几种更新策略 1、先更新缓存再更新数据库 在两个线程一起更新的场景下如果先更新缓存的线程后更新数据库很容易出现一致性问题。 2、先更新数据库再更新缓存 在两个线程一起更新的场景下如果先更新数据库的线程由于执行慢了一些后更新缓存很容易出现一致性问题。 3、先删除缓存再更新数据库 先删除缓存的线程后更新数据库仍然有一致性问题 4、先更新数据库再删除缓存 先更新数据库的线程后删除缓存没有问题删除缓存之后会回源到数据库。但是没删除缓存之前数据库更新了读取会读到脏数据。所以我们一般推荐双删更新之前删一次更新之后删一次。这个时候有人会问如果同时有个读请求读的是写之前的脏数据但是写入到缓存是比较慢的刚刚好在删除之后那缓存数据就还是脏数据是的这个时候一般靠第二次删除延迟来处理延迟删除。这个时候肯定有人问那要是删除失败了怎么办 直接补偿重试消息队列异步重试基于 mysql binlog 增量订阅消费补偿
这个问题我们在这个分布式缓存的里面就不详细聊了之后单独聊这个话题串行化是我们最后的倔强但是高并发就难了所以我们一般是保证最终一致性即可。 6.2 2、缓存穿透 缓存穿透是指缓存和数据库都没有的数据被大量请求比如订单号不可能为 -1但是用户请求了大量订单号为 -1 的数据由于数据不存在缓存就也不会存在该数据所有的请求都会直接穿透到数据库。 如果被恶意用户利用疯狂请求不存在的数据就会导致数据库压力过大甚至垮掉。 注意穿透的意思是都没有直接一路打到数据库。 那对于这种情况我们该如何解决呢 接口增加业务层级的Filter进行合法校验这可以有效拦截大部分不合法的请求。 作为第一点的补充最常见的是使用布隆过滤器针对一个或者多个维度把可能存在的数据值 hash 到 bitmap 中bitmap 证明该数据不存在则该数据一定不存在但是 bitmap 证明该数据存在也只能是可能存在因为不同的数值 hash 到的 bit 位很有可能是一样的hash 冲突会导致误判多个 hash 方法也只能是降低冲突的概率无法做到避免。 另外一个常见的方法则是针对数据库与缓存都没有的数据对空的结果进行缓存但是过期时间设置得较短一般五分钟内。而这种数据如果数据库有写入或者更新必须同时刷新缓存否则会导致不一致的问题存在。
6.3 3、缓存雪崩 缓存雪崩是指缓存中有大量的数据在同一个时间点或者较短的时间段内全部过期了这个时候请求过来缓存没有数据都会请求数据库则数据库的压力就会突增扛不住就会宕机。 针对这种情况一般我们都是使用以下方案 如果是热点数据先预热而且可以考虑设置永远不过期。缓存的过期时间除非比较严格要不考虑设置一个波动随机值比如理论十分钟那这类key的缓存时间都加上一个13分钟过期时间在713分钟内波动有效防止都在同一个时间点上大量过期。方法1避免了有效过期的情况但是要是所有的热点数据在一台redis服务器上也是极其危险的如果网络有问题或者redis服务器挂了那么所有的热点数据也会雪崩查询不到因此将热点数据打散分不到不同的机房中也可以有效减少这种情况。也可以考虑双缓存的方式数据库数据同步到缓存 A 和 BA 设置过期时间B 不设置过期时间如果 A 为空的时候去读 B同时异步去更新缓存但是更新的时候需要同时更新两个缓存。使用缓存组件时可以设置为异步回源或者允许读取未物理删除的数据。 比如设置产品的缓存时间 redis.set(id,value,60*60 Math.random()*1000); 6.4 4、缓存击穿 缓存击穿是指数据库原本有得数据但是缓存中没有一般是缓存突然失效了这时候如果有大量用户请求该数据缓存没有则会去数据库请求会引发数据库压力增大可能会瞬间打垮。 针对这类问题一般有以下做法 如果是热点数据那么可以考虑设置永远不过期。如果数据一定会过期那么就需要在数据为空的时候设置一个互斥的锁只让一个请求通过只有一个请求去数据库拉取数据取完数据不管如何都需要释放锁异常的时候也需要释放锁要不其他线程会一直拿不到锁。 下面是缓存击穿的时候互斥锁的写法注意获取锁之后操作不管成功或者失败都应该释放锁而其他的请求如果没有获取到锁应该等待再重试。当然如果是需要更加全面一点应该加上一个等待次数比如1s中那么也就是睡眠五次达到这个阈值则直接返回空不应该过度消耗机器以免当个不可用的场景把整个应用的服务器带挂了。 public static String getProductDescById(String id) {String desc redis.get(id);// 缓存为空过期了if (desc null) {// 互斥锁只有一个请求可以成功if (redis.setnx(lock_id, 1, 60) 1) {try {// 从数据库取出数据desc getFromDB(id);redis.set(id, desc, 60 * 60 * 24);} catch (Exception ex) {LogHelper.error(ex);} finally {// 确保最后删除释放锁redis.del(lock_id);return desc;}} else {// 否则睡眠200ms接着获取锁Thread.sleep(200);return getProductDescById(id);}}}6.5 5、缓存热点 像微博这种有些热点新闻突然爆了大量用户访问同一个 keykey 在同一个缓存节点很容易就过载节点会卡顿甚至挂掉这种我们就叫缓存热点。 解决方案一般是通过实时数据流比如 Spark 分析热点 Key 一般都有一个增长的过程然后在 Key 后面加上一些随机的编号比如明星出轨_01, 明星出轨_02…目的是让这些 key 分布在不同的机器上而客户端获取的时候带上随机的 key随机访问一个就可以。 想要探测热 Key除了实时数据流也可以在 redis 之上的 proxy 上面做一般我们在公司都不是直接连接 redis 而是连接的 proxy因此我们也可以通过在 proxy 中使用滑动时间窗口对每个 key 进行计数超过一定的阈值就设置为热 key。 那如何快速针对热 key 进行动态处理呢弄一个独立的缓存数据服务根据流量来动态拆分热 key动态的增长成为热 key 我们可以通过分析发现但是如果是秒杀等业务呢需要支持实时拆分热 key用分布式配置中心来配置热 key感知到配置热 key 则进行需要的处理这里因业务而异可以降级成读取本地内存可以进行拆分等等。 当然如果能够正对秒杀等活动或者大促活动拉出独立的集群进行路由隔离影响那也是一种方案。 这是京东的处理方案 https://gitee.com/jd-platform-opensource/hotkey 对任意突发性的无法预先感知的热点请求包括并不限于热点数据如突发大量请求同一个商品、热用户如爬虫、刷子、热接口突发海量请求同一个接口等进行毫秒级精准探测到。 然后对这些热数据、热用户等推送到该应用部署的所有机器JVM内存中以大幅减轻对后端数据存储层的冲击并可以由客户端决定如何使用这些热key譬如对热商品做本地缓存、对热用户进行拒绝访问、对热接口进行熔断或返回默认值。 这些热key在整个应用集群内保持一致性。 6.6 6、缓存大 Key 缓存大 key 是指缓存的值 value 特别大如果同一时间大量请求访问了同一个大 key带宽很容易被占满其他请求进不来。 大 key 定义参考如下 string类型的key超过10KBhash/set/zset/list 等数据结构中元素个数大于 5k/整体占用内存大于 10MB 如何判断是不是大 key一般看网络的出流量如果突增特别厉害但是入流量变化不大的情况下基本可以判断为大 key。 事前我们可以在代码 review 的时候就得判断 value 是不是特别大不能写这种代码。或者封装一层 redis 操作切面异步对 key 的 value 做监控进行打点告警。其次写代码的时候如果发现要 set 这种大的 value 值那就得想办法拆分把对象拆成属性或者按照属性分类。如果是一个不可分割的整体那就得考虑一下技术方案是不是要推翻重来了一般我们不太可能把几 M 的图片直接二进制存 redis。dump RDB 数据进行离线数据分析给出告警但是不够实时。Redis 提供了 bigkeys 参数能够使 redis-cli 以遍历的方式分析 Redis 实例中的所有 Key并返回 Key 的整体统计信息与每个数据类型中 Top1 的大 Keybigkeys 仅能分析并输入六种数据类型STRING 、LIST、HASH、SET、ZSET、STREAM, 命令示例为 redis-cli -h 127.0.0.1 -p 6379 –bigkeys 7 总结 缓存不是银弹是一把刀用得好可以乱杀夸大用不好得包扎一点不夸大得提桶跑路那种。