图解大型网站多级缓存的分层架构

前言

缓存技术存在于应用场景的方方面面。从浏览器请求,到反向代理服务器,从进程内缓存到分布式缓存,其中缓存策略算法也是层出不穷。

假设一个网站,需要提高性能,缓存可以放在浏览器,可以放在反向代理服务器,还可以放在应用程序进程内,同时可以放在分布式缓存系统中。

从用户请求数据到数据返回,数据经过了浏览器,CDN,代理服务器,应用服务器,以及数据库各个环节。每个环节都可以运用缓存技术。

从浏览器/客户端开始请求数据,通过 HTTP 配合 CDN 获取数据的变更情况,到达代理服务器(Nginx)可以通过反向代理获取静态资源。

再往下来到应用服务器可以通过进程内(堆内)缓存,分布式缓存等递进的方式获取数据。如果以上所有缓存都没有命中数据,才会回源到数据库。

缓存的请求顺序是:用户请求 → HTTP 缓存 → CDN 缓存 → 代理服务器缓存 → 进程内缓存 → 分布式缓存 → 数据库。

看来在技术的架构每个环节都可以加入缓存,看看每个环节是如何应用缓存技术的。

image.png

HTTP 缓存

当用户通过浏览器请求服务器的时候,会发起 HTTP 请求,如果对每次 HTTP 请求进行缓存,那么可以减少应用服务器的压力。

当第一次请求的时候,浏览器本地缓存库没有缓存数据,会从服务器取数据,并且放到浏览器的缓存库中,下次再进行请求的时候会根据缓存的策略来读取本地或者服务的信息。

私有缓存

私有缓存是绑定到特定客户端的缓存——通常是浏览器缓存。由于存储的响应不与其他客户端共享,因此私有缓存可以存储该用户的个性化响应。该种缓存

如果响应包含个性化内容并且你只想将响应存储在私有缓存中,则必须指定 private 指令。

Cache-Control: private

image.png

共享缓存

共享缓存位于客户端和服务器之间,可以存储能在用户之间共享的响应,可以供多个客户端使用的缓存,通常依赖于代理服务器。

客户端发起的第一个请求通过代理服务器访问源服务器,缓存生效后会存放在代理服务器,后续客户端发起的相同请求,均由代理服务器提供缓存服务,共享缓存可以减轻源服务器的压力

image.png

其实共享代理可以细分为代理缓存托管缓存,简单理解代理缓存由代理服务器管理,位于客户端与原始服务器之间,减轻服务器负载、提高响应速度。托管缓存由内容提供商或 CDN 管理,分布全球,提供更快的内容传递和更好的用户体验。

缓存处理机制

下方为整体处理机制示意图,后文很多内容针对图中某些环节进行扩展讲解

image.png

上面强缓存中的 Pragma 大多数用于 http 1.0(http 1.1 中也适用),而 Cache-Control 只能应用于 http 1.1

需要注意的是,Expires 为服务端返回的过期时间,这种判断缓存是否过期的方式在  HTTP 1.0 用的比较多,到了 HTTP 1.1 会使用 Cache-Control 的 max-age 属性替代(单位是秒)

Last-Modified/If-Modified-Since 规则

在客户端第一次请求的时候,服务器会返回资源最后的修改时间,记作 Last-Modified。客户端将这个字段连同资源缓存起来。

当客户端再次请求服务器时,会把 Last-Modified 连同请求的资源一起发给服务器,这时 Last-Modified 会被命名为 If-Modified-Since,但其内容一样。

服务器收到请求,会把 If-Modified-Since 字段与服务器上保存的 Last-Modified 字段作比较:

  • 若服务器上的 Last-Modified 最后修改时间大于请求的 If-Modified-Since,说明资源被改动过,就会把资源(包括 Header+Body)重新返回给浏览器,同时返回状态码 200
  • 若资源的最后修改时间小于或等于 If-Modified-Since,说明资源没有改动过,只会返回 Header,并且返回状态码 304。浏览器接受到这个消息就可以使用本地缓存库的数据。

注意,Last-Modified 和 If-Modified-Since 指的是同一个值,只是在客户端和服务器端的叫法不同。

ETag / If-None-Match 规则

客户端第一次请求的时候,服务器会给每个资源生成一个 ETag 标记。这个 ETag 是根据每个资源生成的唯一 Hash 串,资源如何发生变化 ETag 随之更改,之后将这个 ETag 返回给客户端,客户端把请求的资源和 ETag 都缓存到本地。

