距离上次写博客有两三个月了,这段时间去了新公司上班,忙了很多。接手了一个项目,刚好用到redis,先总结下遇到的问题(跟redis相关的问题):

  1、列表问题

  举例:展示商品列表,但是要先展示运营置顶的数据,如果排序的序号一样,则按照id降序排序,就是需要按照sort asc, id desc 来排序;用redis怎么处理?

  【分析】

  首先这个问题可能本身有点问题,因为如果限定了redis,那么处理的方法就给限定死了,当时由于一股劲想着用redis处理,而忘了去想下redis是否适合处理这种问题;

  第二,讲下一开始是怎么用redis处理的:

  1)商品列表存储起来在有序集合,按照sort字段排序比如有序集合goods-by-sort中数据:

  商品id (member) , value(score)

  1          1

  2          1  

  3          3

  4          2

  2)每当创建新商品,加入此队列,sort值是默认值;

  3)每当运营在管理后台修改sort值,则修改此有序集合中对应商品的score值;

  4)删除商品,或者设置不可见,则从这个有序集合中删掉该商品id的数据;

  5)用户获取商品列表时,因为需要按照sort和id排序,所以我当时再新增一个有序集合: goods_list_data,首先从goods_by_sort取出数据,在程序里面重新排序,然后写到goods_temp有序集合,然后rename为goods_list_data有序集合,然后给这个集合设置一个过期时间,比如2分钟。

  6)针对上面第2)到第4)步可能会对goods_by_sort有序集合的数据进行调整,比如修改、新增和删除,那么goods_list_data数据也需要更新,否则用户会一直看到被删除的商品。所以上面这三种情况,我会去更新一个string类型的refresh_goods_data 的key,每次去incr。用一个定时任务,每分钟一次去检查这个值,如果不为0,那么就去更新goods_list_data,然后设置refresh_goods_data的值为0,。否则则不处理,因为goods_list_data有序集合没改动。

  【上面这么做的问题】

  1)耦合很深,不好维护;搞了2个有序集合,还有定时任务;

  2)会有无底洞问题:有序集合存储的数据会越来越多,当然这个可以根据业务处理,比如裁剪,但是维护这个有序集合也是个问题,增删改都要做相应维护。

  【比较好的处理方法】

  1)还是回归到查询数据库,根据sort asc,id desc 排序来分页获取,但是基础数据就从redis中获取;这个要根据数据量,还有sql语句复杂度来评估,如果联表,或者是已经被告知数据库出现这个慢查询sql,那就肯定不能用这个方法。

  2)同事建议这种用sphinx来处理,有道理,不过还没尝试。

  2、redis防雪崩、防穿透、无底洞问题

  【分析和解决方法】

  防止雪崩问题的有效方法:

  1)不设置过期时间,只要数据实时更新到redis,那么给用户的数据就是实时的,不影响后端数据库;

  2)热数据和冷数据的区分,每天定时刷新热数据;

  防穿透问题:

  1)由于在redis中找不到数据,所以会去数据库读取,但是数据库也没有,所以不会写回缓存,导致并发访问时每次兜圈数据库读取;

  2)可以给这类数据写一个null或false到redis,设置一个过期时间,比如2分钟;

  3)要注意的是,这种key不能存储太长时间,key的量多起来,内存占用也会多的。

  无底洞问题:

  1)key如果不过期,那么会一直保存在内存,内存会越来越不够用;

  2)key如果过期,那么过期后,怎么处理,高并发访问数据,数据库会不会挂掉?网上有不少代码用setnx加锁方式,获取到锁的就去db查询然后写回redis,而其他的请求没有获取到锁,则等待一段时间(比如10毫秒)然后再去redis读取,取到就返回,取不到数据的话可以根据业务看要不要直接返回空结果,还是再去获取锁,直到读取到数据或者尝试的次数到达指定次数。

  3、刷缓存问题

  举例:由于是在一个老项目上做优化,之前是没有做redis缓存(严格来说还是有缓存,但是仅仅是把api接口的结果缓存起来设置个过期时间),所以新的优化上线后,如果访问旧的数据,缓存中没有,那么如果不刷数据,就会所有请求到缓存都是空命中,此时要么直接返回说没数据(用户体验非常差),或者去数据库查询,此时是类似雪崩的情况,并发访问数据库,数据库可能会挂掉,那么比较好的处理方式就是先把数据刷到缓存。这里该如何处理?

  【分析】

  1)根据业务,分析哪些数据需要提前刷新到缓存;

  2)增加锁机制,如果获取不到数据,则先去获取锁,获取到锁的则去db查询然后写回redis,db无数据则写null或false到redis并设置过期时间;

  3)根据数据库表中数据量和业务,分析是否可以先刷一部分数据。比如商品有1000万条数据,用户在网站首页可以分页慢慢地看1000万条数据,但是大部分用户可能只会看前面的几十页数据,比如一页20条数据,那么准备2000条最新数据或者热门数据即可。其他的商品,等待用户访问的时候,从redis获取,读取不到从db获取写回redis即可。

  4、商品之间根据标签进行关联,比如:

  商品A: tag1, tag2 ,tag3

  商品B: tag2, tag4

  商品C: tag1, tag5

  商品D: tag4

  所以,商品A和商品B、商品C关联;商品B和商品D关联;商品C和商品A关联;商品D和商品B关联。

  每当要获取商品A关联的商品时,当然可以从db去获取A的标签,然后计算出管理的商品,那么如何用redis处理?

  【分析】

  如果非要用redis处理,那么就是需要提前把关系计算好,存放到集合/有序集合,那么一旦需要获取数据的时候,不需要再去计算,而是直接从缓存读出这些关联的id。

  1)新增商品时,会附带标签。计算关联的商品,是比较耗时的操作,可以放在队列,由后台脚本定时处理;

  2)删除商品时,也是需要放入队列,由后台脚本去处理;

  3)修改标签(给商品新增一个或多个标签、删除一个或多个标签和修改某些标签),也是需要放入队列,由后台脚本去处理;

  【上面这么做的问题】

  1)不好维护;增删改,都需要去维护这个有序集合。好处就是需要获取关联数据时直接从集合/有序集合获取id,基础信息也从redis获取;

  2)请教了同事,说用sphinx也可以处理,还没尝试。

 

  5、用redis能否解决mysql like 的问题

  答案自然是解决不了,只能用sphinx或es这些全文搜索系统。

  6、商品列表有个逻辑是,允许展示用户自己发布的商品(不论审核状态)+其他用户发布的商品(只能审核通过状态)的这些数据。当时用redis处理,搞了两个有序集合,一个是存储网站上所有审核通过的商品;第二个有序集合是存储用户自己发布的商品(不论审核状态)。当需要获取商品列表时,合并两个集合,然后分页取数据。

  【问题】

  并发情况下,合并有序集合的代价是很高的,可能造成阻塞;

  【解决方法】

  1)可以的话直接mysql查询。

  2)使用sphinx:又是同事的建议。

  总结:

  1、redis不是万能的,也有自己的优势和劣势;redis不适合处理sql这种关系型的业务;

  2、redis的性能是很好的,但是人为的操作,使用不当,可能造成阻塞;

  3、除了redis,还有其他的方法可以处理,不能限定死了。处理问题的时候,不仅要考虑能不能处理,还要考虑是否合理。

  

