Zookeeper 技术调研及设计实现_第1页
Zookeeper 技术调研及设计实现_第2页
Zookeeper 技术调研及设计实现_第3页
Zookeeper 技术调研及设计实现_第4页
Zookeeper 技术调研及设计实现_第5页
已阅读5页,还剩21页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Zookeeper技术调研TOC\o"1-3"Zookeeper技术调研 1调研问题解答 2Zookeeper 3Zookeeper简介 3ZooKeeper数据模型和层次命名空间 4Watches监控结点状态的变化 6Watches三个关键点 6关于watch要记住的是: 7Watch事件类型: 7Watcher的事件通知机制是如何实现的 8ZooKeeper访问控制 9ACLPermissions: 9Built-inACLSchemes 9ZookeeperSessions 10Zookeeper角色 13Zookeeper选举 13ZookeeperObserver 15Zookeeper安装 17SystemRequirements 17集群式Zookeeper安装步骤 17Zookeeper基本命令 21Zookeeper典型应用 23配置管理 23集群管理(GroupMembership) 23Zookeeper上实现共享锁 24调研问题解答Zookeeper典型应用的示例代码在Zookeeper项目中。ZK环境的部署;查看章节Zookeeper安装ZK主节点的选举测试;查看章节Zookeeper选举ZK上文件的创建;使用create/znodedata创建或者参考zookeeper示例代码ZK的目录下文件变更的通知;通过设置watch实现,具体请参考zookeeper示例代码客户端连接至ZK的连接的断开通知;客户端的defaultwatcher通知客户端断开连接,与服务器连接的每一个状态变化都会被监控。当与一台server断开连接,客户端会主动再次与另一个可用的server连接,如果session没有timeout,则处于connected状态,否则会收到sessionexpiration通知,我们需求根据业务处理要求去处理sessionexpiration的情况。详情请查看章节ZookeeperSessionZookeeperZookeeper分布式服务框架是ApacheHadoop的一个子项目,它主要是用来解决分布式应用中经常遇到的一些数据管理问题,如:统一命名服务、状态同步服务、集群管理、分布式应用配置项的管理等。本文将从使用者角度详细介绍Zookeeper的组件结构,安装和配置文件中各个配置项的意义,以及分析Zookeeper的典型的应用场景(配置文件的管理、集群管理、同步锁、Leader选举、队列管理等),并用Java实现它们并给出示例代码(代码部分请查看Zookeeper项目)。Zookeeper简介Zookeeper

是一种高性能、可扩展的分布式服务框架。

Zookeeper

的读写速度非常快,并且读的速度要比写的速度更快。另外,在进行读操作的时候,

Zookeeper

依然能够为旧的数据提供服务。这些都是由于

Zookeeper

所提供的一致性保证,它具有如下特点:顺序一致性:客户端的更新顺序与他们的发送顺序相一致原子性:更新操作要么成功要么失败单一镜像:无论客户端连接到哪一个服务器,客户端将看到相同的

Zookeeper

可靠性:一旦一个更新操作被应用,那么在客户端再次更新它之前,它的值将不会改变。这个保证将会产生下面两种结果:如果客户端成功地获得了正确的返回代码,那么说明更新已经成功。如果不能够获得返回代码(由于通信错误、超时等等),那么客户端将不知道更新操作是否生效。当从故障恢复的时候,任何客户端能够看到的执行成功的更新操作将不会被回滚。在特定的一段时间内,客户端看到的系统需要被保证是实时的(在十几秒的时间里)。在此时间段内,任何系统的改变将被客户端看到,或者被客户端侦测到。给予这些一致性保证,

Zookeeper

更高级功能的设计与实现将会变得非常容易,例如:

leader