在浏览器第二次请求服务器相同资源时,会把资源对应的 ETag 一并发送给服务器。在请求时 ETag 会被命名为 If-None-Match,但其内容不变

服务器收到请求后,会把 If-None-Match 与服务器上资源的 ETag 进行比较:

  • 如果不一致,说明资源被改动过,则返回资源(Header+Body),返回状态码 200。
  • 如果一致,说明资源没有被改过,则返回 Header,返回状态码 304。浏览器接受到这个消息就可以使用本地缓存库的数据。
规则使用时机

那么什么时候使用修改日期(Last-Modified)再验证和实体标签再验证(ETag)呢?

  • 如果服务器返回了一个 ETag 首部,客户端就必须使用 If-None-Match 实体标签再验证;
  • 如果服务器返回了一个 Last-Modified 首部,客户端就可以使用 If-Modified-Since 修改日期再验证;
  • 如果 ETag 和 Last-Modified 都提供了,客户端就应该同时使用这两种再验证方案。

如果HTTP/1.1缓存或服务器收到的请求既带有 If-Modified-Since,又带有 If-None-Match,那么只有这两个条件都满足时,才能返回304 Not Modified响应。

缓存控制策略

对于网站来说,缓存是达到高性能的重要组成部分,缓存需要合理配置,因为并不是所有资源都是永久不变的。Cache-Control 首部可以对缓存进行控制,Cache-Control 能用于 HTTP 请求和响应中,支持多个指令,以逗号分隔:

请求首部描述
Cache-Control: no-store不使用缓存。
Cache-Control: no-cache使用缓存前,无论本地副本是否过期,都需要请求源服务器进行验证(协商缓存验证)。
Cache-Control: max-age=秒设置缓存存储的最大期限,超过这个期限缓存被认为过期,时间是相对于请求的时间。
Cache-Control: max-stale=秒客户端愿意接收一个已经过期的资源。可以设置一个可选的秒数,表示响应不能已经过时超过该给定的时间。
Cache-Control: min-fresh=秒客户端希望获取一个能在指定的秒数内保持其最新状态的响应。
响应首部描述
Cache-Control: no-store不使用缓存。
Cache-Control: no-cache使用缓存前,无论本地副本是否过期,都需要请求源服务器进行验证(协商缓存验证)。
Cache-Control: max-age=秒设置缓存存储的最大期限,超过这个期限缓存被认为过期,时间是相对于请求的时间。
Cache-Control: s-maxage=秒同 max-age,仅适用于共享缓存。
Cache-Control: private私有缓存,响应只能被单个客户端缓存。
Cache-Control: public共享缓存,即由缓存代理服务器提供的缓存,响应可以被多个客户端缓存。
Cache-Control: must-revalidate如果本地副本未过期,则可继续供客户端使用,不需要向源服务器再验证;如果本地副本已过期(比如已经超过 max-age),在成功向源服务器验证之前,缓存不能用该资源响应后续请求。
Cache-Control: proxy-revalidate同 must-revalidate,仅适用于共享缓存。

Cache-Control有几个指令特别容易混淆,不能望文生义。比如no-cache,并不是指不能用 cache,客户端仍会把带有 no-cache 的响应缓存下来,只不过每次不会直接用缓存,而是要先去服务端验证一下。如果你想让客户端完全不缓存响应,应该用no-store,带有no-store的响应不会被缓存到任意的磁盘或者内存里,它才是真正的 no-cache

下面是对三个容易混淆的指令进行对比说明:

首部描述
Cache-Control: no-store不使用缓存。
Cache-Control: no-cache无论本地副本是否过期,都需要请求源服务器进行验证。
Cache-Control: must-revalidate如果本地副本未过期,可以使用本地副本;否则,需要请求源服务器进行验证。

CDN 缓存

HTTP 缓存主要是对静态数据进行缓存,把从服务器拿到的数据缓存到客户端/浏览器。

如果在客户端和服务器之间再加上一层 CDN,可以让 CDN 为应用服务器提供缓存,如果在 CDN 上缓存,就不用再请求应用服务器了。并且 HTTP 缓存提到的两种策略同样可以在 CDN 服务器执行。

CDN 的全称是 Content Delivery Network,即内容分发网络。其目的是通过在现有的 Internet 中增加一层新的网络架构,将网站的内容发布到最接近用户的网络"边缘",使用户可以就近取得所需的内容,解决 Internet 网络拥塞状况,提高用户访问网站的响应速度。

