原文地址:https://draveness.me/redis-io-multiplexing/
Redis 和 I/O 多路复用 2016-11-26 Redis 数据库 NoSQL
最近在看 UNIX 网络编程并研究了一下 Redis 的实现,感觉 Redis 的源代码十分适合阅读和分析,其中 I/O 多路复用(mutiplexing)部分的实现非常干净和优雅,在这里想对这部分的内容进行简单的整理。
几种 I/O 模型 为什么 Redis 中要使用 I/O 多路复用这种技术呢?
首先,Redis 是跑在单线程中的,所有的操作都是按照顺序线性执行的,但是由于读写操作等待用户输入或输出都是阻塞的,所以 I/O 操作在一般情况下往往不能直接返回,这会导致某一文件的 I/O 阻塞导致整个进程无法对其它客户提供服务,而 I/O 多路复用就是为了解决这个问题而出现的。
Blocking I/O 先来看一下传统的阻塞 I/O 模型到底是如何工作的:当使用 read 或者 write 对某一个文件描述符(File Descriptor 以下简称 FD)进行读写时,如果当前 FD 不可读或不可写,整个 Redis 服务就不会对其它的操作作出响应,导致整个服务不可用。
这也就是传统意义上的,也就是我们在编程中使用最多的阻塞模型:
阻塞模型虽然开发中非常常见也非常易于理解,但是由于它会影响其他 FD 对应的服务,所以在需要处理多个客户端任务的时候,往往都不会使用阻塞模型。
I/O 多路复用 虽然还有很多其它的 I/O 模型,但是在这里都不会具体介绍。
阻塞式的 I/O 模型并不能满足这里的需求,我们需要一种效率更高的 I/O 模型来支撑 Redis 的多个客户(redis-cli),这里涉及的就是 I/O 多路复用模型了:
时间:
|
阅读:
804 字 ~4分钟
“
天下武功,无坚不摧,唯快不破!
”
以下文章来源于码哥字节 ,作者MageByte技术团队 ** **
学习一个技术,通常只接触了零散的技术点,没有在脑海里建立一个完整的知识框架和架构体系,没有系统观。这样会很吃力,而且会出现一看好像自己会,过后就忘记,一脸懵逼。
跟着「码哥字节」一起吃透 Redis,深层次的掌握 Redis 核心原理以及实战技巧。一起搭建一套完整的知识框架,学会全局观去整理整个知识体系。
系统观其实是至关重要的,从某种程度上说,在解决问题时,拥有了系统观,就意味着你能有依据、有章法地定位和解决问题。
Redis 全景图 全景图可以围绕两个维度展开,分别是:
应用维度:缓存使用、集群运用、数据结构的巧妙使用
系统维度:可以归类为三高
高性能:线程模型、网络 IO 模型、数据结构、持久化机制; 高可用:主从复制、哨兵集群、Cluster 分片集群; 高拓展:负载均衡 Redis 系列篇章围绕如下思维导图展开,这次从 《Redis 唯快不破的秘密》一起探索 Redis 的核心知识点。
吃透Redis
唯快不破的秘密 65 哥前段时间去面试 996 大厂,被问到「Redis 为什么快?」
“
65 哥:额,因为它是基于内存实现和单线程模型
”
面试官:还有呢?
“
65 哥:没了呀。
”
很多人仅仅只是知道基于内存实现,其他核心的原因模凌两可。今日跟着「码哥字节」一起探索真正快的原因,做一个唯快不破的真男人!
Redis 为了高性能,从各方各面都进行了优化,下次小伙伴们面试的时候,面试官问 Redis 性能为什么如此高,可不能傻傻的只说单线程和内存存储了。
唯快不破的秘密
根据官方数据,Redis 的 QPS 可以达到约 100000(每秒请求数),有兴趣的可以参考官方的基准程序测试《How fast is Redis?》,地址:https://redis.io/topics/benchmarks
基准测试
时间:
|
阅读:
1044 字 ~5分钟
最近项目上线的频率颇高,连着几天加班熬夜,身体有点吃不消精神也有些萎靡,无奈业务方催的紧,工期就在眼前只能硬着头皮上了。脑子浑浑噩噩的时候,写的就不能叫代码,可以直接叫做Bug。我就熬夜写了一个bug被骂惨了。
由于是做商城业务,要频繁的对商品库存进行扣减,应用是集群部署,为避免并发造成库存超买超卖等问题,采用 redis 分布式锁加以控制。本以为给扣库存的代码加上锁lock.tryLock就万事大吉了
/** * @author xiaofu * @description 扣减库存 * @date 2020/4/21 12:10 */ public String stockLock() { RLock lock = redissonClient.getLock("stockLock"); try { /** * 获取锁 */ if (lock.tryLock(10, TimeUnit.SECONDS)) { /** * 查询库存数 */ Integer stock = Integer.valueOf(stringRedisTemplate.opsForValue().get("stockCount")); /** * 扣减库存 */ if (stock > 0) { stock = stock - 1; stringRedisTemplate.opsForValue().set("stockCount", stock.toString()); LOGGER.info("库存扣减成功,剩余库存数量:{}", stock); } else { LOGGER.info("库存不足~"); } } else { LOGGER.info("未获取到锁业务结束.."); } } catch (Exception e) { LOGGER.
时间:
|
阅读:
367 字 ~2分钟
Redis如何绑定CPU 源文地址:https://www.yisu.com/zixun/672271.html
绑定 CPU Redis 6.0 开始支持绑定 CPU,可以有效减少线程上下文切换。
CPU 亲和性(CPU Affinity)是一种调度属性,它将一个进程或线程,「绑定」到一个或一组 CPU 上。也称为 CPU 绑定。
设置 CPU 亲和性可以一定程度避免 CPU 上下文切换,提高 CPU L1、L2 Cache 命中率。
早期「SMP」架构下,每个 CPU 通过 BUS 总线共享资源。CPU 绑定意义不大。
而在当前主流的「NUMA」架构下,每个 CPU 有自己的本地内存。访问本地内存有更快的速度。而访问其他 CPU 内存会导致较大的延迟。这时,CPU 绑定对系统运行速度的提升有较大的意义。
现实中的 NUMA 架构比上图更复杂,通常会将 CPU 分组,若干个 CPU 分配一组内存,称为 「node」。
你可以通过 「numactl -H 」 命令来查看 NUMA 硬件信息。
$ numactl -H available: 2 nodes (0-1)node 0 cpus: 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 node 0 size: 32143 MB node 0 free: 26681 MB node 1 cpus: 1 3 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 node 1 size: 32309 MB node 1 free: 24958 MB node distances: node 0 1 0: 10 21 1: 21 10 上图中可以得知该机器有 40 个 CPU,分组为 2 个 node。
时间:
|
阅读:
31 字 ~1分钟
Redis子进程开销与优化 源文地址:https://blog.csdn.net/y532798113/article/details/106870299
1、CPU 开销 RDB和AOF文件生成,属于CPU密集型
优化
不做CPU绑定,也就是不把redis进程绑定在一个CPU上; 不和CPU密集型服务部署在一起; 2、内存 开销 fork内存开销,copy-on-write
优化
linux内核优化,禁止使用:echo never > /sys/kernel/mm/transparent_hugepage/enable, 禁止原因:如果父进程有大量的内存页写入,就证明你的子进程内存开销比较大,因为它会写内存副本,造成很大的内存开销;
不允许单机做部署的时候,大量产生重写;
在Redis主进程写入量比较小的时候,执行save or bgsave时候就会消耗比较小的内存;
3、硬盘 开销 RDB和AOF文件写入,可以结合iostat,iotop分析
优化
不要和负载很高的硬盘部署在一起:存储服务(文件存储)、消息队列等; no-appendfsync-on-rewrite = yes,重写的过程不进行追加redis命令; 根据写入量决定磁盘类型:例如:SSD; 单机多实例持久化文件目录可以考虑分盘;
时间:
|
阅读:
1610 字 ~8分钟
Redis学习文档 Redis安装和启动 安装Redis
mkdir -p /usr/redis cd /usr/redis # 下载redis源码包 wget http://download.redis.io/releases/redis-3.2.9.tar.gz tar -vxzf redis-3.2.9.tar.gz ln -s redis-3.2.9 redis cd redis # 直接make会报错误, zmalloc.h:50:31: 致命错误:jemalloc/jemalloc.h:没有那个文件或目录 # 加 MALLOC=libc 参数可以正常编译 make MALLOC=libc # 将运行文件安装到 /usr/local/bin 下,可以在任意目录下执行redis命令 make install 启动Redis
redis-server 配置文件名称.conf 客户端连接操作
# -h接ip -p接端口 redis-cli -h 127.0.0.1 -p 6379 # 或者直接执行命令 redis-cli -h 127.0.0.1 -p 6379 get hello Redis数据结构及实现 Redis的数据结构分别是: string(字符串) 、 hash(哈希) 、 list(列表) 、 set(集合) 、 zset(有序集 合)
时间:
|
阅读:
175 字 ~1分钟
sequenceDiagram 100.27主 ->> 100.27主 : 崩溃 13:23 100.27主 ->> 111.19从 : 主从切换 13:23 100.27主 ->> + 111.19从 : 请求主从同步 13:44 111.19从 ->> 111.19从 : bgsave生成RDB 13:44 loop BGSAVE 111.19从 ->> + 111.19从 : 子线程bgsave生成RDB崩溃并重试 end loop BGSAVE 111.19从 ->> + 111.19从 : 手动bgsave生成RDB崩溃 end 111.19从 ->> 111.19从 : scan触发崩溃 15:01 111.19从 ->> 100.27主 : 主从切换 111.19从 ->> 111.19从 : 手动启动恢复 15:09 10.105.100.27 日志分析 === REDIS BUG REPORT START: Cut & paste starting from here === 12220:M 13 Jul 13:23:33.
时间:
|
阅读:
724 字 ~4分钟
生产环境出现实例宕机的情况,在redis的日志中会输出宕机时的相应信息,如下面的源代码,下面记录一下分析日志的详细过程。
=== REDIS BUG REPORT START: Cut & paste starting from here === 10430:M 13 Jul 15:01:55.933 # Redis 3.2.3 crashed by signal: 11 10430:M 13 Jul 15:01:55.933 # Crashed running the instuction at: 0x438ea0 10430:M 13 Jul 15:01:55.933 # Accessing address: (nil) 10430:M 13 Jul 15:01:55.933 # Failed assertion: <no assertion failed> (<no file>:0) ------ STACK TRACE ------ EIP: /opt/cachecloud/redis/src/redis-server 0.0.0.0:7000 [cluster](scanCallback+0xb0)[0x438ea0] Backtrace: /opt/cachecloud/redis/src/redis-server 0.0.0.0:7000 [cluster](logStackTrace+0x29)[0x45d3d9] /opt/cachecloud/redis/src/redis-server 0.0.0.0:7000 [cluster](sigsegvHandler+0xaa)[0x45d8ca] /lib64/libpthread.