选举、队列以及可撤销锁等机制的实现。ZooKeeper数据模型和层次命名空间Zookeeper会维护一个具有层次关系的数据结构,它非常类似于一个标准的文件系统,如图1所示:图SEQ图\*ARABIC1层次命名空间Zookeeper数据模型有如下特点:每个子目录项如NameService都被称作为Znode,这个Znode是被它所在的路径唯一标识,如Server1这个Znode的标识/NameService/Server1;Znode有四种类型:Ephemeral,Persistent,Ephemera_Sequence,Persistent_SequenceEphemeralNodes:临时结点,当客户端连接的session生命周期结束时,该结点会被自动删除。Zookeeper的客户端和服务器通信采用长连接方式,每个客户端和服务器通过心跳来保持连接,这个连接状态称为session,如果Znode是临时节点,这个session失效,Znode也就删除了;PersistentNodes:客户端断开连接,结点不会被删除;SequenceNodes–UniqueNaming:自动为结点生成唯一标识;Znode可以有子节点目录,并且每个Znode可以存储数据,注意EPHEMERAL类型的目录节点不能有子节点目录;Znode是有版本的,每个Znode中存储的数据可以有多个版本,也就是一个访问路径中可以存储多份数据Znode的目录名可以自动编号,如App1已经存在,再创建的话,将会自动命名为App2(必须定义为sequence类型的node,否则会抛异常该结点已存在)每个结点的大小不能过大,默认不超过2MB。Zookeeper是一套高吞吐量的系统,为了提高系统的读取速度,Zookeeper不允许从文件中读取需要的数据,而是直接从内存中查找。还句话说,Zookeeper集群中每一台服务器都包含全量的数据,并且这些数据都会加载到内存中。同时Znode的数据支持Append操作,全部都是Replace。所以从上面分析可以看出,如果Znode的过大,那么读写某一个Znode将造成不确定的延时;同时Znode过大,将过快地耗尽Zookeeper服务器的内存,这也是为什么Zookeeper不适合存储大量的数据的原因。Znode可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个是Zookeeper的核心特性,通过设置watches实现,所有对结点的读操作,如getData(),getChildren()和exist()都可以设置一个监听器watch。Watches监控结点状态的变化Watches三个关键点One-timetrigger:当被监控的结点数据发现变化时,一个watchevent会被发送到设置了监听的客户端。如一个客户端调用getData(“/znode1”,true),那么当/znode1这个结点发现数据发生变化或者被删除时,客户端将会收到一个/znode1的watchevent。如果/znode1再次改变,客户端是收不到事件的,因为它是一次性触发,如果需要再次监听,则再次设置监听器,所以是one-timetrigger;发送到client存在数据延迟:watch事件异步发送至观察者。如client执行一次写操作,节点数据内容发生变化,操作返回后,而watch事件可能还在发往client的路上。这种情况下,zookeeper提供有序保证:client不会得知数据变化,直到它获取watch事件。网络延迟或其他因素可能导致不同client在不同时刻获取watch事件和操作返回值。关键点是不同的客户端发送的数据是顺序一致性的。设置watch的数据内容:zookeeper维护两个watch列表:节点的数据watch和子节点watch。getData()和exists()设置了内容watch,getChildren()设置了子节点watch,操作返回的数据类型不同,前者是节点的内容,后者是节点的子节点列表。setData()触发内容watch,create()触发当前节点的"内容watch"和其父节点的"子节点watch",delete()同时触发"内容watch"和"子节点watch"(其子节点被全部删除),以及其父节点的"子节点watch"。说白了,对当前节点的操作,要考虑到对其父节点与子节点的影响。watch在客户端所连接的服务端本地维护。watch的设置、维护、分发操作都很轻量级。当客户端连接到新的服务端,watch将被任一会话事件触发。与服务端断开连接时,不能获取watch事件。客户端重连后,之前注册的watch将被重新注册并在需要时触发。通常这一切透明地发生,用户不会察觉到。有一种情况watch可能丢失:之前对一个尚未建立的节点的设置了existswatch,如果断开期间该节点被建立或删除,那么此watch将丢失。对于watches,Zookeeper提供以下保证watch对于其他事件、watch、异步响应是有序的。zookeeperclientlibrary保证有序分发。客户端监视一个节点,总是先获取watch事件,再发现节点的数据变化。watch事件的顺序对应于zookeeper服务所见的数据更新的顺序。关于watch要记住的是:watch是一次性触发的,如果获取一个watch事件并希望得到新变化的通知,需要重新设置watch。watch是一次性触发的并且在获取watch事件和设置新watch事件之间有延迟,所以不能可靠的观察到节点的每一次变化,要认识到这一点。watchobject只触发一次,比如,一个watchobject被注册到同一个节点的getData()和exists(),节点被删除,仅对应exists()的watchobject被调用。若与服务端断开连接,直到重连后才能获取watch事件。Watch事件类型:ZOO_CREATED_EVENT:节点创建事件,需要watch一个不存在的节点,当节点被创建时触发,此watch通过exists()设置ZOO_DELETED_EVENT:节点删除事件,此watch通过exists()或getData()设置ZOO_CHANGED_EVENT:节点数据改变事件,此watch通过exists()或getData()设置ZOO_CHILD_EVENT:子节点列表改变事件,此watch通getChildren()设置ZOO_SESSION_EVENT:会话失效事件,客户端与服务端断开或重连时触发ZOO_NOTWATCHING_EVENT:watch移除事件,服务端出于某些原因不再为客户端watch节点时触发图SEQ图\*ARABIC2事件与zookeeper操作的对应关系Watcher的事件通知机制是如何实现的看过Google的分布式锁机制Chubby论文会发现,Zookeeper中多了一个事件订阅机制:Watcher。那么Watcher内部究竟是如何实现的呢?其实,在Zookeeper客户端中,有一个成员变量(ZKWatchManager)专门负责管理所有的Watcher,当用户使用如下代码时:List<String>