从技术上全面解决由于网络带宽小、用户访问量大、网点分布不均等原因所造成的用户访问网站响应速度慢的问题。

CDN 分发系统架构

image.png

CDN 工作流程

image.png

用户访问某个站点的内容时,若该站点使用了 CDN 网络,则在用户会在域名解析时获得 CDN 网络 GSLB 设备的 IP 地址。GSLB 设备根据其预设的选择策略(如,地理区域、用户时间等)为用户选择最合适的内容缓存节点,并且使用某种方式(如,基于 DNS、基于 HTTP 重定向、基于 IP 欺骗的方式等)导引用户访问所选的内容缓存节点。

用户继续向缓存节点发出请求,若缓存中包含请求的内容,则直接返回给用户,否则从核心Web服务器中获取该内容,缓存后返回给用户。这样当用户再次访问相同内容或其他用户访问相同内容时,可以直接从缓存中读取,提高了效率。

负载均衡缓存

说完客户端(HTTP)缓存和 CDN 缓存,我们离应用服务越来越近了,在到达应用服务之前,请求还要经过负载均衡器。

虽说它的主要工作是对应用服务器进行负载均衡,但是它也可以作缓存。可以把一些修改频率不高的数据缓存在这里,例如:用户信息,配置信息。通过服务定期刷新这个缓存就行了。

以 Nginx 为例,我们看看它是如何工作的:

  • 用户请求在达到应用服务器之前,会先访问 Nginx 负载均衡器,如果发现有缓存信息,直接返回给用户。
  • 如果没有发现缓存信息,Nginx 回源到应用服务器获取信息。
  • 另外,有一个缓存更新服务,定期把应用服务器中相对稳定的信息更新到 Nginx 本地缓存中。

image.png

进程内缓存

通过了客户端,CDN,负载均衡器,我们终于来到了应用服务器。应用服务器上部署着一个个应用,这些应用以进程的方式运行着,那么在进程中的缓存是怎样的呢?

进程内缓存又叫托管堆缓存,以 Java 为例,这部分缓存放在 JVM 的托管堆上面,同时会受到托管堆回收算法的影响。

由于其运行在内存中,对数据的响应速度很快,通常我们会把热点数据放在这里。

在进程内缓存没有命中的时候,我们会去搜索进程外的缓存或者分布式缓存。这种缓存的好处是没有序列化和反序列化,是最快的缓存。缺点是缓存的空间不能太大,对垃圾回收器的性能有影响。

目前比较流行的实现有 Ehcache、GuavaCache、Caffeine。这些架构可以很方便的把一些热点数据放到进程内的缓存中。

这里我们需要关注几个缓存的回收策略,具体的实现架构的回收策略会有所不同,但大致的思路都是一致的:

  • FIFO(First In First Out):先进先出算法,最先放入缓存的数据最先被移除。
  • LRU(Least Recently Used):最近最少使用算法,把最久没有使用过的数据移除缓存。
  • LFU(Least Frequently Used):最不常用算法,在一段时间内使用频率最小的数据被移除缓存。

在分布式架构的今天,多应用中如果采用进程内缓存会存在数据一致性的问题。

解决方案

保障进程内缓存数据一致性,有以下几种方案

单节点通知修改方案

image.png

第一种方案,可以通过单节点通知其他节点。如上图:写请求发生在 server1,在修改完自己内存数据与数据库中的数据之后,可以主动通知其他 server 节点,也修改内存的数据。

这种方案的缺点是:同一功能的一个集群的多个节点,相互耦合在一起,特别是节点较多时,网状连接关系极其复杂。

消息队列修改方案

image.png

第二种方案,可以通过 MQ 通知其他节点。如上图,写请求发生在 server1,在修改完自己内存数据与数据库中的数据之后,给 MQ 发布数据变化通知,其他 server 节点订阅 MQ 消息,也修改内存数据。

这种方案虽然解除了节点之间的耦合,但引入了MQ,使得系统更加复杂。

前两种方案,节点数量越多,数据冗余份数越多,数据同时更新的原子性越难保证,一致性也就越难保证。

Timer 修改方案

image.png

第三种方案,为了避免耦合,降低复杂性,干脆放弃了“实时一致性”,每个节点启动一个timer,定时从后端拉取最新的数据,更新内存缓存。在有节点更新后端数据,而其他节点通过timer更新数据之间,会读到脏数据。

