Redis和关系型数据库的主要区别,体现在哪些方面?

数据存储方式不同:Redis是基于内存的数据库,而关系型数据库通常是基于磁盘的。Redis的数据存储在内存中,因此读写速度非常快,但是容量受到内存大小的限制;而关系型数据库通常将数据存储在磁盘中,因此读写速度较慢,但是容量可以扩展到很大。

redis事务三大特性 redis事务的特性redis事务三大特性 redis事务的特性


redis事务三大特性 redis事务的特性


数据结构不同:Redis支持多种数据结构,如字符串、哈希表、列表、和有序等;而关系型数据库通常只支持表格结构。

数据库应用场景不同:Redis主要用于缓存、队列、计数器等,而关系型数据库主要用于存储关系型数据。

数据库的处理方式不同:Redis可以对数据进行持久化,包括RDB快照和AOF日志两种方式,保证数据不丢失。而关系型数据库通常采用事务机制来保证数据的一致性和完整性。

数据库的性能不同:Redis的读写性能非常高,因为它使用的是内存存储,而且支持多种数据结构;而关系型数据库的读写性能相对较低,因为它需要通过磁盘进行数据读写,并且数据结构比较单一。

总之,Redis和Redis事务可以保证多个命令的原子性执行。需要注意的是,Redis事务并不是真正的ACID事务,因为Redis并不支持回滚作关系2.watch型数据库各有优缺点,应根据应用场景的需求选择适合的数据库。

使用redis有哪些好处

微博是一个弱关系型社交网络,用户之间有关注和被关注两种关系,比如两个用户A和B,如果A关注B,则B的粉丝中就应该有A。关注这个动作需要两个步骤完成:在A的关注者中添加B;在B的粉丝中添加A。 这两个动作要么都执行成功,要么都不执行。否则就可能会出现A关注了B,但是B的粉丝中没有A的不可容忍的情况。

用redis好处:

1、数据存储在内存中,读写速度快;

2、支持的数据类型资源丰富;如果你快速的在Google中搜索“Redis queues”,你马上就能找到大量的开源项目,这些项目的目的就是利用Redis创建非常好的后端工具,以满足各种队列需求。例如,Celery有一个后台就是使用Redis作为broker,你可以从这里去查看。

3、支持事务,作都是原子性作;

4、可以设置数据存活的生命周期。

golang redis事务 --- 2022-04-03

缓存雪崩解决方案:给缓存的失效时间,加上一个随机值,避免集体失效。使用互斥锁,但是该方案吞吐量明显下降了。双缓存。我们有两个缓存,缓存 A 和缓存 B。缓存 A 的失效时间为 20 分钟,缓存 B 不设失效时间。自己做缓存预热作。然后细分以下几个小点:从缓存 A 读数据库,有则直接返回;A 没有数据,直接从 B 读数据,直接返回,并且异步启动一个更新线程,更新线程同时更新缓存 A 和缓存 B。八 如何解决 Redis 的并发竞争 Key 问题这个问题大致就是,同时有多个子系统去 Set 一个 Key。这个时候要注意什么呢?大家基本都是用 Redis 事务机制。

事务是一个单独的隔离作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。

当然,这是定你是根据你用户的分数做递增的排序。如果你想返回用户及用户的分数,你需要这样执行:

事务是一个原子作:事务中的命令要么全部被执行,要么全部都不执行。

下面介绍golang redis事务用法。

TxPipeline - 以Pipeline的方式作事务

Watch - redis乐观锁支持

以Pipeline的方式作事务

redis分布式怎么做

一 为什么使用 Redis在项目中使用 Redis,主要考虑两个角度:性能和并发。如果只是为了分布式锁这些其他功能,还有其他中间件 Zookpeer 等代替,并非一定要使用 传统MySQL+Memcached架构遇到的问题Redis。

性能:如下图所示,我们在碰到需要执行耗时特别久,且结果不频繁变动的 SQL,就特别适合将运行结果放入缓存。这样,后面的请求就去缓存中读取,使得请求能够迅速响应。

特别是在秒杀系统,在同一时间,几乎所有人都在点,都在下单。。执行的是同一作———向数据库查数据。

