标签 Redis 下的文章 - 酷游博客
首页
关于
友链
Search
1
阿里的简历多久可以投递一次?次数多了有没有影响?可以同时进行吗?
45 阅读
2
Java中泛型的理解
40 阅读
3
Java 14 发布了,再也不怕 NullPointerException 了!
38 阅读
4
Java中的可变参数
37 阅读
5
该如何创建字符串,使用" "还是构造函数?
29 阅读
技术
登录
/
注册
找到
4
篇与
Redis
相关的结果
2025-01-22
老生常谈的 Redis 雪崩、击穿、穿透、预热、降级一次全安排
关于 Redis 的介绍、特点什么的就不再这里赘述了,不然又要水千把字。今天我们就重点看企业中在使用 Redis 常见一些问题以及对应解决方案。 某个请求到达业务系统,想要获取某个数据,一般是先从缓存中获取,如果缓存中不存在就会去数据库中查询,如果查询到结果就将数据保存到缓存中再返回结果。 一个新的技术的引进,必然会带来一些额外的问题,那么 Redis 这么优秀的 NoSQL 数据库会带来什么样的问题呢?我们一起拭目以待。 缓存击穿 缓存击穿根据名字根本无法看懂是什么意思,并且很容易和另一个词——缓存穿透搞混。缓存击穿指的是某个 key 一直在扛着高并发,所谓扛着高并发就是说大量的请求都是获取这个 key 对应的值。 而这个 key 在某个时间突然失效了,那是不是就意味着大量的请求就无法在缓存中获取数据了,而是去请求数据库了,这样很有可能导致数据库被击垮。这就是缓存击穿。 那现在问题知道了,该如何应对呢?这个就比较简单了,既然这个 key 这个受欢迎,那么就不要设置过期时间了,如果该key的数据更新了,那么就通过互斥锁的方式将其更新。 为什么要用互斥锁的方式?如果不使用互斥锁的方式很容易导致数据不一致的情况,这里为了保证缓存和数据库的一致性,就只能牺牲一点点的效率了。 缓存雪崩 不知道各位小伙伴都是来自哪里,我们那边有句方言叫“雪崩”,表示事情砸了的意思。这里的Redis 雪崩似乎有点异曲同工之妙。首先我们需要知道什么是 Redis雪崩, Redis雪崩我们一般都称为缓存雪崩,意思就是说在某个时间节点,大量的 key 失效,导致大量的请求从缓存中获取不到数据而去请求数据库。根据上面的那张图,我们再来画下雪崩的情况的是什么样子的: 上面的黑色的部分表示缓存无效了,也就意味着所有的请求都需要到数据库中去查询数据。那这对于数据库的压力必然是剧增的,如果是在一线互联网这样超高并发的场景下,数据库直接宕机。 重启也没有用,因为重启了还会有巨大的流量涌进来,然后继续被搞宕机。所以对于预防缓存雪崩这种情况的发生意义还是很大的的。 缓存雪崩解决方案之加随机值 上面已经详细介绍了什么是缓存雪崩,他是怎么发生的,那如果防止缓存雪崩呢? 很简单,因为上面刚刚说到,缓存雪崩是由于某个时间节点大量的 key 失效而导致的问题,那现在的问题不就是变成了如何防止同一个时间节点大量的 key 失效这种情况发生吗? 最简单的情况就是把key的过期时间分散开,也就是在设置key的过期时间的时候再加一个随机值,就这样就能完美的解决缓存雪崩的问题。 但是你以为我说到这里就完事了?既然是一次全安排,那么我一定不会仅仅告诉你一种解决方案就完事的。继续看 缓存雪崩解决方案之加锁 可能很多人看到这个方案表示不接受,加锁那不是限制了并发?加锁必然导致阻塞。如果是加锁,那么执行就成就是这个样子了: 流程是这样子的,在多个请求同时到达业务系统时候,只能有一个线程能获取到锁,然后才能继续去缓存或者是数据库中查询数据,然后后面的流程和之前的是一样的,执行完成后释放锁,然后其他线程再争抢锁,然后重复前面的流程。 这个方案的优点是可以很好的保护数据库不会被打挂,缺点就是并发度极低。 上面这个方案其实还是可以再优化下的: 这个就是在缓存中如果获取不到,再去串行的访问数据看,这里不一定非要串行,可以配合线程池,控制一定的并发数。 这个缺点虽然很多,但是也是一种解决方案。用不用就看实际的业务场景了。毕竟没有没用技术方案,只有不适合业务场景的技术方案(手动狗头)。 缓存穿透 缓存穿透意思就是某个不存在的key一直被访问,结果发现数据库中也没有这样的数据,最终导致访问该key的所有请求都直接请求到数据库了。如果是并发高的场景下就容易搞垮数据库。大家有没有发现我们做的一些事情都是在保护“弱小的数据库”。 那现在问题已经知道了,我们该如何去解决这个问题呢? 缓存穿透解决方案之缓存空数据 啥叫缓存空数据?就是假设某个key数据并不存在,那么就存一个 NULL 就好了,但是一定不要忘记设置过期时间,因为假设id=3的记录不存在,然后本次访问没有查询到数据,缓存中存的是null如果过一会儿新增了一条记录为3的数据,如果缓存不设置过期时间,那么这条数据就永远获取不到。 缓存穿透解决方案之布隆过滤器 布隆过滤器?这玩意到底什么意思? 布隆过滤器是一种数据结构,更准确的说是一种概率型的数据结构,因为它能判断某个元素一定不存在或者是可能存在。 就这句话,搞蒙了很多人,今天我非要把你说明白了。布隆过滤器是一个bit数组,一个很长的bit数组和一系列的hash函数构成。先看下图 我们现在来举个例子,假设现在有小强和旺财两个人,他们分别经过三次hash得到的下标是这样子的(布隆过滤器不存储元素,仅仅是为一个元素是否存在打一个标志) 小强经过上面的三个hash后得到的下标分别为:2、4、5,那么该数组的2、4、5位置就会被置为1,也就是此时是这样子的 同样旺财经过上面的三个hash后得到的下标分别为:3、7、11,那么该数组的3、7、11位置就会被置为1,也就是此时是这样子的 现在假设来一个 007 经过上面的三个hash后得到的下标分别为:11、13、15因为13、和15位置是0,所以一定可以判断007 一定不存在。但是现在又来了一个 9527经过上面的三个hash后得到的下标分别为:2、5、7,但是你会发现257三个位置全部是1,那这个到底说明9527是存在还是不存在呢? 从我们上面的讲解可以 9527 之前并不存在,但是由于hash冲突,但是9527的三个下标值也刚好落在已经被置为1的下标位置,这就导致此时是无法判断9527是否存在的。这就是布隆过滤器的原理。 要不来段代码压压惊? 我们来使用 google 包下的类来测试。首先要添加依赖 com.google.guava guava 30.1-jre 代码如下(详细的解释我已经写在注释中了,这个是可以用于实际生产的代码) public class BloomFilterDemo { public static void main(String[] args) { /** * 创建一个插入对象为一亿,误报率为0.01%的布隆过滤器 * 不存在一定不存在 * 存在不一定存在 */ BloomFilter bloomFilter = BloomFilter.create(Funnels.stringFunnel(Charset.forName("utf-8")), 100000000, 0.0001); bloomFilter.put("死"); bloomFilter.put("磕"); bloomFilter.put("Redis"); System.out.println(bloomFilter.mightContain("Redis")); System.out.println(bloomFilter.mightContain("死")); System.out.println(bloomFilter.mightContain("磕")); System.out.println(bloomFilter.mightContain("Java")); } } 结果 完。 等等……缓存穿透、预热、降级你还没说呢。哦,我真的以为本文结束了。 那布隆过滤器是如何解决缓存穿透的问题的呢?既然已经知道了布隆过滤器的原理,那么就可以通过布隆过滤器来快速的判断出一个key是否存在数据库中,如果可能存在再去数据库查询,如果布隆过滤器中不存在那么就需要再去数据库查询了。 4、缓存预热 这又是什么鬼?怎么搞一个缓存还有这么多问题,那还要缓存干啥? 所谓缓存预热就是将一些可能经常使用数据在系统启动的时候预先设置到缓存中,这样可以避免在使用到的时候先去数据库中查询。 这就是缓存预热,名气高大上,实际上很简单有木有,这个缓存预热我在实际场景是经常使用的。 还有一种方式就是添加一个缓存刷新页,这样通过人工干预的方式将一些可能为热点的key添加到缓存中。 5、缓存降级 当访问量突然剧增(例如下班的点,大家都在地铁上刷手机呢)、服务出现问题(如响应时间慢或不响应)或非核心服务影响到核心流程的性能时,仍然需要保证服务还是可用的,即使是有损服务。 系统可以根据一些关键数据进行自动降级,降级的最终目的是保证核心服务可用,即使是有损的。但是有的一些业务的核心服务是不能降级的。这是一种丢卒保帅的思想。 6、结束语 关于技术的学习,大家除了为了应付面试去短期强行的记忆一些知识点外,我还是建议各位在学习阶段能够循序渐进。小孩子从出生到走路一般还有10个月呢,要想会说话时间就更长。 但是这个过程必须是有的,因为小孩子需要一点一点来适应这个未知的世界。我们作为成年人在学习的时候也要保持这种平静心态,有些事情急是没用的。 最后以一句不畏艰险,勇攀高峰来和大家共勉。
技术
# Redis
酷游
1月22日
0
20
0
2025-01-22
新入职的同事问我,为什么会出现数据库和缓存不一致的问题?
关于缓存,相信很多人都不陌生,我们通常会在数据库之上搭建一个缓存服务器,将一些高频的数据存储到缓存中,可以提升查询效率,从而提高响应速度以及并发度。 但是,与此同时也带来了一个问题,那就是如何保证缓存和数据库之间的数据一致性? 在讨论怎么做之前,我们先来看看为什么会出现缓存一致性的问题呢?这些问题是如何发生的呢? 非并发的情况 首先,我们在非并发的场景中,出现不一致的问题大家都能比较容易的理解,因为缓存的操作和数据库的操作是存在一定的时间差的。 而且这两个操作是没办法保证原子性的,也就是说,是有可能一个操作成功,一个操作失败的。 所以,这就必然会存在不一致的情况。 但同时,因为我们的业务系统是开放给用户使用的,所以经常会出现各种各样的并发的场景,因为并发的存在,会使得数据一致性的问题更加的多。 并发的情况 对于数据的操作,无外乎就是读和写两种,那么就会同时存在”读读并发”、”读写并发”和”写写并发”。 对于两个读线程,即使发生并发,因为只是读的动作,所以不会有数据的变更,发生了并发的话也不会有数据不一致的情况。 接下来我们先来分析比较容易理解的”写写并发”的情况。 写写并发 因为在数据库和缓存的操作过程中,可能存在”先写数据库,后删缓存”、”先写数据库,后更新缓存”、”先删缓存库,后写数据库”以及”先更新缓存库,后写数据库”这四种。 其中”删缓存”的这两种是把缓存清空,所以”写写并发”不会存在缓存和数据库不一致的情况。我们就看”更新缓存”的这两种: 先写数据库,后更新缓存: W W 写数据库,更新成20 写数据库,更新成10 写缓存,更新成10 写缓存,更新成20(数据不一致) 先更新缓存,后写数据库: W W 写缓存,更新成20 写缓存,更新成10 写数据库,更新成10 写数据库,更新成20(数据不一致) 以上两种情况,都是两个写线程并发之后,因为乱序的问题,导致最终缓存中的值是20,而数据库中的值是10,最终导致缓存和数据库中的值不一致的情况。 除了写写并发之外,还有一种比较容易被忽视的情况,那就是读写之间的并发也会导致数据库和缓存的不一致。 读写并发 我们知道,当我们使用了缓存之后,一个读的线程在查询数据的过程是这样的: 1、查询缓存,如果缓存中有值,则直接返回 2、查询数据库 3、把数据库的查询结果更新到缓存中 所以,对于一个读线程来说,虽然不会写数据库,但是是会更新缓存的,所以,在一些特殊的并发场景中,就会导致数据不一致的情况。 读写并发的时序如下: W R 读缓存,缓存中没有值 读数据库,数据库中得到结果为10 写数据库和缓存,更新成20 写缓存,更新成10(数据不一致) 也就是说,假如一个读线程,在读缓存的时候没查到值,他就会去数据库中查询,但是如果自查询到结果之后,更新缓存之前,数据库被更新了,但是这个读线程是完全不知道的,那么就导致最终缓存会被重新用一个”旧值”覆盖掉。 这也就导致了缓存和数据库的不一致的现象。 但是这种现象其实发生的概率比较低,因为一般一个读操作是很快的,数据库+缓存的读操作基本在十几毫秒左右就可以完成了。 而在这期间,更好另一个线程执行了一个比较耗时的写操作的概率确实比较低。 当然,根据墨菲定律,只要有可能发生的事情,就一定会发生。所以我们也要引起重视。 总结 我们在本文中介绍了数据库和缓存因为双写存在的不一致的情况,无论是单线程还是多线程,都是有可能会出现数据不一致的。 本文中还提到了在数据库和缓存的操作过程中,可能存在”先写数据库,后删缓存”、”先写数据库,后更新缓存”、”先删缓存库,后写数据库”以及”先更新缓存库,后写数据库”这四种。 那么,到底是应该删除缓存好呢,还是更新缓存好呢?到底应该先操作数据库呢还是先操作缓存呢?哪种方案更好呢?又该如何选择呢? 我们在后面的文章中再展开介绍。后面几篇文章会基于本文作为前提展开,所以大家要先能理解不一致问题出现在什么时候,才能知道要怎么做才能解决。
技术
# Redis
酷游
1月22日
0
16
0
2025-01-22
Redis 为什么要自己实现用SDS实现一个字符串
Redis是一种KV的存储结构,他的key是字符串类型,值也支持字符串,所以字符串是redis中最常见的一个类型了。Redis自己本身是通过C语言实现的,但是他并没有直接使用C语言中的字符数组的方式来实现字符串,而是自己实现了一个SDS,即简单动态字符串,这是为什么呢? 首先,因为字符串在Redis中使用实在是太广泛了 ,所以对他的基本要求就有两点,第一就是要支持任意字符的存储,第二就是各种操作需要高效。 接着我们看看C语言中字符串的实现方式有什么问题呢?很多人可能都忘了,我帮大家回忆一下,C语言中,字符串是通过字符数组实现的,底层呢是开辟了一块连续的空间,依次存放字符串中的每一个字符。为了表示字符串的结束,他会在字符数组的最后一个字符处记录\0, 也就是说,当识别到字符数组中的\0字符的时候,就认为字符串结束了,那么这么做会带来哪些问题呢? 就是这样实现的字符串中就不能保存任意内容了,至少\0就不行,因为遇到他的时候就直接截断了,这肯定是接受不了的。 还有就是因为C中的字符串以\0作为识别字符串结束的方式,所以他的字符串长度判断、字符串追加等操作,都需要从头开始遍历,一直遍历到\0的时候再返回长度或者做追加。这就使得字符串相关的操作效率都很低。 那么,想要解决上面的两个问题要怎么办呢?那就是在用字符数组表示字符串的同时,在这个字符串中增加一个表示分配给该字符数组的总长度的alloc字段,和一个表示字符串现有长度的len字段。这样在获取长度的时候就不依赖\0了,直接返回len的值就行了。 还有呢,就是在做追加操作的时候,只需要判断新追加的部分的len加上已有的len是否大于alloc,如果超过就重新再申请新空间,如果没超过,就直接进行追加就行了。 还有很多其他操作,比如复制、比较等都可以使用类似的思想高效的操作。
技术
# Redis
酷游
1月22日
0
12
0
2025-01-22
再有人问你数据库缓存一致性的问题,直接把这篇文章发给他
在之前的一篇文章《为什么会出现数据库和缓存不一致的问题》中,我们介绍过缓存和数据库会出现数据不一致的几种情况。 我们提到过,在数据库和缓存的操作过程中,可能存在”先写数据库,后删缓存”、”先写数据库,后更新缓存”、”先删缓存库,后写数据库”以及”先更新缓存库,后写数据库”这四种。 那么,到底是应该删除缓存好呢,还是更新缓存好呢?到底应该先操作数据库呢还是先操作缓存呢?哪种方案更好呢?又该如何选择呢? 本文就来展开分析一下。 删除还是更新 为了保证数据库和缓存里面的数据是一致的,很多人会很多人在做数据更新的时候,会同时更新缓存里面的内容。但是我其实告诉大家,应该优先选择删除缓存而不是更新缓存。 首先,我们暂时抛开数据一致性的问题,单独来看看更新缓存和删除缓存的复杂的的问题。 我们放到缓存中的数据,很多时候可能不只是简单的一个字符串类型的值,他还可能是一个大的JSON串,一个map类型等等。 举个栗子,我们需要通过缓存进行扣减库存的时候,你可能需要从缓存中查出整个订单模型数据,把他进行反序列化之后,再解析出其中的库存字段,把他修改掉,然后再序列化,最后再更新到缓存中。 可以看到,更新缓存的动作,相比于直接删除缓存,操作过程比较的复杂,而且也容易出错。 还有就是,在数据库和缓存的一致性保证方面,删除缓存相比更新缓存要更简单一点。 我们在《为什么会出现数据库和缓存不一致的问题》中介绍过的”写写并发”的场景中,如果同时更新缓存和数据库,那么很容易会出现因为并发的问题导致数据不一致的情况。如: 先写数据库,再更新缓存 W W 写数据库,更新成20 写数据库,更新成10 写缓存,更新成10 写缓存,更新成20(数据不一致) 先更新缓存,后写数据库: W W 写缓存,更新成20 写缓存,更新成10 写数据库,更新成10 写数据库,更新成20(数据不一致) 但是,如果是做缓存的删除的话,在写写并发的情况下,缓存中的数据都是要被清除的,所以就不会出现数据不一致的问题。 但是,更新缓存相比删除缓存还是有一个小的缺点,那就是带来的一次额外的cache miss,也就是说在删除缓存后的下一次查询会无法命中缓存,要查询一下数据库。 这种cache miss在某种程度上可能会导致缓存击穿,也就是刚好缓存被删除之后,同一个Key有大量的请求过来,导致缓存被击穿,大量请求访问到数据库。 但是,通过加锁的方式是可以比较方便的解决缓存击穿的问题的。 总之,删除缓存相比较更新缓存,方案更加简单,而且带来的一致性问题也更少。所以,在删除和更新缓存之间,我还是偏向于建议大家优先选择删除缓存。 先写数据库还是先删缓存 在确定了优先选择删除缓存而不是更新缓存之后,留给我们的数据库+缓存更新的可选方案就剩下:”先写数据库后删除缓存”和”先删除缓存后写数据库了”。 那么,这两种方式各自有什么优缺点呢?该如何选择呢? 先写数据库 因为数据库和缓存的操作是两步的,没办法做到保证原子性,所以就有可能第一步成功而第二步失败。 而一般情况下,如果把缓存的删除动作放到第二步,有一个好处,那就是缓存删除失败的概率还是比较低的,除非是网络问题或者缓存服务器宕机的问题,否则大部分情况都是可以成功的。 还有就是,先写数据库后删除缓存虽然不存在”写写并发”导致的数据一致性问题,但是会存在”读写并发”情况下的数据一致性问题。 我们知道,当我们使用了缓存之后,一个读的线程在查询数据的过程是这样的: 1、查询缓存,如果缓存中有值,则直接返回 2、查询数据库 3、把数据库的查询结果更新到缓存中 所以,对于一个读线程来说,虽然不会写数据库,但是是会更新缓存的,所以,在一些特殊的并发场景中,就会导致数据不一致的情况。 读写并发的时序如下: W R 读缓存,缓存中没有值 读数据库,数据库中得到结果为10 写数据库,更新成20 写缓存,更新成10(数据不一致) 也就是说,假如一个读线程,在读缓存的时候没查到值,他就会去数据库中查询,但是如果自查询到结果之后,更新缓存之前,数据库被更新了,但是这个读线程是完全不知道的,那么就导致最终缓存会被重新用一个”旧值”覆盖掉。 这也就导致了缓存和数据库的不一致的现象。 但是这种现象其实发生的概率比较低,因为一般一个读操作是很快的,数据库+缓存的读操作基本在十几毫秒左右就可以完成了。 而在这期间,更好另一个线程执行了一个比较耗时的写操作的概率确实比较低。 先删缓存 那么,如果是先删除缓存后操作数据库的话,会不会方案更完美一点呢? 首先,如果是选择先删除缓存后写数据库的这种方案,那么第二步的失败是可以接受的,因为这样不会有脏数据,也没什么影响,只需要重试就好了。 但是,先删除缓存后写数据库的这种方式,会无形中放大前面我们提到的”读写并发”导致的数据不一致的问题。 因为这种”读写并发”问题发生的前提是读线程读缓存没读到值,而先删缓存的动作一旦发生,刚好可以让读线程就从缓存中读不到值。 所以,本来一个小概率会发生的”读写并发”问题,在先删缓存的过程中,问题发生的概率会被放大。 而且这种问题的后果也比较严重,那就是缓存中的值一直是错的,就会导致后续的所以命中缓存的查询结果都是错的! 延迟双删 那么,虽然先写数据后删除缓存的这种情况,可以大大的降低并发问题的概率,但是,根据墨菲定律,只要有可能发生的坏事,那就基本上会发生。越是庞大的系统发生的概率越高。 那么,有没有什么办法可以来解决一下这种情况带来的不一致的问题呢? 其实是有一个比较常见的方案的,在很多公司内用的也比较多,那就是延迟双删。 因为”读写并发”的问题会导致并发发生后,缓存中的数被读线程写进去脏数据,那么就只需要在写线程在写数据库、删缓存之后,延迟一段时间,在执行一把删除动作就行了。 这样就能保证缓存中的脏数据被清理掉,避免后续的读操作都读到脏数据。当然,这个延迟的时长也很久讲究,到底多久来删除呢?一般建议设置1-2s就可以了。 当然,这种方案也是有一个弊端的,那就是可能会导致缓存中准确的数据被删除掉。当然这也问题不大,就像我们前面说过的,只是增加一次cache miss罢了。 如何选择 前面介绍了几种情况的具体问题和解决方案,那么实际工作中应该如何选择呢? 我觉得主要还是根据实际的业务情况来分析。 比如,如果业务量不大,并发不高的情况,可以选择先更新数据库,后删除缓存的方式,因为这种方案更加简单。 但是,如果是业务量比较大,并发度很高的话,那么建议选择**先删除缓存*,因为这种方式在引入延迟双删、分布式锁等机制会,会使得整个方案会更加趋近于完美,带来的并发问题更少。当然,也会更复杂。 其实,先操作数据库,后操作缓存,是一种比较典型的设计模式——Cache Aside Pattern。 这种模式的主要方案就是先写数据库,后删缓存,而且缓存的删除是可以在旁路异步执行的。 这种模式的优点就是我们说的,他可以解决”写写并发”导致的数据不一致问题,并且可以大大降低”读写并发”的问题,所以这也是Facebook比较推崇的一种模式。 优化方案 Cache Aside Pattern 这种模式中,我们可以异步的在旁路处理缓存。其实这种方案在大厂中确实有的还蛮多的。 主要的方式就是借助数据库的binlog或者基于异步消息订阅的方式。 也就是说,在代码的主要逻辑中,先操作数据库就行了,然后数据库操作完,可以发一个异步消息出来。 然后再由一个监听者在接到消息之后,异步的把缓存中的数据删除掉。 或者干脆借助数据库的binlog,订阅到数据库变更之后,异步的清除缓存。 这两种方式都会有一定的延时,通常在毫秒级别,一般用于在可接受秒级延迟的业务场景中。 缓存更新的设计模式 前面介绍过了Cache Aside Pattern这种关于缓存操作的设计模式,那么其实还有几种其他的设计模式,也一起展开介绍一下: Read/Write Through Pattern 在这两种模式中,应用程序将缓存作为主要的数据源,不需要感知数据库,更新数据库和从数据库的读取的任务都交给缓存来代理。 Read Through模式下,是由缓存配置一个读模块,它知道如何将数据库中的数据写入缓存。在数据被请求的时候,如果未命中,则将数据从数据库载入缓存。 Write Through模式下,缓存配置一个写模块,它知道如何将数据写入数据库。当应用要写入数据时,缓存会先存储数据,并调用写模块将数据写入数据库。 也就是说,这两种模式下,不需要应用自己去操作数据库,缓存自己就把活干完了。 Write Behind Caching Pattern 这种模式就是在更新数据的时候,只更新缓存,而不更新数据库,然后再异步的定时把缓存中的数据持久化到数据库中。 这种模式的优缺点比较明显,那就是读写速度都很快,但是会造成一定的数据丢失。 这种比较适合用在比如统计文章的访问量、点赞等场景中,允许数据少量丢失,但是速度要快。 没有银弹 《人月神话》的作者Fred Brooks在早年有一篇很著名文章《No Silver Bullet》 ,他提到: 在软件开发过程里是没有万能的终杀性武器的,只有各种方法综合运用,才是解决之道。而各种声称如何如何神奇的理论或方法,都不是能杀死“软件危机”这头人狼的银弹。 也就是说,没有哪种技术手段或者方案,是放之四海皆准的。如果有的话,我们这些工程师也就没有存在的必要了。 所以,任何的技术方案,都是一个权衡的过程,要权衡的问题有很多,业务的具体情况,实现的复杂度、实现的成本,团队成员的接受度、可维护性、容易理解的程度等等。 所以,没有一个”完美”的方案,只有”适合”的方案。 但是,如何能选出一个适合的方案,这里面就需要有很多的输入来做支撑了。希望本文的内容可以为你日后的决策提供一点参考!
技术
# Redis
酷游
1月22日
0
4
0
易航博客