list

=

zk.getChildren(path,

watcher);

ZooKeeper会将这个Watcher存储在ZKWatchManager中,同时通知ZooKeeper服务器记录该Client对应的Session中的Path下注册的事件类型。当ZooKeeper服务器发生了指定的事件后,ZooKeeper服务器将通知ZooKeeper客户端,ZooKeeper客户端再从ZKWatchManager中找到对应的回调函数,并予以执行。整个过程中,客户端存储事件的信息和Watcher的执行逻辑,服务端只存储事件的信息。ZooKeeper访问控制zookeeper使用ACL(AccessControlList)控制对节点的访问。ACL与Unix文件访问权限类似,采用权限位的形式控制节点的可操作类型,zookeeper没有拥有者和用户组的概念,使用ACL指定每个用户的访问权限。一个ACL只用于一个节点,注意不能用于该节点的子节点,即每个节点的访问权限由其自身的ACL决定。每一个客户端连接在zookeeper内部有唯一的id,zookeeper将连接和id关联起来,客户端试图访问节点时,用id与节点ACL进行比对,以确定客户端的访问权限。ACL由键值对构成,格式是(scheme:expression,perms)。expression内容格式特定于scheme。ACLPermissions:Create:创建子结点(ZOO_PERM_CREATE)READ:获取该结点的数据以及获取其子结点(ZOO_PERM_READ)WRITE:设置该结结点的数据(ZOO_PERM_WRITE)DELETE:删除子节点(ZOO_PERM_DELETE)ADMIN:拥有设置权限(ZOO_PERM_ADMIN)以上所有的权限(ZOO_PERM_ALL)Built-inACLSchemesworld有一个单一的id,代表任何人auth:不使用id,代表任何通过认证的用户digest:使用username:password生成md5hash做为一个acl的id认证,username:base64encodedSHA1passworddigestip:使用客户端ip做为aclIDZookeeperSessions创建Zookeeper实例的过程,也就是Session创建的过程,Session的创建是异步的,根据传递的connectString(如:3000,:3001,127。0.0.1:3002)解析出来的server,选择其中一个连接(列表将会被“洗牌”之后),如果被选择的server不能建立连接,将会继续选择下一个,直到找到可用server。当获得连接时,当前的状态会切换为CONNECTED状态。ZookeeperSession,它是一个64-bit的数值SessionId,做为client的标志。当客户端连接到另一个Zookeeper服务器,该SessionId作为连接的一部分被发送到服务端(如果是采用安全连接,那么password同时被发送)。 客户端与服务器创建连接时另一个重要的参数是sessiontimeout(ms)。针对客户端发送的sessiontimeout,服务器端会根据自身的minSessionTimeout和maxSessionTimeout对其进行裁剪,使其范围在minSessionTimeout和maxSessionTimeout之间,一般是2*tickTime~20*tickTime(基本事件单元,以毫秒为单位)。 当一个客户端与ZookeeperServer断开连接时,客户端会自动从serverlist中寻找可用的server并建立连接,如果此client的session未过期,那么当前的session状态为connected,否则则为expired(即在session过期后重新建立连接)。当与Zookeeper与服务器断开连接时,Zookeeper不建议我们去重新建立一个sessionobject,因为ZookeeperClient会自动帮我们重新建立连接。唯一需求我们手动建立新的session链接的情况是你收到sessionexpiration。Session的过期状态的维护由Zookeeper服务集群管理而不是客户端。当ZookeeperServer在SessionTimeout时间段内没有收到客户端的信息,则认为该Session过期(不是根据heartbeat)。当Zookeeper集群检查到某个Session过期,它将会把该session(客户端)所创建的EPHEMERAL类型的节点删除,同时通知所以监控那些节点的客户端,此时,该session过期的客户端依然处于disconnected状态,除非客户端能与Zookeeper集群重新建立连接它才会收到sessionexpiration,即监控expiredsession的watch收到sessionexpired通知。创建ZookeeperSession的另一个参数是默认watcher。任何客户端状态的变更(如client与Zookeeper断开连接或者sessionexpires)都会触发这些watchers。Session通过发送请求保持其存活,当客户端空闲一段时间后,client会发送ping请求去保持session存活。Ping请求能让Zookeeper知道client的存活,同时也允许客户端检测Zookeeper服务器的状态。图3为Session的状态转移图,图4为创建Session的过程。更多ZookeeperSession参考资料可以请移步ZookeeperSession详解或者zookeeperprogrammers.pdf官方文档,在附件中可自行查阅。图SEQ图\*ARABIC3客户端session状态转移图图SEQ图\*ARABIC4Session创建流程Zookeeper角色在zookeeper的集群中,各个服务节点共有下面3种角色和4种状态:角色:leader,follower,observer状态:leading,following,observing,looking领导者(Leader):领导者不接受client的请求,负责进行投票的发起和决议,最终更新状态。跟随者(Follower):Follower用于接收客户请求并返回客户结果,参与Leader发起的投票。观察者(observer):Observer可以接收客户端连接,将写请求转发给leader节点。但是Observer不参加投票过程,只是同步leader的状态。Observer为系统扩展提供了一种方法。学习者(Learner):和leader进行状态同步的server统称Learner,上述Follower和Observer都是Learner。Zookeeper选举Zookeeper的核心是原子广播,这个机制保证了各个server之间的同步。实现这个机制的协议叫做Zab协议。Zab协议有两种模式,它们分别是恢复模式和广播模式。当服务启动或者在领导者崩溃后,Zab就进入了恢复模式,当领导者被选举出来,且大多数server的完成了和leader的状态同步以后,恢复模式就结束了。状态同步保证了leader和server具有相同的系统状态。一旦leader已经和多数的follower进行了状态同步后,他就可以开始广播消息了,即进入广播状态。这时候当一个server加入Zookeeper服务中,它会在恢复模式下启动,发现leader,并和leader进行状态同步。待到同步结束,它也参与消息广播。Zookeeper服务一直维持在Broadcast状态,直到leader崩溃了或者leader失去了大部分的followers支持。Broadcast模式极其类似于分布式事务中的2pc(two-phrasecommit两阶段提交):即leader提起一个决议,由followers进行投票,leader对投票结果进行计算决定是否通过该决议,如果通过执行该决议(事务),否则什么也不做。广播模式需要保证proposal被按顺序处理,因此Zookeeper采用了递增的事务id号(zxid)来保证。所有的提议(proposal)都在被提出的时候加上了zxid。实现中zxid是一个64为的数字,它高32位是epoch用来标识leader关系是否改变,每次一个leader被选出来,它都会有一个新的epoch。低32位是个递增计数。当leader崩溃或者leader失去大多数的follower,这时候Zookeeper进入恢复模式,恢复模式需要重新选举出一个新的leader,让所有的server都恢复到一个正确的状态。首先看一下选举的过程,Zookeeper的实现中用了基于Paxos算法(主要是fastpaxos)的实现。具体如下:每个Server启动以后都询问其它的Server它要投票给谁。对于其他server的询问,server每次根据自己的状态都回复自己推荐的leader的id和上一次处理事务的zxid(系统启动时每个server都会推荐自己)收到所有Server回复以后,就计算出zxid最大的哪个Server,并将这个Server相关信息设置成下一次要投票的Server。计算这过程中获得票数最多的的sever为获胜者,如果获胜者的票数超过半数,则改server被选为leader。否则,继续这个过程,直到leader被选举出来。此外恢复模式下,如果是重新刚从崩溃状态恢复的或者刚启动的的server还会从磁盘快照中恢复数据和会话信息。(zk会记录事务日志并定期进行快照,方便在恢复时进行状态恢复)选完leader以后,zookeeper就进入状态同步过程。leader就会开始等待server连接Follower连接leader,将最大的zxid发送给leaderLeader根据follower的zxid确定同步点完成同步后通知follower已经成为uptodate状态Follower收到uptodate消息后,又可以重新接受client的请求进行服务了。ZookeeperObserverObserver是Zookeeper-3.3版本新添加的一个角色,他们的引入是为了解决zookeeper集群扩大后,由于网络可靠性下降可能导致的拜占庭将军问题.observer的行为在大多数情况下与follower完全一致,但是他们不参加选举和投票,而仅仅接受(observing)选举和投票的结果。更多关于Observer的资料请关注zookeeperobserver.pdf或者在线资料:Observers:让ZooKeeper更具可伸缩性。Zookeeper集群中的每一台服务器都可以提供数据的读取服务,所以整个集群中服务器的数量越多,读取的性能就越好。但是follower增加又会降低整个集群的写入性能。Observers对于跨广域网连接的客户端来说是很好的候选方案。这有三个原因。为了获得很好的读性能,有必要让客户端离服务器尽量近,这样往返时延不会太高。然而,将Zookeeper集群分散到两个集群是非常不可取的设计,因为良好配置的Zookeeper应该让投票服务器减少网络延时,而Observers可以被部署在需要访问Zookeeper的任意数据中心中。这样,投票协议不会受到数据中心间链路延时的影响,性能得到提升。投票过程中Observers和领导节点间的消息远少于投票服务器和领导节点间的消息。这有助于在远程数据中心高写负载的情况下降低带宽需求。最后,由于Observers即使失效也不会影响到投票集群,这样如果数据中心间链路发生故障,不会影响到服务本身的可用性。这种故障的发生概率要远高于一个数据中心中机架间的连接的故障概率,所以不依赖于这种链路是个优点。图4显示了一个写请求处理过程:客户进程将一个值提交给它连接的服务器。服务器将消息转送给领导节点,它发起一个一致性协议,一旦最初的服务器从领导节点得到结果,它就可以返回给用户了。图SEQ图\*ARABIC5客户端请求写操作Zookeeper安装SystemRequirementsOS:GNU/Linux,SunSolaris:支持服务器与客户端的生产环境与开发环境FreeBSD:仅仅支持客户端的生产环境与开发环境Win32,MacOSX:支持服务器与客户端的开发环境JDK>=1.6RAM:2GB,80GBIDEharddrives双核集群环境,必须是奇数台服务器,且>=3台,而且保证每个Znode的大小不超过2MB,最大化JVMheapsize,因为Zookeeper不能发生数据交换行为(不允许交换分区的存在),如4GB的内存,把heapsize设为3GB集群式Zookeeper安装步骤下载并安装JDK设置JDK的heapsize尽量设到最大,如4GB内存的设为3GB下载zookeeper的稳定包/releases.html将zookeeper.tar.gz解压到任意目录下,如c:/zookeeper,找到conf目录,复制zoo.cfg.sample并重命名为zoo.cfg,为每台server创建一个myid的文件,并放在dataDir指向的目录,如果是在伪集群,各server的端口号不能相同zoo.cfg基本配置如下:tickTime=2000#minconfigruationinitLimit=10syncLimit=5dataDir=c:/zookeeperdata#minconfigruationclientPort=2181#minconfigruationmaxClientCnxns=60maxSessionTimeout=4#defaultto2tickTimedataLogDir=c:/zookeeperlogsserver.1=34:2888:3888server.2=35:2888:3888server.2=19:2888:3888tickTime