根据交互效果的不同,响应时间没有固定标准。在理想状态下,我们的页面跳转需要在瞬间解决,对于页内作则需要在刹那间解决。

并发:如下图所示,在大并发的情况下,所有的请求直接访问数据库,数据库会出现连接异常。这个时候,就需要使用 Redis 做一个缓冲作,让请求先访问到 Redis,而不是直接访问数据库。

原因主要是以下三点:纯内存作单线程作,避免了频繁的上下文切换采用了非阻塞 I/O 多路复用机制仔细说一说 I/O 多路复用机制,打一个比方:小名在 A 城开了一家快餐店店,负责同城快餐服务。小明因为资金限制,雇佣了一批配送员,然后小曲发现资金不够了,只够买一辆车送快递。

经营方式一客户每下一份订单,小明就让一个配送员盯着,然后让人开车去送。慢慢的小曲就发现了这种经营方式存在下述问题:

时间都花在了抢车上了,大部分配送员都处在闲置状态,抢到车才能去送。

随着下单的增多,配送员也越来越多,小明发现快递店里越来越挤,没办法雇佣新的配送员了。配送员之间的协调很花时间。综合上述缺点,小明痛定思痛,提出了经营方式二。经营方式二小明只雇佣一个配送员。当客户下单,小明按送达地点标注好,依次放在一个地方。,让配送员依次开着车去送,送好了就回来拿下一个。上述两种经营方式对比,很明显第二种效率更高。

在上述比喻中:每个配送员→每个线程每个订单→每个 Socket(I/O 流)订单的送达地点→Socket 的不同状态客户送餐请求→来自客户端的请求明曲的经营方式→服务端运行的代码一辆车→CPU 的核数于是有了如下结论:经营方式一就是传统的并发模型,每个 I/O 流(订单)都有一个新的线程(配送员)管理。经营方式二就是 I/O 多路复用。只有单个线程(一个配送员),通过跟踪每个 I/O 流的状态(每个配送员的送达地点),来管理多个 I/O 流。下面类比到真实的 Redis 线程模型,如图所示:

Redis-client 在作的时候,会产生具有不同类型的 Socket。在服务端,有一段 I/O 多路复用程序,将其置入队列之中。然后,文件分派器,依次去队列中取,转发到不同的处理器中。

三 Redis 的数据类型及使用场景一个合格的程序员,这五种类型都会用到。

String最常规的 set/get 作,Value 可以是 String 也可以是数字。一般做一些复杂的计数功能的缓存。

Hash这里 Value 存放的是结构化的对象,比较方便的就是作其中的某个字段。我在做单点登录的时候,就是用这种数据结构存储用户信息,以 CookieId 作为 Key,设置 30 分钟为缓存过期时间,能很好的模拟出类似 Session 的效果。

List使用 List 的数据结构,可以做简单的消息队列的功能。另外,可以利用 lrange 命令,做基于 Redis 的分页功能,性能,用户体验好。

Set因为 Set 堆放的是一堆不重复值的。所以可以做全局去重的功能。我们的系统一般都是集群部署,使用 JVM 自带的 Set 比较麻烦。另外,就是利用交集、并集、集等作,可以计算共同喜好,全部的喜好,自己的喜好等功能。

Sorted SetSorted Set 多了一个权重参数 Score,中的元素能够按 Score 进行排列。可以做排行榜应用,取 TOP N 作。Sorted Set 可以用来做延时任务。

四 Redis 的过期策略和内存淘汰机制Redis 是否用到家,从这就能看出来。比如你 Redis 只能存 5G 数据,可是你写了 10G,那会删 5G 的数据。怎么删的,这个问题思考过么?

正解:Redis 采用的是定期删除+惰性删除策略。

为什么不用定时删除策略定时删除,用一个定时器来负责监视 Key,过期则自动删除。虽然内存及时释放,但是十分消耗 CPU 资源。在大并发请求下,CPU 要将时间应用在处理请求,而不是删除 Key,因此没有采用这一策略。

