- 浏览: 429593 次
- 性别:
- 来自: 杭州
文章分类
- 全部博客 (269)
- 原创 (7)
- Java (51)
- Java Concurrency (2)
- IDE (16)
- Linux (46)
- Database (23)
- NoSQL (35)
- Web服务器 (23)
- Log日志 (11)
- HTTP (11)
- HTML (2)
- XML (1)
- Test (7)
- Mina (0)
- Amoeba (4)
- Cobar (1)
- 序列化 (2)
- Python (5)
- PHP (1)
- Socket通信 (1)
- Network (3)
- Struts (2)
- Web前端 (10)
- Maven (6)
- SVN (15)
- Json (1)
- XMPP (2)
- Go (1)
- Other (4)
- 未整理 (5)
最新评论
-
u012374672:
[color=darkred][/color][flash=2 ...
Mongo的ORM框架的学习Morphia(annotations) -
b_l_east:
很有问题啊
利用redis的transaction功能,实现分布式下加锁
之前简单的看了一下 Tokyo Tyrant (包括 Tokyo Cabint ) 在 hash 存储上的一些实现,最近Redis 又比较火热,因此,自己也尝试性的去了解了一下 Redis,并且结合 Tokyo Tyrant(以下简称 tt server),说说自己对这两种产品的看法。抛砖引玉,可能有些地方说的不好,欢迎大家拍砖,指正。
目录
服务端处理模型
数据存储方式、持久化比较
复制方式比较
性能方面比较
总结
服务端处理模型
在 tt server 中,是以多线程的方式向客户端提供服务的:一个主线程负责 accept 客户端的socket,一定数目的线程(可以指定)进行读写服务,同时,也有一定数目的timer线程,专门用来负责定时的任务,比如一些定时的
Lua
脚本,同时,如果是slaver,则会有专门一个timer线程,定时负责 do slave 的工作。
而在 Redis 中,采用的则是单线程的模型来处理所有的客户端请求。
应该说这两种模型,都有各自的优点和缺点。多线程可以利用多核CPU的计算能力,但因此也会增加CAS自旋或者是锁的一些消耗,同时,如果线程过多,那么线程之间上下文的切换,也是一种消耗。
而如果是单线程,则可以完全避免锁的消耗,同时,上下文切换消耗也不需要过多的考虑(但仍需要考虑系统上还有其他的进程),这会让单个CPU的利用率比较高。
但是,单线程服务,就意味着不能利用多核。同时,服务端对客户端过来的请求是串行执行和响应的,这也在一定程度上,会影响服务端的并发能力,特别是在有些 请求执行比较耗时的情况下。想象一下,就这么一个线程,可能正在拼命的执行客户端A的一个请求,而此时客户端B,C,D的请求,还仍在等着线程执行完成之 后再去搭理他们。
因此,像 redis 这种单线程的服务模型,如果对一些请求的处理相对较耗时,那其 TPS 也就相应的不能提高上去,也就是说其吞吐量会提不上去;但反过来想, redis 如果能控制每次请求在执行过程是简短并且快速的,那么也许使用单线程,反而会比多线程有更好的性能,毕竟单线程少了上下文切换,以及锁或者 cas 的开销。
而 tt server 则中规中矩:一个线程负责 accept ,一定数目的线程则进行请求的处理。因此,我们在设置 tt server 的时候,也应尽量考虑好工作线程的数目,尽量让CPU数目与工作线程数目一致或者略少。原则是最好的发挥多核CPU的作用,同时又不让工作线程之间去竞争 CPU。当然,这是需要不停的去实验的。
所以,在使用 redis 的时候,应尽量不要去使用一些相对耗时的请求;同时,我想 redis 的作者,也应该会尽量优化每种请求的执行速度(至少是一些常用的请求)。
而在使用 tt server 的时候,需要仔细调整使用的工作线程数目,让每个CPU都物尽其用。
数据存储方式、持久化比较
tt server 的 hash 数据库,是使用文件的方式,然后利用 mmap 系统调用映射到内存中。
这样,就可以利用操作系统的机制,不定期地将数据 flush 到磁盘中。同时,tt server 也提供了 sync 命令,可以让客户端手动将数据 flush 到磁盘中(使用 msync 系统调用)。最后,在关闭 tt server 进程的时候,应该使用 kill -15(TERM信号),或者使用 ttserver 自带的命令:ttserver -kl pid 进行关闭。这样 ttserver 会先把数据 flush 到磁盘上,再退出进程。
同时, tt server 也提供了 ulog 的方式,对数据库的变更操作进行记录,同样,可以利用 ulog 对 ttserver 进行恢复 ,但 ulog 的主要目的,按照我的理解,应是用来实现 replication 的。
而 redis 则是将数据直接写在了内存中,然后利用 redis 的持久化机制 ,将数据写到磁盘中。
redis 提供了两种持久化机制,分别是 RDB (redis DB) 和 AOF (appending only file)。
RDB的过程是:redis 进程 fork 一个子进程,然后子进程对内存中的数据写到一个临时文件,这个时候,两个进程就利用了操作系统的 copy on write 机制,共享一份内存数据,只有当父进程(也就是 redis 进程)对原有的数据进行修改或者删除之后,操作系统才为 redis 进程重新开辟新的内存空间(以页为单位)。Redis 本身也提供了 bgsave(background save) 命令支持手动将数据持久化( save 命令是同步的,而 redis 只有一个线程在服务,结果就是影响 redis 的性能,特别是在大数据量的情况下)。
AOF的过程是:在执行每次命令之后,或者每隔1秒钟之后,Redis会有一个线程将命令以 redis 协议的格式 append 到文件中,这也就是AOF名字的由来,这些命令当然是非只读的,只读不更改数据库,没有必要记录下来。
这里会有两个问题:
1、每次命令之后写文件,还是隔1秒之后写文件,影响会有哪些?
2、这些文件总会不断的膨胀,如何对文件进行压缩呢?
对于第一个问题,也是一个权衡的问题,如果每次命令之后都进行一次写磁盘操作,那么IO的程度可想而知,肯定会影响服务器性能(使用 write 系统调用,会因为文件系统而进入 page buffer,并非立刻写磁盘,而调用 fsync ,则会将 page buffer 中的数据写入磁盘,进行 IO 操作)。而如果每隔1秒进行一次 fsync,那么在这一秒和上一秒之间,如果服务器突然断电,那很有可能这些数据就会丢失。对于这个问题,redis 默认给出的方案是每隔1秒进行一次write。对于1秒的给定,我想,也是基于性能和数据安全的权衡,在性能和数据安全方面都可以让人接受。
对于第二个问题,redis 提供了 rewrite 的机制:当 aof 过大的时候,redis可以自动的进行 rewrite (从 redis 2.4 开始)。rewrite 的过程也是 fork 一个子进程;然后打开一个临时文件,将内存中的数据写入到文件中;在此期间,主进程继续将数据写入老的 aof 文件,同时也会将数据写入到一个内存缓存中;等子进程完成之后,主进程会将缓存中的数据写入到临时文件,再将临时文件进行rename,替换掉原来的文 件。这样,就实现了写 aof 过程中的rewrite。
从数据的存储方式来说,尽管 tt server 和 redis 都是在内存上面进行数据的读写,我但认为两个产品对数据存储方式的观点是不一样的。
tt server 是将磁盘上的文件当作主要的存储方式,然后使用 mmap 将文件映射到内存中。本质上,这是数据应该存储在磁盘中的观点。
而 redis ,一开始就是将数据直接存储在内存中,在之后的持久化过程中,可以理解成只是将数据的日志写入到磁盘中。本质上,这是把数据应该存储在内存中的观点。
可见,由于作者的观点不一样,也就造成了两种实现方式不一样的产品,这还是比较有意思的。
从这个层面上来讲,我更加喜欢 redis 作者的思路,很可能作者就是受到
内存是新的磁盘,磁盘是新的磁带
的启发。
redis自带实现的VM将在以后不再使用(2.4将是最后一个自带vm功能的版本),作者认为数据就应该是放在物理内存中的,没有必要要将数据交换到磁盘中,磁盘只是作为日志的一种存储方式。这也是“内存是新的硬盘”思路的体现。
复制方式比较
tt server 和 redis 都支持 master-slave 方式的通信复制。
tt server 使用了 ulog,并且 slaver 使用了 rts(replication time-stamp) 文件,对上一次的复制时间戳进行保存,实现了复制的续传。
而 redis 则是每次 slave 重新连接到 master 时,master 会将数据进行全量的复制给 slave,而不是增量式的。redis 复制的方式与使用 RDB 持久化方式原理基本相同,也是使用子进程进行内存的dump,在此期间,父进程收集改变数据库的命令,等把子进程收集的数据传输给 slave 之后,再将此期间收集到的数据也传输给 slave。
如果从 slave 数据重建的角度来看,tt server 支持断点复制的实现,应该说是比 redis 先进了一步。
性能方面比较
新浪的 Tim Yang 做了 memcacheDB、Redis、tt server 的性能测试 。 这是比较早期的测试,相信随着版本的升级,两者的性能都会有所提升。不过按照这个测试的结果来看,redis 在数据量不多(500W)并且value 较小的时候,性能表现是很优越的;而对于稍大一些的 value ,tt 则在写方面表现很出色,但读的性能,相对较差。相比之下,redis的读写性能,倒是比较平衡。
但觉得随着时间的迁移,这个测试的参考性可能会打折扣,如果有可能的话,希望能看到更多的测试结果。
总结
1. 从服务器模型来说,tt server 使用 acceptor + workers 的方式提供服务,能够利用多核的性能,但随着而来的是一些同步、加锁的复杂和开销;而 redis 使用了单线程提供服务,利用不了多核,但如果能够将每次服务的速度控制下来,对单个CPU的利用率,反而可以提高。如果想利用机器的多核性能,也可以在一 台机器上搭建多个 redis 实例,但可能更要考虑到机器的内存限制。
2. 从数据存储的方式来说,尽管 tt server 和 redis 都是将数据存储在内存中,但我认为两个产品对“数据是如何存储”的观点是有所不同的。tt server 认为数据是存储在文件中的,只是通过内存映射,将对文件的操作转化成对内存的操作;而 redis 是直接将数据存储到内存中,之后再通过持久化等机制,将数据备份到磁盘中。虽然之前 redis 自己实现了 vm 功能,但redis 后续会取消掉自己实现的 vm 功能,按照“内存是最新的磁盘”这种思路,也就不难理解了:除了增加复杂度之外,还有一个因素,那就是 redis 不需要 vm,能存的数据大小,只能限制在物理内存的范围以内。
从这个方面来将,redis 后续的版本可能就会限制用户使用的数据库大小是要小于物理内存的,而如果使用 tt server ,则用户须让使用数据文件小于物理内存,否则,发生内存交换,是非常损性能的。
总而言之,在使用内存数据库的时候,应该有意识的对数据进行容量规划,避免出现物理内存不够而引起的内存交换。
3. tt server 和 redis 的策略都是从 slaver 配置 master ,而不是从 master 配置 slaver 关系,这样就减轻了 master 的负担,同时,master 不必知道自己有多少个 slaver ,就可以横向的扩增 slaver 。但 tt server 支持所谓的断点复制。需要考虑到的是 redis 在做 replication 的时候,是 fork 一个子进程工作的,如果有多个 replicate 的请求,redis 依然还是一个子进程在工作。这样也会对多个 slaver 产生一定的复制延时。
4. redis 在工作方式上,会 fork 子进程,因此 redis 在容量规划上,需要考虑到 redis fork 出子进程所需要的内存和 CPU,在最差的情况下:bgsave时候,父子两个进程虽然可以使用 copy on write 的好处,但如果在此期间整个表记录都被修改了,那就足足需要一倍的内存,否则,此时父进程会进行 copy ,父进程很可能没有内存可用,就需要进行内存交换,由此所带来的性能代价也是非常高的;与此同时,子进程子在 bgsave 的时候,需要对数据进行压缩,压缩是计算密集型的,因此最好不要和父进程使用同一个CPU,因为父进程使用了单线程事件处理的模型,这种模型的优点是充分 利用CPU的资源,如果出现子进程与父进程抢CPU,那就得不偿失了。
5. redis 支持较多的数据结构,但在使用 sort 等时间复杂性较多的命令时,也会稍微的降低 redis 的性能,应该对这些耗时的命令进行一定的监控。
==================
ps: diecui1202 指出:
Redis复制与可扩展集群搭建 这篇文章里提到一种“增量复制”的方式,大家可以参考一下:
1、 Master写AOF文件;
2、 在业务低峰期将进行内存快照,同时将AOF文件位置地一同写到快照文件中;
3、 当Slave来同步时,Master则是将上一次的内存快照sync给Slave;
4、 Slave根据快照文件构建内存,同时根据快照文件中的AOF文件位置来完成与Master的增量同步;
这个想法一方面可以提高Slave重建的速度,另一方面也可以降低Slave重建时对Master的压力;
发表评论
-
mongodb 地理位置处理
2016-05-16 13:39 1419我只记录我用到的部分,没有完整分析mongodb对地理位置 ... -
Redis配置文件redis.conf
2014-11-14 14:10 1868# Redis configuration file ex ... -
Redis高可用部署及监控
2014-11-12 13:25 1097一、 Re ... -
JCS官方文档的简单笔记,仅供自己参考
2014-09-26 20:08 7791. 基本配置 jcs.default=DCjcs.de ... -
JCS基本配置
2014-09-26 19:39 9431、默认的内存缓存 ... -
NoSQL解决方案比较(MongoDB vs Redis, Tokyo Cabinet, and Berkeley DB)
2013-09-30 14:20 1341NoSQL解决方案比较 NoSQL Solution: E ... -
morphia与spring的整合
2012-12-07 15:06 1484转自: http://www.blogjava.net/wat ... -
Mongo的ORM框架的学习Morphia(十五)Morphia+spring整合
2012-12-07 15:06 1657转自:http://topmanopensource.itey ... -
Mongo的ORM框架的学习Morphia(十二) morphia的Query和Update
2012-12-07 15:06 1875转自:http://topmanopensource.itey ... -
Mongo的ORM框架的学习Morphia(十) morphia应用
2012-12-05 14:47 1462转自:http://topmanopensource.itey ... -
Mongo的ORM框架的学习Morphia(九) morphia简单使用
2012-12-05 14:44 1380转自 http://topmanopensource.itey ... -
Mongo的ORM框架的学习Morphia(八) morphia数据库访问接口
2012-12-05 14:35 2019转自:http://topmanopensource.itey ... -
Mongo的ORM框架的学习Morphia(annotations)
2012-12-05 14:33 2543一:@Entity的使用 @Entity ... -
Instagram的Redis实践(内存占用优化)
2012-11-30 10:43 1201转自:http://blog.nosqlfan.com/htm ... -
SQL 和Mongo 对比图表
2012-11-28 14:54 2209参看官方说明: http://www.mongodb ... -
MongoDB 入门指南、示例
2012-11-23 10:38 854转自:http://www.cnblogs.com/hoojo ... -
mongodb中使用MapReduce
2012-11-23 10:12 1213MapReduce函数的用法如下: db.users.ma ... -
python的redis用法
2012-11-22 15:48 1170#! /usr/bin/env python #coding ... -
Python连接redis
2012-11-22 15:46 5621一、Redis是流行的NOSQL内存数据库,以Key-Valu ... -
【pipeline】【分布式的id生成器】【分布式锁【watch】【multi】】【redis分布式】
2012-08-29 10:42 1376转自 http://www.bwkeji.com/a/wang ...
相关推荐
例如,Memcached适合简单的键值对存储,MongoDB适合处理复杂的文档结构,Redis适用于需要高速读写和多数据结构操作的场景,而Tokyo Tyrant则提供了一个轻量级的解决方案。 在学习和使用过程中,可能会涉及到的知识...
例如:Tokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB。 2. 列存储数据库:这部分数据库通常是用来应对分布式存储的海量数据。键仍然存在,但是它们的特点是指向了多个列。这些列是由列家族来安排的。例如:...
* 键值(Key-Value)存储数据库:相关产品有 Tokyo Cabinet/Tyrant、Redis、Voldemort、Berkeley DB。典型应用:内容缓存,主要用于处理大量数据的高访问负载。数据模型:一系列键值对。优势:快速查询;劣势:存储的...
1. **键值(Key-Value)存储数据库**:这类数据库通过键值对的形式存储数据,例如Tokyo Cabinet/Tyrant、Redis、Voldemort、Berkeley DB。它们适用于内容缓存等需要处理大量数据的高访问负载场景。优点在于能够实现...
- **键值(Key-Value)存储数据库**:例如Tokyo Cabinet/Tyrant、Redis、Voldemort等。这类数据库以键值对的形式存储数据,适合于内容缓存场景。 - **列存储数据库**:如Cassandra、HBase、Riak等。它们通过列簇存储...
1. 键值(Key-Value)存储数据库,如Redis、Tokyo Cabinet/Tyrant,适合内容缓存,优点是查询快速,但结构化程度低。 2. 列存储数据库,如Cassandra、HBase,适用于分布式文件系统,优点在于查找速度快,扩展性强,但...
- **键值存储数据库**:如Tokyo Cabinet/Tyrant、Redis等,适用于需要快速查询的应用场景。 - **列存储数据库**:如Cassandra、HBase等,适合分布式文件系统等应用。 - **文档型数据库**:如CouchDB、MongoDB等,...
1. **键值(Key-Value)存储数据库**:如Tokyo Cabinet/Tyrant、Redis、Voldemort等。这类数据库适用于需要高速访问的大规模数据存储场景。其数据模型为一系列键值对,具有快速查询的优势,但存储的数据缺少结构化特性...
1. 键值(Key-Value)存储数据库:以键值对的形式存储数据,典型产品包括Redis、Tokyo Cabinet/Tyrant等。主要应用在内容缓存的场景中,优势是快速查询,劣势是存储的数据缺少结构化。 2. 列存储数据库:采用列簇式...
1. **键值存储**:如Tokyo Cabinet/Tyrant、Berkeley DB、MemcacheDB、Redis等,特点是使用键值对形式存储数据,访问速度快,但缺乏复杂查询功能。 2. **文档数据库**:如MongoDB、CouchDB等,使用JSON或类似格式...
比如,键值存储数据库如Tokyo Tyrant和Voldemort适合缓存应用;列存储数据库如HBase适用于分布式文件系统;文档型数据库如MongoDB适合结构化程度较低的数据;图形数据库如Neo4j适用于处理复杂的网络结构数据。 总结...
Tokyo Cabinet具有高性能和多种存储引擎选择,Tokyo Tyrant则通过热备份、update log和异步复制提高可用性,并允许通过Lua脚本进行原子性操作。 3. MongoDB:MongoDB是一个面向文档的数据库,支持无固定规格的JSON...
Tokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB 内容缓存,主要用于处理大量数据的高访问负载,也用于一些日志系统等等 Key 指向 Value 的键值对,通常用HashTable来实现 查找速度快 数据无结构化,通常只被...
其中,键值存储数据库如Tokyo Cabinet/Tokyo Tyrant,以极高的读写速度著称,适合高速缓存和实时数据处理;文档数据库如MongoDB,以JSON文档形式存储数据,便于数据的检索和管理;列族存储数据库如HBase,适用于大...
- **Tokyo Cabinet/Tokyo Tyrant (TC/TT)**:作为键值存储系统,适用于需要快速访问和简单数据结构的场景,如缓存服务或轻量级数据存储。 Tokyo Cabinet提供了多种数据存储方式,包括哈希数据库(TCHDB)、B+树...
例如Tokyo Cabinet/Tyrant、Redis、Voldemort和Oracle BDB。 2. 列存储数据库:列存储数据库适用于存储大量分布式数据,键指向多列,列由列族组织。这类数据库如Cassandra、HBase和Riak,适合大数据分析和实时数据...
* Key-Value 存储,例如 Tokyo Cabinet/Tyrant, Redis, Voldemort, Oracle BDB。 * 列式数据库,例如 Cassandra, HBase, Riak。 * 文档型数据库,例如 CouchDB, MongoDB。 * 图结构数据库,例如 Neo4J, InfoGrid, ...
- 示例包括Tokyo Cabinet/Tyrant、Redis、Voldemort等。 2. **列存储数据库**: - 专为处理分布式存储的海量数据设计,数据按列组织。 - 键仍然存在,但指向多个列,这些列按照列族进行组织。 - 示例包括...
2. 永久性:“数据不会丢失”,Tokyo Tyrant、Flare 属于这种类型 3. 两种兼具型:临时性和永久性兼具,集合了临时性键值存储和永久性键值存储的有点,Redis 属于这种类型 面向文档的数据库的特点是: 1. 不需要...