:基本事件单元,以毫秒为单位。它用来指示心跳,最小的

session

过期时间为两倍的

tickTimedataDir

:存储内存中数据库快照的位置,如果不设置参数,更新事务日志将被存储到默认位置dataLogDir:日志存放的位置,这里最好不要跟dataDir同一目录,以免发生写竞争clientPort

:监听客户端连接的端口server.id=host:port:port:指示了不同的

Zookeeper

服务器的自身标识,作为集群的一部分的机器应该知道

ensemble

中的其它机器。用户可以从“

server.id=host:port:port.

”中读取相关的信息。

在服务器的

data(

dataDir

参数所指定的目录)目录下创建一个文件名为

myid

的文件,这个文件中仅含有一行的内容,指定的是自身的

id

值。比如,服务器“

1

”应该在

myid

文件中写入“

1

”。这个

id

值必须是

ensemble

中唯一的,且大小在

1

255

之间。这一行配置中,第一个端口(

port

)是从(

follower

)机器连接到主(

leader

)机器的端口,第二个端口是用来进行

leader

选举的端口。在这个例子中,每台机器使用三个端口,分别是:

clientPort

:2181

port

2888

port

3888

。更多的参数配置,请查看zookeeperAdmin.pdf启动Zookeeper打开命令行cmd,将目录切换到zookeeper的目录如cdc:/zookeeper,运行如下命令启动zookeeperservers,在集群模式下,必须将所有的服务器启动,选举出master客户端才可连接:win32:bin/zkServer.cmdmaxos||linux:bin/zkServer.shstart图SEQ图\*ARABIC6服务器启动截图客户端启动如下图所示:bin/zkCli.sh–server:2181图SEQ图\*ARABIC7客户端运行截图如果服务器无法启动,检查各台机器zoo.cfg配置是否正确,其次,myid文件是否存在于dataDir目录下,注意myid是不带后缀的,xp系统默认的notepad编缉器会在myid后面加.txt,这是xp系统的bug。因为要选举主服务器,所以客户端只有在选举结束后才可以连接上。Zookeeper基本命令使用zkCli.sh连接zookeeper服务后,输入help可获得命令列表图SEQ图\*ARABIC8命令列表[zk::2181(CONNECTED)1]ls/[zookeeper]创建一个新的

