基于Redis和Nginx实现高并发缓存架构

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 基于Redis和Nginx实现高并发缓存架构

1 缓存架构设计

一谈到缓存架构,很多人想到的是Redis,但其实整套体系的缓存架构并非只有Redis,而应该是多个层面多个软件结合形成一套非常良性的缓存体系。比如下面缓存架构设计就涉及到了多个层面的缓存软件。本文只提供思路不提供整体代码

1.1 缓存架构设计

架构图综合了多种缓存和多层面的缓存设计,从前端页面缓存到代理服务器lvs和nginx缓存,以及后端服务redis缓存,包括缓存数据同步等。

对上述架构,我们来个宏观解说:


1、HTML页面做缓存,浏览器端可以缓存HTML页面和其他静态资源,防止用户频繁刷新对后端造成巨大压力

2、Lvs实现记录不同协议以及不同用户请求链路缓存

3、Nginx这里会做HTML页面缓存配置以及Nginx自身缓存配置

4、数据查找这里用Lua取代了其他语言查找,提高了处理的性能效率,并发处理能力将大大提升

5、数据缓存采用了Redis集群+主从架构,并实现缓存读写分离操作 6、集成Canal实现数据库数据增量实时同步Redis

2 Redis集群高级应用

这里安装6个redis,配置如下:

点击跳转:redis集群部署

3 Nginx缓存

为了提升网站的整体性能,我们一般会采用缓存,从宏观层面来说,会采用浏览器缓存和后端缓存,Nginx处于Web网站的服务最外层,而且支持浏览器缓存配置和后端数据缓存,用它来做部分数据缓存,效率更高。

Web缓存是可以自动保存常见文档副本的HTTP 设备。当Web请求抵达缓存时,如果本地有“已缓存的”副本,就可以从本地设备而不是服务器中提取这个文 档。


3.1 OpenRestry安装

OpenResty® 是一个基于 Nginx 与 Lua 的高性能 Web 平台,其内部集成了大量精良的 Lua 库、第三方模块以及大多数的依赖项。用于方便地搭建能够处理超高并发、扩展性极高的动态 Web 应用、 Web 服务和动态网关。


OpenResty 通过lua脚本扩展 nginx 功能,可提供负载均衡、请求路由、安全认证、服务鉴权、流量控制与日志监控等服务。


OpenResty® 通过汇聚各种设计精良的 Nginx 模块(主要由 OpenResty 团队自主开发),从而将 Nginx 有效地变成一个强大的通用 Web 应用平台。这样, Web 开发人员和系统工程师可以使用 Lua 脚本语言调动 Nginx 支持的各种 C 以及 Lua 模块,快速构造出足以胜任 10K 乃至 1000K 以上单机并发连接的高性能 Web 应用系统。


关于 OpenRestry 的学习,大家可以参考:http://openresty.org/cn/


安装依赖库

yum install wget libtermcap-devel ncurses-devel libevent-devel readline-devel pcre-devel gcc
openssl openssl-devel per

下载安装包

wget https://openresty.org/download/openresty-1.11.2.5.tar.gz

解压安装

tar -xf openresty-1.11.2.5.tar.gz
cd openresty-1.11.2.5
./configure --prefix=/usr/local/openresty --with-luajit --without-http_redis2_module --with-
http_stub_status_module --with-http_v2_module --with-http_gzip_static_module --with-
http_sub_module --add-module=/usr/local/server/ngx_cache_purge-2.3/
make && make install

安装完成后,在 /usr/local/openrestry/nginx 目录下是安装好的nginx。

3.2 浏览器缓存

客户端侧缓存一般指的是浏览器缓存、app缓存等等,目的就是加速各种静态资源的访问,降低服务器压力。

我们通过配置Nginx设置网页缓存信息,从而降低用户对服务器频繁访问造成的巨大压力。我们先配置一个案例,再

基于案例去讲解Nginx缓存。

3.2.1 Nginx Web缓存配置

nginx 提供了 expires 、 etag 、 if-modified-since 指令来进行浏览器缓存控制。我们使用 expires 来配置Nginx对网页的缓存。


语法: expires [modified] time; 默认值: expires off;

上下文: http, server,

location, if in location


上传html

将1.html上传到服务器的 /usr/local/server/html 目录下。

配置nginx

修改 /usr/local/openrestry/nginx/conf/nginx.conf 文件,配置如下:

    server {
        listen 80;
        server_name localhost;
        location / {
         #静态文件路径
        root /usr/local/server/html;
         #缓存10秒
        expires 10s;
}
    }

过期时间配置说明

expires 30s; #30秒
expires 30m; #30分钟
expires 2h; #2个小时
expires 30d; #30天

第一次请求<http://192.168.211.141/1.html>

