考虑到绝大部分写业务的程序员,在实际开发中使用redis的时候,只会setvalue和getvalue两个操作,对redis整体缺乏一个认知。又恰逢博主某个同事下周要去培训redis,所以博主斗胆以redis为题材,对redis常见问题做一个总结,希望能够弥补大家的知识盲点。

首先我们先介绍些redis的基本概念,redis是Nosql数据库,是一个key-value存储系统。虽然redis是key-value的存储系统,但是redis支持的value存储类型是非常的多,比如字符串、链表、集合、有序集合和哈希。

好啦!步入正题!我们先探讨一下Redis是什么,Redis为什么这么快、然后在探讨一下为什么Redis是单线程的?

1、Redis简介

Redis是一个开源的内存中的数据结构存储系统,它可以用作:数据库、缓存和消息中间件。

它支持多种类型的数据结构,如字符串(Strings),散列(Hash),列表(List),集合(Set),有序集合(Sorted Set或者是ZSet)与范围查询,Bitmaps,Hyperloglogs 和地理空间(Geospatial)索引半径查询。其中常见的数据结构类型有:String、List、Set、Hash、ZSet这5种。

2,那么为什么要使用类似redis这样的Nosql数据库呢?

1) 当数据量的总大小一个机器放不下时;

2) 数据索引一个机器的内存放不下时;

3) 访问量(读写混合)一个实例放不下时。

单机时代,存储只用一台机器装mysql,如果每次存储成千上万条数据,这样很会导致mysql的性能很差,存储以及读取速度很慢,然后就演变成缓存+mysql+垂直拆分的方式。

Cache作为中间缓存时代,将所有的数据先保存到缓存中,然后再存入mysql中,减小数据库压力,提高效率。

但是当数据再次增加到又一个量级,上面的方式也不能满足需求,由于数据库的写入压力增加,缓存只能缓解数据库的读取压力。读写集中在一个数据库上让数据库不堪重负,大部分网站开始使用主从复制技术来达到读写分离,以提高读写性能和读库的可扩展性。Mysql的master-slave模式成为这个时候的网站标配了。

主从分离模式时代,在redis的高速缓存,MySQL的主从复制,读写分离的基础之上,这时MySQL主库的写压力开始出现瓶颈,而数据量的持续猛增,由于MyISAM使用表锁,在高并发下会出现严重的锁问题,大量的高并发MySQL应用开始使用InnoDB引擎代替MyISAM。

Nosql数据库的优势

1)易扩展

这些类型的数据存储不需要固定的模式,无需多余的操作就可以进行横向的扩展。相对于关系型数据库可以减少表和字段特别多的情况。也无型之间在架构的层面上带来了可扩展的能力

2)大数据量提高性能

3)多样灵活的数据模型

3、使用redis有什么缺点

分析:大家用redis这么久,这个问题是必须要了解的,基本上使用redis都会碰到一些问题,常见的也就几个。(一)缓存和数据库双写一致性问题(二)缓存雪崩问题(三)缓存击穿问题(四)缓存的并发竞争问题这四个问题,我个人是觉得在项目中,比较常遇见的,具体解决方案,后文给出。

4、为什么使用redis

分析:博主觉得在项目中使用redis,主要是从两个角度去考虑:性能和并发。当然,redis还具备可以做分布式锁等其他功能,但是如果只是为了分布式锁这些其他功能,完全还有其他中间件(如zookpeer等)代替,并不是非要使用redis。因此,这个问题主要从性能和并发两个角度去答。回答:如下所示,分为两点(一)性能我们在碰到需要执行耗时特别久,且结果不频繁变动的SQL,就特别适合将运行结果放入缓存。这样,后面的请求就去缓存中读取,使得请求能够迅速响应。

(二)并发在大并发的情况下,所有的请求直接访问数据库,数据库会出现连接异常。这个时候,就需要使用redis做一个缓冲操作,让请求先访问到redis,而不是直接访问数据库。

5,那么为什么Redis是单线程的

我们首先要明白,上边的种种分析,都是为了营造一个Redis很快的氛围!官方FAQ表示,因为Redis是基于内存的操作,CPU不是Redis的瓶颈,Redis的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且CPU不会成为瓶颈,那就顺理成章地采用单线程的方案了(毕竟采用多线程会有很多麻烦!)。

