1.浏览器缓存过期机制
1.1 最后修改时间 last-modified
浏览器缓存机制是优化网页加载速度和减少服务器负载的重要手段。以下是关于浏览器缓存过期机制、
Last-Modified
和ETag
的详细讲解:一、
Last-Modified
头部
定义:
Last-Modified
表示服务器上资源的最后修改时间。作用:用于资源的条件请求,帮助浏览器判断缓存的资源是否是最新的。
工作流程:
浏览器第一次请求资源时,服务器返回资源内容和
Last-Modified
时间。下次请求同一资源时,浏览器发送
If-Modified-Since
头部,值为之前的Last-Modified
时间。服务器比较资源的当前修改时间与
If-Modified-Since
的值:
- 如果资源未修改,返回
304 Not Modified
,浏览器继续使用缓存。- 如果资源已修改,返回新的资源内容和更新后的
Last-Modified
时间。示例:
Last-Modified: Wed, 21 Oct 2023 07:28:00 GMT
二、
ETag
头部
定义:
ETag
(Entity Tag)是服务器为资源生成的唯一标识符,通常是资源内容的哈希值或版本号。作用:比
Last-Modified
更加精确,用于验证资源是否变化。工作流程:
浏览器第一次请求资源时,服务器返回资源内容和
ETag
值。下次请求同一资源时,浏览器发送
If-None-Match
头部,值为之前的ETag
。服务器比较当前资源的
ETag
与If-None-Match
的值:
- 如果
ETag
未变化,返回304 Not Modified
,浏览器继续使用缓存。
- 如果
ETag
变化,返回新的资源内容和新的ETag
值。示例:
ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4"
五、
Last-Modified
vsETag
- 精确度:
Last-Modified
仅记录最后修改时间,可能无法检测到在同一秒内的多次修改。ETag
通常基于内容的哈希值,能够更精确地检测到任何变化。- 性能:
- 生成
ETag
可能需要更多的计算资源,尤其是在大规模资源或高频请求的情况下。Last-Modified
相对简单,性能开销较小。- 使用场景:
- 对于静态资源,
ETag
更加适用。- 对于动态资源,可以结合
Last-Modified
和其他缓存策略使用。六、最佳实践
- 合理设置缓存策略:
- 对于不经常变化的静态资源,设置较长的
max-age
以充分利用缓存。- 对于经常变化的资源,使用较短的
max-age
或结合验证机制。- 使用
ETag
和Last-Modified
:
- 同时使用两者可以提供更可靠的缓存验证,但需注意服务器的性能开销。
- 如果服务器性能有限,可以选择只使用其中一个。
- 版本化资源:
- 通过在资源URL中包含版本号(如
style.v1.css
),可以在资源更新时强制浏览器下载新版本,避免缓存问题。七、总结
浏览器缓存机制通过多种HTTP头部字段控制资源的缓存和过期,
Last-Modified
和ETag
是其中重要的验证手段。合理配置这些头部字段,可以显著提升网页性能,优化用户体验,同时有效管理服务器资源。
第一次访问
第二次访问
1.2 Etag 标记
但是如果访问的时间一样的,怎么办?If-Modefied精确到的是秒,要知道的是,计算机一秒中可以干好多事的,比如一秒中修改上千次的图片
# 使用 touch 模拟访问时间是一样的(移走1.jpeg,在重新上传一张图片,重命名为1.jpeg)
[root@Rocky9.4 html]#touch -t 202407020931.48 1.jpeg
第一次访问
第一次访问是由于我将时间设置成一样了,但是因为服务器返回的Etag是新的,而浏览器保存的还是旧的,所以Etag不一致,所以返回状态码是200
第二次访问
第二次访问,Etag也统一了,所以返回了状态码304
1.3 过期时间 expires 和 Cache-Control
一、浏览器缓存机制概述
浏览器缓存通过在本地存储网页资源(如HTML、CSS、JavaScript、图片等),避免每次访问网页时都从服务器重新下载这些资源,从而加快页面加载速度,提高用户体验,同时减少服务器带宽的使用。
明白了,你希望更详细地了解浏览器缓存中的
Expires
和Cache-Control
头部,以及它们之间的关系和具体应用。以下是更深入的讲解:二、
Expires
头部1. 定义与作用
Expires
是一个HTTP响应头,用于指定资源的绝对过期时间。它告诉浏览器在指定的时间之前,可以直接从缓存中使用该资源,而无需向服务器重新请求。2. 格式
Expires
的值是一个绝对的HTTP日期和时间,格式为:Wdy, DD Mon YYYY HH:MM:SS GMT
。示例:
Expires: Wed, 21 Oct 2025 07:28:00 GMT
3. 使用场景
- 适用于静态资源,如图片、CSS、JavaScript文件,这些资源不经常变化。
- 适合设置较长的缓存时间,减少浏览器对服务器的请求频率,提升加载速度。
4. 缺点
- 使用绝对时间,可能受客户端和服务器时间不同步的影响。
- 当资源更新时,若不改变
Expires
,可能导致浏览器继续使用过期的缓存,出现内容不一致的问题。三、
Cache-Control
头部1. 定义与作用
Cache-Control
是一个更为灵活和强大的HTTP响应头,用于控制缓存策略。它可以替代或补充Expires
头部,提供更精确的缓存控制。2. 常用指令
max-age=秒数
:指定资源在多少秒内被认为是新鲜的。max-age
的优先级高于Expires
。示例:
Cache-Control: max-age=3600
no-cache
:资源必须在使用前重新验证(即使资源没有过期)。示例:
Cache-Control: no-cache
no-store
:禁止任何形式的缓存,既不存储请求信息,也不存储响应信息。示例:
Cache-Control: no-store
public
:响应可被任何缓存区缓存,包括浏览器和中间缓存(如CDN)。示例:
Cache-Control: public
private
:响应仅为单个用户缓存,不能被共享缓存(如CDN)缓存。示例:
Cache-Control: private
must-revalidate
:一旦资源过期,必须向服务器验证其有效性。示例:
Cache-Control: must-revalidate
proxy-revalidate
:与must-revalidate
类似,但仅适用于共享缓存。示例:
Cache-Control: proxy-revalidate
3. 使用场景
- 动态资源:可以灵活设置缓存策略,如需要频繁更新但又希望利用缓存提升性能的资源。
- 细粒度控制:通过组合多个指令,实现更复杂的缓存策略。
4. 与
Expires
的关系
- 优先级:当同时存在
Cache-Control: max-age
和Expires
时,Cache-Control
优先级更高。- 推荐使用:现代浏览器和服务器更推荐使用
Cache-Control
,因为它更灵活且不依赖绝对时间。四、
Expires
与Cache-Control
的对比
特性 Expires
Cache-Control
类型 绝对时间 相对时间及其他缓存指令 格式 HTTP日期格式 指令列表 优先级 低于 Cache-Control
高于 Expires
灵活性 较低,只有一个绝对过期时间 高,可以组合多种指令控制缓存行为 推荐使用场景 主要用于向后兼容旧浏览器 现代Web应用的首选缓存控制方式 五、实际应用示例
1. 设置长时间缓存(适用于不经常变化的静态资源)
Cache-Control: public, max-age=31536000 Expires: Wed, 21 Oct 2025 07:28:00 GMT
- 解释:资源可以被公共缓存(如CDN)缓存,且在1年内(31536000秒)不需要重新验证。
2. 设置短时间缓存,需重新验证(适用于可能会频繁更新的资源)
Cache-Control: no-cache
- 解释:浏览器每次使用缓存前必须向服务器验证资源是否有更新。
3. 禁止缓存(适用于敏感数据)
Cache-Control: no-store
- 解释:禁止任何形式的缓存,确保每次请求都从服务器获取最新数据。
六、结合
ETag
和Last-Modified
使用缓存验证即使设置了
Cache-Control
或Expires
,浏览器在某些情况下仍可能需要验证缓存资源的有效性。此时,ETag
和Last-Modified
提供了有效的验证机制:
ETag
:提供资源的唯一标识符,确保缓存的资源与服务器上的一致。Last-Modified
:记录资源的最后修改时间,供浏览器进行条件请求。示例:
Cache-Control: max-age=3600, must-revalidate ETag: "33a64df551425fcc55e4d42a148795d9f25f89d4" Last-Modified: Wed, 21 Oct 2023 07:28:00 GMT
七、最佳实践
- 优先使用
Cache-Control
:
- 由于其灵活性和优先级,现代Web开发中应优先配置
Cache-Control
头部。
- 合理设置
max-age
:
- 根据资源的更新频率,合理设置缓存时间。静态资源可以设置较长时间,动态资源设置较短时间或不缓存。
- 结合使用
ETag
和Last-Modified
:
- 提供双重验证机制,确保缓存的资源始终是最新的。
- 版本化静态资源:
- 通过在资源URL中添加版本号(如
style.v1.css
),确保资源更新时浏览器能够获取到最新版本,避免缓存问题。
- 使用CDN:
- 配合缓存头部,利用内容分发网络(CDN)提升全球范围内的资源加载速度,并有效管理缓存策略。
八、总结
Expires
和Cache-Control
都用于控制资源的缓存和过期,但Cache-Control
提供了更高的灵活性和优先级。ETag
和Last-Modified
是用于缓存验证的强大工具,确保浏览器使用最新的资源。- 最佳实践 是结合使用这些HTTP头部,合理设置缓存策略,提升Web应用的性能和用户体验。
1.4 CDN
CDN(内容分发网络,Content Delivery Network)是一种通过将内容复制并缓存到全球多个地理位置的服务器上,从而加速用户访问速度的技术。它主要的目的是提高网站或应用的性能、稳定性、可扩展性,同时减少服务器负载和带宽消耗。
一、CDN的工作原理
CDN的核心思想是将网站的静态资源(如HTML文件、CSS文件、JavaScript、图片、视频等)缓存到分布在全球的边缘服务器(Edge Servers)上。当用户请求访问某个资源时,CDN会根据用户的地理位置,选择距离用户最近的服务器提供资源,从而减少加载时间和提高访问速度。
1. 资源分发与缓存
- 资源分发:当你将资源上传到CDN服务时,CDN提供商会将这些内容分发到位于世界各地的数据中心。
- 缓存:CDN的服务器会将常用的静态内容缓存到本地存储中,当有新的请求时,如果内容已经存在并且没有过期,则直接返回缓存的内容。
2. 边缘服务器与原始服务器
- 边缘服务器(Edge Server):这些是部署在全球各地的服务器,负责将资源提供给终端用户。用户访问时,通常会被路由到离他们最近的边缘服务器,以减少延迟。
- 原始服务器(Origin Server):原始服务器是网站的源服务器,存储网站的所有内容。如果CDN的边缘服务器没有缓存某个请求的内容,它会从原始服务器获取并返回给用户。
3. 缓存策略
CDN通常会使用一些缓存策略来决定哪些内容需要缓存,以及缓存多久。常见的缓存策略包括:
- 缓存时间(TTL,Time to Live):决定缓存的有效期。例如,静态资源如图片、CSS文件可能会缓存较长时间,而动态内容可能缓存较短时间。
- 缓存控制(Cache-Control):通过设置HTTP头来控制缓存行为(如
max-age
、no-cache
)。- 动态内容缓存:CDN一般针对动态内容(如用户特定数据、实时信息)使用不同的缓存策略,可能会使用“按需缓存”或“低过期时间”的方式进行处理。
4. 智能路由与负载均衡
CDN通常会根据多个因素(如地理位置、网络负载、带宽等)选择最优的边缘服务器来响应用户请求。这一过程称为智能路由或负载均衡。通过此方式,CDN能够确保用户始终通过最快的路径获取到资源。
二、CDN的优势
- 提高加载速度
- 减少延迟:通过将内容分发到全球多个节点,用户总是能够从离自己最近的节点获取资源,从而大幅减少延迟,提高加载速度。
- 更高的可用性:通过分布式缓存,用户能够在多个服务器之间获取资源,即使某个服务器出现故障,也不会影响服务的可用性。
- 减轻原始服务器负载
- CDN缓存了大量静态内容,减少了原始服务器的直接负担,降低了带宽使用和处理请求的压力。
- 提升网站的可扩展性
- CDN帮助网站应对流量激增,能够在不同地区和时段自动调整资源的分配和流量管理,提供更好的扩展性。
- 增强网站的安全性
- DDoS防护:许多CDN提供DDoS攻击防护,能够通过分布式架构分担攻击流量,从而减轻原始服务器的压力。
- SSL加密:CDN服务提供SSL证书支持,帮助加密数据传输,提升安全性。
- 节省带宽成本
- 通过减少从原始服务器到客户端的流量,CDN有助于降低带宽费用,尤其是对于全球性网站。
- 高可用性和容错性
- CDN通过将资源缓存到多个节点,提升了资源的冗余度。在某个节点出现故障时,流量可以被自动引导到其他正常工作的节点,保证网站的高可用性。
三、CDN的类型
- 静态内容CDN
- 主要缓存静态内容,如图片、JavaScript文件、CSS文件等。通过将这些内容缓存到多个位置,能够加速资源加载速度。
- 动态内容CDN
- 动态内容指的是根据用户请求生成的内容,比如数据库查询结果或用户个性化信息。动态内容通常不缓存,但现代CDN提供商提供了对动态内容的优化方案,通过智能缓存策略加速动态内容的加载。
- 直播和视频流CDN
- 专门用于视频流、直播视频内容的传输,优化了大带宽视频数据的分发和传输。常见的技术包括流媒体协议如 HLS(HTTP Live Streaming)和 DASH(Dynamic Adaptive Streaming over HTTP)。
- 边缘计算CDN
- 这种类型的CDN不仅提供缓存功能,还支持在边缘服务器上执行计算任务。它能够在靠近用户的地方处理请求,提高性能和降低延迟。
四、CDN的工作流程
- 资源上传到CDN:
- 将网站的静态资源上传到CDN供应商的服务器。资源可能会分发到多个全球节点进行缓存。
- 用户请求访问资源:
- 用户访问网页时,浏览器向CDN发起请求。CDN会根据用户的地理位置,智能选择离用户最近的服务器响应请求。
- 缓存命中与未命中:
- 如果边缘服务器已缓存该资源(缓存命中),CDN直接返回缓存的内容。
- 如果缓存过期或没有缓存该资源(缓存未命中),CDN会向原始服务器请求资源,并将返回的资源缓存起来供后续用户使用。
- 返回资源给用户:
- 一旦缓存的资源通过CDN的边缘节点返回给用户,用户的浏览器会在本地缓存该资源,下次访问时,直接从浏览器本地获取。
五、CDN的服务提供商
目前,全球有多个主要的CDN服务提供商,最知名的包括:
- Cloudflare
- 提供免费和收费的CDN服务,支持全球分布的边缘节点,提供DDoS防护和Web应用防火墙(WAF)。
- Akamai
- 全球领先的CDN供应商,服务覆盖范围广,适用于大规模企业和高流量网站,提供强大的内容加速和安全功能。
- Amazon CloudFront
- AWS提供的CDN服务,能够与AWS的其他服务(如S3、EC2等)无缝集成,提供高可扩展性和灵活性。
- Fastly
- 以高性能为特点,支持即时缓存清除和高效的动态内容传输,适用于对延迟要求极高的应用。
- KeyCDN
- 提供较为简单和成本效益高的CDN解决方案,适用于中小型网站。
六、CDN的优化策略
- 合理设置缓存过期时间:
- 根据内容的更新频率,合理设置缓存过期时间(TTL),避免缓存过期导致频繁访问原始服务器。
- 使用分布式缓存:
- 利用CDN的全球节点分布,将内容缓存到多个节点,从而提供更好的负载均衡和冗余。
- 压缩和优化内容:
- 对资源进行压缩(如图片、CSS、JavaScript等),减少传输的数据量,提高加载速度。
- 结合HTTPS加密:
- 使用CDN的SSL证书加密功能,为网站提供HTTPS支持,提升数据传输的安全性。
七、总结
CDN是一种通过将网站内容分发到全球多个节点,减少延迟、提高加载速度、减轻服务器负载的技术。它不仅能加速资源的交付,还能提高网站的安全性、可用性和可扩展性。随着互联网应用的增长,CDN已成为优化网站性能和提供全球用户良好体验的重要工具。
1.4.1 用户请求CDN流程
用户请求CDN资源的流程可以分为几个步骤。这个流程涉及到用户如何向CDN发起请求,CDN如何决定从哪个服务器提供资源,以及缓存如何影响响应时间。以下是详细的用户请求CD能资源的流程:
一、请求流程概述
- 用户发起请求:用户的浏览器或应用程序向服务器请求某个资源(如图片、CSS、JavaScript文件等)。
- DNS解析:请求首先通过DNS解析,将资源的域名解析为CDN的IP地址。
- 路由到CDN边缘节点:用户的请求被路由到距离用户最近的CDN边缘节点。
- 边缘节点缓存检查:CDN的边缘节点检查缓存中是否已有该资源。
- 缓存命中或未命中:根据缓存的情况,决定是直接返回缓存的内容,还是从源服务器获取最新的资源。
- 返回资源给用户:资源通过边缘节点传输给用户,用户的浏览器接收并展示。
二、详细步骤
1. 用户发起请求
用户在浏览器中输入网址或点击链接时,浏览器会发起HTTP请求来请求某个资源。这些资源通常是静态文件,如HTML、CSS、JavaScript文件,或者图片、视频等媒体文件。
例如,用户请求资源:
https://www.example.com/images/logo.png
。2. DNS解析
用户请求的域名(如
www.example.com
)会通过DNS解析,转化为一个IP地址。通常,这个域名已经指向CDN提供商的域名解析系统。
- 传统方式:直接访问原始服务器的IP。
- CDN方式:DNS解析返回的是CDN边缘服务器的IP,而不是源服务器的IP。
CDN提供商通常会在多个地理位置部署多个边缘节点(edge node),当请求发起时,DNS会返回离用户最近的CDN边缘节点的IP地址,确保请求被路由到最近的服务器。
3. 请求被路由到CDN边缘节点
DNS解析完成后,浏览器向CDN的边缘节点发送请求。CDN边缘节点是部署在全球各地的服务器,它们缓存了资源内容,能够快速响应用户请求。
CDN边缘节点的选择通常由以下因素决定:
- 地理位置:用户的IP地址与边缘节点的地理位置之间的距离,尽可能选择距离用户最近的节点。
- 网络负载:当前边缘节点的负载情况。如果某个节点过载,CDN会选择其他负载较低的节点。
4. 边缘节点缓存检查
边缘节点收到请求后,会检查缓存中是否已有该资源。这一步称为缓存命中检查。
- 缓存命中:如果边缘节点缓存中已经存在该资源,并且资源没有过期,则直接从缓存中读取并返回给用户。
- 缓存未命中:如果缓存中没有该资源,或者资源已经过期,则会将请求转发给源服务器(origin server)。
5. 缓存命中或未命中
缓存命中:如果资源已经存在并且有效,CDN会直接将缓存的资源返回给用户。这是加速访问的关键步骤,因为用户不需要访问源服务器,节省了时间和带宽。
例如,若用户请求
https://www.example.com/images/logo.png
,CDN的边缘节点可能已经缓存了这个文件,且TTL(过期时间)没有到期,此时CDN直接返回文件。缓存未命中:如果缓存中没有该资源,或者缓存的资源已经过期,CDN会向源服务器发起请求以获取资源。
6. 从源服务器获取资源
当缓存未命中时,CDN边缘节点会向原始服务器(origin server)请求该资源。此时,源服务器会根据请求返回最新的资源,并且将该资源缓存到边缘节点,以供下次请求使用。
- 资源返回后,CDN会缓存到边缘节点并设置适当的缓存过期时间(TTL)。这意味着下一次请求时,边缘节点可以直接返回缓存的内容,而不需要再访问源服务器。
7. 返回资源给用户
无论是缓存命中还是从源服务器获取资源,最终,CDN的边缘节点会把响应数据返回给用户的浏览器。用户的浏览器从CDN边缘节点接收到资源,并进行展示。
8. 浏览器缓存
在资源返回给浏览器后,浏览器也会根据响应头(如
Cache-Control
、Expires
等)进行本地缓存,以便在下一次访问时直接从本地缓存中获取资源,而不再发送请求到CDN或源服务器。三、缓存策略与内容更新
CDN中的缓存策略非常关键,它决定了缓存内容的过期时间、更新方式以及缓存策略的灵活性。
- TTL(Time to Live,生存时间)
- 每个缓存的资源都会设置一个TTL,TTL指定了该资源在CDN边缘节点缓存的有效期。TTL过期后,缓存的内容会被认为是过期的,需要重新向源服务器请求内容。
- 缓存清除
- 主动清除:CDN提供商允许通过管理控制台或API来主动清除缓存中的某些资源。这对于资源更新频繁或紧急更新的情况非常重要。
- 自动清除:当资源的TTL到期时,CDN会自动清除缓存并向源服务器请求新的内容。
- 缓存验证
- 使用
ETag
和Last-Modified
等HTTP头部字段,CDN可以验证缓存是否有效。即使TTL未到期,CDN也可以通过向源服务器发送条件请求(If-None-Match
或If-Modified-Since
)来判断缓存是否需要更新。四、CDN的优势
- 减少延迟:用户总是能从离自己最近的边缘服务器获取资源,减少了传输延迟。
- 提高可用性:即使源服务器宕机,CDN仍可以从其他节点提供缓存的内容,保持服务可用。
- 减轻源服务器负担:通过缓存大量请求,CDN能够减轻源服务器的负载,减少带宽消耗。
- 提高网站性能:加速资源加载,提升用户体验,尤其是对于全球用户。
五、CDN请求流程示意图
用户请求 --> DNS解析 --> CDN边缘节点 --> 缓存检查 --> | | | 缓存命中 缓存未命中 | | | | 返回缓存的资源 从源服务器请求资源 | | | | 返回给用户的资源 缓存资源并返回给用户 |
六、总结
- CDN工作流程:CDN通过将资源分发到多个边缘节点,利用智能路由、缓存和负载均衡技术,将资源快速交付给用户,减少延迟,提高网站性能。
- 缓存命中与未命中:CDN根据缓存策略决定是否直接返回缓存的内容,或者向源服务器请求更新内容。
- 浏览器与CDN缓存:浏览器本地缓存和CDN的缓存共同工作,确保资源加载更快,减少重复请求。
CDN在提高网站性能、增强网站可用性、降低带宽消耗等方面发挥了重要作用,是现代Web应用不可或缺的组成部分。
1.4.2 CDN分层缓存
CDN(Content Delivery Network,内容分发网络)的分层缓存(Layered Caching)是指通过多级缓存架构有效提升内容分发效率的一种策略。在CDN中,请求的内容通常会经过多个层级的缓存节点,以实现更佳的性能和资源利用率。整个流程通常可以分为以下几个层次:
- L1 边缘节点缓存(Edge Cache):
这是离用户最近的一层缓存节点。当用户向CDN请求内容时,边缘节点首先检查本地缓存是否已存有该内容。若存在并未过期,便直接从该节点返回内容给用户,降低传输延迟,提高用户体验;若缓存中无此内容或内容已过期,则向上层的缓存节点或源站请求。- L2 区域或中间层缓存(Mid-Tier/Regional Cache):
当边缘节点未能在本地拿到所需内容时,会将请求向上层的区域缓存节点发出。区域缓存通常位于更靠近源站的核心网络,储存那些在一定时间窗口内被多个边缘节点重复请求的内容。通过在此层进行缓存,CDN减少了向源站多次重复请求同一内容的频率。这一层有助于将热门内容在更广的地理范围内进行共享,降低源站负载,并减少跨区域的回源请求延迟。- 源站(Origin Server):
当所有中间层缓存与边缘缓存均无请求内容时,才会到达最终的源站。源站是内容的原始出处,CDN会从这里获取最新版本的内容,然后将其分发给请求用户,并在适当的层级缓存节点中储存副本,以便满足未来类似请求。分层缓存的工作原理
以下是一个典型的用户请求过程:
- 用户访问网站,请求某个资源(例如一张图片)。
- 用户的DNS解析请求将用户导向离他最近的L1边缘节点。
- L1节点检查自身是否缓存了该资源。
- 如果有,则直接将资源返回给用户,请求结束。这称为“缓存命中”。
- 如果没有,则L1节点向其上层的L2区域节点发起请求。
- L2节点执行相同的检查,查看自身是否缓存了该资源。
- 如果有,则将资源返回给L1节点,L1节点再将其返回给用户。同时,L1节点也会缓存该资源,以便下次相同的请求可以直接命中。
- 如果没有,则L2节点继续向上,向源站发起请求。
- 源站将资源返回给L2节点,L2节点再返回给L1节点,L1节点最终返回给用户。L1和L2节点都会缓存该资源。
分层缓存的优势
- 减轻源站压力: 通过多层缓存,大部分用户请求都可以在L1或L2节点得到满足,大大减少了回源站的请求数量,从而减轻了源站的负载。
- 提高缓存命中率: 分层结构使得更常用的内容可以缓存在更靠近用户的L1节点上,从而提高整体的缓存命中率,减少用户访问延迟。
- 降低网络拥塞: 由于大量请求在CDN内部完成,减少了跨区域和跨运营商的网络传输,有助于缓解网络拥塞。
- 更好的可扩展性: 分层结构使得CDN系统更容易扩展,可以通过增加L1和L2节点来应对不断增长的用户访问量。
分片缓存(Chunked Caching)
在某些情况下,CDN还会使用分片缓存技术,将大文件(例如视频文件)分割成多个小片段(chunks),然后分别缓存这些片段。当用户请求文件时,CDN只需传输用户需要的片段,而不是整个文件。这对于提高大文件传输效率和支持流媒体播放非常有用。
总结
CDN分层缓存是一种有效的提高网站性能和用户体验的技术。通过合理地组织和管理多层缓存节点,CDN可以更好地分配资源,提高缓存命中率,并减轻源站的压力。
2.Redis 安装及连接
Redis简介:
Redis(Remote Dictionary Server)是一个开源的内存数据结构存储系统,可以用作数据库、缓存和消息队列中间件。它以Key-Value形式存储数据,提供多种数据结构和丰富的功能特性。Redis的核心价值在于高速访问、简单的数据操作模型以及丰富的数据结构支持,使其在需要快速读写、实时计算和高并发的场景中表现突出。Redis的主要特性:
内存存储:
Redis将数据存储在内存中,从而达到非常高的访问速度(读写操作通常在微秒级别)。这使其在对实时性要求高的场景(如会话存储、实时排行、实时计数器等)表现优异。多种数据结构支持:
相较于传统的Key-Value存储仅支持字符串,Redis支持多种丰富的数据结构类型,这些数据结构以简单命令即可操作:
- String(字符串):最基础的数据结构,可存储普通字符串、数字、二进制数据。
- Hash(哈希):类似于Key-Value映射的集合,可方便存储对象属性并对属性进行增删改操作。
- List(列表):双端链表实现,支持从头尾插入、弹出元素,可用来实现消息队列、任务列表等功能。
- Set(集合):无序集合结构,支持求交集、并集和差集等集合运算,常用于去重、标签管理。
- Sorted Set(有序集合):每个元素会关联一个分数(score),Redis会根据分数对元素进行排序,可用于排行榜、延时队列等场景。
- Bitmap(位图)、HyperLogLog、Geo(地理位置)等特殊数据类型:满足统计计数、地理位置查询等特殊需求。
持久化能力:
虽然Redis是内存数据库,但它并非易失性存储。Redis提供两种持久化机制,让数据在断电后仍能恢复:
- RDB(Redis Database Backup):定时生成内存快照并持久化到磁盘,恢复速度快,数据略有延迟。
- AOF(Append Only File):将每次写操作以日志的形式追加到文件中,数据恢复更为完整,可根据策略对AOF文件进行定期重写压缩。
可以根据业务需求选择合适的持久化方案,或同时开启RDB和AOF实现数据安全与高效率的折中。
高可用与分布式:
Redis提供主从复制(Master-Slave Replication)实现数据的多份冗余,主节点负责写操作,从节点同步主节点的数据,提供读取分流和故障切换。当主节点出现故障时,可手动或借助Redis Sentinel(哨兵)实现自动故障转移。
对于更大规模的数据集与访问压力,Redis Cluster可以将数据分片至多个节点,提升整体存储能力和吞吐性能。事务支持:
Redis提供简单的事务机制(MULTI/EXEC命令),可以将一组操作打包,保证这些操作的顺序性和原子性。虽然不支持复杂的回滚功能,但事务可以确保一组命令要么都执行要么都不执行。Lua脚本扩展:
Redis内置了Lua解释器,用户可以在Redis内原子执行Lua脚本,对数据进行复杂操作,而无需在客户端与Redis之间多次往返,提高复杂操作的性能和一致性。丰富的使用场景:
凭借高性能和多数据结构支持,Redis可广泛应用于各种场景:
- 缓存热点数据(例如:热门商品信息、用户会话数据、应用程序配置)
- 消息队列与任务调度(利用List或Stream)
- 实时统计(计数器、排行榜、实时分析)
- 分布式锁(利用SetNx命令实现简单的分布式锁机制)
简单易用的命令行与客户端支持:
Redis提供简洁直观的命令行客户端和与主流编程语言(如Java、Python、Go、C#等)兼容的客户端库,降低学习成本与集成难度。
总结:
Redis作为一个内存数据存储系统,具有高性能、丰富的数据类型、灵活的持久化策略以及高可用性架构支持。它在高并发、低延迟与实时处理场景中得到广泛应用,已成为构建现代互联网应用的重要基础组件。
2.1 dnf 安装 Redis
# Rocky 9.4 由系统源提供
[root@redis1.xyy.org ~]#dnf info redis
Name : redis
Version : 6.2.7
Release : 1.el9
Architecture : x86_64
Size : 1.3 M
Source : redis-6.2.7-1.el9.src.rpm
Repository : appstream
Summary : A persistent key-value database
URL : https://redis.io
License : BSD and MIT
Description : Redis is an advanced key-value store. It is often referred to as a data
: structure server since keys can contain strings, hashes, lists, sets and
: sorted sets.
:
: You can run atomic operations on these types, like appending to a string;
: incrementing the value in a hash; pushing to a list; computing set
: intersection, union and difference; or getting the member with highest
: ranking in a sorted set.
:
: In order to achieve its outstanding performance, Redis works with an
: in-memory dataset. Depending on your use case, you can persist it either
: by dumping the dataset to disk every once in a while, or by appending
: each command to a log.
:
: Redis also supports trivial-to-setup master-slave replication, with very
: fast non-blocking first synchronization, auto-reconnection on net split
: and so forth.
:
: Other features include Transactions, Pub/Sub, Lua scripting, Keys with a
: limited time-to-live, and configuration settings to make Redis behave like
: a cache.
:
: You can use Redis from most programming languages also.
[root@Rocky9.4 ~]#
# CentOS 7由 epel 源提供
[root@CentOS7 ~]#yum info redis
Name : redis
Arch : x86_64
Version : 3.2.12
Release : 2.el7
Size : 1.4 M
Repo : installed
From repo : epel
Summary : A persistent key-value database
URL : http://redis.io
License : BSD
[root@redis1.xyy.org ~]#dnf install redis
[root@redis1.xyy.org ~]#systemctl enable --now redis
[root@redis1.xyy.org ~]#pstree -p | grep redis
|-redis-server(4237)-+-{
redis-server}(4238)
| |-{
redis-server}(4239)
| |-{
redis-server}(4240)
| `-{
redis-server}(4241)
[root@redis1.xyy.org ~]#
[root@redis1.xyy.org ~]#redis-cl
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> INFO Server
# Server
redis_version:6.2.7
redis_git_sha1:00000000
redis_git_dirty:0
redis_build_id:ec192bdd77ecd321
redis_mode:standalone
os:Linux 5.14.0-427.13.1.el9_4.x86_64 x86_64
arch_bits:64
monotonic_clock:POSIX clock_gettime
multiplexing_api:epoll
atomicvar_api:c11-builtin
gcc_version:11.3.1
process_id:4237
process_supervised:systemd
run_id:37144e0c3a2930dac6148605d26afae8ee4d38ba
tcp_port:6379
server_time_usec:1734486571682241
uptime_in_seconds:37314
uptime_in_days:0
hz:10
configured_hz:10
lru_clock:6433323
executable:/usr/bin/redis-server
config_file:/etc/redis/redis.conf
io_threads_active:0
127.0.0.1:6379>
2.2 编译安装 Redis
从 Redis 官方下载地址 获取稳定版压缩包,如 redis-7.4.0.tar.gz
。
# 1.创建 Redis 用户(不需要登录权限,只是用于运行 Redis 服务以提高安全性)
useradd -r -s /sbin/nologin redis
# 2.获取源码包
wget https://download.redis.io/releases/redis-7.4.0.tar.gz
# 3.解压并进入源码目录
tar xf redis-7.4.0.tar.gz
cd redis-7.4.0
# 4.开始编译(在某些发行版下可开启 USE_SYSTEMD=yes 选项,以生成可与 systemd 交互的可执行文件。)
make -j $(nproc) USE_SYSTEMD=yes
# 5.安装到指定位置
make PREFIX=/apps/redis install
# 6.建立软链接(方便在命令行中使用redis-server、redis-cli)
ln -s /apps/redis/bin/redis-* /usr/bin/
# 7.创建所需目录
mkdir -p /apps/redis/{
etc,log,data,run}
# 8.拷贝源码目录中自带redis.conf,拷贝到配置目录:
cp redis.conf /apps/redis/etc/
# 9.redis.conf:修改关键配置
#bind:改为 0.0.0.0 或保留默认看实际需要;
#requirepass:设置 Redis 密码,如 requirepass 123456;
#dir:RDB/快照文件存放目录,一般设为 /apps/redis/data;
#logfile:日志文件路径,如 /apps/redis/log/redis-6379.log;
#pidfile:pid 文件路径,如 /apps/redis/run/redis-6379.pid;
sed -i -e 's/bind 127.0.0.1/bind 0.0.0.0/' \
-e "/# requirepass/a requirepass 123456" \
-e "/^dir .*/c dir /apps/redis/data/" \
-e "/^logfile .*/c logfile /apps/redis/log/redis-6379.log" \
-e "/^pidfile .*/c pidfile /apps/redis/run/redis-6379.pid" \
/apps/redis/etc/redis.conf
# 10.设置文件权限
chown -R redis:redis /apps/redis
# 11.内核与系统参数优化(不优化会有告警)
# 11.1 调整内核参数
vim /etc/sysctl.conf
net.core.somaxconn = 1024
vm.overcommit_memory = 1
sysctl -p
# 11.2 禁用透明大页(THP)
echo never > /sys/kernel/mm/transparent_hugepage/enabled
# 可以写入启动脚本(如 /etc/rc.local 或 /etc/rc.d/rc.local)以在重启后继续生效。
# 12.创建Systemd服务并启动
# CentOS/Rocky:/usr/lib/systemd/system/redis.service
# Ubuntu:/lib/systemd/system/redis.service(或 /etc/systemd/system/redis.service)
[Unit]
Description=Redis persistent key-value database
After=network.target
[Service]
ExecStart=/apps/redis/bin/redis-server /apps/redis/etc/redis.conf --supervised systemd
ExecStop=/bin/kill -s QUIT $MAINPID
# 启动notify一定要编译了 USE_SYSTEMD=yes,否则启动服务有问题
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
# 13.刷新并启动服务
systemctl daemon-reload
systemctl enable --now redis
systemctl status redis
# 14.查看Redis版本或者信息
redis-server -v
# 查看服务信息
redis-cli -a 123456 INFO Server
# 测试插入和查询数据
redis-cli -a 123456 set mykey "Hello World"
redis-cli -a 123456 get mykey
#! /bin/bash
#-----------------------------------------------------
#Author: XingYuyu
#Date: 2024-08-12
#Blog: http://8.141.4.74
#Filename: install_redis.sh
#Description: [Online Install Redis for Rocky Linux ,Ubuntu,CentOS ]
#-----------------------------------------------------
VERSION=redis-7.4.0
PASSWORD=123456
INSTALL_DIR=/apps/redis
os_type() {
awk -F'[ "]' '/^NAME/{print $2}' /etc/os-release
}
color() {
RES_COL=80
MOVE_TO_COL="echo -en \e[${RES_COL}G"
SETCOLOR_SUCCESS="echo -en \e[1;32m"
SETCOLOR_FAILURE="echo -en \e[1;31m"
SETCOLOR_WARNING="echo -en \e[1;33m"
SETCOLOR_NORMAL="echo -en \e[0m"
echo -n "$1" && $MOVE_TO_COL
echo -n "["
if [ $2 = "success" -o $2 = "0" ]; then
${SETCOLOR_SUCCESS}
echo -n $" OK "
elif [ $2 = "failure" -o $2 = "1" ]; then
${SETCOLOR_FAILURE}
echo -n $"FAILED"
else
${SETCOLOR_WARNING}
echo -n $"WARNING"
fi
${SETCOLOR_NORMAL}
echo -n $"]"
echo
}
install_redis() {
wget https://download.redis.io/releases/${VERSION}.tar.gz || {
color "Redis 源码下载失败" 1
exit
}
tar xf ${VERSION}.tar.gz
cd ${VERSION}
CPUS=lscpu | awk '/^CPU\(s\)/{print $2}'
make -j $CPUS USE_SYSTEMD=yes PREFIX=${INSTALL_DIR} install && color "Redis 编译安装完成" 0 || {
color "Redis 编译安装失败" 1
exit
}
ln -s ${INSTALL_DIR}/bin/redis-* /usr/bin/
mkdir -p ${INSTALL_DIR}/{
etc,log,data,run}
cp redis.conf ${INSTALL_DIR}/etc/
sed -i -e 's/bind 127.0.0.1/bind 0.0.0.0/' -e "/# requirepass/a requirepass $PASSWORD" -e "/^dir .*/c dir ${INSTALL_DIR}/data/" -e "/^logfile .*/c logfile ${INSTALL_DIR}/log/redis-6379.log" -e "/^pidfile .*/c pidfile ${INSTALL_DIR}/run/redis-6379.pid" ${INSTALL_DIR}/etc/redis.conf
if id redis &>/dev/null; then
color "Redis 用户已经存在,无需创建" 0
else
useradd -r -s /sbin/nologin redis
color "Redis 用户创建成功" 0
fi
chown -R redis.redis ${INSTALL_DIR}
cat >>/etc/sysctl.conf <<EOF
net.core.somaxconn = 1024
vm.overcommit_memory = 1
EOF
sysctl -p
if [ `os_type` == "Ubuntu" ];then
cat >> /lib/systemd/system/rc-local.service <<EOF
[Install]
WantedBy=multi-user.target
EOF
echo '#!/bin/bash' > /etc/rc.local
echo 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' >>/etc/rc.local
chmod +x /etc/rc.local
/etc/rc.local
# Ubuntu 的service文件放在/lib/systemd/system/下或者/etc/systemd/system/下不能放在/usr/lib/下
cat > /lib/systemd/system/redis.service <<EOF
[Unit]
Description=Redis persistent key-value database
After=network.target
[Service]
ExecStart=${INSTALL_DIR}/bin/redis-server ${INSTALL_DIR}/etc/redis.conf --supervised systemd
ExecStop=/bin/kill -s QUIT \$MAINPID
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
EOF
else
echo 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' >>/etc/rc.d/rc.local
chmod +x /etc/rc.d/rc.local
/etc/rc.d/rc.local
cat > /usr/lib/systemd/system/redis.service <<EOF
[Unit]
Description=Redis persistent key-value database
After=network.target
[Service]
ExecStart=${INSTALL_DIR}/bin/redis-server ${INSTALL_DIR}/etc/redis.conf --supervised systemd
ExecStop=/bin/kill -s QUIT \$MAINPID
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
EOF
fi
systemctl daemon-reload
systemctl enable --now redis &>/dev/null
systemctl is-active redis &> /dev/null && color "Redis 服务启动成功,Redis信息如下:" 3 || {
color "Redis 启动失败" 1 ;exit; }
#sleep 5
redis-cli -a $PASSWORD INFO Server 2>/dev/null
}
install_CentOS7() {
. /etc/init.d/functions
# jemalloc-devel依赖于epel源
yum -y install epel-release && yum -y install gcc jemalloc-devel systemd-devel || {
color "安装软件包失败,请检查网络配置" 1
exit
}
rpm -q wget &>/dev/null || yum -y install wget &>/dev/null
wget https://download.redis.io/releases/${VERSION}.tar.gz || {
action "Redis 源码下载失败" false
exit
}
tar xf ${VERSION}.tar.gz
cd ${VERSION}
CPUS=lscpu | awk '/^CPU\(s\)/{print $2}'
make -j $CPUS USE_SYSTEMD=yes PREFIX=${INSTALL_DIR} install && action "Redis 编译安装完成" || {
action "Redis 编译安装失败" false
exit
}
ln -s ${INSTALL_DIR}/bin/redis-* /usr/bin/
mkdir -p ${INSTALL_DIR}/{
etc,log,data,run}
cp redis.conf ${INSTALL_DIR}/etc/
sed -i -e 's/bind 127.0.0.1/bind 0.0.0.0/' -e "/# requirepass/a requirepass $PASSWORD" -e "/^dir .*/c dir ${INSTALL_DIR}/data/" -e "/^logfile .*/c logfile ${INSTALL_DIR}/log/redis-6379.log" -e "/^pidfile .*/c pidfile ${INSTALL_DIR}/run/redis-6379.pid" ${INSTALL_DIR}/etc/redis.conf
if id redis &>/dev/null; then
action "Redis 用户已经存在" false
else
useradd -r -s /sbin/nologin redis
fi
chown -R redis.redis ${INSTALL_DIR}
cat >>/etc/sysctl.conf <<EOF
net.core.somaxconn = 1024
vm.overcommit_memory = 1
EOF
sysctl -p
echo 'echo never > /sys/kernel/mm/transparent_hugepage/enabled' >>/etc/rc.d/rc.local
chmod +x /etc/rc.d/rc.local
/etc/rc.d/rc.local
cat >/usr/lib/systemd/system/redis.service <<EOF
[Unit]
Description=Redis persistent key-value database
After=network.target
[Service]
ExecStart=${INSTALL_DIR}/bin/redis-server ${INSTALL_DIR}/etc/redis.conf --supervised systemd
ExecReload=/bin/kill -s HUP \$MAINPID
ExecStop=/bin/kill -s QUIT \$MAINPID
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable --now redis &>/dev/null
systemctl is-active redis &> /dev/null && ${COLOR}"Redis 服务启动成功,Redis信息如下:"${END} || {
${COLOR}"Redis 启动失败"${END};exit; }
#sleep 5
redis-cli -a $PASSWORD INFO Server 2>/dev/null
}
install_Ubuntu() {
apt -y install make gcc libjemalloc-dev libsystemd-dev || {
color "安装软件包失败,请检查网络配置" 1
exit
}
install_redis
}
install_Rocky() {
# jemalloc-devel依赖于epel源
yum -y install epel-release && yum -y install gcc jemalloc-devel systemd-devel || {
color "安装软件包失败,请检查网络配置" 1
exit
}
rpm -q wget &>/dev/null || yum -y install wget &>/dev/null
install_redis
}
if [ $(os_type) == 'CentOS' ]; then
install_CentOS7
elif [ $(os_type) == 'Rocky' ]; then
install_Rocky
elif [ $(os_type) == 'Ubuntu' ]; then
install_Ubuntu
else
color "未识别的操作系统" 1
fi
2.3 连接到 Redis
2.3.1 客户端连接到 Redis
1.本机无密码连接
redis-cli
2.跨主机无密码连接
redis-cli -h HOSTNAME/IP -p PORT
3.跨主机密码连接
redis-cli -h HOSTNAME/IP -p PORT -a PASSWORD
2.3.2 程序连接 Redis
redis 支持多种开发语言访问
https://redis.io/docs/latest/develop/clients/
shell 脚本写入数据到 Redis
#!/bin/bash
NUM=100
PASS=123456
for i in `seq $NUM`; do
redis-cli -h 127.0.0.1 -a "$PASS" --no-auth-warning set key${i} value${i}
echo "key${i} value${i} 写入完成"
done
echo "$NUM 个key写入到Redis完成"
3.Redis 的多实例
在生产环境中,为了更好地利用资源、实现多租户隔离或分离不同业务的数据与配置,运维人员往往会在一台服务器上运行多个 Redis 实例。Redis 的多实例部署并非Redis内建的特性,而是通过为每个实例指定独立的配置文件、独立的运行端口与数据目录来实现的。以下是关于Redis多实例的详细讲解:
为什么需要多实例
- 资源隔离与多租户支持:
在某些场景下,不同的业务线或不同的用户需要独立的Redis服务,以免数据和性能相互影响。多实例可以为每个业务运行独立的Redis,保证数据和访问流量的隔离。- 不同的配置要求:
某些业务可能需要不同的持久化策略(RDB或AOF)、内存管理策略或安全设置。多实例部署允许针对每个实例使用单独的配置文件,从而灵活定制每个实例的行为。- 更好地利用硬件资源:
一台物理机/虚拟机的CPU、内存、网络资源较为充裕时,可以在同一台机器上运行多个Redis实例,充分利用硬件资源。尤其在内存较大时,不同实例分别作为缓存、队列、会话存储使用,可以最大化硬件利用率。配置多实例的关键点
独立的配置文件:
每个实例都需要一个独立的配置文件(例如redis-6379.conf
,redis-6380.conf
)。
在配置文件中需要注意如下参数:
port
:每个实例必须使用不同的端口,如6379、6380、6381等。pidfile
:每个实例需要独立的PID文件,如/var/run/redis_6379.pid
、/var/run/redis_6380.pid
。logfile
:为每个实例指定独立的日志文件,如/var/log/redis_6379.log
、/var/log/redis_6380.log
。dir
:为每个实例指定独立的数据目录,如/var/lib/redis/6379/
、/var/lib/redis/6380/
,确保RDB或AOF文件不冲突。daemonize yes
:通常在生产中,多实例都以守护进程方式后台运行。利用 systemd 的进程监督能力,即使用--supervised systemd
参数时,必须将daemonize
设为no
。如果将daemonize
设为yes
,则与 systemd 的监督模式相矛盾,导致 Redis 无法正常通过 systemd 进行管理和监控。独立的启动命令:
启动时为每个实例指定相应的配置文件。常用命令形式:redis-server /path/to/redis-6379.conf redis-server /path/to/redis-6380.conf
确保每个实例正常监听自己的端口并使用自己的配置。
服务管理与守护进程:
为每个实例创建单独的systemd服务文件或init脚本,方便运维管理。如在systemd中创建/etc/systemd/system/redis@6379.service
、redis@6380.service
等文件,然后通过systemctl start redis@6379
启动指定实例。安全与访问控制:
确保为每个实例设置合理的访问控制,如bind
参数、protected-mode
设置、requirepass
或ACL策略。多实例运行时应确保不同实例的数据和访问策略独立,避免安全隐患。监控与报警:
多实例运行时需要对每个实例分别进行监控,收集其内存使用、连接数、QPS、延迟、慢查询等指标,并对异常情况及时报警。举例:多实例文件组织形式
/etc/redis/ ├─ redis-6379.conf ├─ redis-6380.conf └─ redis-6381.conf /var/lib/redis/ ├─ 6379/ │ ├─ dump.rdb │ └─ appendonly.aof ├─ 6380/ │ ├─ dump.rdb │ └─ appendonly.aof └─ 6381/ ├─ dump.rdb └─ appendonly.aof /var/log/ ├─ redis_6379.log ├─ redis_6380.log └─ redis_6381.log
总结
Redis多实例部署是通过为每个实例提供独立的端口、独立的配置文件以及数据和日志目录来实现的。这种方式在同一台服务器上实现了灵活的资源分配和多租户支持。通过精心配置和管理,运维人员能够同时运行多个Redis实例,为不同应用提供高效、独立而又经济实惠的内存数据存储服务。
案例:以编译安装为例实现 Redis 多实例
# 生成的文件列表
[root@Rocky9.4 ~]#ll /apps/redis/
total 0
drwxr-xr-x 2 redis redis 134 Dec 17 23:22 bin
drwxr-xr-x 2 redis redis 22 Dec 18 20:04 data
drwxr-xr-x 2 redis redis 24 Dec 18 20:04 etc
drwxr-xr-x 2 redis redis 28 Dec 17 23:22 log
drwxr-xr-x 2 redis redis 28 Dec 18 20:04 run
[root@Rocky9.4 redis]#tree /apps/redis/
/apps/redis/
├── bin
│ ├── redis-benchmark
│ ├── redis-check-aof -> redis-server
│ ├── redis-check-rdb -> redis-server
│ ├── redis-cli
│ ├── redis-sentinel -> redis-server
│ └── redis-server
├── data
│ ├── dump-6379.rdb
│ ├── dump-6380.rdb
│ └── dump-6381.rdb
├── etc
│ ├── redis_6379.conf
│ ├── redis_6380.conf
│ ├── redis_6381.conf
│ └── redis.conf
├── log
│ ├── redis-6379.log
│ ├── redis-6380.log
│ └── redis-6381.log
└── run
├── redis-6379.pid
├── redis-6380.pid
└── redis-6381.pid
5 directories, 19 files
# 配置文件需要修改的地方
vim /apps/redis/etc/redis_6379.conf
bind 0.0.0.0 -::1
port 6379
daemonize no
pidfile /apps/redis/run/redis-6379.pid
logfile /apps/redis/log/redis-6379.log
# 写入数据的时候,并且满足save才会生产dump-6379.rdb这个文件
dbfilename dump-6379.rdb
dir /apps/redis/data/
# 3600秒,写一次数据 300秒,100次数据,60秒,10000次数据 满足就会备份,为了更快的看到效果可以更改,例如:save 60 1
save 3600 1 300 100 60 10000
appendfilename "appendonly-6379.aof"
vim /apps/redis/etc/redis_6380.conf
bind 0.0.0.0 -::1
port 6380
daemonize no
pidfile /apps/redis/run/redis-6380.pid
logfile /apps/redis/log/redis-6380.log
dbfilename dump-6380.rdb
dir /apps/redis/data/
save 3600 1 300 100 60 10000
appendfilename "appendonly-6380.aof"
vim /apps/redis/etc/redis_6381.conf
bind 0.0.0.0 -::1
port 6381
daemonize no
pidfile /apps/redis/run/redis-6381.pid
logfile /apps/redis/log/redis-6381.log
dbfilename dump-6381.rdb
dir /apps/redis/data/
save 3600 1 300 100 60 10000
appendfilename "appendonly-6381.aof"
# 创建service文件
# 1./usr/lib/systemd/system/redis6379.service
[Unit]
Description=Redis persistent key-value database
After=network.target
[Service]
ExecStart=/apps/redis/bin/redis-server /apps/redis/etc/redis_6379.conf --supervised systemd
ExecStop=/bin/kill -s QUIT $MAINPID
Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
[root@Rocky9.4 ~]#
# 2./usr/lib/systemd/system/redis6380.service
[Unit]
Description=Redis persistent key-value database
After=network.target
[Service]
ExecStart=/apps/redis/bin/redis-server /apps/redis/etc/redis_6380.conf --supervised systemd
ExecStop=/bin/kill -s QUIT $MAINPID
#Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
[root@Rocky9.4 ~]#
# 3./usr/lib/systemd/system/redis6381.service
[Unit]
Description=Redis persistent key-value database
After=network.target
[Service]
ExecStart=/apps/redis/bin/redis-server /apps/redis/etc/redis_6381.conf --supervised systemd
ExecStop=/bin/kill -s QUIT $MAINPID
#Type=notify
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0755
[Install]
WantedBy=multi-user.target
[root@Rocky9.4 ~]#
systemctl daemon-reload
systemctl enable --now redis6379.service redis6380.service redis6381.service
# 这里有个问题,通过二进制安装好的Redis,start的时候用tab键无法补全
4.Redis 持久化
Redis 是一个基于内存的数据结构存储系统,但它提供了多种持久化机制,可以将内存中的数据保存到磁盘中,从而在 Redis 重启或服务器宕机后依然能够恢复数据。Redis 主要提供了两种持久化方式:RDB(Redis Database) 和 AOF(Append Only File)。这两种方式可以单独使用,也可以配合使用,具体选择取决于业务需求(对数据一致性、写入性能、磁盘空间等的不同要求)。
4.1 RDB(Redis Database)
RDB 方式是 Redis 最早的持久化模式,即在某个时间点对内存数据做快照,并保存到一个 .rdb
文件中
4.1.1 RDB 的工作机制
方法1:
SAVE 命令是“阻塞式”保存,Redis 不会创建子进程,而是直接由主进程把内存数据写到 RDB 文件里。
[root@Rocky9.4 redis]#( redis-cli -a 123456 save & );pstree -p | grep redis-server;ls /apps/redis/data/ -lh
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
|-redis-server(28847)-+-{
redis-server}(28854)
| |-{
redis-server}(28855)
| |-{
redis-server}(28856)
| |-{
redis-server}(28857)
| `-{
redis-server}(28858)
total 180M
-rw-r--r-- 1 redis redis 180M Dec 23 18:48 dump_6379.rdb
-rw-r--r-- 1 redis redis 48K Dec 23 21:45 temp-28847.rdb
使用 python 脚本存入一千万条数据,再进行备份看到下面的现象
# 这个需要使用pip install redis来安装redis包
import redis
pool=redis.ConnectionPool(host="10.0.0.41",port=6379,password="123456")
r=redis.Redis(connection_pool=pool)
for i in range(10000000):
r.set("k%d" % i,"v%d" % i)
data=r.get("k%d" % i)
print(data)
方法2:
BGSAVE 才是“后台”保存,Redis 会 fork 一个子进程来完成 RDB 持久化,主进程继续对外提供服务。
[root@Rocky9.4 data]#redis-cli -a 123456
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
127.0.0.1:6379> bgsave
Background saving started
127.0.0.1:6379>
# 生产临时文件,fork 子进程 pid是920,从temp-920.rdb也可以看出是进程920在备份
[root@Rocky9.4 data]#pstree -p | grep redis-server;ls /apps/redis/data/ -lh
|-redis-server(638)-+-redis-server(920)
| |-{
redis-server}(666)
| |-{
redis-server}(667)
| |-{
redis-server}(668)
| |-{
redis-server}(669)
| `-{
redis-server}(671)
total 128M
-rw-r--r-- 1 redis redis 67M Dec 24 14:43 temp-920.rdb
# 备份结束以后,将文件重命名
[root@Rocky9.4 data]#pstree -p | grep redis-server;ls /apps/redis/data/ -lh
|-redis-server(638)-+-{
redis-server}(666)
| |-{
redis-server}(667)
| |-{
redis-server}(668)
| |-{
redis-server}(669)
| `-{
redis-server}(671)
total 180M
-rw-r--r-- 1 redis redis 180M Dec 24 14:43 dump_6379.rdb
# 也可以查看日志
[root@Rocky9.4 data]#tail -f ../log/redis-6379.log
# bgsave的日志,会显示出具体的子进程编号
638:M 24 Dec 2024 15:15:14.746 * Background saving started by pid 1037
1037:C 24 Dec 2024 15:15:22.016 * DB saved on disk
1037:C 24 Dec 2024 15:15:22.026 * Fork CoW for RDB: current 0 MB, peak 0 MB, average 0 MB
638:M 24 Dec 2024 15:15:22.095 * Background saving terminated with success
# save的日志
638:M 24 Dec 2024 15:20:09.364 * DB saved on disk
方法3:
Redis 会在配置文件中设置触发 RDB 生成快照