第二次请求 <http://192.168.211.141/1.html>

3.2.2 Http缓存控制头

参数说明:


HTTP 中最基本的缓存机制,涉及到的 HTTP 头字段,包括 Cache-Control, Last-Modified, If-Modified-Since, Etag,If-None-Match 等。


Last-Modified/If-Modified-Since


Etag是服务端的一个资源的标识,在 HTTP 响应头中将其传送到客户端。所谓的服务端资源可以是一个Web页面,也可以是JSON或XML等。服务器单独负责判断记号是什么及其含义,并在HTTP响应头中将其传送到客户端。比如,浏览器第一次请求一个资源的时候,服务端给予返回,并且返回了ETag: “50b1c1d4f775c61:df3” 这样的字样给浏览器,当浏览器再次请求这个资源的时候,浏览器会将If-None-Match: W/“50b1c1d4f775c61:df3” 传输给服务端,服务端拿到该ETAG,对比资源是否发生变化,如果资源未发生改变,则返回304HTTP状态码,不返回具体的资源。


Last-Modified :标示这个响应资源的最后修改时间。web服务器在响应请求时,告诉浏览器资源的最后修改时间。


If-Modified-Since :当资源过期时(使用Cache-Control标识的max-age),发现资源具有 Last-Modified 声明,则再次向web服务器请求时带上头。


If-Modified-Since ,表示请求时间。web服务器收到请求后发现有头 If-Modified-Since 则与被请求资源的最后修改时间进行比对。若最后修改时间较新,说明资源有被改动过,则响应整片资源内容(写在响应消息包体内),HTTP 200;若最后修改时间较旧,说明资源无新修改,则响应 HTTP 304 (无需包体,节省浏览),告知浏览器继续使用所保存的 cache


Pragma行是为了兼容 HTTP1.0 ,作用与 Cache-Control: no-cache 是一样的


Etag/If-None-Match

Etag :web服务器响应请求时,告诉浏览器当前资源在服务器的唯一标识(生成规则由服务器决定),如果给定URL中的资源修改,则一定要生成新的Etag值。


If-None-Match :当资源过期时(使用Cache-Control标识的max-age),发现资源具有Etage声明,则再次向web服务

器请求时带上头 If-None-Match (Etag的值)。web服务器收到请求后发现有头 If-None-Match 则与被请求资源的相应校验串进行比对,决定返回200或304。


Etag:

Last-Modified 标注的最后修改只能精确到秒级,如果某些文件在1秒钟以内,被修改多次的话,它将不能准确标注文件的修改时间,如果某些文件会被定期生成,当有时内容并没有任何变化,但 Last-Modified 却改变了,导致文件没法使用缓存有可能存在服务器没有准确获取文件修改时间,或者与代理服务器时间不一致等情形 Etag是服务器自动生成或者由开发者生成的对应资源在服务器端的唯一标识符,能够更加准确的控制缓存。 Last-Modified 与 ETag 是可以一起使用的,服务器会优先验证 ETag ,一致的情况下,才会继续比对 Last-Modified ,最后才决定是否返回304。

3.3 代理缓存

用户如果请求获取的数据不是需要后端服务器处理返回,如果我们需要对数据做缓存来提高服务器的处理能力,我们

可以按照如下步骤实现:


1、请求Nginx,Nginx将请求路由给后端服务

2、后端服务查询Redis或者MySQL,再将返回结果给Nginx

3、Nginx将结果存入到Nginx缓存,并将结果返回给用户

4、用户下次执行同样请求,直接在Nginx中获取缓存数据

3.3.1 proxy_cache

proxy_cache 是用于 proxy 模式(一般也可称为反代)的缓存功能,proxy_cache 在 Nginx 配置的 http 段、server

段(location 段)中分别写入不同的配置。http 段中的配置用于定义 proxy_cache 空间,server 段中的配置用于调

用 http 段中的定义,启用对 server 的缓存功能。

属性使用说明proxy_cache_path:


Example

proxy_cache_path /usr/local/openresty/nginx/cache levels=1:2

keys_zone=openresty_cache:10m max_size=10g inactive=60m use_temp_path=off;


【作用】指定缓存存储的路径,缓存存储在/usr/local/openresty/nginx/cache目录


【levels=1:2】设置一个两级目录层次结构存储缓存,在单个目录中包含大量文件会降低文件访问速度,因此我们建议对大多数部署使用两级目录层次结构。如果 levels 未包含该参数,Nginx 会将所有文件放在同一目录中。


【keys_zone=openresty_cache:10m】设置共享内存区域,用于存储缓存键和元数据,例如使用计时器。拥有内存中的密钥副本,Nginx 可以快速确定请求是否是一个 HIT 或 MISS 不必转到磁盘,从而大大加快了检查速度。1 MB 区域可以存储大约 8,000 个密钥的数据,因此示例中配置的 10 MB 区域可以存储大约 80,000 个密钥的数据。


