微信搜索关注「水滴与银弹」公众号,第一时间获取优质技术干货。7年资深后端研发,给你呈现不同的技术视角。python
你们好,我是 Kaito。程序员
我常常听到不少人讨论,关于「把 Redis 看成队列来用是否合适」的问题。redis
有些人表示同意,他们认为 Redis 很轻量,用做队列很方便。shell
也些人则反对,认为 Redis 会「丢」数据,最好仍是用「专业」的队列中间件更稳妥。后端
究竟哪一种方案更好呢?缓存
这篇文章,我就和你聊一聊把 Redis 看成队列,到底是否合适这个问题。微信
我会从简单到复杂,一步步带你梳理其中的细节,把这个问题真正的讲清楚。markdown
看完这篇文章后,我但愿你对这个问题你会有全新的认识。网络
在文章的最后,我还会告诉你关于「技术选型」的思路,文章有点长,但愿你能够耐心读完。运维
首先,咱们先从最简单的场景开始讲起。
若是你的业务需求足够简单,想把 Redis 看成队列来使用,确定最早想到的就是使用 List 这个数据类型。
由于 List 底层的实现就是一个「链表」,在头部和尾部操做元素,时间复杂度都是 O(1),这意味着它很是符合消息队列的模型。
若是把 List 看成队列,你能够这么来用。
生产者使用 LPUSH 发布消息:
127.0.0.1:6379> LPUSH queue msg1
(integer) 1
127.0.0.1:6379> LPUSH queue msg2
(integer) 2
复制代码
消费者这一侧,使用 RPOP 拉取消息:
127.0.0.1:6379> RPOP queue
"msg1"
127.0.0.1:6379> RPOP queue
"msg2"
复制代码
这个模型很是简单,也很容易理解。
但这里有个小问题,当队列中已经没有消息了,消费者在执行 RPOP 时,会返回 NULL。
127.0.0.1:6379> RPOP queue
(nil) // 没消息了
复制代码
而咱们在编写消费者逻辑时,通常是一个「死循环」,这个逻辑须要不断地从队列中拉取消息进行处理,伪代码通常会这么写:
while true:
msg = redis.rpop("queue")
// 没有消息,继续循环
if msg == null:
continue
// 处理消息
handle(msg)
复制代码
若是此时队列为空,那消费者依旧会频繁拉取消息,这会形成「CPU 空转」,不只浪费 CPU 资源,还会对 Redis 形成压力。
怎么解决这个问题呢?
也很简单,当队列为空时,咱们能够「休眠」一会,再去尝试拉取消息。代码能够修改为这样:
while true:
msg = redis.rpop("queue")
// 没有消息,休眠2s
if msg == null:
sleep(2)
continue
// 处理消息
handle(msg)
复制代码
这就解决了 CPU 空转问题。
这个问题虽然解决了,但又带来另一个问题:当消费者在休眠等待时,有新消息来了,那消费者处理新消息就会存在「延迟」。
假设设置的休眠时间是 2s,那新消息最多存在 2s 的延迟。
要想缩短这个延迟,只能减少休眠的时间。但休眠时间越小,又有可能引起 CPU 空转问题。
鱼和熊掌不可兼得。
那如何作,既能及时处理新消息,还能避免 CPU 空转呢?
Redis 是否存在这样一种机制:若是队列为空,消费者在拉取消息时就「阻塞等待」,一旦有新消息过来,就通知个人消费者当即处理新消息呢?
幸运的是,Redis 确实提供了「阻塞式」拉取消息的命令:BRPOP / BLPOP,这里的 B 指的是阻塞(Block)。
如今,你能够这样来拉取消息了:
while true:
// 没消息阻塞等待,0表示不设置超时时间
msg = redis.brpop("queue", 0)
if msg == null:
continue
// 处理消息
handle(msg)
复制代码
使用 BRPOP 这种阻塞式方式拉取消息时,还支持传入一个「超时时间」,若是设置为 0,则表示不设置超时,直到有新消息才返回,不然会在指定的超时时间后返回 NULL。
这个方案不错,既兼顾了效率,还避免了 CPU 空转问题,一箭双雕。
注意:若是设置的超时时间太长,这个链接过久没有活跃过,可能会被 Redis Server 断定为无效链接,以后 Redis Server 会强制把这个客户端踢下线。因此,采用这种方案,客户端要有重连机制。
解决了消息处理不及时的问题,你能够再思考一下,这种队列模型,有什么缺点?
咱们一块儿来分析一下:
第一个问题是功能上的,使用 List 作消息队列,它仅仅支持最简单的,一组生产者对应一组消费者,不能知足多组生产者和消费者的业务场景。
第二个问题就比较棘手了,由于从 List 中 POP 一条消息出来后,这条消息就会当即从链表中删除了。也就是说,不管消费者是否处理成功,这条消息都没办法再次消费了。
这也意味着,若是消费者在处理消息时异常宕机,那这条消息就至关于丢失了。
针对这 2 个问题怎么解决呢?咱们一个个来看。
从名字就能看出来,这个模块是 Redis 专门是针对「发布/订阅」这种队列模型设计的。
它正好能够解决前面提到的第一个问题:重复消费。
即多组生产者、消费者的场景,咱们来看它是如何作的。
Redis 提供了 PUBLISH / SUBSCRIBE 命令,来完成发布、订阅的操做。
假设你想开启 2 个消费者,同时消费同一批数据,就能够按照如下方式来实现。
首先,使用 SUBSCRIBE 命令,启动 2 个消费者,并「订阅」同一个队列。
// 2个消费者 都订阅一个队列
127.0.0.1:6379> SUBSCRIBE queue
Reading messages... (press Ctrl-C to quit)
1) "subscribe"
2) "queue"
3) (integer) 1
复制代码
此时,2 个消费者都会被阻塞住,等待新消息的到来。
以后,再启动一个生产者,发布一条消息。
127.0.0.1:6379> PUBLISH queue msg1
(integer) 1
复制代码
这时,2 个消费者就会解除阻塞,收到生产者发来的新消息。
127.0.0.1:6379> SUBSCRIBE queue
// 收到新消息
1) "message"
2) "queue"
3) "msg1"
复制代码
看到了么,使用 Pub/Sub 这种方案,既支持阻塞式拉取消息,还很好地知足了多组消费者,消费同一批数据的业务需求。
除此以外,Pub/Sub 还提供了「匹配订阅」模式,容许消费者根据必定规则,订阅「多个」本身感兴趣的队列。
// 订阅符合规则的队列
127.0.0.1:6379> PSUBSCRIBE queue.*
Reading messages... (press Ctrl-C to quit)
1) "psubscribe"
2) "queue.*"
3) (integer) 1
复制代码
这里的消费者,订阅了 queue.* 相关的队列消息。
以后,生产者分别向 queue.p1 和 queue.p2 发布消息。
127.0.0.1:6379> PUBLISH queue.p1 msg1
(integer) 1
127.0.0.1:6379> PUBLISH queue.p2 msg2
(integer) 1
复制代码
这时再看消费者,它就能够接收到这 2 个生产者的消息了。
127.0.0.1:6379> PSUBSCRIBE queue.*
Reading messages... (press Ctrl-C to quit)
...
// 来自queue.p1的消息
1) "pmessage"
2) "queue.*"
3) "queue.p1"
4) "msg1"
// 来自queue.p2的消息
1) "pmessage"
2) "queue.*"
3) "queue.p2"
4) "msg2"
复制代码
咱们能够看到,Pub/Sub 最大的优点就是,支持多组生产者、消费者处理消息。
讲完了它的优势,那它有什么缺点呢?
其实,Pub/Sub 最大问题是:丢数据。
若是发生如下场景,就有可能致使数据丢失:
到底是怎么回事?
这其实与 Pub/Sub 的实现方式有很大关系。
Pub/Sub 在实现时很是简单,它没有基于任何数据类型,也没有作任何的数据存储,它只是单纯地为生产者、消费者创建「数据转发通道」,把符合规则的数据,从一端转发到另外一端。
一个完整的发布、订阅消息处理流程是这样的:
看到了么,整个过程当中,没有任何的数据存储,一切都是实时转发的。
这种设计方案,就致使了上面提到的那些问题。
例如,若是一个消费者异常挂掉了,它再从新上线后,只能接收新的消息,在下线期间生产者发布的消息,由于找不到消费者,都会被丢弃掉。
若是全部消费者都下线了,那生产者发布的消息,由于找不到任何一个消费者,也会所有「丢弃」。
因此,当你在使用 Pub/Sub 时,必定要注意:消费者必须先订阅队列,生产者才能发布消息,不然消息会丢失。
这也是前面讲例子时,咱们让消费者先订阅队列,以后才让生产者发布消息的缘由。
另外,由于 Pub/Sub 没有基于任何数据类型实现,因此它也不具有「数据持久化」的能力。
也就是说,Pub/Sub 的相关操做,不会写入到 RDB 和 AOF 中,当 Redis 宕机重启,Pub/Sub 的数据也会所有丢失。
最后,咱们来看 Pub/Sub 在处理「消息积压」时,为何也会丢数据?
当消费者的速度,跟不上生产者时,就会致使数据积压的状况发生。
若是采用 List 看成队列,消息积压时,会致使这个链表很长,最直接的影响就是,Redis 内存会持续增加,直到消费者把全部数据都从链表中取出。
但 Pub/Sub 的处理方式却不同,当消息积压时,有可能会致使消费失败和消息丢失!
这是怎么回事?
仍是回到 Pub/Sub 的实现细节上来讲。
每一个消费者订阅一个队列时,Redis 都会在 Server 上给这个消费者在分配一个「缓冲区」,这个缓冲区其实就是一块内存。
当生产者发布消息时,Redis 先把消息写到对应消费者的缓冲区中。
以后,消费者不断地从缓冲区读取消息,处理消息。
可是,问题就出在这个缓冲区上。
由于这个缓冲区实际上是有「上限」的(可配置),若是消费者拉取消息很慢,就会形成生产者发布到缓冲区的消息开始积压,缓冲区内存持续增加。
若是超过了缓冲区配置的上限,此时,Redis 就会「强制」把这个消费者踢下线。
这时消费者就会消费失败,也会丢失数据。
若是你有看过 Redis 的配置文件,能够看到这个缓冲区的默认配置:client-output-buffer-limit pubsub 32mb 8mb 60。
它的参数含义以下:
Pub/Sub 的这一点特色,是与 List 做队列差别比较大的。
从这里你应该能够看出,List 实际上是属于「拉」模型,而 Pub/Sub 其实属于「推」模型。
List 中的数据能够一直积压在内存中,消费者何时来「拉」均可以。
但 Pub/Sub 是把消息先「推」到消费者在 Redis Server 上的缓冲区中,而后等消费者再来取。
当生产、消费速度不匹配时,就会致使缓冲区的内存开始膨胀,Redis 为了控制缓冲区的上限,因此就有了上面讲到的,强制把消费者踢下线的机制。
好了,如今咱们总结一下 Pub/Sub 的优缺点:
有没有发现,除了第一个是优势以外,剩下的都是缺点。
因此,不少人看到 Pub/Sub 的特色后,以为这个功能很「鸡肋」。
也正是以上缘由,Pub/Sub 在实际的应用场景中用得并很少。
目前只有哨兵集群和 Redis 实例通讯时,采用了 Pub/Sub 的方案,由于哨兵正好符合即时通信的业务场景。
咱们再来看一下,Pub/Sub 有没有解决,消息处理时异常宕机,没法再次消费的问题呢?
其实也不行,Pub/Sub 从缓冲区取走数据以后,数据就从 Redis 缓冲区删除了,消费者发生异常,天然也没法再次从新消费。
好,如今咱们从新梳理一下,咱们在使用消息队列时的需求。
当咱们在使用一个消息队列时,但愿它的功能以下:
Redis 除了 List 和 Pub/Sub 以外,还有符合这些要求的数据类型吗?
其实,Redis 的做者也看到了以上这些问题,也一直在朝着这些方向努力着。
Redis 做者在开发 Redis 期间,还另外开发了一个开源项目 disque。
这个项目的定位,就是一个基于内存的分布式消息队列中间件。
但因为种种缘由,这个项目一直不温不火。
终于,在 Redis 5.0 版本,做者把 disque 功能移植到了 Redis 中,并给它定义了一个新的数据类型:Stream。
下面咱们就来看看,它能符合上面提到的这些要求吗?
咱们来看 Stream 是如何解决上面这些问题的。
咱们依旧从简单到复杂,依次来看 Stream 在作消息队列时,是如何处理的?
首先,Stream 经过 XADD 和 XREAD 完成最简单的生产、消费模型:
生产者发布 2 条消息:
// *表示让Redis自动生成消息ID
127.0.0.1:6379> XADD queue * name zhangsan
"1618469123380-0"
127.0.0.1:6379> XADD queue * name lisi
"1618469127777-0"
复制代码
使用 XADD 命令发布消息,其中的「*」表示让 Redis 自动生成惟一的消息 ID。
这个消息 ID 的格式是「时间戳-自增序号」。
消费者拉取消息:
// 从开头读取5条消息,0-0表示从开头读取
127.0.0.1:6379> XREAD COUNT 5 STREAMS queue 0-0
1) 1) "queue"
2) 1) 1) "1618469123380-0"
2) 1) "name"
2) "zhangsan"
2) 1) "1618469127777-0"
2) 1) "name"
2) "lisi"
复制代码
若是想继续拉取消息,须要传入上一条消息的 ID:
127.0.0.1:6379> XREAD COUNT 5 STREAMS queue 1618469127777-0
(nil)
复制代码
没有消息,Redis 会返回 NULL。
以上就是 Stream 最简单的生产、消费。
这里再也不重点介绍 Stream 命令的各类参数,我在例子中演示时,凡是大写的单词都是「固定」参数,凡是小写的单词,都是能够本身定义的,例如队列名、消息长度等等,下面的例子规则也是同样,为了方便你理解,这里有必要提醒一下。
下面咱们来看,针对前面提到的消息队列要求,Stream 都是如何解决的?
1) Stream 是否支持「阻塞式」拉取消息?
能够的,在读取消息时,只须要增长 BLOCK 参数便可。
// BLOCK 0 表示阻塞等待,不设置超时时间
127.0.0.1:6379> XREAD COUNT 5 BLOCK 0 STREAMS queue 1618469127777-0
复制代码
这时,消费者就会阻塞等待,直到生产者发布新的消息才会返回。
2) Stream 是否支持发布 / 订阅模式?
也没问题,Stream 经过如下命令完成发布订阅:
下面咱们来看具体如何作?
首先,生产者依旧发布 2 条消息:
127.0.0.1:6379> XADD queue * name zhangsan
"1618470740565-0"
127.0.0.1:6379> XADD queue * name lisi
"1618470743793-0"
复制代码
以后,咱们想要开启 2 组消费者处理同一批数据,就须要建立 2 个消费者组:
// 建立消费者组1,0-0表示从头拉取消息
127.0.0.1:6379> XGROUP CREATE queue group1 0-0
OK
// 建立消费者组2,0-0表示从头拉取消息
127.0.0.1:6379> XGROUP CREATE queue group2 0-0
OK
复制代码
消费者组建立好以后,咱们能够给每一个「消费者组」下面挂一个「消费者」,让它们分别处理同一批数据。
第一个消费组开始消费:
// group1的consumer开始消费,>表示拉取最新数据
127.0.0.1:6379> XREADGROUP GROUP group1 consumer COUNT 5 STREAMS queue >
1) 1) "queue"
2) 1) 1) "1618470740565-0"
2) 1) "name"
2) "zhangsan"
2) 1) "1618470743793-0"
2) 1) "name"
2) "lisi"
复制代码
一样地,第二个消费组开始消费:
// group2的consumer开始消费,>表示拉取最新数据
127.0.0.1:6379> XREADGROUP GROUP group2 consumer COUNT 5 STREAMS queue >
1) 1) "queue"
2) 1) 1) "1618470740565-0"
2) 1) "name"
2) "zhangsan"
2) 1) "1618470743793-0"
2) 1) "name"
2) "lisi"
复制代码
咱们能够看到,这 2 组消费者,均可以获取同一批数据进行处理了。
这样一来,就达到了多组消费者「订阅」消费的目的。
3) 消息处理时异常,Stream 可否保证消息不丢失,从新消费?
除了上面拉取消息时用到了消息 ID,这里为了保证从新消费,也要用到这个消息 ID。
当一组消费者处理完消息后,须要执行 XACK 命令告知 Redis,这时 Redis 就会把这条消息标记为「处理完成」。
// group1下的 1618472043089-0 消息已处理完成
127.0.0.1:6379> XACK queue group1 1618472043089-0
复制代码
若是消费者异常宕机,确定不会发送 XACK,那么 Redis 就会依旧保留这条消息。
待这组消费者从新上线后,Redis 就会把以前没有处理成功的数据,从新发给这个消费者。这样一来,即便消费者异常,也不会丢失数据了。
// 消费者从新上线,0-0表示从新拉取未ACK的消息
127.0.0.1:6379> XREADGROUP GROUP group1 consumer1 COUNT 5 STREAMS queue 0-0
// 以前没消费成功的数据,依旧能够从新消费
1) 1) "queue"
2) 1) 1) "1618472043089-0"
2) 1) "name"
2) "zhangsan"
2) 1) "1618472045158-0"
2) 1) "name"
2) "lisi"
复制代码
4) Stream 数据会写入到 RDB 和 AOF 作持久化吗?
Stream 是新增长的数据类型,它与其它数据类型同样,每一个写操做,也都会写入到 RDB 和 AOF 中。
咱们只须要配置好持久化策略,这样的话,就算 Redis 宕机重启,Stream 中的数据也能够从 RDB 或 AOF 中恢复回来。
5) 消息堆积时,Stream 是怎么处理的?
其实,当消息队列发生消息堆积时,通常只有 2 个解决方案:
而 Redis 在实现 Stream 时,采用了第 2 个方案。
在发布消息时,你能够指定队列的最大长度,防止队列积压致使内存爆炸。
// 队列长度最大10000
127.0.0.1:6379> XADD queue MAXLEN 10000 * name zhangsan
"1618473015018-0"
复制代码
当队列长度超过上限后,旧消息会被删除,只保留固定长度的新消息。
这么来看,Stream 在消息积压时,若是指定了最大长度,仍是有可能丢失消息的。
除了以上介绍到的命令,Stream 还支持查看消息长度(XLEN)、查看消费者状态(XINFO)等命令,使用也比较简单,你能够查询官方文档了解一下,这里就不过多介绍了。
好了,经过以上介绍,咱们能够看到,Redis 的 Stream 几乎覆盖到了消息队列的各类场景,是否是以为很完美?
既然它的功能这么强大,这是否是意味着,Redis 真的能够做为专业的消息队列中间件来使用呢?
可是还「差一点」,就算 Redis 能作到以上这些,也只是「趋近于」专业的消息队列。
缘由在于 Redis 自己的一些问题,若是把其定位成消息队列,仍是有些欠缺的。
到这里,就不得不把 Redis 与专业的队列中间件作对比了。
下面咱们就来看一下,Redis 在做队列时,到底还有哪些欠缺?
其实,一个专业的消息队列,必需要作到两大块:
前面咱们讨论的重点,很大篇幅围绕的是第一点展开的。
这里咱们换个角度,从一个消息队列的「使用模型」来分析一下,怎么作,才能保证数据不丢?
使用一个消息队列,其实就分为三大块:生产者、队列中间件、消费者。
消息是否会发生丢失,其重点也就在于如下 3 个环节:
1) 生产者会不会丢消息?
当生产者在发布消息时,可能发生如下异常状况:
若是是状况 1,消息根本没发出去,那么从新发一次就行了。
若是是状况 2,生产者没办法知道消息到底有没有发成功?因此,为了不消息丢失,它也只能继续重试,直到发布成功为止。
生产者通常会设定一个最大重试次数,超过上限依旧失败,须要记录日志报警处理。
也就是说,生产者为了不消息丢失,只能采用失败重试的方式来处理。
但发现没有?这也意味着消息可能会重复发送。
是的,在使用消息队列时,要保证消息不丢,宁肯重发,也不能丢弃。
那消费者这边,就须要多作一些逻辑了。
对于敏感业务,当消费者收到重复数据数据时,要设计幂等逻辑,保证业务的正确性。
从这个角度来看,生产者会不会丢消息,取决于生产者对于异常状况的处理是否合理。
因此,不管是 Redis 仍是专业的队列中间件,生产者在这一点上都是能够保证消息不丢的。
2) 消费者会不会丢消息?
这种状况就是咱们前面提到的,消费者拿到消息后,还没处理完成,就异常宕机了,那消费者还可否从新消费失败的消息?
要解决这个问题,消费者在处理完消息后,必须「告知」队列中间件,队列中间件才会把标记已处理,不然仍旧把这些数据发给消费者。
这种方案须要消费者和中间件互相配合,才能保证消费者这一侧的消息不丢。
不管是 Redis 的 Stream,仍是专业的队列中间件,例如 RabbitMQ、Kafka,其实都是这么作的。
因此,从这个角度来看,Redis 也是合格的。
3) 队列中间件会不会丢消息?
前面 2 个问题都比较好处理,只要客户端和服务端配合好,就能保证生产端、消费端都不丢消息。
可是,若是队列中间件自己就不可靠呢?
毕竟生产者和消费这都依赖它,若是它不可靠,那么生产者和消费者不管怎么作,都没法保证数据不丢。
在这个方面,Redis 其实没有达到要求。
Redis 在如下 2 个场景下,都会致使数据丢失。
基于以上缘由咱们能够看到,Redis 自己的没法保证严格的数据完整性。
因此,若是把 Redis 当作消息队列,在这方面是有可能致使数据丢失的。
再来看那些专业的消息队列中间件是如何解决这个问题的?
像 RabbitMQ 或 Kafka 这类专业的队列中间件,在使用时,通常是部署一个集群,生产者在发布消息时,队列中间件一般会写「多个节点」,以此保证消息的完整性。这样一来,即使其中一个节点挂了,也能保证集群的数据不丢失。
也正由于如此,RabbitMQ、Kafka在设计时也更复杂。毕竟,它们是专门针对队列场景设计的。
但 Redis 的定位则不一样,它的定位更可能是看成缓存来用,它们二者在这个方面确定是存在差别的。
最后,咱们来看消息积压怎么办?
4) 消息积压怎么办?
由于 Redis 的数据都存储在内存中,这就意味着一旦发生消息积压,则会致使 Redis 的内存持续增加,若是超过机器内存上限,就会面临被 OOM 的风险。
因此,Redis 的 Stream 提供了能够指定队列最大长度的功能,就是为了不这种状况发生。
但 Kafka、RabbitMQ 这类消息队列就不同了,它们的数据都会存储在磁盘上,磁盘的成本要比内存小得多,当消息积压时,无非就是多占用一些磁盘空间,相比于内存,在面对积压时也会更加「坦然」。
综上,咱们能够看到,把 Redis 看成队列来使用时,始终面临的 2 个问题:
到这里,Redis 是否能够用做队列,我想这个答案你应该会比较清晰了。
若是你的业务场景足够简单,对于数据丢失不敏感,并且消息积压几率比较小的状况下,把 Redis 看成队列是彻底能够的。
并且,Redis 相比于 Kafka、RabbitMQ,部署和运维也更加轻量。
若是你的业务场景对于数据丢失很是敏感,并且写入量很是大,消息积压时会占用不少的机器资源,那么我建议你使用专业的消息队列中间件。
好了,总结一下。这篇文章咱们从「Redis 可否用做队列」这个角度出发,介绍了 List、Pub/Sub、Stream 在作队列的使用方式,以及它们各自的优劣。
以后又把 Redis 和专业的消息队列中间件作对比,发现 Redis 的不足之处。
最后,咱们得出 Redis 作队列的合适场景。
这里我也列了一个表格,总结了它们各自的优缺点。
最后,我想和你再聊一聊关于「技术方案选型」的问题。
你应该也看到了,这篇文章虽然始于 Redis,但并不止于 Redis。
咱们在分析 Redis 细节时,一直在提出问题,而后寻找更好的解决方案,在文章最后,又聊到一个专业的消息队列应该怎么作。
其实,咱们在讨论技术选型时,就是一个关于如何取舍的问题。
而这里我想传达给你的信息是,在面对技术选型时,不要不通过思考就以为哪一个方案好,哪一个方案很差。
你须要根据具体场景具体分析,这里我把这个分析过程分为 2 个层面:
这篇文章所讲到的内容,都是以业务功能角度出发作决策的。
但这里的第二点,从技术资源角度出发,其实也很重要。
技术资源的角度是说,你所处的公司环境、技术资源可否匹配这些技术方案。
这个怎么解释呢?
简单来说,就是你所在的公司、团队,是否有匹配的资源能 hold 住这些技术方案。
咱们都知道 Kafka、RabbitMQ 是很是专业的消息中间件,但它们的部署和运维,相比于 Redis 来讲,也会更复杂一些。
若是你在一个大公司,公司自己就有优秀的运维团队,那么使用这些中间件确定没问题,由于有足够优秀的人能 hold 住这些中间件,公司也会投入人力和时间在这个方向上。
但若是你是在一个初创公司,业务正处在快速发展期,暂时没有能 hold 住这些中间件的团队和人,若是贸然使用这些组件,当发生故障时,排查问题也会变得很困难,甚至会阻碍业务的发展。
而这种情形下,若是公司的技术人员对于 Redis 都很熟,综合评估来看,Redis 也基本能够知足业务 90% 的需求,那当下选择 Redis 未必不是一个好的决策。
因此,作技术选型不仅是技术问题,还与人、团队、管理、组织结构有关。
也正是由于这些缘由,当你在和别人讨论技术选型问题时,你会发现每一个公司的作法都不相同。
毕竟每一个公司所处的环境和文化不同,作出的决策固然就会各有差别。
若是你不了解这其中的逻辑,那在作技术选型时,只会趋于表面现象,没法深刻到问题根源。
而一旦你理解了这个逻辑,那么你在看待这个问题时,不只对于技术会有更加深入认识,对技术资源和人的把握,也会更加清晰。
但愿你之后在作技术选型时,可以把这些因素也考虑在内,这对你的技术成长之路也是很是有帮助的。
想看更多硬核技术文章?欢迎关注个人公众号「水滴与银弹」。
我是 Kaito,是一个对于技术有思考的资深后端程序员,在个人文章中,我不只会告诉你一个技术点是什么,还会告诉你为何这么作?我还会尝试把这些思考过程,提炼成通用的方法论,让你能够应用在其它领域中,作到触类旁通。