当前位置: 首页 > 后端技术 > Node.js

为什么单线程Redis的性能那么高?

时间:2023-04-03 16:02:01 Node.js

本文首发于公众号:程序员周先森。本平台不定期更新,喜欢我的文章,请关注我的微信公众号。实际项目开发中不可避免的问题之一就是缓存问题,而缓存问题也是面试必须要问的知识点之一。如果面试官比较好,他可能会简单的问你28定律或者热数据和冷数据,但是如果你问的再深一点,你可能会问缓存更新、降级、预热、雪崩、穿透等问题。这些问题可能会让大部分平时不太关注缓存的朋友望而却步。这些问题其实都和缓存服务器息息相关。我们日常生活中经常使用的缓存服务器一般有两种:Redis和Memcached。本文正式进入Redis系列文章。这篇文章主要讲Redis为什么用单线程那么快?既然有两种缓存服务器,为什么要选择Redis呢?Redis和Memcached有什么区别?Redis和Memcached的区别Redis支持常见的数据类型:Redis不仅支持简单的key/value类型的数据,还提供了string(字符串)、list(链表)、set(集合)、zset(有序集合)和Storageofhash(散列类型)等数据结构。Memcache仅支持简单数据类型String。Redis支持数据持久化。它可以将内存中的数据保存在磁盘上,重启时可以再次加载使用。Memecache将所有数据存储在内存中。集群模式:Memcached没有原生集群模式,需要依赖客户端向集群分片写入数据;但Redis目前原生支持Cluster模式。Memcached是一种多线程、非阻塞IO多路复用网络模型;Redis采用单线程多路复用IO多路复用模型。Redis是一个键值存储系统。它支持相对较多的存储值类型,包括string(字符串)、list(链表)、set(集合)、zset(有序集合)和hash(散列类型)。这些数据类型支持push/pop、add/remove、intersection、union、difference等更丰富的操作,而且这些操作是原子的。在此基础上,redis支持多种方式的排序。为了保证效率,数据缓存在内存中。不同的是redis会周期性的将更新的数据写入磁盘或者将修改操作写入附加的记录文件,并在此基础上实现主从同步。简单的说,Redis就是一个数据库,但是与传统数据库不同的是,Redis的数据是存储在内存中的,所以存储和写入的速度都非常快,所以Redis在缓存方向应用的比较广泛。Redis也常用于分布式锁。Redis提供了多种数据类型来支持不同的业务场景。此外,Redis支持事务、持久化、LUA脚本、LRU驱动的事件和多集群解决方案。Redis中常用的数据类型其实只有五种:String、Hash、List、Set、ZSet。我们可以先看看这五种基本数据类型的用法:String常用命令:set、get、decr、incr、mget等。String数据结构是一种简单的Key-Value类型,Value可以是字符串也可以是数字。常规Key-Value缓存应用;常规统计:博客数、阅读数等。Hash常用命令:hget、hset、hgetall等。Hash特别适合存储对象。列出常用命令:lpush、rpush、lpop、rpop、lrange等。链表是Redis最重要的数据结构之一。RedisList是双向链表,支持反向查找和遍历,操作起来更方便,但带来了额外的内存开销。Set常用命令:sadd、spop、smembers、sunion等。其实Set和List都是列表选项,Set可以自动去重。当你需要存储一个没有重复数据的列表数据时,Set是最好的选择。您可以轻松地基于Set实现交、并、差运算。SortedSet常用命令:zadd、zrange、zrem、zcard等。与Set相比,SortedSet增加了一个权重参数Score,使得集合中的元素可以根据Score进行有序排列。如果按存储方式来划分数据库工作方式,可以分为硬盘数据库和内存数据库两种。Redis之所以读写数据这么快,其实是因为Redis将数据存储在内存中,所以在读写数据的时候不会受到硬盘I/O速度的限制,读写速度自然是非常快的。硬盘数据库在内存中存储一??个索引,然后根据索引在硬盘中查询对应的值,这样效率肯定会相对慢一些。Redis是基于Key-Value数据库,基于内存的单线程单进程模型。经过官方测试,每秒的查询数可以高达100,000+,那么Redis为什么这么快呢?最关键的一点其实刚才已经提到了,因为Redis是完全基于内存的,Redis收到的大部分请求直接操作内存就可以完成,所以对请求的处理速度非常快,而且Redis使用单thread避免了不必要的上下文切换和竞争锁机制,不会有频繁的线程切换带来的CPU消耗,不会出现多线程死锁等一系列问题。在Redis中使用多路复用I/O模型而不是非阻塞I/O。非阻塞I/O之前在Nginx中已经提到过,这里不再重复介绍。让我们关注多路复用I/O多路复用模型。多路I/O多路复用模型实际上是使用select、poll、epoll同时监听多个流的I/O事件。当没有I/O事件时,即线程会阻塞在空闲状态。当有I/O事件需要处理时,线程从阻塞状态唤醒,然后使用epoll轮询所有有I/O事件的流。多路复用其实就是多个网络连接复用同一个线程。使用多I/O多路复用技术,可以让单个进程高效处理多个连接请求,Redis对内存中的数据进行操作。所以数据运行速度非常快,不会出现速度瓶颈,Redis可以有很高的吞吐量和性能。Redis的瓶颈主要来自于机器内存或者网络带宽。CPU不是Redis的瓶颈,单线程更容易实现,所以Redis采用单线程的方式顺理成章,但是单线程的方式无法发挥多核CPU的优势。是的,比如在执行耗时操作时,Redis的并发度会降低。因为单线程,一次只能处理一个操作,执行耗时操作会导致并发度下降。有一个简单的解决办法:在多核CPU下,单机开多个Redis实例即可解决这个问题。欢迎关注公众号:程序员周先森。