定期删除+惰性删除如何工作定期删除,Redis 默认每个 100ms 检查,有过期 Key 则删除。需要说明的是,Redis 不是每个 100ms 将所有的 Key 检查一次,而是随机抽取进行检查。如果只采用定期删除策略,会导致很多 Key 到时间没有删除。于是,惰性删除派上用场。

采用定期删除+惰性删除就没其他问题了么不是的,如果定期删除没删除掉 Key。并且你也没及时去请求 Key,也就是说惰性删除也没生效。这样,Redis 的内存会越来越高。那么就应该采用内存淘汰机制。

在 redis.conf 中有一行配置:

# maxmemory-policy volatile-lru

该配置就是配内存淘汰策略的:noeviction:当内存不足以容纳新写入数据时,新写入作会报错。allkeys-lru:当内存不足以容纳新写入数据时,在键空间中,移除最近最少使用的 Key。(使用,目前项目在用这种)(最近最久使用算法)allkeys-random:当内存不足以容纳新写入数据时,在键空间中,随机移除某个 Key。(应该也没人用吧,你不删最少使用 Key,去随机删)volatile-lru:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,移除最近最少使用的 Key。这种情况一般是把 Redis 既当缓存,又做持久化存储的时候才用。(不)volatile-random:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,随机移除某个 Key。(依然不)volatile-ttl:当内存不足以容纳新写入数据时,在设置了过期时间的键空间中,有更早过期时间的 Key 优先移除。(不)五 Redis 和数据库双写一致性问题一致性问题还可以再分为最终一致性和强一致性。数据库和缓存双写,就必然会存在不一致的问题。前提是如果对数据有强一致性要求,不能放缓存。我们所做的一切,只能保证最终一致性。

另外,我们所做的方案从根本上来说,只能降低不一致发生的概率。因此,有强一致性要求的数据,不能放缓存。首先,采取正确更新策略,先更新数据库,再删缓存。其次,因为可能存在删除缓存失败的问题,提供一个补偿措施即可,例如利用消息队列。

六 如何应对缓存穿透和缓存雪崩问题这两个问题,一般中小型传统软件企业很难碰到。如果有大并发的项目,流量有几百万左右,这两个问题一定要深刻考虑。缓存穿透,即黑客故意去请求缓存中不存在的数据,导致所有的请求都怼到数据库上,从而数据库连接异常。

缓存穿透解决方案:利用互斥锁,缓存失效的时候,先去获得锁,得到锁了,再去请求数据库。没得到锁,则休眠一段时间重试。采用异步更新策略,无论 Key 是否取到值,都直接返回。Value 值中维护一个缓存失效时间,缓存如果过期,异步起一个线程去读数据库,更新缓存。需要做缓存预热(项目启动前,先加载缓存)作。提供一个能迅速判断请求是否有效的拦截机制,比如,利用布隆过滤器,内部维护一系列合法有效的 Key。迅速判断出,请求所携带的 Key 是否合法有效。如果不合法,则直接返回。缓存雪崩,即缓存同一时间大面积的失效,这个时候又来了一波请求,结果请求都怼到数据库上,从而导致数据库连接异常。

但是并不使用 Redis 的事务机制。因为我们的生产环境,基本都是 Redis 集群环境,做了数据分片作。你一个事务中有涉及到多个 Key 作的时候,这多个 Key 不一定都存储在同一个 redis-server 上。因此,Redis 的事务机制,十分鸡肋。

如果对这redis乐观锁支持,可以通过watch一些Key, 如果这些key的值没有被其他人改变的话,才可以提交事务。个 Key 作,不要求顺序

这种情况下,准备一个分布式锁,大家去抢锁,抢到锁就做 set 作即可,比较简单。

如果对这个 Key 作,要求顺序

设有一个 key1,系统 A 需要将 key1 设置为 valueA,系统 B 需要将 key1 设置为 valueB,系统 C 需要将 key1 设置为 valueC。

期望按照 key1 的 value 值按照 valueA > valueB > valueC 的顺序变化。这种时候我们在数据写入数据库的时候,需要保存一个时间戳。

设时间戳如下:

系统 A key 1 {valueA 3:00}

系统 B key 1 {valueB 3:05}

系统 C key 1 {valueC 3:10}

