A. 电脑经常出现"0x0002" 是什么意思
软件在内存中调试错误,发生异常
Google File System(简称GFS)是适用于大规模且可扩展的分布式文件系统,可以部署在廉价的商务服务器上,在保证系统可靠性和可用 性的同时,大大降低了系统的成本。GFS的设计目标是高性能、高可靠、高可用性。
GFS把机器故障视为正常现象,可以很好地处理系统故障。GFS系统通常会部署在上百台甚至上千台廉价服务器上,并会有相当多台廉价服务器上部署GFS Client来访问GFS服务,所以应用故障、操作系统bug、连接故障、网络故障、甚至机器供电故障都是经常发生的故障。GFS系统可以支持系统监控、故障检测、故障容忍和自动恢复,提供了非常高的可靠性。其次,GFS系统中的文件一般都是大文件,且文件操作大部分场景下都是append而不是overwrite。一旦文件写入完成后,大部分操作都是读文件且是顺序读。
GFS提供了非标准(比如POSIX)的文件系统接口,支持 create、delete、open、close、read以及write。另外GFS支持snapshot和record append操作。snapshot可以以很低的代价创建文件或者目录树的拷贝,record append可以支持多个client并发地向同一个文件append data,同时还能保证每个client的append操作的原子性。
master记录了文件系统的metadata,包括名字空间、权限控制信息、文件到chunk的mapping以及chunk的分布。master也负责chunk的lease管理、无用chunk的垃圾回收、chunk迁移等。master定期与chunkserver通信,向chunkserver发送指令并搜集chunkserver的状态。GFS client通过GFS的API与GFS系统通信(读写数据)。client向master请求获取metadata,真正的读写数据是直接与chunkserver交互。client和chunkserver都不cache文件数据。因为大部分应用都是基于API来streaming read 大文件且系统的文件数据太多,所以client缓存文件数据没有意义。chunkserver所在机器的Linux的buffer cache以及cache了频繁访问的数据,chunkserver也是没有去cache文件数据的。
单点master大大简化了系统设计,因为master知晓所有的meta信息,所以可以执行更加复杂的chunk位置分配和副本策略。但是,在读写数据时必须降低master的参与,以避免单点的master称为系统瓶颈。client不会通过master来读写文件数据,但是client会向master发送查询chunk位置分布的请求,然后client端缓存chunk的分布信息,然后直接向chunkserver读写数据。大致的读过程如下:
1、client根据文件名、byte offset以及chunk size计算出要读取的文件的chunk index
2、client通过文件名、chunk index向master查询chunk的分布
3、master回复chunk handler以及副本分布
4、client 缓存chunk的meta信息,key由文件名和chunk index组成
5、client从chunk的分布信息中查找距离自己最新的chunkserver,并发送查询请求。查询请求中包括chunk hander以及byte range。后续对相同chunk的查询不需要再次向master查询meta信息,因为client已经缓存了meta信息。
chunk size是GFS系统的关键参数,通常设置为64MB,远大于文件系统的block大小。每个chunk的副本都chunkserver所在机器上以Linux file存储。之所为将chunk size定为64MB,主要有以下考虑:
1、可以减少client访问master查询meta信息的次数,降低master的访问压力。因为chunk size设计比较大,顺序访问一个超大文件时因为chunk数较少且client缓存了chunk meta信息,所以访问master的次数就会降低。甚至,client可以缓存所有文件的chunk的meta信息,就算是随机读文件,master也不会成为系统性能瓶颈。
2、可以减少网络开销,保持client与chunkserver的TCP连接,可以执行更多的chunk操作。
3、可以减少master上需要在内存中记录的meta data数据量,降低master的内存占用。
size大的缺点是:小文件包含很少的chunk,甚至只有一个。这样的话,在多个client高并发查询该小文件时对应的chunk会成为热点。实际上,这种情况在GFS系统中很少发生,因为大部分client的操作都是顺序读大文件。但是,考虑以下场景,我们部署一个服务的二进制文件到GFS系统中,然后数百台的服务器同时查询二进制文件并启动服务,此时该二进制文件副本所在的chunkserver立马就会成为查询瓶颈。当然,可以通过增加副本数和分散服务器的查询时间来解决这种场景下的问题。
master主要存储三种类型的metadata:file和chunk的名字空间,file到chunk的mapping信息以及chunk的副本分布。所有的metadata都在master的内存中存储。前两种meta信息可以持久化存储,将操作日志存储在master的本地磁盘以及将备份日志存储在远端机器上。master不持久化存储chunk的副本分布信息,而是通过与chunkserver交互来获取chunkserver上的chunk信息。
4.1 in-memory data structure
meta信息在内存中,所有master的操作很快。另外,master可以高效地定期在后台scan所有的meta数据,来执行垃圾回收、副本修复、均衡等。metadata都记录在内存中,所以GFS系统会比较关注chunk的数量以及master的可用内存量。但是在实际场景下,这不是问题。每个64MB的chunk的metadata小于64字节,大部分的chunk都是满负荷存储的,除了文件最后一个chunk的空间是没有完全被占用。由于文件的名字空间采用了前缀压缩的方式存储,单个文件的meta信息也是小于64字节。如果需要扩大系统规模的话,可以很简单地通过增大master的内存就可以了。相比于系统的高可靠、高性能和简洁性,增加内存是很最小的代价了。
4.2 chunk 分布
并没有持久化存储chunk的副本分布信息,而是在master启动时向chunkserver查询其chunk信息,然后通过heartbeat来持续更新master的副本分布信息,以与chunkserver数据保持一致。GFS起初设计时尝试将chunk的分布信息持久化存储在master端,随后发现通过master启动时拉取然后通过heartbeat同步chunk信息的方式更简单。因为,当chunkserver加入、退出、名字改变、重启等行为经常发生,这会导致维护master的chunk meta数据的正确性是非常困难的。从另一个角度考虑就是,只有chunkserver汇报的chunk信息才是集群中最真实的chunk分布,因为master不需要自己维护一个chunk分布状态,只需要以chunkserver的状态汇报为准即可。
4.3 操作日志
日志记录了GFS集群数据更改的历史记录。操作日志对GFS来说是至关重要的,因为它不仅是metadata的持久化记录,还记录了并发操作的时序。因为操作日志很重要,所以必须可靠地存储。在metadata的change没有持久化之前,client是不能看到的数据的更改。当client修改数据时,操作记录需要保存在多个远端机器上,而且只有当操作记录持久化存储在本地和远端以后,才会回复client数据更改成功。
可以通过回放操作日志来恢复文件系统。为了减少系统启动时replay的时间,必须缩减回放的日志量。master可以定期存储metadata的checkpoint,master重启时可以从checkpoint加载metadata,然后回放checkpoint之后的少量日志即可。
1、client向master查询chunk的primary所在的chunkserver以及其他副本的分布,如果没有primary的花,master会选择一个作为该chunk的primary
2、master回复client primary和其他副本的分布信息。client会cache返回的metadata
3、client将数据发送所有的副本。client可以以任意顺序执行。每个chunkserser都会在内存的LRUbuffer中记录数据。
4、当所有的副本都返回已经接收数据成功后,client会向primary发送一个写请求。primary会为每一个数据更改的请求附加一个序列号,数据更改是按照序列号的顺序执行的。
5、primary将数据更改同步到其他副本中,副本也是按照序列号执行数据更改操作。
6、primary接收到其他副本回复的数据操作完成
7、primary返回client结果。期间发生的所有错误都会报给client。
GFS集群一般都会有上百台的chunkserver,分布在多个机架上。chunkserver也会接收来自本机架或者其他机架的上百个client的查询请求。不同机架的服务器通信可能会途径一个或者多个交换机转发。chunk的副本分布选择策略主要目的是尽量提高数据的可靠性和可用性,同时最大化地充分利用网络带宽。所以,仅仅将副本跨机器部署是不够的。GFS将副本是跨机架部署的,这样可以保证在一个机架被损坏或者下线时,chunk至少会有副本是可用的。
chunk的副本在下列情况下会被创建:创建chunk、副本修复、rebalance。当master创建chunk时,会选择存储该chunk副本的chunkserver。主要考虑以下几点:
1、新副本所在chunkserver的磁盘利用率低于系统的平均水平
2、限制每个chunkserver最近一段时间创建chunk的数量
3、每个chunk的所有副本不能都在一个机架
chunk的副本数少于一定数量是,master会复制一个副本。这可能发生在chunkserver宕机或者chunkserver汇报自己的副本损坏或者chunkserver所在机器的磁盘损坏等等。每个chunk 复制任务都有优先级,按照优先级由高到低子master中排队等待执行。master还会定期扫描当前副本的分布情况,一旦发现磁盘使用量或者机器负载不均衡,就会发起负载均衡操作。无论是chunk创建、chunk复制还是负载均衡,选择chunk副本的位置的策略都是相同的,并且需要限制副本修复和均衡的速度,否则会影响系统的正常读写服务。
Google的成功表明单master的设计师可行的。这不仅简化了系统,而且能够较好地实现一致性,给予性能考虑,GFS提出了“记录至少原子性追加一次”的一致性模型。通过租约的方式将每个chunk的修改授权到chunkserver从而减少了master的负载,通过流水线的方式复制多个副本以减少延时。master维护的元数据很多,需要设计高效的数据结构,且要保证占用内存小和支持快照操作。支持COW的B树可以满足需求,但是实现确实相当复杂。
C. /proc文件系统的作用
proc 文件系统
在Linux中有额外的机制可以为内核和内核模块将信息发送给进程-- /proc
文件系统。最初设计的目的是允许更方便的对进程信息进行访问(因此得名),现在它被每一个有有趣的东西报告的内核使用,例如/proc/moles
有模块的列表/proc/meminfo 有内存使用的统计表。
使用proc 文件系统的方法和使用设备驱动程序非常相似--创建一个/proc
文件需要的所有信息的结构,包括任何处理函数的指针(在我们的例子中只有一个,当某人试图从/proc
文件读时调用的那一个)。然后,init_mole 在内核中登记该结构而cleanup_mole 注销它。
我们使用proc_register_dynamic(这是在2.0 版中的情况,在2.2 版中如果我们将节点设置为0系统将自动为我们做到)
的原因是我们不想预先决定我们的文件的节点数字,而是为防止冲突而由内核决定它。通常的文件系统存在于磁盘上而不是内存中(/proc
在内存中),在这中情况下,节点数是是指向文件的索引节点所在的磁盘位置的指针。节点包含文件的信息(例如文件的存取权限)和指向磁盘位置或文件数据可以
被找到的几个位置的指针。
因为当文件被打开或关闭的时候不能得到调用,所以在这个模块中没有地方放置MOD_INC_USE_COUNT
和MOD_DEC_USE_COUNT,并且,如果文件被打开随后模块被移除,我们没有办法避免后果。在下一章我们会看到一个艰难的但更灵活的可以处理
/proc文件的实现方式,它也可以让我们防止那个问题。
Linux 内核提供了一种通过/proc 文件系统,在运行时访问内核内部数据结构、改变内核设置的机制。尽管在各种硬件平台上的Linux
系统的/proc 文件系统的基本概念都是相同的,但本文只讨论基于intel x86 架构的Linux /proc 文件系统。
_________________ _________________ _________________
/proc --- 一个虚拟文件系统
/proc 文件系统是一种内核和内核模块用来向进程(process)
发送信息的机制(所以叫做/proc)。这个伪文件系统让你可以和内核内部数据结构进行交互,获取 有关进程的有用信息,在运行中(on the
fly) 改变设置(通过改变内核参数)。 与其他文件系统不同,/proc 存在于内存之中而不是硬盘上。如果你察看文件/proc/mounts
(和mount 命令一样列出所有已经加载的文件系统),你会看到其中 一行是这样的:
grep proc /proc/mounts
/proc /proc proc rw 0 0
/proc 由内核控制,没有承载/proc 的设备。因为/proc
主要存放由内核控制的状态信息,所以大部分这些信息的逻辑位置位于内核控制的内存。对/proc 进行一次'ls -l' 可以看到大部分文件都是0
字节大的;不过察看这些文件的时候,确实可以看到一些信息。这怎么可能?这是因为/proc
文件系统和其他常规的文件系统一样把自己注册到虚拟文件系统层(VFS) 了。然而,直到当VFS 调用它,请求文件、目录的i-node
的时候,/proc 文件系统才根据内核中的信息建立相应的文件和目录。
加载proc 文件系统
如果系统中还没有加载proc 文件系统,可以通过如下命令加载proc 文件系统:
mount -t proc proc /proc
上述命令将成功加载你的proc 文件系统。
proc 文件系统可以被用于收集有用的关于系统和运行中的内核的信息。下面是一些重要的文件:
* /proc/cpuinfo - CPU 的信息(型号, 家族, 缓存大小等)
* /proc/meminfo - 物理内存、交换空间等的信息
* /proc/mounts - 已加载的文件系统的列表
* /proc/devices - 可用设备的列表
* /proc/filesystems - 被支持的文件系统
* /proc/moles - 已加载的模块
* /proc/version - 内核版本
* /proc/cmdline - 系统启动时输入的内核命令行参数
proc 中的文件远不止上面列出的这么多。想要进一步了解的读者可以对/proc
的每一个文件都'more'一下或读参考文献[1]获取更多的有关/proc
目录中的文件的信息。我建议使用'more'而不是'cat',除非你知道这个文件很小,因为有些文件(比如kcore) 可能会非常长。
通过/proc 与内核交互
上面讨论的大部分/proc 的文件是只读的。而实际上/proc 文件系统通过/proc 中可读写的文件提供了对内核的交互机制。写这些文件可以改变内核的状态,因而要慎重改动这些文件。/proc/sys 目录存放所有可读写的文件的目录,可以被用于改变内核行为。
/proc/sys/kernel - 这个目录包含反通用内核行为的信息。/proc/sys/kernel/{domainname, hostname} 存放着机器/网络的域名和主机名。这些文件可以用于修改这些名字。
$ hostname
machinename.domainname.com
$ cat /proc/sys/kernel/domainname
domainname.com
$ cat /proc/sys/kernel/hostname
machinename
$ echo "new-machinename" > /proc/sys/kernel/hostname
$ hostname
new-machinename.domainname.com
这样,通过修改/proc 文件系统中的文件,我们可以修改主机名。很多其他可配置的文件存在于/proc/sys/kernel/。这里不可能列出所有这些文件,读者可以自己去这个目录查看以得到更多细节信息。
另一个可配置的目录是/proc/sys/net。这个目录中的文件可以用于修改机器/网络的网络属性。比如,简单修改一个文件,你可以在网络上瘾藏匿的计算机。
$ echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all
这将在网络上瘾藏你的机器,因为它不响应icmp_echo。主机将不会响应其他主机发出的ping 查询。
$ ping machinename.domainname.com
no answer from machinename.domainname.com
要改回缺省设置,只要
$ echo 0 > /proc/sys/net/ipv4/icmp_echo_ignore_all
/proc/sys 下还有许多其它可以用于改变内核属性。读者可以通过参考文献[1], [2] 获取更多信息。
结论
/proc 文件系统提供了一个基于文件的Linux 内部接口。它可以用于确定系统的各种不同设备和进程的状态。对他们进行配置。因而,理解和应用有关这个文件系统的知识是理解你的Linux 系统的关键。