当前位置: 首页 > news >正文

Java高级编程——选redis还是memcache,源码怎么说?

2019独角兽企业重金招聘Python工程师标准>>> hot3.png

memcache和redis是互联网分层架构中,最常用的KV缓存。不少同学在选型的时候会纠结,到底是选择memcache还是redis。

画外音:不鼓励粗暴的实践,例如“memcache提供的功能是redis提供的功能的子集,不用想太多,选redis准没错”。

虽然redis比memcache更晚出来,且功能确实也更丰富,但对于一个技术人,了解“所以然”恐怕比“选择谁”更重要一些

什么时候倾向于选择redis?

业务需求决定技术选型,当业务有这样一些特点的时候,选择redis会更加适合。

复杂数据结构

value是哈希,列表,集合,有序集合这类复杂的数据结构时,会选择redis,因为mc无法满足这些需求。

最典型的场景,用户订单列表,用户消息,帖子评论列表等。

持久化

mc无法满足持久化的需求,只得选择redis。

但是,这里要提醒的是,真的使用对了redis的持久化功能么?

千万不要把redis当作数据库用:

(1)redis的定期快照不能保证数据不丢失

(2)redis的AOF会降低效率,并且不能支持太大的数据量

不要期望redis做固化存储会比mysql做得好,不同的工具做各自擅长的事情,把redis当作数据库用,这样的设计八成是错误的。

缓存场景,开启固化功能,有什么利弊?

如果只是缓存场景,数据存放在数据库,缓存在redis,此时如果开启固化功能:

优点是,redis挂了再重启,内存里能够快速恢复热数据,不会瞬时将压力压到数据库上,没有一个cache预热的过程。

缺点是,在redis挂了的过程中,如果数据库中有数据的修改,可能导致redis重启后,数据库与redis的数据不一致。

因此,只读场景,或者允许一些不一致的业务场景,可以尝试开启redis的固化功能。

天然高可用

redis天然支持集群功能,可以实现主动复制,读写分离。

redis官方也提供了sentinel集群管理工具,能够实现主从服务监控,故障自动转移,这一切,对于客户端都是透明的,无需程序改动,也无需人工介入。

而memcache,要想要实现高可用,需要进行二次开发,例如客户端的双读双写,或者服务端的集群同步。

但是,这里要提醒的是,大部分业务场景,缓存真的需要高可用么?

(1)缓存场景,很多时候,是允许cache miss

(2)缓存挂了,很多时候可以通过DB读取数据

所以,需要认真剖析业务场景,高可用,是否真的是对缓存的主要需求?

画外音:即时通讯业务中,用户的在线状态,就有高可用需求。

存储的内容比较大

memcache的value存储,最大为1M,如果存储的value很大,只能使用redis。

什么时候倾向于memcache?

纯KV,数据量非常大,并发量非常大的业务,使用memcache或许更适合。

这要从mc与redis的底层实现机制差异说起。

内存分配

memcache使用预分配内存池的方式管理内存,能够省去内存分配时间。

redis则是临时申请空间,可能导致碎片。

从这一点上,mc会更快一些。

虚拟内存使用

memcache把所有的数据存储在物理内存里。

redis有自己的VM机制,理论上能够存储比物理内存更多的数据,当数据超量时,会引发swap,把冷数据刷到磁盘上。

从这一点上,数据量大时,mc会更快一些。

网络模型

memcache使用非阻塞IO复用模型,redis也是使用非阻塞IO复用模型。

但由于redis还提供一些非KV存储之外的排序,聚合功能,在执行这些功能时,复杂的CPU计算,会阻塞整个IO调度。

从这一点上,由于redis提供的功能较多,mc会更快一些。

线程模型

memcache使用多线程,主线程监听,worker子线程接受请求,执行读写,这个过程中,可能存在锁冲突。

redis使用单线程,虽无锁冲突,但难以利用多核的特性提升整体吞吐量。

从这一点上,mc会快一些。

最后说两点

代码可读性,代码质量