本以为会有什么重大的技术要点才使得Redis使用单线程就可以这么快,没想到就是一句官方看似糊弄我们的回答!但是,我们已经可以很清楚的解释了为什么Redis这么快,并且正是由于在单线程模式的情况下已经很快了,就没有必要在使用多线程了!

但是,我们使用单线程的方式是无法发挥多核CPU 性能,不过我们可以通过在单机开多个Redis 实例来完善!

6、Redis为什么这么快

1、完全基于内存,绝大部分请求是纯粹的内存操作,非常快速。数据存在内存中,类似于HashMap,HashMap的优势就是查找和操作的时间复杂度都是O(1);

2、数据结构简单,对数据操作也简单,Redis中的数据结构是专门进行设计的;

3、采用单线程,避免了不必要的上下文切换和竞争条件,也不存在多进程或者多线程导致的切换而消耗 CPU,不用去考虑各种锁的问题,不存在加锁释放锁操作,没有因为可能出现死锁而导致的性能消耗;

4、使用多路I/O复用模型,非阻塞IO;

5、使用底层模型不同,它们之间底层实现方式以及与客户端之间通信的应用协议不一样,Redis直接自己构建了VM 机制 ,因为一般的系统调用系统函数的话,会浪费一定的时间去移动和请求;

以上几点都比较好理解,下边我们针对多路 I/O 复用模型进行简单的探讨:

(1)多路 I/O 复用模型

多路I/O复用模型是利用 select、poll、epoll 可以同时监察多个流的 I/O 事件的能力,在空闲的时候,会把当前线程阻塞掉,当有一个或多个流有 I/O 事件时,就从阻塞态中唤醒,于是程序就会轮询一遍所有的流(epoll 是只轮询那些真正发出了事件的流),并且只依次顺序的处理就绪的流,这种做法就避免了大量的无用操作。

这里“多路”指的是多个网络连接,“复用”指的是复用同一个线程。采用多路 I/O 复用技术可以让单个线程高效的处理多个连接请求(尽量减少网络 IO 的时间消耗),且 Redis 在内存中操作数据的速度非常快,也就是说内存内的操作不会成为影响Redis性能的瓶颈,主要由以上几点造就了 Redis 具有很高的吞吐量。

7、如何应对缓存穿透和缓存雪崩问题

分析:这两个问题,说句实在话,一般中小型传统软件企业,很难碰到这个问题。如果有大并发的项目,流量有几百万左右。这两个问题一定要深刻考虑。缓存穿透,即黑客故意去请求缓存中不存在的数据,导致所有的请求都怼到数据库上,从而数据库连接异常。解决方案:(一)利用互斥锁,缓存失效的时候,先去获得锁,得到锁了,再去请求数据库。没得到锁,则休眠一段时间重试(二)采用异步更新策略,无论key是否取到值,都直接返回。value值中维护一个缓存失效时间,缓存如果过期,异步起一个线程去读数据库,更新缓存。需要做缓存预热(项目启动前,先加载缓存)操作。(三)提供一个能迅速判断请求是否有效的拦截机制,比如,利用布隆过滤器,内部维护一系列合法有效的key。迅速判断出,请求所携带的Key是否合法有效。如果不合法,则直接返回。缓存雪崩,即缓存同一时间大面积的失效,这个时候又来了一波请求,结果请求都怼到数据库上,从而导致数据库连接异常。解决方案:(一)给缓存的失效时间,加上一个随机值,避免集体失效。(二)使用互斥锁,但是该方案吞吐量明显下降了。(三)双缓存。我们有两个缓存,缓存A和缓存B。缓存A的失效时间为20分钟,缓存B不设失效时间。自己做缓存预热操作。然后细分以下几个小点

1,从缓存A读数据库,有则直接返回。

2,A没有数据,直接从B读数据,直接返回,并且异步启动一个更新线程。

3,更新线程同时更新缓存A和缓存B。

8、如何解决redis的并发竞争key问题

