前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[database][redis]redis技术分析

[database][redis]redis技术分析

作者头像
皮振伟
发布2018-04-09 10:17:58
9540
发布2018-04-09 10:17:58
举报
文章被收录于专栏:皮振伟的专栏皮振伟的专栏

前言: 解读一下redis的源代码~ 因为hash算法,skiplist等相关文章很多,前人之述备矣,这里不做解读。这里会解读一些相对较“冷门”的代码。 分析: 代码选自官网(https://redis.io/)最新版(3.2.6)。 1,network redis自己实现了网络库,具体代码参考anet.c,ae.c,ae_epoll.c,ae_evport.c,ae.h,ae_kqueue.c,ae_select.c。 在ae.c中,实现了event loop的整体逻辑,平台差异的地方分别在ae_*.c中。以epoll(ae_epoll.c)为例:

实现了aeApiCreate等几个API。细心的你可能也发现了,为什么API是static函数,那么多个obj进行链接的时候,可以找到symbol吗? 其实redis是这样处理的,在ae.c中:

这样的写法,其实作者并不是最欣赏的。毕竟header file和source file都有各自相对固定的用法。本着对antirez的尊重,还是要说一下,这里实现挺巧妙的。 如果有需要,把这几个文件copy出去,作为一个基础版的网络库使用,也不失为一个好办法。 2,malloc Linux上对于绝大部分程序而言,都是默认使用glibc的malloc(即ptmalloc)。redis在zmalloc.h,zmalloc.c中做了封装,另外还可以使用tcmalloc,jemalloc(redis已经把jemalloc的代码集成在了deps/jemalloc/目录下)。 另外,在zmalloc中,还实现了一定的内存分析能力:

原理很简单,就是分析/proc/self/smaps文件。不过,在这里,作者要说一句,分析/proc/self/smaps并不是完完全玩准确的,总体来说,会有一点点偏低。 zmalloc给用户提供了更多的malloc使用选择;但是,这也就变相说明了redis没有slab能力(相比之下,memcached则实现了slab)。 3,bitmap setbit命令的入口setbitCommand函数。对待bitmap,其实和普通的value一样。只不过,redis会以bit的与或非运算来计算到具体的bit上。关于bit计算,不讨论。来看下面的一条调用路径(作用是查找到当前key对应的value): setbitCommand→lookupStringForBitCommand→sdsgrowzero:

差别在于: 如果新设置的bit位置大于之前的bitmap的范围,那么就要调用sdsMakeRoomFor来增长value的大小。尽管在sdsMakeRoomFor函数中,buf增加是以1K为单位增大的,会尽量避免复杂的增长操作,但是,也会有一定的逻辑判断损失。所以,用户可以预计bitmap的是范围后,先执行一次setbit最大范围,会有一定的性能提升。 例如:预计1000W的bitmap,那么先setbit bitmap 10000001 1,会比依次递增bit高效一些。 4,aof_fsync 回写数据使用的aof_fsync:

在linux上会使用fdatasync,那么就意味着,不能通过db文件的时间来判断数据是否下沉。fdatasync为了提高性能,只保存数据,不保存数据的元信息。(百度百科http://baike.baidu.com/item/fdatasync是作者写的 (=^ω^=)) 5,aof 配置文件中两个变量:auto-aof-rewrite-percentage&auto-aof-rewrite-min-size,redis读取到之后,配置给aof_rewrite_perc&aof_rewrite_min_size。

随着db变大,那么aof文件的大小,也会随着变大。growth是增量百分比,所以,合理估计db的大小,合理配置aof的比例大小。 6,timer redis并没有使用真正意义上的timer(linux kernel提供了timer的api,不过redis并没有使用)。redis把定时任务,放到一个链表中。

进入polling循环之前,先计算所有timer中的最近一个要超时的时间,作为timeout值。如果poll返回,要么是有网络事件,要么就是超时,则可以处理timer的callback。 好在现在的timer事件不多,不然,这里会是一个瓶颈。 7,save save有两种,save和back ground save。 save是redis进程(注意,redis是单线程的)执行save,把数据回写到db文件中。 bgsave是redis进程fork出来一个子进程来执行save。 如果db的大小比较大的情况下,执行save会花费更多的时间,在此期间不能处理其他的请求。

save中,先把数据写入到tmp文件中,然后再rename一下。这样做的好处在于:write是一个比较慢的过程,rename会比较快。另外,这里使用的是glibc的buffered io,即FILE族函数。 后记: 其他细节,慢慢补充吧。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2017-01-31,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 AlwaysGeek 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
云数据库 Redis
腾讯云数据库 Redis(TencentDB for Redis)是腾讯云打造的兼容 Redis 协议的缓存和存储服务。丰富的数据结构能帮助您完成不同类型的业务场景开发。支持主从热备,提供自动容灾切换、数据备份、故障迁移、实例监控、在线扩容、数据回档等全套的数据库服务。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档