znode

create/zkmyData

。这个命令创建了一个新的

znode

”以及与它关联的字符串:[zk::2181(CONNECTED)2]create/zkmyDataCreated/zk再次使用

命令来查看现在

zookeeper

中所包含的内容:[zk::2181(CONNECTED)3]ls/[zk,zookeeper]此时看到,

节点已经被创建。运行get确认第二步中所创建的

znode

是否包含我们所创建的字符串:[zk::2181(CONNECTED)4]get/zkmyDataZxid=0x40000000ctime=TueJan1818:48:39CST2011Zxid=0x40000000cmtime=TueJan1818:48:39CST2011pZxid=0x40000000ccversion=0dataVersion=0aclVersion=0ephemeralOwner=0x0dataLength=6numChildren=0下面我们通过

所关联的字符串进行设置:[zk::2181(CONNECTED)5]set/zkshenlan211314cZxid=0x40000000cctime=TueJan1818:48:39CST2011mZxid=0x40000000dmtime=TueJan1818:52:11CST2011pZxid=0x40000000ccversion=0dataVersion=1aclVersion=0ephemeralOwner=0x0dataLength=13numChildren=0下面我们将刚才创建的

Znode

[zk::2181(CONNECTED)6]delete/zk最后再次使用

ZooKeeper

所包含的内容:[zk::2181(CONNECTED)7]ls/[zookeeper]经过验证,

节点已经被删除。Zookeeper典型应用配置管理配置的管理在分布式应用环境中很常见,例如同一个应用系统需要多台PCServer运行,但是它们运行的应用系统的某些配置项是相同的,如果要修改这些相同的配置项,那么就必须同时修改每台运行这个应用系统的PCServer,这样非常麻烦而且容易出错。像这样的配置信息完全可以交给Zookeeper来管理,将配置信息保存在Zookeeper的某个目录节点中,然后将所有需要修改的应用机器监控配置信息的状态,一旦配置信息发生变化,每台应用机器就会收到Zookeeper的通知,然后从Zookeeper获取新的配置信息应用到系统中。图SEQ图\*ARABIC9配置管理部署集群管理(GroupMembership)Zookeeper能够很容易的实现集群管理的功能,如有多台Server组成一

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论