分析:这个问题大致就是,同时有多个子系统去set一个key。这个时候要注意什么呢?大家思考过么。需要说明一下,博主提前百度了一下,发现答案基本都是推荐用redis事务机制。博主不推荐使用redis的事务机制。因为我们的生产环境,基本都是redis集群环境,做了数据分片操作。你一个事务中有涉及到多个key操作的时候,这多个key不一定都存储在同一个redis-server上。因此,redis的事务机制,十分鸡肋。回答:如下所示(1)如果对这个key操作,不要求顺序这种情况下,准备一个分布式锁,大家去抢锁,抢到锁就做set操作即可,比较简单。(2)如果对这个key操作,要求顺序假设有一个key1,系统A需要将key1设置为valueA,系统B需要将key1设置为valueB,系统C需要将key1设置为valueC.期望按照key1的value值按照 valueA--valueB--valueC的顺序变化。这种时候我们在数据写入数据库的时候,需要保存一个时间戳。假设时间戳如下

系统A key 1 {valueA 3:00}系统B key 1 {valueB 3:05}系统C key 1 {valueC 3:10}那么,假设这会系统B先抢到锁,将key1设置为{valueB 3:05}。接下来系统A抢到锁,发现自己的valueA的时间戳早于缓存中的时间戳,那就不做set操作了。以此类推。

其他方法,比如利用队列,将set方法变成串行访问也可以。总之,灵活变通。

9、注意点

Jia-qun-( 860-170-416 )-跟各位大神一起沟通交流学习!

一,我们知道Redis是用”单线程-多路复用IO模型”来实现高性能的内存数据服务的,这种机制避免了使用锁,但是同时这种机制在进行sunion之类的比较耗时的命令时会使redis的并发下降。因为是单一线程,所以同一时刻只有一个操作在进行,所以,耗时的命令会导致并发的下降,不只是读并发,写并发也会下降。而单一线程也只能用到一个CPU核心,所以可以在同一个多核的服务器中,可以启动多个实例,组成master-master或者master-slave的形式,耗时的读命令可以完全在slave进行。

需要改的redis.conf项:

pidfile/var/run/redis/redis_6377.pid #pidfile要加上端口号port6377 #这个是必须改的logfile/var/log/redis/redis_6377.log #logfile的名称也加上端口号dbfilenamedump_6377.rdb #rdbfile也加上端口号二、“我们不能任由操作系统负载均衡,因为我们自己更了解自己的程序,所以,我们可以手动地为其分配CPU核,而不会过多地占用CPU,或是让我们关键进程和一堆别的进程挤在一起。”。CPU 是一个重要的影响因素,由于是单线程模型,Redis 更喜欢大缓存快速 CPU, 而不是多核

在多核 CPU 服务器上面,Redis 的性能还依赖NUMA 配置和处理器绑定位置。最明显的影响是 redis-benchmark 会随机使用CPU内核。为了获得精准的结果,需要使用固定处理器工具(在 Linux 上可以使用 taskset)。最有效的办法是将客户端和服务端分离到两个不同的 CPU 来高校使用三级缓存。

10、扩展

以下也是你应该知道的几种模型,祝你的面试一臂之力!

1、单进程多线程模型:MySQL、Memcached、Oracle(Windows版本);

2、多进程模型:Oracle(Linux版本);

3、Nginx有两类进程,一类称为Master进程(相当于管理进程),另一类称为Worker进程(实际工作进程)。启动方式有两种:

(1)单进程启动:此时系统中仅有一个进程,该进程既充当Master进程的角色,也充当Worker进程的角色。

(2)多进程启动:此时系统有且仅有一个Master进程,至少有一个Worker进程工作。

(3)Master进程主要进行一些全局性的初始化工作和管理Worker的工作;事件处理是在Worker中进行的。