那么,设系统 B 先抢到锁,将 key1 设置为{valueB 3:05}。接下来系统 A 抢到锁,发现自己的 valueA 的时间戳早于缓存中的时间戳,那就不做 set 作了,以此类推。其他方法,比如利用队列,将 set 方法变成串行访问也可以。

更多Redis相关技术文章,请访问Redis教程栏目进行学习!

redis中如何保证原子性

go redis事务常用函数:

原子性:

原子性是数据库的事务中的特性。在数据库事务的情景下,原子性指的是:一个事务(transaction)中的所有作,要么全部完成,要么全部不完成,不会结束在中间某个环节。

对于Redis而言,命令的原子性指的是:一个作的不可以再分,作要么执行,要么不执行。

Redis作原子性的原因:

Redis的作之所以是原子性的,是因为Redis是单线程的。

Redis在并发中的表现:

Redis的API是原子性的作,那么多个命令在并发中也是原子性的吗?

有以下代码:

$redis= newRedis();

$redis->connect('127.0.0.1',6379);

for($i= 0;$iget('val');

$num++;

usleep(10000);

}用两个终端执行上面的程序,发现val的结果是小于2000的值,那么可以知道,在程序中执行多个Redis命令并非是原子性的,这也和普通数据库的表现是一样的。

如果想在上面的程序中实现原子性,可以将get和set改成单命令作,比如incr,或者使用Redis的事务,或者使用从上面的例子我们可以看到,事务中的命令要全部执行完之后才能获取每个命令的结果,但是如果一个事务中的命令B依赖于他上一个命令A的结果的话该怎么办呢?就比如说实现类似Ja中的i++的功能,先要获取当前值,才能在当前值的基础上做加一作。这种场合仅仅使用上面介绍的MULTI和EXEC是不能实现的,因为MULTI和EXEC中的命令是一起执行的,并不能将其中一条命令的执行结果作为另一条命令的执行参数,所以这个时候就需要引进Redis事务家族中的另一成员:WATCH命令Redis+Lua的方式实现。

对Redis来说,执行get、set以及eval等API,都是一个一个的任务,这些任务都会由Redis的线程去负责执行,任务要么执行成功,要么执行失败,这就是Redis的命令是原子性的原因。

更多Redis相关知识,请访问Redis使用教程栏目!