【max_size=10g】设置缓存大小的上限。它是可选的; 不指定值允许缓存增长以使用所有可用磁盘空间。当缓存大小达到限制时,一个称为缓存管理器的进程将删除最近最少使用的缓存,将大小恢复到限制之下的文件。


【inactive=60m】指定项目在未被访问的情况下可以保留在缓存中的时间长度。在此示例中,缓存管理器进程会自动从缓存中删除 60 分钟未请求的文件,无论其是否已过期。默认值为 10 分钟(10m)。非活动内容与过期内容不同。Nginx 不会自动删除缓存 header 定义为已过期内容(例如 Cache-Control:max-age=120)。过期(陈旧)内容仅在指定时间内未

被访问时被删除。访问过期内容时,Nginx 会从原始服务器刷新它并重置 inactive 计时器。


【use_temp_path=off】表示NGINX会将临时文件保存在缓存数据的同一目录中。这是为了避免在更新缓存时,磁盘之间互相复制响应数据,我们一般关闭该功能。


proxy_cache:


设置是否开启对后端响应的缓存,如果开启的话,参数值就是zone的名称,比如:proxy_cache openresty_cache;


proxy_cache_valid:


针对不同的response code设定不同的缓存时间,如果不设置code,默认为200,301,302,也可以用any指定所有code

Example:

【proxy_cache_valid 200 304 10s;】所有200/304响应的数据都缓存10秒。

【proxy_cache_valid any 1m;】所有请求响应的值都缓存1分钟。


proxy_cache_min_uses:


指定在多少次请求之后才缓存响应内容,这里表示将缓存内容写入到磁盘。 Example: 【proxy_cache_min_uses 3;】同一个请求达到了3次,才将缓存写入磁盘。


proxy_cache_lock:


默认不开启,开启的话则每次只能有一个请求更新相同的缓存,其他请求要么等待缓存有数据要么限时等待锁释放;nginx1.1.12才开始有。


proxy_cache_key:


缓存文件的唯一key,可以根据它实现对缓存文件的清理操作

3.3.2 缓存操作

我们在 nginx.conf 中添加如下配置:

        #缓存配置
        proxy_cache_path /usr/local/openresty/nginx/cache levels=1:2 keys_zone=openresty_cache:10m
        max_size=10g inactive=60m use_temp_path=off;
        server {
        listen 80;
        server_name localhost;
        #html配置
        location ~ \.html {
        #静态文件路径
        root /usr/local/server/html;
        #缓存10秒
        expires 10s;
        }
        #非html配置
        location / {
        #启用缓存openresty_cache
        proxy_cache openresty_cache;
        #针对指定请求缓存
        #proxy_cache_methods GET;
        #设置指定请求会缓存
        proxy_cache_valid 200 304 10s;
        #最少请求1次才会缓存
        proxy_cache_min_uses 3;
        #如果并发请求,只有第1个请求会去服务器获取数据
        #proxy_cache_lock on;
        #唯一的key
        proxy_cache_key $host$uri$is_args$args;
        proxy_pass http://myip:18081;
      }
  }

此时 /usr/local/openresty/nginx/cache 目录下只有1个temp文件夹。

我们执行3次请求 <http://192.168.211.141/user/wangwu> ,可以发现此时多了一些其他目录,这些目录就是存

储每个请求对应的缓存。

4 Canal的使用

java利用canal监听数据库

大数据同步工具Canal