应用场景

为什么不能频繁使用进程内缓存?

分层架构设计,有一条准则:站点层、服务层要做到无数据无状态,这样才能任意的加节点水平扩展,数据和状态尽量存储到后端的数据存储服务,例如数据库服务或者缓存服务。

可以看到,站点与服务的进程内缓存,实际上违背了分层架构设计的无状态准则,故一般不推荐使用。

那么什么情况下可以考虑使用进程内缓存?

情况一,只读数据,可以考虑在进程启动时加载到内存。

其实此时也可以把数据加载到 redis / memcache,进程外缓存服务也能解决这类问题。

情况二,极高并发,如果透传后端压力极大的场景,可以考虑使用进程内缓存。

例如,秒杀业务,并发量极高,需要站点层挡住流量,可以使用内存缓存。

情况三,一定程度上允许数据不一致业务

例如,有一些计数场景,运营场景,页面对数据一致性要求较低,可以考虑使用进程内页面缓存。

再次强调下,进程内缓存的适用场景并不如 redis/memcache 广泛,不要为了炫技而使用。

分布式缓存

与进程内缓存相对应的就是进程外缓存,它拥有更大的缓存容量,并且可以部署到不同的物理节点,通常会用分布式缓存的方式实现。

分布式缓存是与应用分离的缓存服务,最大的特点是,自身是一个独立的应用/服务,与本地应用隔离,多个应用可直接共享一个或者多个缓存应用/服务。

image.png

既然是分布式缓存,缓存的数据会分布到不同的缓存节点上,每个缓存节点缓存的数据大小通常也是有限制的。

数据被缓存到不同的节点,为了能方便的访问这些节点,需要引入缓存代理,类似 Twemproxy。他会帮助请求找到对应的缓存节点。

同时如果缓存节点增加了,这个代理也会只能识别并且把新的缓存数据分片到新的节点,做横向的扩展。

为了提高缓存的可用性,会在原有的缓存节点上加入 Master/Slave 的设计。当缓存数据写入 Master 节点的时候,会同时同步一份到 Slave 节点。

一旦 Master 节点失效,可以通过代理直接切换到 Slave 节点,这时 Slave 节点就变成了 Master 节点,保证缓存的正常工作。

每个缓存节点还会提供缓存过期的机制,并且会把缓存内容定期以快照的方式保存到文件上,方便缓存崩溃之后启动预热加载。

当缓存做成分布式的时候,数据会根据一定的规律分配到每个缓存应用/服务上,需要缓存的数据量比较大就需要扩展多个缓存节点来实现,这么多的缓存节点,客户端的请求不知道访问哪个节点怎么办?缓存的数据又如何放到这些节点上?

下面介绍三种缓存数据分片的算法,有了这些算法缓存代理就可以方便的找到分片的数据

哈希分片

image.png

Hash 分片的算法就是对缓存的 Key 做哈希计算,然后对总的缓存节点个数取余。你可以这么理解:

比如说,我们部署了三个缓存节点组成一个缓存的集群,当有新的数据要写入时,我们先对这个缓存的 Key 做比如 crc32Hash 算法生成 Hash 值,然后对 Hash 值模 3,得出的结果就是要存入缓存节点的序号。

这个算法最大的优点就是简单易理解,缺点是当增加或者减少缓存节点时,缓存总的节点个数变化造成计算出来的节点发生变化,从而造成缓存失效不可用。

所以如果采用这种方法,最好建立在你对于这组缓存命中率下降不敏感,比如下面还有另外一层缓存来兜底的情况下。那有没有更好的方案能解决这个问题呢?那就是一致性 Hash 分片算法。

一致性哈希分片

用一致性 Hash 算法可以很好地解决增加和删减节点时,命中率下降的问题。在这个算法中,我们将整个 Hash 值空间组织成一个虚拟的圆环,然后将缓存节点的 IP 地址或者主机名做 Hash 取值后,放置在这个圆环上。当我们需要确定某一个 Key 需要存取到哪个节点上的时候,先对这个 Key 做同样的 Hash 取值,确定在环上的位置,然后按照顺时针方向在环上“行走”,遇到的第一个缓存节点就是要访问的节点。比方说下面这张图里面,Key 1Key 2 会落入到 Node 1 中,Key 3Key 4 会落入到 Node 2 中,Key 5 落入到 Node 3 中,Key 6 落入到 Node 4 中。