为什么使用Redis及其产品定位(转载自://www.q/cn/articles/tq-w

mongodb内置数据分析功能(mapreduce);而Redis不支持。

传统MySQL+Memcached架构遇到的问题 实际MySQL 是适合进行海量存储的,通过Memcached将热点数据加载到cache,加速访问,很多公司都曾经使用过这样的架构,但随着业务数据量的不断增加,和访问量的持续增长,我们遇到了很多问题: 1. MySQL需要不断的进行拆库

实际MySQL 是适合进行海量存储的,通过Memcached将热点数据加载到cache,加速访问,很多公司都曾经使用过这样的架构,但随着业务数据量的不断增加,和访问量的持续增长,我们遇到了很多问题:

1. MySQL需要不断的进行拆库拆表,Memcached也需不断跟着扩容,扩容和维护工作占据大量开发时间。

2. Memcached与MySQL数据库数据一致性问题。

3. Memcached数据命中率低或down机,大量访问直接穿透到DB,MySQL无法支撑。

4. 跨机房cache同步Redis 和关系型数据库的主要区别有以下几个方面:问题。

众多NoSQL百花齐放,如何选择

最近几年,业界不断涌现出很多各种各样的NoSQ产品,那么如何才能正确地使用好这些作品,化地发挥其长处,是我们需要深入研究和思考的问题,实际归根结底最重要的是了解这些产品的定位,并且了解到每款产品的tradeoffs,在实际应用中做到扬长避短,总体上这些NoSQL主要用于解决以下几种问题

1. 少量数据存储,高速读写访问。此类产品通过数据全部in-momery的方式保证高速访问,同时提供数据落地的功能,实际这正是Radis最主要的适用场景。

2. 海量数据存储,分布式系统支持,数据一致性保证,方便的集群添加/删除。

3. 这方面代表性的是dynamo和bigtables 2篇论文所阐述的思路。前者是一个完全无中心的设计,之间通过gossip方式传递集群信息,数据保证最终一致性,后者是一个中心化的方案设计,通过类似一个分布式锁服务来保证强一致性,数据写入先写内存和redo log,然后定期compat归并到磁盘上,将随机写优化为顺序写,提高写入性能。

4. Schema free,auto-sharding等。比如目前常见的一些文档数据库都是支持schema-free的,直接存储json格式数据,并且支持auto-sharding等功能,,比如mongodb。

面对这些不同类型的NoSQL产品,我们需要根据我们的业务场景选择最合适的产品。

Redis适用场景,如何正确的使用

前面已经分析过,Redis最适合所有数据in-momory的场景,虽然Redis也提供持久化功能,但实际更多的是一个disk-backed的功能,跟传统意义上的持久化有比较大的别,那么可能大家就会有疑问,似乎Redis更像一个加强版的Memcached,那么何时使用Memcached,何时使用Redis呢?

1.网络IO模型

Memcached是多线程,非阻塞IO复用的网络模型,分为主线程和worker子线程,线程网络连接,接受请求后,将连接描述字pipe 传递给worker线程,进行读写IO, 网络层使用libnt封装的库,多线程模型可以发挥多核作用,但是引入了cache coherency和锁的问题,比如,Memcached最常用的stats 命令,实际Memcached所有作都要对这个全局变量加锁,进行计数等工作,带来了性能损耗。 (Memcached网络IO模型)

Redis使用单线程的IO复用模型,自己封装了一个简单的AeEvent处理框架,主要实现了epoll、kqueue和select,对于单纯只有IO作来说,单线程可以将速度优势发挥到,但是Redis也提供了一些简单的计算功能,比如排序、聚合等,对于这些作,单线程模型实际会影响整体吞吐量,CPU计算过程中,整个IO调度都是被阻塞住的。

2.内存管理方面

Memcached使用预分配的内存池的方式,使用slab和大小不同的ck来管理内存,Item根据大小选择合适的ck存储,内存池的方式可以省去申请/释放内存的开销,并且能减小内存碎片产生,但这种方式也会带来一定程度上的空间浪费,并且在内存仍然有很大空间时,新的数据也可能会被剔除,原因可以参考Timyang的文章:

Redis使用现场申请内存的方式来存储数据,并且很少使用free-list等方式来优化内存分配,会在一定程度上存在内存碎片,Redis跟据存储命令参数,会把带过期时间的数据单独存放在一起,并把它们称为临时数据,非临时数据是永远不会被剔除的,即便物理内存不够,导致swap也不会剔除任何非临时数据(但会尝试剔除部分临时数据),这点上Redis更适合作为存储而不是cache。

Redis更适合作为存储而不是cache。

3.数据一致性问题

Memcached提供了cas命令,可以保证多个并发访问作同一份数据的一致性问题。 Redis没有提供cas 命令,并不能保证这点,不过Redis提供了事务的功能,可以保证一串 命令的原子性,中间不会被任何作打断。

4.存储方式及其它方面

Memcached基本只支持简单的key-value存储,不支持枚举,不支持持久化和等功能

Redis除key/value之外,还支持list,set,sorted set,hash等众多数据结构,提供了KEYS

进行枚举作,但不能在线上使用,如果需要枚举线上数据,Redis提供了工具可以直接扫描其dump文件,枚举出所有数据,Redis还同时提供了持久化和等功能。

5.关于不同语言的客户端支持

在不同语言的客户端方面,Memcached和Redis都有丰富的第三方客户端可供选择,不过因为Memcached发展的时间更久一些,目前看在客户端支持方面,Memcached的很多客户端更加成熟稳定,而Redis由于其协议本身就比Memcached复杂,加上作者不断增加新的功能等,对应第三方客户端跟进速度可能会赶不上,有时可能需要自己在第三方客户端基础上做些修改才能更好的使用。

根据以上比较不难看出,当我们不希望数据被踢出,或者需要除key/value之外的更多数据类型时,或者需要落地功能时,使用Redis比使用Memcached更合适。

关于Redis的一些周边功能

Redis除了作为存储之外还提供了一些其它方面的功能,比如聚合计算、pubsub、scripting等,对于此类功能需要了解其实现原理,清楚地了解到它的局限性后,才能正确的使用,比如pubsub功能,这个实际是没有任何持久化支持的,消费方连接闪断或重连之间过来的消息是会全部丢失的,又比如聚合计算和scripting等功能受Redis单线程模型所限,是不可能达到很高的吞吐量的,需要谨慎使用。

总的来说Redis作者是一位非常勤奋的开发者,可以经常看到作者在尝试着各种不同的新鲜想法和思路,针对这些方面的功能就要求我们需要深入了解后再使用。

总结:

后续关于Redis文章:

关于作者

redis不支持以下哪种特性

MongoDB 更类似 MySQL,支持字段索引、游标作,其优势在于查询功能比较强大,擅长查询 JSON 数据,能存储海量数据,但是不支持事务。

redis不支持滚特性和持久Redis事务错误处理性。当作被打断时,不支持事务中的回滚特性,Redis不支持数据的持久化,不能将内存中的数据保持在磁盘中,重启的时候不饿能再次加载进行使用。Redis是一个开源的使用ANSIC语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。

redis主要解决什么问题

mongodb从1.8版本后,采用binlog方式(MySQL同样采用该方式)支持持久化,增加可靠性;

redis是内存数据库,访问速度非常快,所以能够解决的也都是这些缓存类型的问题,如下:

缓存穿透,即黑客故意去请求缓存中不存在的数据,导致所有的请求都怼到数据库上,从而数据库连接异常。

最常用的一种使用Redis的情景是会话缓存(session cache)。用Redis缓存会话比其他存储(如Memcached)的优势在于:Redis提供持久化。当维护一个不是严格要求一致性的缓存时,如果用户的购物车信息全部丢失,大部分人都会不高兴的,现在,他们还会这样吗?

幸运的是,随着 Redis 这些年的改进,很容易找到怎么恰当的使用Redis来缓存会话的文档。甚至广为人知的商业平台Magento也提供Redis的插件。

2、全页缓存(FPC)

除基本的会话token之外,Redis还提供很简便的FPC平台。回到一致性问题,即使重启了Redis实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,这是一个极大改进,类似PHP本地FPC。

再次以Magento为例,Magento提供一个插件来使用Redis作为全页缓存后端。

此外,对WordPress的用户来说,Pantheon有一个非常好的插件 wp-redis,这个插件能帮助你以最快速度加载你曾浏览过的页面。

3、队列

Reids在内存存储引擎领域的一大优点是提供 list 和 set 作,这使得Redis能作为一个很好的消息队列平台来使用。Redis作为队列使用的作,就类似于本地程序语言(如Python)对 list 的 push/pop 作。

排行榜/计数器

Redis在内存中对数字进行递增或递减的作实现的非常好。(Set)和有序(Sorted Set)也使得我们在执行这些作的时候变的非常简单,Redis只是正好提供了这两种数据结构。所以,我们要从排序中获取到排名最靠前的10个用户–我们称之为“user_scores”,我们只需要像下面一样执行即可:

ZRANGE user_scores 0 10 WITHSCORES

Agora Games就是一个很好的例子,用Ruby实现的,它的排行榜就是使用Redis来存储数据的,你可以在这里看到。

5、发布/

(但肯定不是最不重要的)是Redis的发布/功能。发布/的使用场景确实非常多。我已看见人们在社交网络连接中使用,还可作为基于发布/的脚本触发器,甚至用Redis的发布/功能来建立聊天系统!(不,这是真的,你可以去核实)。

Redis提供的所有特性中,我感觉这个是喜欢的人最少的一个,虽然它为用户提供如果此多功能。

等等?

MongoDB和Redis的区别是什么

Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,支持多种类型的数据结构,可用作数据库,高速缓存和消息队列。

MongoDB和Redis的区别是什么

1、内存管理机制

Redis 数据全部存在内存,定期写入磁盘,当内存不够时,可以选择指定的 LRU 算法删除数据。

MongoDB 数据存在内存,由 linux系统 mmap 实现,当内存不够时,只将热点数据放入内存,其他数据存在磁盘。

2、支持的数据结构

R12345678011121314edis 支持的数据结构丰富,包括hash、set、list等。

MongoDB 数据结构比较单一,但是支持丰富的数据表达,索引,最类似关系型数据库,支持的查询语言非常丰富。

3、数据量和性能:

当物理内存够用的时1.TxPipeline候,redis>mongodb>mysql

当物理内存不够用的时候,redis和mongodb都会使用虚拟内存。

实际上如果redis要开始虚拟内存,那很明显要么加内存条,要么你换个数据库了。

但是,mongodb不一样,只要,业务上能保证,冷热数据的读写比,使得热数据在物理内存中,mmap的交换较少。

mongodb还是能够保证性能。

4、性能

mongodb依赖内存,TPS较高;Redis依赖内存,TPS非常高。性能上Redis优于MongoDB。

5、可靠性

Redis依赖快照进行持久化;AOF增强可靠性;增强可靠性的同时,影响访问性能。

可靠性上MongoDB优于Redis。

7、事务支持情况

Redis 事务支持比较弱,只能保证事务中的每个作连续执行;mongodb不支持事务。

8、集群

MongoDB 集群技术比较成熟,Redis从3.0开始支持集群。

相关视频教程:《MongoDB教程》、《Redis教程》

redis支持事务吗

概述

相信学过Mysql等其他数据库的同学对事务这个词都不陌生,事务表示的是一组动作,这组动作要么全部执行,要么全部不执行。为什么会有这样的需求呢?看看下面的场景:

转账汇款,设现在有两个账户A和B,现在需要将A中的一万块大洋转到B的账户中,这个动作也需要两个步骤完成:从A的账户中划走一万块;在B的账户中增加一万块。这两个动作要么全部执行成功,要么全部不执行,否则自会有人问候你的!!! Redis作为一种高效的分布式数据库,同样支持事务。

Redis事务

举个例子,使用redis-cli连接redis,然后在命令行工具中输入如下命令:

12345678011121314151617181920

127.0.0.1:6379> MULTIOK127.0.0.1:6379> set set title winwill2012QUEUED127.0.0.1:6379> set desc jaQUEUED127.0.0.1:6379> EXEC1) OK2) OK3) OK127.0.0.1:6379>127.0.0.1:6379> get "h.me"127.0.0.1:6379> get title"winwill2012"127.0.0.1:6379> get desc"ja"127.0.0.1:6379>