看过mc和redis的代码,从可读性上说,redis是我见过代码最清爽的软件,甚至没有之一,或许简单是redis设计的初衷,编译redis甚至不需要configure,不需要依赖第三方库,一个make就搞定了。

而memcache,可能是考虑了太多的扩展性,多系统的兼容性,代码不清爽,看起来费劲。

例如网络IO的部分,redis源码1-2个文件就搞定了,mc使用了libevent,一个fd传过来传过去,又pipe又线程传递的,特别容易把人绕晕。

画外音:理论上,mc只支持kv,而redis支持了这么多功能,mc性能应该高非常多非常多,但实际并非如此,真的可能和代码质量有关。

水平扩展的支持

不管是mc和redis,服务端集群没有天然支持水平扩展,需要在客户端进行分片,这其实对调用方并不友好。如果能服务端集群能够支持水平扩展,会更完美一些。

转载于:https://my.oschina.net/u/3301138/blog/1835910

相关文章:

  • Python学习——文件操作和异常处理
  • radhat6.6上安装oracle12c RAC (三)
  • 复制cp 近半年【181天:2018-01-01至20180627 这段时间】图片到upoad目录下
  • javascript 中数组的创建 添加 与将数组转换成字符串 页面三种提交请求的方式...
  • Spark MLlib系列(二):基于协同过滤的电影推荐系统
  • spark-submit提交Spark Streamming+Kafka程序
  • Jmeter
  • linux使用--根目录空间不足,追加空间到根目录下
  • Java中有几种类型的流?以及常见的实现类都有哪些?
  • 【Redis学习笔记】2018-06-28 redis命令源码学习1
  • docker 系列之 配置阿里云镜像加速器
  • js 表
  • java 虚拟机内存划分,类加载过程以及对象的初始化
  • sql求倒数第二大的数,效率不高,但写法新颖
  • ansible结合zabbix_api批量添加主机
  • AHK 中 = 和 == 等比较运算符的用法
  • Apache Zeppelin在Apache Trafodion上的可视化
  • eclipse(luna)创建web工程
  • eclipse的离线汉化
  • isset在php5.6-和php7.0+的一些差异
  • JS笔记四:作用域、变量(函数)提升
  • Sass 快速入门教程
  • Spring Boot MyBatis配置多种数据库
  • vue脚手架vue-cli
  • 安装python包到指定虚拟环境
  • 初识MongoDB分片
  • 利用阿里云 OSS 搭建私有 Docker 仓库
  • 强力优化Rancher k8s中国区的使用体验
  • 如何优雅的使用vue+Dcloud(Hbuild)开发混合app
  • 腾讯大梁:DevOps最后一棒,有效构建海量运营的持续反馈能力
  • 在electron中实现跨域请求,无需更改服务器端设置
  • 这几个编码小技巧将令你 PHP 代码更加简洁
  • Linux权限管理(week1_day5)--技术流ken
  • "无招胜有招"nbsp;史上最全的互…
  • #### go map 底层结构 ####
  • $emit传递多个参数_PPC和MIPS指令集下二进制代码中函数参数个数的识别方法
  • (附源码)php新闻发布平台 毕业设计 141646
  • (附源码)ssm户外用品商城 毕业设计 112346
  • (附源码)计算机毕业设计ssm基于Internet快递柜管理系统
  • (十八)三元表达式和列表解析
  • (转)Scala的“=”符号简介
  • (转)我也是一只IT小小鸟
  • .net core 依赖注入的基本用发
  • .NET Core使用NPOI导出复杂,美观的Excel详解
  • .net Stream篇(六)
  • .NET 反射 Reflect
  • .net6+aspose.words导出word并转pdf
  • .net6Api后台+uniapp导出Excel
  • .NET的微型Web框架 Nancy
  • .net之微信企业号开发(一) 所使用的环境与工具以及准备工作
  • //解决validator验证插件多个name相同只验证第一的问题
  • @DependsOn:解析 Spring 中的依赖关系之艺术
  • [Angular] 笔记 9:list/detail 页面以及@Output
  • [BIZ] - 1.金融交易系统特点
  • [BZOJ 2142]礼物(扩展Lucas定理)