image.png

这时如果在 Node 1Node 2 之间增加一个 Node 5,你可以看到原本命中 Node 2Key 3 现在命中到 Node 5,而其它的 Key 都没有变化;同样的道理,如果我们把 Node 3 从集群中移除,那么只会影响到 Key 5 。所以你看,在增加和删除节点时,只有少量的 Key漂移 到其它节点上,而大部分的 Key 命中的节点还是会保持不变,从而可以保证命中率不会大幅下降。

image.png

不过,事物总有两面性。虽然这个算法对命中率的影响比较小,但它还是存在问题:

  • 缓存节点在圆环上分布不平均,会造成部分缓存节点的压力较大;
  • 当某个节点故障时,这个节点所要承担的所有访问都会被顺移到另一个节点上,会对后面这个节点造成压力。

一致性哈希的脏数据问题

极端情况下,比如一个有三个节点 A、B、C 承担整体的访问,每个节点的访问量平均,A 故障后,B 将承担双倍的压力(A 和 B 的全部请求),当 B 承担不了流量 Crash 后,C 也将因为要承担原先三倍的流量而 Crash,这就造成了整体缓存系统的雪崩。

解决方案就是在一致性 Hash 算法中引入虚拟节点的概念,它将一个缓存节点计算多个 Hash 值分散到圆环的不同位置,这样既实现了数据的平均,而且当某一个节点故障或者退出的时候,它原先承担的 Key 将以更加平均的方式分配到其他节点上,从而避免雪崩的发生。

其次,就是一致性 Hash 算法的脏数据问题。为什么会产生脏数据呢? 比方说,在集群中有两个节点 AB,客户端初始写入一个 Key 为 k,值为 3 的缓存数据到 Cache A 中。这时如果要更新 k 的值为 4,但是缓存 A 恰好和客户端连接出现了问题,那这次写入请求会写入到 Cache B 中。接下来缓存 A 和客户端的连接恢复,当客户端要获取 k 的值时,就会获取到存在 Cache A 中的脏数据 3,而不是 Cache B 中的 4

所以,在使用一致性 Hash 算法时一定要设置缓存的过期时间,这样当发生漂移时,之前存储的脏数据可能已经过期,就可以减少存在脏数据的几率。

image.png

很显然,数据分片最大的优势就是缓解缓存节点的存储和访问压力,但同时它也让缓存的使用更加复杂。在 MultiGet(批量获取)场景下,单个节点的访问量并没有减少,同时节点数太多会造成缓存访问的 SLA(即“服务等级协议”,SLA 代表了网站服务可用性)得不到很好的保证,因为根据木桶原则,SLA 取决于最慢、最坏的节点的情况,节点数过多也会增加出问题的概率,因此我推荐 46 个节点为佳。

按照数据范围分片

常见场景就是按照 时间区间ID区间 来切分。例如:按日期将不同月甚至是日的数据分散到不同的库中;将 userId1~9999 的记录分到第一个库, 10000~20000 的分到第二个库,以此类推。某种意义上,某些系统中使用的 “冷热数据分离” ,将一些使用较少的历史数据迁移到其他库中,业务功能上只提供热点数据的查询,也是类似的实践。

这样的优点在于:

  • 单表大小可控
  • 天然便于水平扩展,后期如果想对整个分片集群扩容时,只需要添加节点即可,无需对其他分片的数据进行迁移
  • 使用分片字段进行范围查找时,连续分片可快速定位分片进行快速查询,有效避免跨分片查询的问题。

缺点:

  • 热点数据成为性能瓶颈。连续分片可能存在数据热点,例如按时间字段分片,有些分片存储最近时间段内的数据,可能会被频繁的读写,而有些分片存储的历史数据,则很少被查询

参考链接

  • 一篇文章让你明白你多级缓存的分层架构 - 掘金 (juejin.cn)
  • 分布式多级缓存SDK设计的思考-腾讯云开发者社区-腾讯云 (tencent.com)
  • 多级缓存架构设计 - 秦羽的思考 - 博客园 (cnblogs.com)
  • HTTP 缓存 - HTTP | MDN (mozilla.org)
  • 30分钟搞懂 HTTP 缓存 - 掘金 (juejin.cn)
  • 【CDN 最佳实践】CDN缓存策略解读和配置策略 - 知乎 (zhihu.com)
  • CDN图解(秒懂 + 史上最全) - 疯狂创客圈 - 博客园 (cnblogs.com)
  • 009.Nginx缓存配置 - 木二 - 博客园
  • 进程内缓存,究竟怎么玩?-阿里云开发者社区 (aliyun.com)
  • Hash分片,一致性Hash分片和按照数据范围分片三种常用的数据分片方式-腾讯云开发者社区-腾讯云 (tencent.com)