从输出中可以看到,当输入MULTI命令后,返回OK表示事务开始成功,然后依次输入需要在本次事务中执行的所有命令,每次输入一个命令并不会马上执行,而是返回”QUEUED”,这表示命令已经被接受并且暂时保存起来,输入EXEC命令后,本次事务中的所有命令才会被依次执行,可以看到一次性返回了三个OK,这里返回的结果与发送的命令是按顺序一一对应的,这说明这次事务中的命令全都执行成功了。

再举个例子,在命令行工具中输入如下命令:

12345678011121314151617

127.0.0.1:6379> MULTIOK127.0.0.1:6379> set a aQUEUED127.0.0.1:6379> sett b b(error) ERR unknown command 'sett'127.0.0.1:6379> set c cQUEUED127.0.0.1:6379> EXEC(error) EXECABORT Transaction discarded because of previous errors.127.0.0.1:6379> get a(nil)127.0.0.1:6379> get b(nil)127.0.0.1:6379> get c(nil)127.0.0.1:6379>

和前面的例子一样,先输入MULTI输入EXEC表示中间的命令属于一个事务,不同的是中间输入的命令有一个错误(set写成了sett),这样因为有一个错误的命令导致事务中的其他命令都不执行了(通过后续的get命令可以验证),可见事务中的所有命令式同呼吸共命运的。