相关实践学习
基于Redis实现在线游戏积分排行榜
本场景将介绍如何基于Redis数据库实现在线游戏中的游戏玩家积分排行榜功能。
云数据库 Redis 版使用教程
云数据库Redis版是兼容Redis协议标准的、提供持久化的内存数据库服务,基于高可靠双机热备架构及可无缝扩展的集群架构,满足高读写性能场景及容量需弹性变配的业务需求。 产品详情:https://www.aliyun.com/product/kvstore &nbsp; &nbsp; ------------------------------------------------------------------------- 阿里云数据库体验:数据库上云实战 开发者云会免费提供一台带自建MySQL的源数据库&nbsp;ECS 实例和一台目标数据库&nbsp;RDS实例。跟着指引,您可以一步步实现将ECS自建数据库迁移到目标数据库RDS。 点击下方链接,领取免费ECS&amp;RDS资源,30分钟完成数据库上云实战!https://developer.aliyun.com/adc/scenario/51eefbd1894e42f6bb9acacadd3f9121?spm=a2c6h.13788135.J_3257954370.9.4ba85f24utseFl
目录
相关文章
|
6天前
|
存储 缓存 NoSQL
解决Redis缓存数据类型丢失问题
解决Redis缓存数据类型丢失问题
121 85
|
3天前
|
缓存 监控 NoSQL
Redis经典问题:缓存穿透
本文详细探讨了分布式系统和缓存应用中的经典问题——缓存穿透。缓存穿透是指用户请求的数据在缓存和数据库中都不存在,导致大量请求直接落到数据库上,可能引发数据库崩溃或性能下降。文章介绍了几种有效的解决方案,包括接口层增加校验、缓存空值、使用布隆过滤器、优化数据库查询以及加强监控报警机制。通过这些方法,可以有效缓解缓存穿透对系统的影响,提升系统的稳定性和性能。
|
1月前
|
缓存 NoSQL 关系型数据库
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
本文详解缓存雪崩、缓存穿透、缓存并发及缓存预热等问题,提供高可用解决方案,帮助你在大厂面试和实际工作中应对这些常见并发场景。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:如何解决Redis缓存雪崩、缓存穿透、缓存并发等5大难题
|
26天前
|
NoSQL Java 数据处理
基于Redis海量数据场景分布式ID架构实践
【11月更文挑战第30天】在现代分布式系统中,生成全局唯一的ID是一个常见且重要的需求。在微服务架构中,各个服务可能需要生成唯一标识符,如用户ID、订单ID等。传统的自增ID已经无法满足在集群环境下保持唯一性的要求,而分布式ID解决方案能够确保即使在多个实例间也能生成全局唯一的标识符。本文将深入探讨如何利用Redis实现分布式ID生成,并通过Java语言展示多个示例,同时分析每个实践方案的优缺点。
55 8
|
1月前
|
缓存 NoSQL PHP
Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出
本文深入探讨了Redis作为PHP缓存解决方案的优势、实现方式及注意事项。Redis凭借其高性能、丰富的数据结构、数据持久化和分布式支持等特点,在提升应用响应速度和处理能力方面表现突出。文章还介绍了Redis在页面缓存、数据缓存和会话缓存等应用场景中的使用,并强调了缓存数据一致性、过期时间设置、容量控制和安全问题的重要性。
43 5
|
21天前
|
弹性计算 API 持续交付
后端服务架构的微服务化转型
本文旨在探讨后端服务从单体架构向微服务架构转型的过程,分析微服务架构的优势和面临的挑战。文章首先介绍单体架构的局限性,然后详细阐述微服务架构的核心概念及其在现代软件开发中的应用。通过对比两种架构,指出微服务化转型的必要性和实施策略。最后,讨论了微服务架构实施过程中可能遇到的问题及解决方案。
|
1月前
|
Cloud Native Devops 云计算
云计算的未来:云原生架构与微服务的革命####
【10月更文挑战第21天】 随着企业数字化转型的加速,云原生技术正迅速成为IT行业的新宠。本文深入探讨了云原生架构的核心理念、关键技术如容器化和微服务的优势,以及如何通过这些技术实现高效、灵活且可扩展的现代应用开发。我们将揭示云原生如何重塑软件开发流程,提升业务敏捷性,并探索其对企业IT架构的深远影响。 ####
43 3
|
1月前
|
Cloud Native 安全 数据安全/隐私保护
云原生架构下的微服务治理与挑战####
随着云计算技术的飞速发展,云原生架构以其高效、灵活、可扩展的特性成为现代企业IT架构的首选。本文聚焦于云原生环境下的微服务治理问题,探讨其在促进业务敏捷性的同时所面临的挑战及应对策略。通过分析微服务拆分、服务间通信、故障隔离与恢复等关键环节,本文旨在为读者提供一个关于如何在云原生环境中有效实施微服务治理的全面视角,助力企业在数字化转型的道路上稳健前行。 ####
|
20天前
|
Java 开发者 微服务
从单体到微服务:如何借助 Spring Cloud 实现架构转型
**Spring Cloud** 是一套基于 Spring 框架的**微服务架构解决方案**,它提供了一系列的工具和组件,帮助开发者快速构建分布式系统,尤其是微服务架构。
141 68
从单体到微服务:如何借助 Spring Cloud 实现架构转型
|
22天前
|
设计模式 负载均衡 监控
探索微服务架构下的API网关设计
在微服务的大潮中,API网关如同一座桥梁,连接着服务的提供者与消费者。本文将深入探讨API网关的核心功能、设计原则及实现策略,旨在为读者揭示如何构建一个高效、可靠的API网关。通过分析API网关在微服务架构中的作用和挑战,我们将了解到,一个优秀的API网关不仅要处理服务路由、负载均衡、认证授权等基础问题,还需考虑如何提升系统的可扩展性、安全性和可维护性。文章最后将提供实用的代码示例,帮助读者更好地理解和应用API网关的设计概念。
51 8