本文由博客一文多发平台 OpenWrite 发布!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/299656.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Hive 之 UDF 运用(包会的)

文章目录 UDF 是什么?reflect静态方法调用实例方法调用 自定义 UDF(GenericUDF)1.创建项目2.创建类继承 UDF3.数据类型判断4.编写业务逻辑5.定义函数描述信息6.打包与上传7.注册 UDF 函数并测试返回复杂的数据类型 UDF 是什么? H…

记一次靶场渗透测试(1)

本环境为黑盒测试,在不提供虚拟机帐号密码的情况下进行黑盒测试拿到域控里面的flag。 环境搭建 内网网段:192.168.93.0/24 外网网段:192.168.1.0/24 攻击机: kali:192.168.1.10 靶场: CentOS(内)&am…

Linux笔记之制作基于ubuntu20.4的最小OpenGL C++开发docker镜像

Linux笔记之制作基于ubuntu20.4的最小OpenGL C开发docker镜像 —— 2024-04-03 夜 code review! 文章目录 Linux笔记之制作基于ubuntu20.4的最小OpenGL C开发docker镜像1.这里把这本书的例程代码放在了Dockerfile所在的文件夹内以使镜像预装例程代码2.创建Dockerfile3.构建Do…

PDF编辑和格式转换工具 Cisdem PDFMaster for Mac

Cisdem PDFMaster for Mac是一款功能强大的PDF编辑和格式转换工具。它为用户提供了直观且易于使用的界面,使常用功能触手可及,从而帮助用户轻松管理、编辑和转换PDF文件。 软件下载:Cisdem PDFMaster for Mac v6.0.0激活版下载 作为一款完整的…

15 个最佳 Word 文档恢复工具 [免费下​​载]

MS Word 文档恢复的重要性 对于严重依赖 Microsoft Word 创建和编辑文档的个人和企业来说,MS Word 文档恢复是一个至关重要的方面。 文件损坏、系统崩溃和其他意外事件可能会导致 Word 文档中存储的重要数据丢失。 及时恢复这些文档有助于节省时间、精力和资源。 本…

GD32F470_寻迹避障模块 TCRT5000红外反射传感器模块移植

2.6 红外循迹传感器 红外循迹传感器采用TCRT5000红外反射传感器,一种集发射与接收于一体的光电传感器,它由一个红外发光二极管和一个NPN红外光电三极管组成。检测反射距离1mm-25mm适用,传感器特设M3固定安装孔,调节方向与固定方便…

【绩效管理】帮助零售企业建立分层分类绩效考核体系项目纪实

购物中心张经理评价:“员工的绩效管理一直是困扰我公司的难题,我们只懂得怎么经营,至于怎么做人力资源管理,真是一点都不懂。这次华恒智信为我们提供的服务对我们的帮助很大。基于企业实际调研情况,华恒智信专家明确指…

前端学习之DOM编程-案例div移动

这个案例是当你的鼠标按压下去后&#xff0c;div跟着你的鼠标移动而移动&#xff0c;当你的鼠标抬起后&#xff0c;div不随着鼠标移动而移动。类似于电脑移动应用图标的感觉。 代码 <!DOCTYPE html> <html lang"en"> <head><meta charset&quo…

day02-SpringCloud02(Nacos、Feign、Gateway)

1.Nacos 配置管理 Nacos 除了可以做注册中心&#xff0c;同样可以做配置管理来使用。 1.1.统一配置管理 当微服务部署的实例越来越多&#xff0c;达到数十、数百时&#xff0c;逐个修改微服务配置就会让人抓狂&#xff0c;而且很容易出错。我们需要一种统一配置管理方案&#x…

比例多路阀控制器US-DAT2-A

液压比例阀放大器是一种用于精确控制液压系统的技术&#xff0c;它通过电信号实现对液压阀的连续量控制。接收来自控制器的低功率电信号&#xff0c;然后将其放大并转换为高功率信号&#xff0c;这个高功率信号足以驱动比例阀的开启和关闭。这种技术允许进行非常精细的调节&…