如果客户端在发送EXEC命令之前断线了,则会清空事务队列,事务中的所有命令都不会被执行。而一旦客户端发送了EXEC命令之后,事务中的所有命令都会被执行,即使此后客户端断线也没关系,因为已经保存了事务中的所有命令。

除了保证事务中的所有命令要么全执行要么全不执行外,Redis的事务还能保证一个事务中的命令依次执行而不会被其他命令插入。试想一个客户端A需要执行几条命令,同时客户端B发送了几条命令,如果不使用事务,则客户端B的命令有可能会插入到客户端A的几条命令中,如果想避免这种情况发生,也可以使用事务。

如果一个事务中的某个命令执行出错,Redis会怎样处理呢?要回答这个问题,首先要搞清楚是什么原因导致命令执行出错:

语法错误 就像上面的例子一样,语法错误表示命令不存在或者参数错误

这种情况需要区分Redis的版本,Redis 2.6.5之前的版本会忽略错误的命令,执行其他正确的命令,2.6.5之后的版本会忽略这个事务中的所有命令,都不执行,就比如上面的例子(使用的Redis版本是2.8的)

运行错误 运行错误表示命令在执行过程中出现错误,比如用GET命令获取一个散列表类型的键值。

这种错误在命令执行之前Redis是无法发现的,所以在事务里这样的命令会被Redis接受并执行。如果食物里有一条命令执行错误,其他命令依旧会执行(包括出错之后的命令)。比如下例:

127.0.0.1:6379> MULTIOK127.0.0.1:6379> set key 1QUEUED127.0.0.1:6379> SADD key 2QUEUED127.0.0.1:6379> set key 3QUEUED127.0.0.1:6379> EXEC1) OK2) (error) WRONGTYPE Operation against a key holding the wrong kind of value3) OK127.0.0.1:6379> get key"3"

Redis中的事务并没有关系型数据库中的事务回滚(rollback)功能,因此使用者必须自己收拾剩下的烂摊子。不过由于Redis不支持事务回滚功能,这也使得Redis的事务简洁快速。

回顾上面两种类型的错误,语法错误完全可以在开发的时候发现并作出处理,另外如果能很好地规划Redis数据的键的使用,也是不会出现命令和键不匹配的问题的。

WATCH命令

换个角度思考上面说到的实现i++的方法,可以这样实1、会话缓存(Session Cache)现:

i的值,保证i的值不被修改

获取i的原值

这样就能够避免竞态条件,保证i++能够正确执行。

WATCH命令可以一个或多个键,一旦其中有一个键被修改(或删除),之后的事务就不会执行,一直持续到EXEC命令(事务中的命令是在EX使用 Redis 的常见问题缓存和数据库双写一致性问题缓存雪崩问题缓存击穿问题缓存的并发竞争问题二 单线程的 Redis 为什么这么快这个问题是对 Redis 内部机制的一个考察。很多人都不知道 Redis 是单线程工作模型。EC之后才执行的,EXEC命令执行完之后被的键会自动被UNWATCH)

举个例子:

1234567801112131415

127.0.0.1:6379> set mykey 1OK127.0.0.1:6379> WATCH mykeyOK127.0.0.1:6379> set mykey 2OK127.0.0.1:6379> MULTIOK127.0.0.1:6379> set mykey 3QUEUED127.0.0.1:6379> EXEC(nil)127.0.0.1:6379> get mykey"2"127.0.0.1:6379>

上面的例子中,首先设置mykey的键值为1,然后使用WATCH命令mykey,随后更改mykey的值为2,然后进入事务,事务中设置mykey的值为3,然后执行EXEC运行事务中的命令,使用get命令查看mykey的值,发现mykey的值还是2,也就是说事务中的命令根本没有执行(因为WATCHmykey的过程中,mykey被修改了,所以随后的事务便会被取消)。

有了WATCH命令,我们就可以自己实现i++功能了,伪代码如下:

12345678011

def incr($key): WATCH $key $value = GET $key if not $value $value = 0 $value = $value + 1 MULTI SET $key $value result = EXEC return result[0]

因为EXEC返回的是多行字符串,使用result[0]表示返回值的个字符串。

注意:由于WATCH命令的作用只是当被的键被修改后取消之后的事务,并不能保证其他客户端不修改的值,所以当EXEC命令执行失败之后需要手动重新执行整个事务。

执行EXEC命令之后会取消使用WATCH命令的键,如果不想执行事务中的命令,也可以使用UNWATCH命令来取消。