标题:【Redis20】Redis进阶:线程与安全问题

文章目录
    分类:存储运维 标签:Redis

    Redis进阶:线程与安全问题

    之前我们其实已经提到过,Redis 是单线程的,那么,为什么它的作者坚持只使用单线程呢?在 Redis 6 之后,也增加了多线程的内容,但是这个多线程并不是说命令处理实现了多线程,而只是网络IO部分,为什么又仅仅只是给这一块增加了多线程呢?最后,我们还要看一看 Redis 中的安全问题。


    怎么样,今天的内容是不是还是有点意思的?当然,这些内容也偏理论,没啥好实践的东西,咱们慢慢一起消化。

    单线程

    在 Redis 中,所有命令的执行都是单一的一个线程来进行的。虽说也有一些其它的线程来执行类似于 BGSAVE 之类的操作,但是,主要的命令执行过程依然是雷打不动的单线程。因此,我们不能完全说 Redis 是一个单线程应用,它同样是基于多线程、多进程的一个应用软件,只是说,对于比较核心的部分,它确实是使用单线程来处理的。


    对于 Redis 来说,采用单线程的原因无外乎这么几点:

    • 内存操作本来就很快

    • 基于事件驱动的 epoll(IO多路复用)

    • 避免了多线程的上下文切换和调度

    • 避免资源竞争(所以可以方便地实现分布式锁)

    • 内部优化的数据结构提升效率(ziplist、跳表之类的)

    这东西吧,有利有就弊。单线程的问题就是:一是不能充分利用多核 CPU ,二是大键操作很费劲,比如经典的 KEYS * 问题或者尝试 DELETE 一个内容很大的键,非常酸爽。


    虽说有这些问题,但是,大部分情况下对于我们日常的应用开发来说,最最普通的 Redis 就已经非常能顶了。如果确实有多线程类似情况的需要,官方的建议是直接分布式部署,也就是使用 Redis Cluster 来实现。

    多线程

    好了,说完单线程的优劣,再来说说多线程的问题。上面已经说过,整个 Redis 架构肯定不是单线程的啦,像 BGSAVE 、BGREWRITEAOF、UNLINK 这类的命令,就是不会阻塞当前的命令线程的,而是在后台开启一个子进程来进行处理的。


    而在 Redis6 中,新增加的其实是对于网络IO方面的多线程处理。也就是说,Redis 的作者们认为:单个主线程处理网络请求的速度差点意思,毕竟一旦涉及到 IO ,不管是磁盘还是网络,明显都是要低于内存的处理速度的。因此,大神们就加上了网络IO的多线程能力,从而进一步提升 Redis 的处理能力。


    对于 IO 多线程的配置,只有两项。

    io-threads 4
    io-threads-do-reads no

    注意,默认情况下,io-threads-do-reads 是 no ,表示对于官方来说,默认情况下 IO 多线程也是关闭的。因此,要使用这个能力,需要将这个配置改成 yes 。然后就是 io-threads ,表示 IO 线程数量。官方推荐的是比 CPU 核数少一点,比如 8 核的 CPU 设置成 6 就可以了。


    多线程会不会带来线程安全的问题?不会,为啥呢?因为它的流程是在获取网络IO、解析命令时使用多线程处理,之后继续进入的依然是最主要的那个核心单线程操作内存,操作完成之后,将数据再交回多线程部分进行结果输出。


    如果在实际应用中,发现 Redis 实例的 CPU 开销不大,吞吐量却没有提升,可以考虑使用Redis 6.0的多线程机制,加速网络处理,进而提升实例的吞吐量。

    安全问题

    对于我来说,在 Redis 这一块是有经历过安全问题的。相信不少同学可能也会被搞过,那就是网络上的各路大神把你没设密码,开放了 Redis 的服务器变成了他的矿机。莫名其妙的 CPU 就满了,一查全是矿机程序,还会挂一个定时任务自动检查和下载这些矿机程序,非常高大上。


    其实上面就已经说出了 Redis 的安全防范策略:端口和密码。


    首先,我们要把服务实例设置成本地或者指定 ip 访问,也就是配置文件中的 bind_address ,然后呢,端口也要控制,最好在服务器配置的时候就形成内网组网,这样就不必开放外网端口号了。这一块在各种云服务提供商那里都比较好配置,端口的开放也可以通过云服务商提供的服务来操作。当然服务器本身的 iptables 或者 firewall 也可以配置上,多层防护总是没错的。


    另一点就是密码,线上正式生产环境,一定一定要设置密码。本来当时我的服务器就是内网用的,但是,为了测一个什么东西开放了外网端口,同时也一直没设置密码,然后我就给忘了关端口了..... 也就是说,密码是最底限的保障,就算你忘了自己开过了外网端口访问,起码还会多一层密码的保护。


    改端口号?改成16379啥的?用处不大,自己给自己找个心理安慰,大神们会扫端口然后尝试自动连接的。另外,Redis 的 RESP 协议没有注入问题,这个可以放心。


    其它的就是一些正常的服务器安全防护了,像是目录权限,运行实例的用户、用户组权限之类的。千万别把 redis.conf 放到 web 能访问的目录去呀,这个基础常识相信不用多说了吧。

    总结

    今天的内容简单吧,一个是单线程多线程的问题,另一个就是服务器安全的问题。这两块有可能平常你用不到,但在面试的时候却都是非常常见的面试题。但咱们一直说不是以面试为基础,而是以学习到真本事为标准嘛。所以,至少在遇到问题的时候,你能想起来这些内容,为什么会这样,是因为什么,然后才好找到解决方案,你说是不。


    参考文档:


    https://redis.io/docs/manual/security/

    视频链接

    微信文章地址:https://mp.weixin.qq.com/s/L_661w379Aud7PUgzULfHA

    B站视频地址:https://www.bilibili.com/video/BV1h14y1o7db

    微信视频地址:https://mp.weixin.qq.com/s/GMmuYQWhY7u4_6Di5MAX2w

    搜索
    关注