分布式存储的七方面问题
2021-05-17 09:32:18为什么是7方面的问题?虽说7面只比6面多了一面,又比8面少了1面;然而并非刻意为之。存储领域内的很多知识,可以归结于7个方面: 复制、存储引擎、事务、分析、多核、计算和编译。
动机
为什么是7方面的问题?虽说7面只比6面多了一面,又比8面少了1面;然而并非刻意为之。存储领域内的很多知识,可以归结于7个方面: 复制、存储引擎、事务、分析、多核、计算和编译。
分布式存储
什么是分布式存储呢?如果一个存储系统,不管是对象、块、文件、kv、log、olap、oltp,只要对所管理的数据做了Partitioning&Replication,不管姿势对不对,其实都可以归纳于分布式存储。分布式存储就是:Partitioning以多机scale,Replication以灾备容错。
1. 复制
复制是解决可用性,可扩展性和高性能的关键。为了灾备,数据需要冗余存储;为了高可用,服务需要hot standby。缺乏灾备的系统难以在生产环境使用。元数据和数据的维护均离不开复制,复制可转移而不可消除。复制引出了多副本一致性问题,而一致性保证需要考虑各种软件和硬件故障,以及误操作。共识算法和复制日志是解决复制问题的核心,具体涉及:
2. 存储引擎
此处的引擎是指本地的持久化存储引擎,持久化存储引擎要考虑CPU和memory系统和持久化设备之间的速度和带宽差异,可以总结为1-3-5。
1是指fsync的调用,以及和fsync地位等同的函数的调用。调用次数,调用频率,在多少数据上施加调用等。设备的带宽和利用率是否合理,fsync的调用怎么均摊到更多io次数和吞吐之上呢?
3是指读/写/空间的放大。怎么tradeoff,牺牲一个保住其他两个呢?
5是指WAL的5个LSN,分别为prepare point,commit point,apply point,checkpoint,prune point。
数据结构和算法
内存和磁盘数据的管理,需要用到丰富的数据结构和算法。此外解压缩和编解码算法用于降低数据的size,也很有意思。
3. 事务
事务是指ACID,很多存储系统,其实可以用事务做baseline进行分析,看这个系统在原子性,一致性,隔离性和持久化四个方面的设计究竟走多远。其实事务反应了正确性和并发性的折中。作为事务的使用方,理论上(实践上未必),并发访问存储系统时,不需要担心结果不正确的问题。假如这种担忧存在,一定是事务处理上,牺牲了某些正确性,偏向了并发性,将错误处理和选择权交给了使用方处理,使用方需要额外花费心智在客户代码中插入fence代码和做容错处理。
存储引擎部分,其实已经或多或少地涉及到了事务处理的提交协议,提交协议主要解决事务的A和D。事务处理的核心是并发控制(concurrency control)协议。并发控制主要解决这样的问题:
这两个问题本质是隔离性和一致性,冲突事务加以同步,前置的提交事务对后置outstanding事务可见。
理想的正确性是这样子的:所有的事务,不管是否存在冲突,都一个一个串行执行,时间上没有任何重叠。理想的并发性是这样子的:所有事务都没有冲突,可以以最佳的并行度同时执行。但现实是冲突始终存在,解决冲突,意味着在并行执行的某个环节插入了同步点,需要判断和仲裁是否有冲突。
冲突等待,是lock-based CC协议;冲突夭折重试,是timestamp ordering CC协议。前者就是所谓的悲观事务,后者则为乐观事务。事务处理在Jim Gray的书中和知名教材里其实已经讲得很清楚了。这里只提一下乐观事务的冲突检查的直观性的简单的理解:两个事务存在两种定序方法,一种是由TSO分配的时间戳确定的顺序,一种是由数据依赖(WAW,RAW,WAR)确定顺序。如果这两种顺序破坏事务之间的偏序关系,那么这两个事务必然冲突,可以选择让一个事务夭折并且重试。
定序是一个比较关键的问题,比如乐观事务的begin和commit的时间戳分配,悲观事务的基于时间戳的死锁预防也会用到时间戳的分配。
存储系统自身做了partitioning之后,单个partition的事务处理可下沉于本地存储引擎,然而如果一个操作涉及对多个partition的修改,则需要考虑跨partition的事务处理能力。其实分布式事务并没有一个清晰的定义,但蕴含了“跨(across)”的意思,不管是提交协议还是CC协议,都依赖于分布式存储系统的实现或者单机事务的实现。虽然有很多文献中反复用到2PC和3PC,但有时候是指提交协议,有时候是指CC协议,有时候是指提交协议和CC协议的混合体。
事务给存储系统的行为做出了明确的定义和保证,从事务的角度可推测系统的实现,比如加锁的粒度,多版本的管理,全局同步点,怎么处理write-too-late问题。
4. 分析
分析处理涵盖的东西太多了。从一个角度看,是怎么实现SQL语言;从另一个角度看,是怎么实现一个分布式系统由SQL驱动起来工作。一条文本的SQL语句,历经分词,语法分析,访问catalog和语意分析,关系代数的等价变化,形成逻辑的查询计划,然后根据数据的分布,算子自身特点和计算资源状况,生成物理执行计划。
一条SQL可以对应多个逻辑执行计划,一个逻辑执行计划,对应多个物理执行计划。比如join的顺序,join的算子的实现。谓词过滤时谓词的顺序,谓词是否下沉。一个关系代数的算子,有多种的不同实现算法,而多个关系算子,不同的计算顺序也会有不同的执行效率。根据先验知识,使用启发式的策略;或者利用数据分布的统计信息,采用某种cost估算模型;又或者根据已有执行经验,自适应地调整到最优或者次优的执行计划。
在计算层,通过三大优化策略parallelism,pipelining和batch加速处理。比如数据经过parititioning形成多个partition,放置于多机上,采用MPP的方式,做多机的并行处理。计算的过程可以看成是把关系作为输入,流经执行树的叶子节点,汇聚于根节点,每个节点的对应算子的具体算法实现所输入数据进行处理后输出。从计算模型的角度看,有这么几种情况:
在存储层,数据采用列式存储,可获得很好的编码效率,降低读放大和空间放大,访问持久化存储的带宽被高效利用,CPU和Memory的带宽增速相对于持久化存储带宽增速表现出了显著的差异,使用CPU的计算交换磁盘带宽,提升了数据的处理能力。
列存,向量化执行引擎,MPP是现代分析性数据库的关键技术。
5. 多核
从编程实现的角度看,多核scale,CC协议,共识算法是计算机中比较有挑战,并且是纯自然的问题。即便技术上不深入接触数据库,也对这三个问题相当地痴迷,被数据库技术的吸引加入这个领域,或多或少和这三个问题相关。
为什么多核如此重要呢?
假设摩尔定律,没有功率墙的限制,世界会怎样呢?显然我们不需要修改老代码,只要增加单核晶体管数量,老代码自然而然会提升。我们撞到了功率墙后,发现需要增加核数以提升计算速度。现在问题来了,我们的代码已经写成了多线程执行,那么随着核数增长,修改worker线程池的大小,老代码的计算能力会随着核数增加而持续增加吗?显然不是这样,因为多核上的scale受到阿姆达尔定律的制约,当代码中串行执行的部分占比1%时,256核机器只能最多加速到72倍,如果是10%,只能最多加速到10倍。显然修改线程池的大小,并不是一个好方法,减少代码中contention才是关键。
这种情况下,speedup想要随着核数而scale,发现很多算法,数据结构,CC协议和分析处理的算子实现,需要case-by-case重构以减少contention,重构方式是采用lockfree算法。但是这还不是事实的全部,当面对多核scale时,其实我们面对的是一个新的分布式系统,这个新的分布式系统是以interconnect为网络,以核为计算资源,并且还需要考虑屏蔽内存体系的延迟。如果说原来的分布式系统中,我们倾向于每个机器各干各的,数据做到均衡,计算资源就可以充分利用。对于多核编程同样有这个问题,怎么将原来的任务均匀地拆成多个子任务,然后多个子任务可以齐头并进,几乎同时冲线结束。显然数据拆分不均衡,跨核通信等因素都会造成快核等慢核的问题。同时,多核处理时,倾向于协作完成一个共同的任务,而非各干各的,这种情况下,将任务均匀拆分成子任务的的调度代码,共享的数据结构的访问代码,多核彼此之间等待本身就是同步点,即contention,总之,contention怎么降低呢?
现实中,lockfree算法,怎么描述和验证正确性呢?我们对比其他两个问题的思路,或许有解法。比如共识算法中,采用invariant描述算法;而CC协议中,采用反例(anormaly)攻击算法。或许这两种方法相互结合,能够帮助我们研究lockfree算法。
多核scale的挑战性很大,但这可以让具有优势的传统数据库和数据库的新进入者,处于赛道的同一起跑线,比拼谁的代码case-by-case优化做得好。