关于redis的使用的更多相关文章

  1. 使用redis构建可靠分布式锁

    关于分布式锁的概念,具体实现方式,直接参阅下面两个帖子,这里就不多介绍了. 分布式锁的多种实现方式 分布式锁总结 对于分布式锁的几种实现方式的优劣,这里再列举下 1. 数据库实现方式 优点:易理解 缺 ...

  2. Ignite性能测试以及对redis的对比

    测试方法 为了对Ignite做一个基本了解,做了一个性能测试,测试方法也比较简单主要是针对client模式,因为这种方法和使用redis的方式特别像.测试方法很简单主要是下面几点: 不作参数优化,默认 ...

  3. mac osx 安装redis扩展

    1 php -v查看php版本 2 brew search php|grep redis 搜索对应的redis   ps:如果没有brew 就根据http://brew.sh安装 3 brew ins ...

  4. Redis/HBase/Tair比较

    KV系统对比表 对比维度 Redis Redis Cluster Medis Hbase Tair 访问模式    支持Value大小 理论上不超过1GB(建议不超过1MB) 理论上可配置(默认配置1 ...

  5. Redis数据库

    Redis是k-v型数据库的典范,设计思想及数据结构实现都值得学习. 1.数据类型 value支持五种数据类型:1.字符串(strings)2.字符串列表(lists)3.字符串集合(sets)4.有 ...

  6. redis 学习笔记(2)

    redis-cluster 简介 redis-cluster是一个分布式.容错的redis实现,redis-cluster通过将各个单独的redis实例通过特定的协议连接到一起实现了分布式.集群化的目 ...

  7. redis 学习笔记(1)

    redis持久化 snapshot数据快照(rdb) 这是一种定时将redis内存中的数据写入磁盘文件的一种方案,这样保留这一时刻redis中的数据镜像,用于意外回滚.redis的snapshot的格 ...

  8. python+uwsgi导致redis无法长链接引起性能下降问题记录

    今天在部署python代码到预生产环境时,web站老是出现redis链接未初始化,无法连接到服务的提示,比对了一下开发环境与测试环境代码,完全一致,然后就是查看各种日志,排查了半天也没有查明是什么原因 ...

  9. nginx+iis+redis+Task.MainForm构建分布式架构 之 (redis存储分布式共享的session及共享session运作流程)

    本次要分享的是利用windows+nginx+iis+redis+Task.MainForm组建分布式架构,上一篇分享文章制作是在windows上使用的nginx,一般正式发布的时候是在linux来配 ...

  10. windows+nginx+iis+redis+Task.MainForm构建分布式架构 之 (nginx+iis构建服务集群)

    本次要分享的是利用windows+nginx+iis+redis+Task.MainForm组建分布式架构,由标题就能看出此内容不是一篇分享文章能说完的,所以我打算分几篇分享文章来讲解,一步一步实现分 ...

随机推荐

  1. (二)springboot整合thymeleaf模板

    在我们平时的开发中,用了很久的jsp作view显示层,但是标签库和JSP缺乏良好格式的一个副作用就是它很少能够与其产生的HTML类似.所以,在Web浏览器或HTML编辑器中查看未经渲染的JSP模板是非 ...

  2. JSP内容复习

    JSP的3个编译指令,7个动作指令,9个内置对象 三个编译指令(通知servlet引擎的处理消息,只在JSP转换成Servlet时起作用) 1.编译指令 page page指令用户定义JSP页面中的全 ...

  3. Maven依赖解析

    本文将记录Maven工程中依赖解析机制,内容包括: Maven依赖基本结构 从仓库解析依赖的机制 依赖传递性解析实例 1. Maven依赖基本结构 上篇文章记录了Maven依赖的聚合与继承,POM中依 ...

  4. [转]分布式消息中间件 MetaQ 作者庄晓丹专访

    MetaQ(全称Metamorphosis)是一个高性能.高可用.可扩展的分布式消息中间件,思路起源于LinkedIn的Kafka,但并不是Kafka的一个Copy.MetaQ具有消息存储顺序写.吞吐 ...

  5. [转]oracle系统表v$session、v$sql字段说明

    在本视图中,每一个连接到数据库实例中的 session都拥有一条记录.包括用户 session及后台进程如 DBWR, LGWR, arcchiver等等. V$SESSION中的常用列 V$SESS ...

  6. Java8 方式解决Stream流转其他数组

    Java8 方式解决Stream流转其他数组 一. 题记:原来的List转数组用的是如下方式: example private static void listToStringArray(List l ...

  7. iOS11、iPhone X、Xcode9 适配

    更新iOS11后,发现有些地方需要做适配,整理后按照优先级分为以下三类: 1.单纯升级iOS11后造成的变化: 2.Xcode9 打包后造成的变化: 3.iPhoneX的适配 一.单纯升级iOS11后 ...

  8. 《java.util.concurrent 包源码阅读》04 ConcurrentMap

    Java集合框架中的Map类型的数据结构是非线程安全,在多线程环境中使用时需要手动进行线程同步.因此在java.util.concurrent包中提供了一个线程安全版本的Map类型数据结构:Concu ...

  9. ecshop根据订单号查询物流信息

    目标:订单详情页可以根据订单查询当前物流信息. 效果图: 思路:点击后异步请求快递查询api,接受返回信息,拼接. 代码: admin下:order_info.htm //一:顶部插入jquery,在 ...

  10. python学习笔记 tuple

    1. ()去声明.与list类似,但是其元素不能改变. 2. 需要注意的是1中的不能改变是指()中的元素不能改变,如果其元素是一个list,那么list中的元素是可以改变的,不论是大小还是其他的. 3 ...