面经分享(Flask,轻量级Web框架)

1. Flask的核心特点 a. 轻量级&#xff1a;核心简洁&#xff0c;只提供了基本的功能&#xff0c;其他高级功能可以通过插件或扩展来添加。 b. 灵活性&#xff1a;允许开发者选择适合自己项目的组件和工具&#xff0c;没有强制的项目结构和设计模式。 c. 易于扩展&#xff1a;提…

深度剖析:网络安全中的红蓝对抗策略

红蓝对抗 红蓝对抗服务方案 在蓝队服务中&#xff0c;作为攻击方将开展对目标资产的模拟入侵&#xff0c;寻找攻击路径&#xff0c;发现安全漏洞和隐患。除获取目标系统的关键信息&#xff08;包括但不限于资产信息、重要业务数据、代码或管理员账号等&#xff09;外&#x…

ubuntu20.04.6将虚拟机用户目录映射为磁盘Z

文章目录 linux虚拟机设置为NAT模式安装sshd服务映射目录到windows磁盘安装samba套件修改配置文件smb.conf重启smbd并设置用户名和密码 windows映射遇到的问题1、设置好之后映射不成功2、smbd下载失败3、smbd密码配置问题4、当有改动时候&#xff0c;最好重启一下smbd服务 linu…

碧桂园服务净利降两成,关联交易收入仅占2.9%,发力增值服务充电桩日进超10万

自2018年分拆上市以来&#xff0c;碧桂园服务经历过非常高速的发展&#xff0c;曾是物管市场的“并购王”&#xff0c;但从2023年开始&#xff0c;希望从外延式的增长向内生式增长转型&#xff0c;将往期的经验与教训&#xff0c;通过投后管理沉淀下来&#xff0c;向高质量发展…

【Ambari】Ansible自动化部署大数据集群

目录 一&#xff0e;版本说明和介绍信息 1.1 大数据组件版本 1.2 Apache Components 1.3 Databases支持版本 二&#xff0e;安装包上传和说明 三&#xff0e;服务器基础环境配置 3.1global配置修改 3.2主机名映射配置 3.3免密用户名密码配置 3.4 ansible安装 四. 安…

2024年MathorCup妈妈杯数学建模思路C题思路解析+参考成品

1 赛题思路 (赛题出来以后第一时间在群内分享&#xff0c;点击下方群名片即可加群) 2 比赛日期和时间 报名截止时间&#xff1a;2024年4月11日&#xff08;周四&#xff09;12:00 比赛开始时间&#xff1a;2024年4月12日&#xff08;周五&#xff09;8:00 比赛结束时间&…

认知觉醒:开启自我改变的原动力-- 读书笔记

文章目录 关于本书以及作者内容第一章 大脑——一切问题的起源摘抄思考 第二章 生命留给我们的彩蛋摘抄思考 第三章 人类的终极能能力摘抄思考 第四章 专注力——情绪和智慧的交叉地带摘抄思考 第五章 学习力——学习不是一味地努力摘抄思考 第六章 行动力——没有行动世界只是…

DFS:floodfill算法解决矩阵联通块问题

floodfill&#xff0c;翻译为洪水灌溉&#xff0c;而floodfill算法本质上是为了解决在矩阵中性质相同的联通块问题。 一、图像渲染 . - 力扣&#xff08;LeetCode&#xff09; class Solution { public:int dx[4]{0,0,1,-1};int dy[4]{1,-1,0,0};int prev;//记住初始值int m,…

《QT实用小工具·十六》IP地址输入框控件

1、概述 源码放在文章末尾 该项目为IP地址输入框控件&#xff0c;主要包含如下功能&#xff1a; 可设置IP地址&#xff0c;自动填入框。 可清空IP地址。 支持按下小圆点自动切换。 支持退格键自动切换。 支持IP地址过滤。 可设置背景色、边框颜色、边框圆角角度。 下面…

2023年度总结:允许迷茫,破除迷茫;专注自身,把握当下

0、前言 &#x1f4dc;为什么24年已经过了几个月&#xff0c;才提笔写这年度总结呢&#xff1f;毫不羞愧直问我的内心&#xff0c;其实就是懒罢了。直到前几天朋友看到了我去年写的总结&#xff0c;我自己点进那篇总结&#xff0c;完完整整的看了一遍&#xff0c;又翻看我23年…