常用缓存技巧

本文涉及的产品
云数据库 Tair(兼容Redis),内存型 2GB
Redis 开源版,标准版 2GB
推荐场景:
搭建游戏排行榜
简介: 在项目中,大家经常会遇到处理高并发的情况,缓存是应对高并发的有效手段之一。这篇文章简单介绍一下常用的缓存手段。

简介

在项目中,大家经常会遇到处理高并发的情况,缓存是应对高并发的有效手段之一。这篇文章简单介绍一下常用的缓存手段。当然,使用缓存有一个前提:

  1. 数据不是实时变更的
  2. 获取新数据不必特别及时

方法

一、CDN

CDN一般用来做静态资源的缓存,但是稍微进行修改,便可以用来缓存动态接口的返回。当请求资源在CDN不存在时,请求会到回源机上,在回源机的Nginx上,根据路由规则,将请求转发到不同服务,返回结果会存在到CDN上。如下图所示:

Nginx实现

upstream fs.com_backend {
    server   127.0.0.1:8080 weight=1 max_fails=2 fail_timeout=10s;
    check interval=3000 rise=3 fall=3 timeout=1000 type=tcp default_down=false;
}

upstream hd.com_upstream {
    server   127.0.0.1:8080 weight=1 max_fails=2 fail_timeout=10s;
    check interval=3000 rise=3 fall=3 timeout=1000 type=tcp default_down=false;
}

server {
        listen       8080;
        server_name  aaa.d2s.com;
        charset utf-8;

        access_log /home/work/logs/nginx/d2s.com.log web;
        error_log /home/work/logs/nginx/d2s.com.log.err;

        error_page   403 404 500 502 503 504  http://hd.com/webfile/zt/hd/2014042802/tw.html;

        expires -1;

        location ~ /.git {
            deny all;
            access_log off;
            log_not_found off;
        }

        location ~ /([^/]*)/openbuy/info {
            expires 300s;
            proxy_set_header Host "****";
            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_pass http://fs.com_backend;
        }

        location ~ /([^/]*)/eventapi/ {
            rewrite /(.*)/eventapi/(.*) /$1/$2 break;
            expires 300s;
            proxy_set_header Host "****";
            proxy_set_header X-Forwarded-For $remote_addr;
            proxy_pass http://hd.com_upstream;
        }
}

注意事项

  1. 注意流量

    正常情况下,回源的请求会比较少,但某些情况下,会导致请求激增,如市场在google上推了广告,请求后面会添加很多数据,如果CDN没有做处理,这些请求都会穿透CDN打到回源机上,导致请求暴增。如果服务性能有限,不但会导致该服务受影响,该Nginx上的其他功能可能也会受影响。

  2. 注意稳定性

    因为请求会转发到服务上,如果服务不稳定,返回的数据有误或者服务500了,Nginx没做任何判断便返回,会导致一段时间内,用户请求的数据全是错误的。这种情况一旦发生,反馈到开发的时候,因为CDN缓存失效,重新获取了正确数据,此时症状已经消失,开发很难定位问题。建议在Nginx上添加相关正确性的校验。

二、Nginx缓存

​ Nginx也能缓存返回的结果,而且由于Nginx本身能够支持较高的并发,且易于配置,所以使用Nginx缓存是一个及其方便有效的手段。

Nginx部分实现

server {
  listen 80;
  #listen 445;
  server_name  abc.com;

  access_log /home/work/logs/nginx/abc.com.log albproxy;
  error_log /home/work/logs/nginx/abc.com.err;

  #include vhosts/black.ini;

  error_page   403 404 500 502 503 504  http://promo.com/webfile/globalweb/$local/404.html;


  if ($app_uri ~* "^(hello/getstock.*)"){
    set $cache_rewrite "nginxcache3s";
  }

  location ~* ^/[^/]*/nginxcache3s/.* {
    proxy_pass_header X-Accel-Expires;
    rewrite ^/([^/]*)/nginxcache3s/(.*)$ /$1/$2 break;

    proxy_cache cache_one;
    proxy_cache_valid 200 3s;
    proxy_cache_key $host$uri;
    proxy_ignore_headers Expires Cache-Control;

    proxy_set_header Host  $host;
    set_real_ip_from   10.0.0.0/8;
    real_ip_header     X-Forwarded-For;
    proxy_set_header   X-Real-IP        $remote_addr;
    real_ip_recursive on;
    proxy_set_header X-Forwarded-For  $http_x_forwarded_for;
    #后端标识ssl请求
    proxy_set_header Missl $sslparam;
    proxy_set_header LOGID $logid;
    proxy_pass http://web_backend;
  }
}

注意事项

  1. 慎重使用

    使用Nginx缓存确实很方便,也可以迅速提高接口性能,可以说是居家旅行必备良药。不过这些操作一般需要运维同学帮忙操作,如果频繁使用该方法,一是占用了运维很多时间做这种重复性工作,二是操作的过程中可能出现各种问题,三是会导致Nginx文件很繁杂,后期迁移和维护成本会较高。

三、 Redis

​ Redis是处理高并发情况的必备方案之一。一般的处理过程如下:

注意事项

  1. 缓存穿透

    如果Redis没有数据,获取数据的时候也没有数据,这个时候,如果没有将结果写入Redis,则每次请求都会穿透Redis。建议

    • 获取数据为空的情况下,也存数据
    • 增加基础校验
  2. 缓存击穿

    如果有个key位热点key,请求qps特别高,当该key失效的时候,大量的请求会到逻辑层,导致服务不稳定,建议

    • 热点数据设置为永不过期。可以使用脚本等方案异步更新数据。
    • 加互斥锁。如果key不存在,则只允许一个请求进入逻辑层。
  3. 缓存雪崩

    如果大量key在同一时间过期,所有请求都会到逻辑层,导致服务不稳定,建议

    • 缓存数据的过期时间设置随机,防止同一时间大量数据过期现象发生
    • 如果缓存数据库是分布式部署,将热点数据均匀分布在不同的缓存数据库中
    • 热点数据设置为永不过期

四、MemoryCache

​ MemoryCache是内存缓存,一般在同一台机器上安置服务和MemoryCache,将MemoryCache和Redis并用。虽然Redis性能极高,但终归还需要通过请求去获取数据,MemoryCache直接从本地内存获取数据,速度更加快速。如下图所示:

​ 当Redis中没有数据,是否需要获取数据和再次写入Redis,需要根据具体业务情况来设计。例如如果Redis是异步写入的,则没必要去执行计算数据的逻辑,也没必要再次写入Redis。

注意事项

  1. 数据丢失风险

    Memeory Cache是内存缓存,没有持久化机制,重启后数据就没有了。

  2. OOM

    Memeory Cache使用不规范,容易造成大量内存消耗,产生OOM问题

  3. 存储数据变更风险

    在Golang中,如果存储的数据为指针结构,存储操作完成后,指针指向的数据更改,则Memeory Cache中的数据也会被更改

总结

​ 本文介绍了常用的四种方案,CDN、Nginx缓存、Redis、MemoryCache,灵活组合使用这四个等级的方案,可以有效的处理高并发问题。大家如果有其他方案,欢迎一起讨论。

​ 本章的图片,大家可以通过https://www.processon.com/view/link/5ec7e780f346fb69070fe20a查看

最后

大家如果喜欢我的文章,可以关注我的公众号(程序员麻辣烫)

相关实践学习
Serverless极速搭建Hexo博客
本场景介绍如何使用阿里云函数计算服务命令行工具快速搭建一个Hexo博客。
相关文章
|
6月前
|
缓存
你了解缓存吗?
你了解缓存吗?
你了解缓存吗?
|
2月前
|
存储 缓存 NoSQL
|
5月前
|
存储 缓存 对象存储
合理地处理不需要的缓存
【6月更文挑战第8天】本文介绍了管理缓存数据过期的重要性,以避免内存浪费和过时信息的使用。缓存系统通常允许设置默认过期策略或为每个对象指定绝对或滑动过期时间。缓存服务常使用LRU策略进行逐出,但过度使用可能导致内存超出异常。
52 10
合理地处理不需要的缓存
|
5月前
|
存储 缓存 NoSQL
在应用中使用缓存服务
【6月更文挑战第24天】本文介绍redis缓存的基本知识和使用。Redis超越简单的键值存储,Redis查询直接针对键,不支持复杂查询,适合特定场景的高性能缓存。用于减少数据库交互,优化性能。并提供练习源码查阅。
88 1
|
存储 缓存 API
缓存 #23
缓存 #23
47 0
|
存储 缓存 NoSQL
聊聊缓存
拿破仑说:胜利属于坚持到最后的人。 而正巧,咱们今天就是要聊一个,关于怎么让系统在狂轰乱炸甚至泰山压顶的情况下,都屹立不倒并坚持到最后的话题:缓存。
176 0
|
存储 缓存 前端开发
缓存的认识
缓存是架构设计中一个重要的手段。缓存的主要特点是技术比较简单,同时对性能提升的效果又很显著,所以缓存在很多业务场景中被使用到。
129 0
|
缓存 开发框架 NoSQL
7.4缓存
缓存是一个用来保存数据的区域,从缓存中读取数据要比从数据源读取数据的速度快很多。如果可以从缓存中获取要获取的数据则称之为“缓存命中”,多次请求命中的请求占全部请求的百分比叫做“命中率”,如果数据源中的数据保存到了缓存后,发生了变化则称之为“缓存数据不一致”
|
存储 缓存 算法
聊聊缓存那些事
说到缓存,作为技术同学想必大家都不会陌生,平常工作中或多或少也用到过。但是要结构化的说清楚缓存到底是什么,怎么用,用了有问题怎么解,也不是一件简单的事。所以这篇文章也是站在服务端研发的视角,对自己过去经验的一些总结,希望对大家有哪怕一丁点的帮助,也就值得了。 本篇文章计划分为两个章节来写: ● 缓存基础篇:讲一下缓存的基本原理、特性等。 ● 缓存进阶篇:讲一下缓存的实战场景,疑难问题的解决方案等。
161 0
|
存储 缓存 JSON
缓存的注意点
设计缓存的考虑