分布式之redis核心知识盘点?的更多相关文章

  1. Redis核心知识之—— 时延问题分析及应对、性能问题和解决方法【★★★★★】

    参考网址: Redis时延问题分析及应对:http://www.cnblogs.com/me115/p/5032177.html Redis常见的性能问题和解决方法:http://www.search ...

  2. Java核心知识盘点(三)- 框架篇-Spring

    Spring的两大核心特性:IOC.AOP IOC:控制反转.依赖注入,它并不是一种技术实现,而是一种思想.把一些相互依赖对象的创建.协调工作交给Spring容器来管理,每个对象只需要关注其自身的业务 ...

  3. Java核心知识盘点(二)- 缓存使用

    Redis有哪些数据类型 String.Hash.List.Set.ZSet String:字符串 Hash:哈希 Set:集合 List:列表 ZSet:有序集合 Redis内部结构 1.Redis ...

  4. Java核心知识盘点(一)- 数据存储

    MySQL 索引使用的注意事项 1.索引的目的:在于提高查询效率,插入和更新的操作,数据库的操作是慢的,但是查询操作会非常快,索引可以对表中一个或多个字段进行加索引动作. 2.索引的类型: 1.唯一索 ...

  5. 小D课堂 - 新版本微服务springcloud+Docker教程_5-01分布式核心知识之熔断、降级

    笔记: 第五章 互联网架构服务降级熔断 Hystrix 实战 1.分布式核心知识之熔断.降级讲解     简介:系统负载过高,突发流量或者网络等各种异常情况介绍,常用的解决方案 1.熔断:       ...

  6. 零基础的学习者应该怎么开始学习呢?Python核心知识学习思维分享

    近几年,Python一路高歌猛进,成为最受欢迎的编程语言之一,受到无数编程工作者的青睐. 据悉,Python已经入驻部分小学生教材,可以预见学习Python将成为一项提高自身职业竞争力的必修课.那么零 ...

  7. Redis 核心篇:唯快不破的秘密

    天下武功,无坚不摧,唯快不破! 学习一个技术,通常只接触了零散的技术点,没有在脑海里建立一个完整的知识框架和架构体系,没有系统观.这样会很吃力,而且会出现一看好像自己会,过后就忘记,一脸懵逼. 跟着「 ...

  8. 新书介绍 -- 《Redis核心原理与实践》

    大家好,今天给大家介绍一下我的新书 -- <Redis核心原理与实践>. 后端开发的同学应该对Redis都不陌生,Redis由于性能极高.功能强大,已成为业界非常流行的内存数据库. < ...

  9. 分布式缓存Redis使用心得

    一.缓存在系统中用来做什么 1. 少量数据存储,高速读写访问.通过数据全部in-momery 的方式来保证高速访问,同时提供数据落地的功能,实际这正是Redis最主要的适用场景. 2. 海量数据存储, ...

随机推荐

  1. mysql 中文支持

    show variables like 'character%';  SHOW VARIABLES LIKE 'collation_%'; recommend to use utf8mb4 inste ...

  2. 建荣AX3298作为航拍启动流程

    启动函数: SDK-3298\demo\helloftv\main.c 板级配置文件:SDK-3298\board\AX3292\mvl8801\board_config.h 1,定义了 debug串 ...

  3. 古墓丽影:崛起 PC版今日发售

    之前xbox one的独占游戏 古墓丽影: 崛起(Rise of the Tomb Raider™), 今天正式在steam发售了, 之前就可以预购.简单看了一下, 画风跟前代类似, 但是画面更好, ...

  4. jvm各区域OutOfMemory测试方法

    1.堆溢出 VM options:-Xmx9999k -Xmn3333k public class HeapOverMemory { public static void main(String[] ...

  5. 游戏编程模式 Game Programming Patterns (Robert Nystrom 著)

    第1篇 概述 第1章 架构,性能和游戏 (已看) 第2篇 再探设计模式 第2章 命令模式 (已看) 第3章 享元模式 (已看) 第4章 观察者模式 (已看) 第5章 原型模式 (已看) 第6章 单例模 ...

  6. supervisor 文档

    supervisor 是用 Python 开发的一个 C/S 服务.是 Linux/Unix 系统下的进程管理工具.它可以很方便的监听.启动.停止.重启一个或多个进程.用Supervisor管理的进程 ...

  7. lay-verify 无效

    lay-verify 无效 使用lay-verify有两个需要注意的地方: form标签需要添加 class="layui-form" 提交按钮需要添加 lay-submit=&q ...

  8. innobackupex: error while loading shared libraries: libssl.so.6

    我遇到过这个问题,但由于测试环境不允许上网,所以虽然搜到了一篇解决办法,但我也未亲自测试,先记录下来别人的解决办法. 参考文章:http://blog.itpub.net/29654823/views ...

  9. QT中资源文件的使用

    1.在工程中点右键,选添加文件: 在下一页中输入一个资源文件名,如uires,这样工程树下就会出现资源文件夹. 2.右键,选择“Open in Editor”打开它 3.添加或修改前缀名,前缀的作用类 ...

  10. IOS屏幕旋转思路和实践

    这段时间同事在做一个直播项目,项目有个需求:一个界面需要手动设置屏幕的方向,设置好之后方向不能变化.完成这个需求花了特别大的精力,归因是网上关于屏幕旋转的知识比较凌乱,解决问题花费不少时间,最后决定把 ...