也有不少团队,在思考异构计算加速数据处理,这同样充满机会。但是,依靠程序员的心智构造精巧而高质量的代码,费时费力。或许的确应该通过编译器的后端技术一劳永逸解决这类问题,现在做不到,不代表未来也做不到。到时候,有人看着前人写得如此复杂的代码,就好比我们现在看到泥板书和带孔的卡片。
6. 计算
计算主要讲执行引擎, 执行引擎是一个很大的scope,目前roadmap已经建立,但是缺乏baseline,待两者都ready之后,会补充。
7. 编译
编译对数据库的渗透是全方位的:比如计算引擎在向量化之外可采用编译技术优化性能。数据库中很多case-by-case的性能优化,需要深入研究体系结构,异构计算加速处理也需要使用编译技术。流批DSL脚本使用现有的SQL执行引擎做计算,UDF扩充等。目前动机已经明了,但roadmap和baseline尚未建立,两者ready之后,也会补充进来。
oracle数据库的后台进程有哪些
DBWR进程:该进程执行将缓冲区写入数据文件,是负责缓冲存储区管理的一个ORACLE后台进程。 当缓冲区中的一缓冲区被修改,它被标志为“弄脏”,DBWR的主要任务是将“弄脏”的缓冲区写入磁盘,使缓冲区保持“干净”。 由于缓冲存储区的缓冲区填入数据库或被用户进程弄脏,未用的缓冲区的数目减少。 当未用的缓冲区下降到很少,以致用户进程要从磁盘读入块到内存存储区时无法找到未用的缓冲区时,DBWR将管理缓冲存储区,使用户进程总可得到未用的缓冲区。 ORACLE采用LRU(LEAST RECENTLY USED)算法(最近最少使用算法)保持内存中的数据块是最近使用的,使I/O最小。 在下列情况预示DBWR 要将弄脏的缓冲区写入磁盘:当一个服务器进程将一缓冲区移入“弄脏”表,该弄脏表达到临界长度时,该服务进程将通知DBWR进行写。 该临界长度是为参数DB-BLOCK-WRITE-BATCH的值的一半。 当一个服务器进程在LRU表中查找DB-BLOCK-MAX-SCAN-CNT缓冲区时,没有查到未用的缓冲区,它停止查找并通知DBWR进行写。 出现超时(每次3秒),DBWR 将通知本身。 当出现检查点时,LGWR将通知DBWR.在前两种情况下,DBWR将弄脏表中的块写入磁盘,每次可写的块数由初始化参数DB-BLOCK- WRITE-BATCH所指定。 如果弄脏表中没有该参数指定块数的缓冲区,DBWR从LUR表中查找另外一个弄脏缓冲区。 如果DBWR在三秒内未活动,则出现超时。 在这种情况下DBWR对LRU表查找指定数目的缓冲区,将所找到任何弄脏缓冲区写入磁盘。 每当出现超时,DBWR查找一个新的缓冲区组。 每次由DBWR查找的缓冲区的数目是为寝化参数DB-BLOCK- WRITE-BATCH的值的二倍。 如果数据库空运转,DBWR最终将全部缓冲区存储区写入磁盘。 在出现检查点时,LGWR指定一修改缓冲区表必须写入到磁盘。 DBWR将指定的缓冲区写入磁盘。 在有些平台上,一个实例可有多个DBWR.在这样的实例中,一些块可写入一磁盘,另一些块可写入其它磁盘。 参数DB-WRITERS控制DBWR进程个数。 LGWR进程:该进程将日志缓冲区写入磁盘上的一个日志文件,它是负责管理日志缓冲区的一个ORACLE后台进程。 LGWR进程将自上次写入磁盘以来的全部日志项输出,LGWR输出:当用户进程提交一事务时写入一个提交记录。 每三秒将日志缓冲区输出。 当日志缓冲区的1/3已满时将日志缓冲区输出。 当DBWR将修改缓冲区写入磁盘时则将日志缓冲区输出。 LGWR进程同步地写入到活动的镜象在线日志文件组。 如果组中一个文件被删除或不可用,LGWR 可继续地写入该组的其它文件。 日志缓冲区是一个循环缓冲区。 当LGWR将日志缓冲区的日志项写入日志文件后,服务器进程可将新的日志项写入到该日志缓冲区。 LGWR 通常写得很快,可确保日志缓冲区总有空间可写入新的日志项。 注意:有时候当需要更多的日志缓冲区时,LWGR在一个事务提交前就将日志项写出,而这些日志项仅当在以后事务提交后才永久化。 ORACLE使用快速提交机制,当用户发出COMMIT语句时,一个COMMIT记录立即放入日志缓冲区,但相应的数据缓冲区改变是被延迟,直到在更有效时才将它们写入数据文件。 当一事务提交时,被赋给一个系统修改号(SCN),它同事务日志项一起记录在日志中。 由于SCN记录在日志中,以致在并行服务器选项配置情况下,恢复操作可以同步。 CKPT进程:该进程在检查点出现时,对全部数据文件的标题进行修改,指示该检查点。 在通常的情况下,该任务由LGWR执行。 然而,如果检查点明显地降低系统性能时,可使CKPT进程运行,将原来由LGWR进程执行的检查点的工作分离出来,由 CKPT进程实现。 对于许多应用情况,CKPT进程是不必要的。 只有当数据库有许多数据文件,LGWR在检查点时明显地降低性能才使CKPT运行。 CKPT进程不将块写入磁盘,该工作是由DBWR完成的。 初始化参数CHECKPOINT-PROCESS控制CKPT进程的使能或使不能。 缺省时为FALSE,即为使不能。 SMON进程:该进程实例启动时执行实例恢复,还负责清理不再使用的临时段。 在具有并行服务器选项的环境下,SMON对有故障CPU或实例进行实例恢复。 SMON进程有规律地被呼醒,检查是否需要,或者其它进程发现需要时可以被调用。 PMON进程:该进程在用户进程出现故障时执行进程恢复,负责清理内存储区和释放该进程所使用的资源。 例:它要重置活动事务表的状态,释放封锁,将该故障的进程的ID从活动进程表中移去。 PMON还周期地检查调度进程(DISPATCHER)和服务器进程的状态,如果已死,则重新启动(不包括有意删除的进程)。 PMON有规律地被呼醒,检查是否需要,或者其它进程发现需要时可以被调用。 RECO进程:该进程是在具有分布式选项时所使用的一个进程,自动地解决在分布式事务中的故障。 一个结点RECO后台进程自动地连接到包含有悬而未决的分布式事务的其它数据库中,RECO自动地解决所有的悬而不决的事务。 任何相应于已处理的悬而不决的事务的行将从每一个数据库的悬挂事务表中删去。 当一数据库服务器的RECO后台进程试图建立同一远程服务器的通信,如果远程服务器是不可用或者网络连接不能建立时,RECO自动地在一个时间间隔之后再次连接。 RECO后台进程仅当在允许分布式事务的系统中出现,而且DISTRIBUTED ?C TRANSACTIONS参数是大于进程:该进程将已填满的在线日志文件拷贝到指定的存储设备。 当日志是为ARCHIVELOG使用方式、并可自动地归档时ARCH进程才存在。 LCKn进程:是在具有并行服务器选件环境下使用,可多至10个进程(LCK0,LCK1……,LCK9),用于实例间的封锁。 Dnnn进程(调度进程):该进程允许用户进程共享有限的服务器进程(SERVER PROCESS)。 没有调度进程时,每个用户进程需要一个专用服务进程(DEDICATEDSERVER PROCESS)。 对于多线索服务器(MULTI-THREADED SERVER)可支持多个用户进程。 如果在系统中具有大量用户,多线索服务器可支持大量用户,尤其在客户_服务器环境中。 在一个数据库实例中可建立多个调度进程。 对每种网络协议至少建立一个调度进程。 数据库管理员根据操作系统中每个进程可连接数目的限制决定启动的调度程序的最优数,在实例运行时可增加或删除调度进程。 多线索服务器需要SQL*NET版本2或更后的版本。 在多线索服务器的配置下,一个网络接收器进程等待客户应用连接请求,并将每一个发送到一个调度进程。 如果不能将客户应用连接到一调度进程时,网络接收器进程将启动一个专用服务器进程。 该网络接收器进程不是ORACLE实例的组成部分,它是处理与ORACLE有关的网络进程的组成部分。 在实例启动时,该网络接收器被打开,为用户连接到ORACLE建立一通信路径,然后每一个调度进程把连接请求的调度进程的地址给予于它的接收器。 当一个用户进程作连接请求时,网络接收器进程分析请求并决定该用户是否可使用一调度进程。 如果是,该网络接收器进程返回该调度进程的地址,之后用户进程直接连接到该调度进程。 有些用户进程不能调度进程通信(如果使用SQL*NET以前的版本的用户),网络接收器进程不能将如此用户连接到一调度进程。 在这种情况下,网络接收器建立一个专用服务器进程,建立一种合适的连接.即主要的有:DBWR,LGWR,SMON 其他后台进程有PMON,CKPT等
应用程序错误怎么办
运行某些程序的时候,有时会出现内存错误的提示,然后该程序就关闭。 “0x????????”指令引用的“0x????????”内存。 该内存不能为“read”。 “0x????????”指令引用的“0x????????”内存,该内存不能为“written”。 不知你出现过类似这样的故障吗?(0x后面内容有可能不一样。 ) 一般出现这个现象有方面的,一是硬件,即内存方面有问题,二是软件,这就有多方面的问题了。 1、微软IE缓冲溢出漏洞引起2、内存或虚拟内存地址使用冲突造成 程序的运行需要分配一定的内存地址给程序使用,当程序结束时释放留出空间让给新的程序使用,win是多任务的系统 有时前程序未结束 又有新的任务开始 到底要多少内存或虚拟内存来保证我们同时运行的工作任务呢?也许win在这个问题上没弄好,所以有此错误常常发生,一般运行大型软件或多媒体后出现这种情况 3、劣质内存条也会出现这个问题 一般来说,内存出现问题的可能性并不大,主要方面是:内存条坏了、内存质量有问题,还有就是2个不同牌子不同容量的内存混插,也比较容易出现不兼容的情况,同时还要注意散热问题,特别是超频后。 你可以使用MemTest 这个软件来检测一下内存,它可以彻底的检测出内存的稳定度。 假如你是双内存,而且是不同品牌的内存条混插或者买了二手内存时,出现这个问题,这时,你就要检查是不是内存出问题了或者和其它硬件不兼容。 4、微软Windows系统的漏洞,windows把内存地址0X到0X0000ffff指定为分配null指针的地址范围,如果程序试图访问这一地址,则认为是错误。 c/c++编写的程序通常不进行严格的错误检查,当采用malloc来分配内存而可供分配的地址空间不够的情况下返回null指针。 但是代码不检查这种错误,认为地址分配已经成功,于是就访问0X的地址,于是就发生内存违规访问,同时该进程被终止。 ASCII字符填充组成的pif文件时会出现以下情况: 一个非法的pif文件(用ascii字符\x\填充)至少要369字节,系统才认为是一个合法的pif文件,才会以pif的图标[,0]显示,才会在属性里有程序、 字体、内存、屏幕”等内容。 而且仅仅当一个非pif文件的大小是369字节时察看属性的“程序”页时,不会发生程序错误,哪怕是370字节也不行。 当对一个大于369字节的非法pif文件察看属性的“程序”页时,Explorer会出错,提示:\***\指令引用的\***\内存。 该内存不能为\read\ ,问题出在pif文件的16进制地址: 0x[0x87]0x[0x01]和 0x[0xC3]0x[0x02] 即使是一个合法pif文件,只要改动这四处的任意一处,也会引起程序错误。 而只 要把0x和0x的值改为[0xFF][0xFF],那么其它地址任意更改 都不会引起错误。 5、可能没有完全正确安装apache服务,且启动了它的原故; 把服务中的 OracleOraHomeXXHTTPServer改成停止6、应用程序没有检查内存分配失败程序需要一块内存用以保存数据时,就需要调用操作系统提供的“功能函数”来申请,如果内存分配成功,函数就会将所新开辟的内存区地址返回给应用程序,应用程序就可以通过这个地址使用这块内存。 这就是“动态内存分配”,内存地址也就是编程中的“指针”。 内存不是永远都招之即来、用之不尽的,有时候内存分配也会失败。 当分配失败时系统函数会返回一个0值,这时返回值“0”已不表示新启用的指针,而是系统向应用程序发出的一个通知,告知出现了错误。 作为应用程序,在每一次申请内存后都应该检查返回值是否为0,如果是,则意味着出现了故障,应该采取一些措施挽救,这就增强了程序的“健壮性”。 若应用程序没有检查这个错误,它就会按照“思维惯性”认为这个值是给它分配的可用指针,继续在之后的运行中使用这块内存。 真正的0地址内存区保存的是计算机系统中最重要的“中断描述符表”,绝对不允许应用程序使用。 在没有保护机制的操作系统下(如DOS),写数据到这个地址会导致立即死机,而在健壮的操作系统中,如Windows等,这个操作会马上被系统的保护机制捕获,其结果就是由操作系统强行关闭出错的应用程序,以防止其错误扩大。 这时候,就会出现上述的“写内存”错误,并指出被引用的内存地址为“0x”。 内存分配失败故障的原因很多,内存不够、系统函数的版本不匹配等都可能有影响。 因此,这种分配失败多见于操作系统使用很长时间后,安装了多种应用程序(包括无意中“安装”的病毒程序),更改了大量的系统参数和系统文件之后。 7、应用程序由于自身BUG引用了不正常的内存指针在使用动态分配的应用程序中,有时会有这样的情况出现:程序试图读写一块“应该可用”的内存,但不知为什么,这个预料中可用的指针已经失效了。 有可能是“忘记了”向操作系统要求分配,也可能是程序自己在某个时候已经注销了这块内存而“没有留意”等等。 注销了的内存被系统回收,其访问权已经不属于该应用程序,因此读写操作也同样会触发系统的保护机制,企图“违法”的程序唯一的下场就是被操作终止运行,回收全部资源。 计算机世界的法律还是要比人类有效和严厉得多啊! 像这样的情况都属于程序自身的BUG,你往往可在特定的操作顺序下重现错误。 无效指针不一定总是0,因此错误提示中的内存地址也不一定为“0x”,而是其他随机数字。
为什么还有那么多人用SVN
SVN是Subversion的简称,是一个开放源代码的版本控制系统,相较于RCS、CVS,它采用了分支管理系统,它的设计目标就是取代CVS。 互联网上很多版本控制服务已从CVS迁移到Subversion。 说得简单一点SVN就是用于多个人共同开发同一个项目,共用资源的目的。 svn服务器有2种运行方式:独立服务器和借助apache运行。 两种方式各有利弊,用户可以自行选择。 svn存储版本数据也有2种方式:BDB(一种事务安全型表类型)和FSFS(一种不需要数据库的存储系统)。 因为BDB方式在服务器中断时,有可能锁住数据,所以还是FSFS方式更安全一点。 所有的文档都显示SVN可以取代CVS,同时SVN的问题和缺点都被隐藏了。 不幸的是,我们并不认为SVN是CVS的替代品,尽管很多缺陷都被修改了。 更有甚者,它甚至让人重回CVS。 CVS和SVN的比较类似于比较C++和Java。 很明显CVS和SVN都远比SourceSafe强大的多,如同C++和Java比Basic强大的多。 CVS代表了几乎代码控制系统的所有功能项,尽管有时他的实现并不很方便。 SVN修正并添加了一些CVS并不拥有的功能。 例如,创建标志和分支dubious,你在编辑文件时其他人不会有任何通知。 SVN并不是CVS的替代品,只是个不同的系统,类似于CVS。 它有些特有的功能,足以作为采用它的理由。 这些功能使他更适合于开发环境,例如对PowerBuilder。 下面你可以找到两者的相对优势、劣势。 1 存储类型格式CVS是个基于RCS文件的版本控制系统。 每个CVS文件都不过是普通的文件,加上一些额外信息。 这些文件会简单的重复本地文件的树结构。 因此,不必担心有什么数据损失,如果必要的话可以手工修改RCS文件。 SVN是基于关系数据库的(BerkleyDB)或一系列二进制文件的(FS_FS)。 一方面这解决了许多问题 (例如,并行读写共享文件)以及添加了许多新功能(例如运行时的事务特性。 )。 然而另一方面,数据存储由此变得不透明。 2 速度CVS比较慢。 整体而言,由于架构实现的不同, SVN的确比CVS快很多。 在网络上它只传输很少的信息并支持更多的离线模式的功能。 但这也是有代价的。 速度的代价就是巨大的存储(完全备份所有的工作文件)。 3 标志&分支SVN采用标志和分支而抛弃了其他三件东西,实际上这意味着他们把这个概念替换为在档案库内部复制文件或目录以便保存日志。 这样一来,无论标志创建还是分支创建都只是仓库内部的文件复制了。 对分支而言:分支不过是在仓库内部的一个单独的目录而已了,不像早期还有些什么交错。 对标志而言:已经不能对代码加标志了。 在某种程度上说,SVN全文件编号补足了这个缺陷,SVN里整个仓库都有版本号,但不是针对单个文件。 4 元数据CVS只允许存储文件。 SVN允许一个文件有任意多的可命名属性,功能十分完全。 5 文件类型CVS最初是为文本文件存储而设计的。 因此其他文件类型(二进制,统一码)文件的支持几乎没有,如需要的话则要有其他信息,并且客户端服务器端都要调整。 SVN会关心所有的文件类型,不需要你来手工操作。 6回滚CVS允许任意的回滚,在任意一个已递交的版本上,尽管这要花些时间(所有的文件都要分别处理)。 SVN不允许递交后回滚。 建议把版本库里好的状态版本加到末尾,覆盖掉损坏的版本。 而损坏的版本无论如何也是会存在数据库里的。 (SVN的滚回操作实际上是merge操作)7事务CVS中的“零或一”事务原则根本没有实现。 如果检入几个文件的话(加到服务器上),很有可能部分文件完成了,而另几个没有。 作为一个潜规则,手工纠正这些并且对余下的文件 (而不是所有文件)一一重复检入。 这样这些文件将在两阶段中被检入。 SVN的确支持“零或一”事务原则,这是SVN的一大优势。 SVN站在更高层次上对安全产品,从系统和控制的角度进行了有机和无隙的整合。 由于SVN没有自己的远程管理工具,只能上服务器上用命令行操作,故操作起来比较复杂。 为此,svn俱乐部开发出svn管家对svn进行远程管理,svn管家推出了windows版本和linux版本,部署很方便,不用安装额外的环境如mysql、PHP或JAVA。 svn管家不仅可以方便的远程修改用户密码,更可以对svn进行远程管理,极大地方便了SVN的用户。 所以虽然说SVN有缺点,但是对于使用者来说还是有继续使用下去的价值的。 它的优势比它的缺点更耀眼,所以才会有那么多人还使用SVN
发表评论