星期三 三月 21, 2007

DTRACE简介(2)

      通过上一次的介绍,相信大家对DTRACE已经有了一个初步的认识。上一次结束时专门留了一个例子,可能大家第一次看有很多不明白的地方,没有关系,随着我们对DTRACE更多的介绍,很快就会”云开雾散“了。

      D语言作为一种编程语言,自然就有其语法、关键字、数据结构、运算符、函数等,我将一一介绍。

      D语言中标志符名称与C语言类似,由字母、数字和下划线组成,其中第一个字符必须是字母或者下划线。D语言预留了一些关键字供DTRACE本身使用,关键字不能用做D变量的名称。D关键字列表参阅《Solaris动态跟踪指南》,这里只列出一些常用的。
     

       表1 - 常用DTRACE关键字

关键字 描述
inline 编译期间将指定的D变量替换为预定义的值或者表达式,inline可以申明类型
sizeof 计算对象的大小
self
 表示将D变量存放在线程(thread)的私有空间里
this
 表示D变量的有效范围在this所在的子句内
 

   

 

 

      D语言中定义了整数类型和浮点类型,以及用于表示ASCII字符串的string类型。整数类型随机器字长的不同而不同。机器字长可以用命令isainfo -b来查看。

       表2 - D整数类型

 类型名称32位机器字长
64位机器字长
 char1个字节
 1个字节
 short
2个字节
 2个字节
 int
4个字节
 4个字节
 long
4个字节
 8个字节
 longlong
8个字节
 8个字节


 

 

 

 

       一点小知识,C语言中有ILP32和LP64两种数据模型,ILP32指的就是int/long/pointer(指针)是32位,LP64指的是long/pointer是64位。

       对于整数类型,又分为带符号(signed)和无符号(unsigned)两种,因为是否带符号决定了对其最高位(most-significant)的解释。无符号整型通常是在相应的整型前面添加unsigned或者u限定符。

        表3 - D整数类型别名

     

 类型名称说明
 int8_t / uint8_t
1字节带符号整数 / 1字节无符号整数
 int16_t / uint16_t
2字节带符号整数 / 2字节无符号整数
 int32_t / uint32_t
4字节带符号整数 / 4字节无符号整数
 int64_t / uint64_t
8字节带符号整数 / 8字节无符号整数
 intptr_t / uintptr_t
大小等于指针的带符号整数 / 大小等于指针的无符号整数

 

 

 


 

      D语言中也定义了转义序列如'\\n'表示回车。

      D语言中定义了算术运算符、关系运算符、逻辑运算符、按位运算符、赋值运算符、递增和递减运算符、条件表达式(即 ? : 运算符),由于这些运算符及其优先级与C语言基本相同,就不在这里占用篇幅了。D语言也支持”强制类型转换“,即把一种类型转换为另一种兼容类型,比如将指针转换为整数。

      除了上面的数据类型,D语言还提供有数组(array)关联数组(associative array),关联数组中有一种特殊类型叫做聚合(aggregation),在后面会看到。关联数组通过一个称为键(key)的名称来检索数据,用过Perl的朋友相信不会陌生。定义关联数组,只需作以下赋值操作即可:

      name[key]=expression;

      例如: people["sam.wan",30]=100

      D语言中的变量是不需要预定义就可以直接使用的。但是在没有赋值之前,是不能出现在谓词中和赋值运算等号右侧。请看下面的3个例子:

例子1
# dtrace -n 'BEGIN{a=1;exit(0);}END{printf("a=%d\\n",a);}'
dtrace: description 'BEGIN' matched 2 probes
CPU     ID                    FUNCTION:NAME
  0      1                           :BEGIN
  0      2                             :END a=1


例子2
# dtrace -n 'BEGIN/a==0/{exit(0);}END{printf("a=%d\\n",a);}'
dtrace: invalid probe specifier BEGIN/a==0/{exit(0);}END{printf("a=%d\\n",a);}: in predicate: failed to resolve a: Unknown variable name


例子3
# dtrace -n 'BEGIN{a=a+1;exit(0);}END{printf("a=%d\\n",a);}'
dtrace: invalid probe specifier BEGIN{a=a+1;exit(0);}END{printf("a=%d\\n",a);}: in action list: a has not yet been declared or assigned

      缺省情况下,D语言中定义的变量是全局范围的。在多线程环境中,全局变量是不安全的,因为可能多个线程都会进行访问,因此,D语言引入了线程局部变量标志符self。通过在一个变量前面添加self->修饰,可以将该变量存放在线程自己的局部空间中,这样不会受到其它线程的影响,这种方法对于现在越来越多的并发操作环境十分有利。线程局部变量与全局变量在不同的名称空间(name space)中,因此即使名字相同也不会冲突,比如self->aaa和aaa是两个不同的变量。

       特别需要提醒注意的是,在使用完一个变量之后,要将该标量赋值为'0',这样DTRACE就会回收释放其所占用的内存空间。对用一个好的程序员来说,释放空间和分配空间同样重要。

      D语言中还有一种特殊的变量叫“子句局部变量(Clause Local)”,通过在变量名前添加this->修饰符完成。子句局部变量的作用域只在其定义的子句内有效。D语言中的变量缺省情况下会被赋值为0,但是子句局部变量除外。

      除用户定义的变量外,D语言本身提供了一些非常有用的内置变量,所有这些内置变量都是全局变量。

      表4 - DTrace内置变量

 类型和名称说明
int64_t arg0,...,arg9
探测器的前10个输入参数(64位整数)。如果当前探测器参数个数少于10,则未定义的参数值不确定
args[]
与arg0...arg9不同,args[]是有类型的,其类型对应与当前探测器的参数类型。
uintptr_t caller
进入当前探测器之前的当前线程的程序计数器(PC)位置
chipid_t chip
当前物理芯片的CPU芯片标志符
processorid_t cpu
当前CPU的编号
cpuinfo_t \*curcpu
当前CPU的信息(具体结构后面会讲到)
lwpsinfo_t \*curlwpsinfo
与当前线程关联的轻量进程(LightWeight Process,LWP)的信息(具体结构见后)
psinfo_t \*curpsinfo
与当前线程关联的进程的信息
kthread_t \*curthread
当前线程在内核中的数据结构(kthread_t)的地址,kthread_t的定义在<sys/thread.h>中。
string cwd
当前进程的工作路径(Current Working Directory)
uint_t epid
当前探测器的已启用的探测器ID号。
int errno
当前线程最后一次执行的系统调用的返回错误值
string execname
当前进程的名称
gid_t gid
组ID
uint_t id
当前探测器的唯一ID号,dtrace -l的第一列
uint_t ipl
触发探测器时当前CPU的中断优先级(Interrupt Priority Level,IPL)。
lgrp_id_t lgrp
当前CPU所属的延迟组(Latency Group)的ID
pid_t pid
当前进程号
pid_t ppid
当前进程的父进程
string probefunc
当前探测器的函数名
string probemod
当前探测器的模块名
string probename
当前探测器的名字
string probeprov
当前探测器的提供器名
psetid_t pset
当前CPU所属的处理器集(Processor Set)的ID
string root
当前进程的根目录名
uint_t stackdepth
当前线程的栈帧(Stack Frame)的深度。即其调用的函数的层次数。
id_t tid
当前线程的线程ID
uint64_t timestamp
以纳秒(ns)为单位的时间计数器。此计数器从过去的任意点递增,仅用于相对计算中。
uid_t uid
当前进程的实际用户ID
uint64_t uregs[]
当前线程的用户寄存器值
uint64_t vtimestamp
以纳秒(ns)为单位的时间计数器,实际是当前线程在CPU中已运行的时间减去DTrace谓词和操作所花费的时间。同timestamp一样,仅用于相对计算。
uint64_t walltimestamp
自1970年1月1日00:00世界标准时间以来的纳秒数。


 

     Dtrace还可以使用反引号(backquote `)访问操作系统内核中定义的变量,但不能进行修改。

     内核中定义的变量可以通过查看内核的变量符号表(Name Symbol)来找到。

     #echo "::nm"|mdb -k|more

     比如我们想通过DTrace来查看每秒钟freemem的值。freemem表示当前系统中可用的内存页数

     #dtrace -qn 'tick-1sec{printf("%d pages of freemem\\n",`freemem)}'

     由于Solaris可用动态加载模块,各个模块可能有相同的变量名,为了避免冲突,可用使用模块名来区分,比如访问a模块的x变量:a`x

      DTrace还提供操作和子例程。

     如果DTrace子句为空,则会采用缺省操作。缺省操作即显示已启用的探测器的标志符。
 

     数据记录操作

      数据记录操作总会往指定的缓冲区中放入数据。
      void trace(expression) 将expression的结果放到指定的缓冲区(在后面会提到)。

      void tracemem(address,size_t nbytes),从address地址复制nbytes的内容到指定缓冲区。

      void printf(string format,...) 格式化输出。具体格式可用参见printf(3C)手册页。

      void printa(aggregation)/void printa(string format,aggregation) 显示及格式化聚合(在后面会提到)

      void stack(void)/void stack(int nframes) 将指定长度的栈帧记录拷贝到指定的缓冲区。

      void ustack(int nframes,int size)/void ustack(int nframes)/void ustack(void),同上,只是操作的是用户栈    

      破坏性操作

       void stop(void) 停止触发当前探测器的进程

       void raise(int signal) 将指定的信号signal发送至触发当前探测器的进程

       void copyout(void \*buf,uintptr_t addr,size_t nbytes) 从buf地址拷贝nbytes字节到当前进程的addr地址处。

       void copyoutstr(string str,uintptr_t addr,size_t maxlen) 将字符串string拷贝到当前进程的addr地址处

       void system(string program,..) 执行程序

       内核破坏性操作(下面的操作将会影响整个系统的运行)

       void breakpoint(void) 发生一个内核断点

       void panic(void) 触发panic()操作(这个相信大家都再熟悉不过了)

       void chill(int nanoseconds) DTrace执行nanoseconds时间的spin操作(循环),如果nanoseconds> 500milliseconds,则会失败。

        特殊操作

        推测性操作(Speculative Actions),有speculate(),commit(),discard(),在后面会提到。

        void exit(int status) 立即停止DTrace跟踪。

        子例程

        与操作不同,子例程只会影响DTrace的内部状态。

        void \*alloca(size_t size)  分配size字节的临时空间,返回一个8字节对齐的指针。

        string basename(char \*str)  从str中去除前缀和目录名

        void bcopy(void \*src,void \*dest,sizt_t size) 从src拷贝size字节到dest。

        string cleanpath(char \*str) 去除str中的/./和/../等

        void \*copyin(uintptr_t addr,size_t size) 从用户地址空间addr处拷贝size字节到Dtrace临时缓冲区中,并返回缓冲区地址。

        string \*copyinstr(uintptr_t addr) 从用户地址空间addr除拷贝已null结尾的ASCII字符串到Dtrace临时缓冲区,并返回缓冲区地址。

         void copyinto(uintptr_t addr,size_t size,void \*dest) 从用户地址空间addr处拷贝size字节到Dtrace临时缓冲区的dest处。

          string dirname(char \*str) 返回str的目录名

          size_t msgdsize(mblk_t \*mp) 返回mp指向的数据消息的字节数

          size_t msgsize(mblk_t \*mp) 返回mp消息字节数

          int mutex_owned(kmutex_t \*mutex) 如果当前线程拥有互斥锁mutex,则返回非零;否则返回0

          kthread_t \*mutex_owner(kmutex_t \*mutex) 返回mutex互斥锁的属主的线程数据结构kthread_t的指针。如果没有属主或者该互斥锁是自旋锁(Spin Mutex),则返回null。

         int mutex_type_adaptive(kmutex_t \*mutex) 如果mutex是自适应互斥锁(MUTEX_ADAPTIVE类型),则返回非0,否则返回0。

         int progenyof(pid_t pid) 如果触发当前探测器的进程是指定进程的子孙,则返回非0

         int rand(void) 返回一个伪随机整数

         int rw_iswriter(krwlock_t \*rwlock) 如果指定的读写锁rwlock被一个写入者占有或者要求获得,则返回非0,否则返回0

         int rw_write_held(krwlock_t \*rwlock) 如果指定的读写锁当前被一个写入者占有,则返回非0,否则返回0

         int speculation(void) 为speculate()操作预留一个推测性跟踪缓冲区,并返回这个缓冲区的标志符。

         string strjoin(char \*str1,char \*str2) 串联str1和str2到临时空间,并返回其地址。

         size_t strlen(string str) 返回指定字串的长度(不包括结尾的空字节null)

      看了这么多操作和子例程,是不是有点受打击了?没有关系,慢慢来,先熟悉一下,在今后具体使用时,就会印象深刻。

      关于前面的copyin/copyinstr/copyinto子例程再多作一点说明:

      在Solaris(UNIX)系统中,用户程序是运行在用户地址空间里面,当用户程序执行系统调用比如open(2)时,才会进入到内核空间执行(我们通常称之为"陷入trap";),为了访问用户地址空间的字符串,就必须将其拷贝到内核空间里面来,否则内核找不到相应的地址,就会报错。看下面的一个例子。

      我们想知道是什么程序在调用open(2),以及打开什么文件。这里很自然我们会用到syscall提供器的open:entry探测器。此探测器的参数可用从open(2)的手册页查到(所有的syscall提供器提供的探测器都可用在相对应的系统调用手册中查到)

      int open(const char \*path, int oflag, /\* mode_t mode \*/);

      我们只关心第一个参数arg0,这是一个字符串指针(即将要打开的文件名)。对于字符串指针,可以使用"%s"进行格式化输出。

#!/usr/sbin/dtrace -qs
syscall::open:entry,
syscall::open64:entry
{
     printf("%s[%d] opened %s\\n",execname,pid,arg0);
}

       运行一下看看


 # ./who_open_what.d
dtrace: failed to compile script ./who_open_what.d: line 5: printf( ) argument #4 is incompatible with conversion #3 prototype:
        conversion: %s
         prototype: char [] or string (or use stringof)
          argument: int64_t


       错误,为什么,因为传递给内核的是一个用户地址空间的指针,内核无法访问该地址,内核只看到一个指针,因此Dtrace认为格式化用的是"%s",但是传递的却是一个int64_t类型,不匹配。

       正确的程序应该是:

 

#!/usr/sbin/dtrace -qs
syscall::open:entry,
syscall::open64:entry
{
     printf("%s[%d] opened %s\\n",execname,pid,copyinstr(arg0));
}

        再来看看

 


# ./who_open_what.d
nfsmapid[272] opened /etc/default/nfs
nfsmapid[272] opened /etc/resolv.conf
init[1] opened /etc/inittab
init[1] opened /etc/svc/volatile/init-next.state
init[1] opened /etc/svc/volatile/init-next.state
init[1] opened /etc/inittab
...

 


        是不是很有趣。

        更多有趣的还在后头,别走开哦  :)
 

      

 


 

 

        
 

 

星期二 三月 20, 2007

DTRACE简介(1)

      记得几年前看过一部美国大片叫《全民公敌(Enemy of the State)》,在里面,谋杀国会议员的主谋强沃特和他的属下,为了取回记录着其犯罪事实的磁碟片,用高科技的卫星监视,使主人公史密斯的行踪处于严密的监控中。当时就对美国高科技跟踪系统惊叹不已。当然作为一个普通公民,是不希望自己受到监视的。但是对于计算机系统,如果能够对系统的运行情况进行监视并了如指掌,进而发现其中的臭虫(bug),那将是一件令IT管理者和开发者兴奋的事。今天我要介绍的SolarisTM Dtrace就是这样一个好帮手!

      我的第一篇Blog就提到了Dtrace,但是没有作更多的说明。今天我将对Dtrace作比较详细的介绍,一是作为自己学习Dtrace的一点心得,二是希望对还没有使用Dtrace的朋友们提供一点入门知识,更详细的信息请参阅第一篇Blog中提到的资源。为了与中文版的《Solaris动态跟踪指南》保持一致,下面的术语都采用书中的翻译。
      DTRACE(全称Dynamic Tracing)是SolarisTM 10中引入的一种可以对核心(kernel)和应用程序(user application)进行动态跟踪并且对系统运行不构成任何危险的技术。下面是理解Dtrace的几个要点:

     1. Dtrace的实现是紧密地结合到核心里的(intimately integrated),即Dtrace的源代码是分布到了Kernel的各个部分中。除了Dtrace的执行程序dtrace.c和头文件<sys/dtrace.h>,<sys/dtrace_impl.h>外,其它实现dtrace的代码遍布到Solaris Source tree的各个文件。具体请参见 Bryan Cantrill的Blog - "The Observation Deck"

     2. Dtrace架构中一个很重要的组件是"探测器(Probe)",简单讲,探测器就是核心源代码中某一个特点的”“。在普通的Solaris 10内核中,这样的”点“有4万多个,而且还可以随着模块的加载而增加。探测器在没有被”启用(enable)“时,对核心是没有任何影响的,这时的核心与没有dtrace功能的核心如Solaris 8/9是没有任何区别的。当探测器被启用后,Solaris会动态地往核心中为启用的探测器加入相应的指令来实现探测器被"触发(fire)"时的“操作(action)"。

     3. Dtrace架构可以简单的理解为”Dtrace提供器(Provider)和Dtrace使用者(Consumer)”模式。如下图所示:

 dtrace architecture

       ”提供器“提供了”探测器“,而”使用者“通过libdtrace(3LIB)库和相应的设备文件或者其它方式来使用”提供器“提供的”探测器"。如上图所示,除了我们下面将会介绍的/usr/sbin/dtrace命令外,Solaris 10系统中还有很多收集统计信息的工具比如intrstat(1M),plockstat(1M),lockstat(1M)等都是Dtrace使用者。使用plockstat -V -p <pid>,你就可以看到plockstat使用的dtrace命令。
    4. Dtrace本身是安全的,即不会对内核的运行造成影响。Dtrace可以读取内核变量,却不能修改内核变量。但是Dtrace提供了”破坏性(destructive)"的操作比如panic(),如果你使用了这些动作,是会中断系统运行的。

     在学习Dtrace的过程中,要切记上面的几点。

     下面就重点介绍一下Dtrace中日常使用最频繁的一个Dtrace使用者/usr/sbin/dtrace命令。dtrace(1M)可以以命令行形式调用,也可以通过D-script调用。D-script是用Dtrace提供的D语言来编写的脚本程序。D语言类似于C和awk,但是没有程序控制如for,if等机制,也许是为了更好的控制系统的稳定性。

      命令行调用的例子:  dtrace -n 'syscall::open\*:entry{trace(execname)}'

      D-script例子:

#!/usr/sbin/dtrace -s
syscall::open:entry,
syscall::open64:entry
{
    trace(execname);
}                                   

      不管是命令行方式还是脚本方式,都要指定至少一个探测器。每个探测器都是一个“四元组(4-tuple)",但是有的部分可以省略。探测器的具体格式如下:

       Provider:Module:Function:Name

      各部分的含义如下:

      - Provider即提供器,发布此探测器的Dtrace提供器的名称。比如:syscall是所有系统调用的提供器,sysinfo是系统统计信息的提供器,proc是进程信息的提供器。不同系统不同版本的Solaris的提供器的数量不同。使用下面的命令可以查看系统中有多少个提供器.

        #dtrace -l|grep -v "PROVIDER"|awk '{print $2}'|sort -u

       - Module即模块,是此探测器对应于特定的程序位置时,其所在模块的名称。对于应用程序,模块名可以是动态链接库的名字,比如:libc,或者主程序a.out。有的探测器没有模块名。

       - Function即函数,探测器所在函数的名称

       - Name即名字,最后一个组成部分。

      探测器的四元组名字如果某个部分为空,则表示匹配该字段的所有可能性,星号(\*)也是通配符,表示匹配任意字符串。现在我们再来看上面的两个例子。第一个命令行例子表示启用syscall提供器中所有模块里面名字以open开头的函数的entry探测器;而第二个脚本例子表示匹配syscall提供器中所有模块里面名字是open或者open64函数的entry探测器,其中的逗号表示或者的关系。命令行方式调用时,如果不使用-l开关,则指定的探测器将被启用,对于脚本方式,-s后面即D-script程序的正文部分。

      一个D程序的结构如下:

0      #!/usr/sbin/dtrace -s
1      pragma D option quiet
2      probe_description_1 
3      / predicate_1 /
4     {
5           action_1;
6           action_2;
7             ...
8            action_n;
9      }
10      probe_description_2
11      / predicate_2 /
12     {
13           action_1;
14           action_2;
15             ...
16            action_n;
17      }
... 
18      probe_description_n
19      / predicate_n /
20     {
21           action_1;
22           action_2;
23             ...
24            action_n;
25      }

      上面的伪代码(pseudo-code)描述了一个D程序的大致结构,其中除了探测器描述部分,其它的部分如谓词、操作都不是必须的。第0行指明D程序的解释器(interpreter),就是/usr/sbin/dtrace;第1行使用pragma关键字指定特定的D程序编译指令;从第2行起就是对相应的探测器的启用,并定义在指定的探测器被触发时应该执行的操作,操作以分号结尾。其中,在探测器描述和操作之间用 / / 符号隔开的部分称为"谓词(Predicate)"。前面已经提到,在D语言中,没有if语句和循环,只有通过谓词来进行判断,谓词是一系列的逻辑运算,如果计算结果是false(0),则忽略探测器的触发,当然更不会执行该探测器定义的任何操作;只有当谓词计算为true(非0)时,相应的操作才会被执行。D程序的执行是从上至下顺序执行的,花括号{}包围的部分是对应探测器被触发且谓词为真时的执行子句块,对于同一个探测器描述,可以指定多个执行子句块。

      当你编辑完成一个D程序,并且使用dtrace -s或者通过直接添加执行权限来执行时,Dtrace首先会将你的脚本程序编译成一个安全的中间格式(有点类似于Java程序的运行机制),然后才会被加载到内核中执行。Dtrace的执行环境还会检查并处理运行时错误(run-time errors)比如被零除(dividing by zero),访问无效地址等。因此Dtrace是相当安全的。

       当Dtrace程序被加载到内核执行时,相应的探测点被启用,如果有涉及探测点的事件发生,我们就把它称之为“触发”,如果此时谓词计算为true,则相应的操作就会被执行。为便于大家理解“启用”和“触发”两个概念,我们举一个日常生活中的实际例子。

        现在全国各个城市为了更好地规范交通秩序,都安装了很多“电子警察”(就是“探测器”),安装完成就打开(即“启用”),如果有车闯红灯,就会激活安装在地上的感应线(”触发“),那么”电子警察“就会拍照,很快罚单就会送到你家里(这就是”操作“)。

        通过上面这个例子,大家应该有个更加形象的认识了吧。

        作为今天的结束,下面是一个监视谁(用户ID)使用什么命令访问一个文件(文件以参数形式传递)的例子。

  who_access_thisfile.d

 


#!/usr/sbin/dtrace -qs
syscall::creat\*:return,
syscall::open\*:return
/arg0 != -1 && fds[arg0].fi_pathname == $1 /
{
        printf("uid#%d %s %s\\n",uid,execname,$1);
}


      chmod +x who_access_thisfile.d,然后执行./who_access_thisfile.d /etc/passwd,在另一个终端上试试cat /etc/passwd, vi /etc/passwd,看看你都看到了什么信息,你原来能做到吗?

      更多的信息,将在下一次中介绍。

    
  

     
 

星期四 三月 15, 2007

VirtualBox + Belenix

      今天在我的LAPTOP上玩了一下VirtualBox上跑Belenix,感觉还不错。

      VirtualBox是InnoTek公司开发的一款虚拟机软件,它是按照GNU Public License (GPL)进行分发的。VirtualBox比Xen功能强大并且具有更为友好的用户界面,同时它本身又比VMWare少用系统资源。是一款不可多得的开源虚拟机软件。

       Belenix是基于OpenSolaris的Live CD(可直接从光盘运行),非常适合用来测试OpenSolaris。

       我的LAPTOP配置了1G内存,安装的是Slackware Linux(current),内核是2.6.15.2,我分配了512M内存给VirtualBox跑Belenix。我是从VirtualBox网站下载的针对Linux所有发行版的最新1.3.8版的安装文件。

       安装非常简单:

       1. chmod +x VirtualBox_1.3.8_Linux_x86.run

       2. ./VirtualBox_1.3.8_Linux_x86.run install  (卸载使用uninstall参数)

      安装过程中会根据你当前的内核编译模块vboxdrv.ko,模块会放在 /lib/modules/`uname -r`/misc/下面,另外会生成一个启动脚本,在Slackware下是/etc/rc.d/rc.vboxdrv,同时你需要把你的用户加入到vboxusers组中。

      启动时,首先运行启动脚本 /etc/rc.d/rc.vboxdrv start,启动脚本会产生相应的设备文件/dev/vboxdrv,并加载模块vboxdrv.ko到核心里,然后你就可以使用VirtualBox命令,之后的操作就像使用VMWare一样简单了。

       下面是一些屏幕截图的链接

 

        大家感兴趣可以自己试试! :)

     
      

推荐一个很酷的东东 -- Snap Preview Anywhere[tm]

      Snap  Preview Anywhere[tm] 是
Snap公司提供的一个免费的显示网页超链接缩略图的软件。你只要在其主页http://www.snap.com/登记,你就可以向你的网页中添加script来获得缩略图功能。这样当别人访问你的网页时,只要他或她把鼠标放在一个链接上,一会儿就能看到这个链接网页的缩略图,就像你刚才把鼠标放在snap的主页上一样。是不是很酷?

  

星期日 三月 11, 2007

ZFS:你用得完吗?

        ZFS是SUN公司开发的业界第一个128位的文件系统。它具有以下优点:

1. 可证实的数据完整性

      数据完整性是所有用户都关心的头等大事,如果存储的数据都不完整了,那还有存储干什么呢?有人说,不用ZFS,我有RAID-5啊。说这话的朋友可能不知道RAID-5有个致命的问题--写漏洞(write hole)。因为RAID-5在写数据和校验信息时不是原子操作(atomicity),就可能出现新的数据已经写到磁盘上,但是新的校验信息还没有写完的情况,比如整个磁盘阵列异常掉电时,这样当下次读取这块数据时,就会得到一堆”垃圾“。虽然可以靠添加非易失性存储(NVRAM)来解决这种问题,但这无疑增加了企业的成本。而相比之下,ZFS并不需要添加任何新的硬件。这都要感谢ZFS基于“事务性“(transaction)的面向对象的处理方式。

      ZFS是一种”树状“文件系统,其超级块(uberblock)就是整个文件系统的”根节点“,数据块就是”叶节点“,而地址块就是中间的”枝节点“。如下图所示:

      Intial Block tree
                            图1 初始状态

     其中树的每个节点都是一个对象。ZFS对文件块(除文件系统超级块uberblock)的修改操作都采用”写时拷贝(Copy-On-Write)“技术实现,而从”叶节点”到“根节点”的操作是事务性的,即一个分支要么被修改,要么就什么也没有改变。

     下面是对数据块data1和data2进行修改的示意图:

     cow data1 and data2

                          图2 对data1和data2数据块作“写时拷贝(COW)”
       cow indirect block

                          图3 对间接地址块作“写时拷贝(COW)”

      rewite uberblock
                        图4 修改超级块(uberblock)

      尽管这里修改数据块data1和data2有4个图,实际上从图1到图4的操作是“事务性的原子操作“,即最终的结果要么就是图1的状态,要么就是图4的状态,不可能是中间状态。

      由于每个数据块有256位的校验码(checksum),在遍历数据的过程中,ZFS会使用数据块的校验码校验数据的正确性,一旦发现有错,ZFS就能自行进行纠正(self-healing)。这样就绝对的保证了数据的完整性。

2. 卓越的性能

      ZFS采用了一种称为"RAID-Z"的技术,"RAID-Z"与RAID-5类似,也是数据和校验相结合的模式,但是与RAID-5不同的是,ZFS使用可变的条带宽度(Dynamic Stripe Width),每一个数据块就是一个条带,因此,ZFS的每次写操作都是一个完整的条带写操作,这样就不需要像RAID-5一样作”读-修改-写“,再加上ZFS的”写时拷贝“技术,可以将随机写操作转换为顺序写操作并且在多个磁盘上并发的完成,因此,ZFS的性能比传统的RAID技术要好很多。

3. 简单的管理

       ZFS本身就集成了卷管理(Storage Pool)的功能,不需要你在卷管理软件和文件系统之间折腾,甚至不需要你修改/etc/vfstab和/etc/dfs/dfstab,因为ZFS可以自动安装及共享文件系统。你会发现你是否真的还需要花钱去雇人来对你的文件系统进行管理,因为这一切已经被ZFS变成一件愉快的事。

        创建一个镜像池,你只需要:

        # zpool create home mirror c0t0d0 c1t0d0

        创建一个文件系统,

       # zfs mount -c home/user1 /export/home/user1

       更多的例子,你可以在《ZFS: the last word in file systems》中找到

4. 巨大的存储量

      正如文章开篇说所,ZFS是128位的文件系统。这里128位指的是ZFS可以寻址的数据块的地址位数。每个数据块是512个字节,即2\^9bytes=2\^12bits,因此一个ZFS可以存储(2\^128)\*(2\^12)=2\^140bits。到底这个2\^140bits是什么样一个概念,可能很多朋友都不知道,下面引用ZFS的开发者Jeff Bonowick的Blog上一个形象的例子来告诉大家。

 


      大家都知道摩尔定律,但是摩尔定律忽略了一点,那就是任何物质都有其上限。根据Seth Lloyd的研究,1公斤的物质(1升的空间内)其极限是每秒执行10\^51次运算,存储10\^31位(bit)信息,而一个存满了的ZFS可以存储2\^140位信息,因此至少需要(2\^140bits)/(10\^31bits/kg)=136 billion公斤物质。

      为了将这个”设备“运行起来,它必须是以纯能量的方式。按照爱因斯坦E=mc\^2,需要的能量是1.2x10\^28焦耳。海洋的质量是1.4x10\^21公斤。让1公斤水温度升高1摄氏度需要4000焦耳能量,因此让1公斤水从凝固到沸腾(100摄氏度)需要400000焦耳能量,再加上每公斤蒸发需要的2000000焦耳能量。蒸发整个海洋共需要(2000000+400000)焦耳/公斤\*1.4x10\^21公斤=3.4x10\^27焦耳。可见要运行一个存满ZFS的设备需要的能量远超过把海洋蒸发完的能量。

 



       现在你该相信ZFS就是"the last word in filesystem”了吧。

5. ZFS是开源的(Open)

       秉承SUN的开源思想,ZFS项目也是开源的。如果你是软件开发人员并且对文件系统感兴趣的话,你可以加入到ZFS的项目中:http://www.opensolaris.org/os/community/zfs

6. ZFS是免费的

       ”天下没有免费的午餐“,这句话在SUN公司就不成立了。有了功能如此强大的ZFS,作为公司的决策者,你还有必要花钱去单独买昂贵的卷管理软件吗?

 

 

 




 


 

     
 


 

星期六 三月 10, 2007

推荐一篇介绍“虚拟化技术”的文章

      今天在网上闲逛,看到了一篇赵柯翻译的Linux上的虚拟化技术”,特与大家分享。尽管标题上写的是Linux,实际上虚拟化技术的使用相当广泛。

     
 

     
 

星期五 三月 09, 2007

Logical Domains aka LDOMs

      相信大家对虚拟化分区(virtualization and partitioning technology)技术都不陌生了,从Sun Fire[TM] 3800服务器开始,就有了硬件分区及系统域(System Domains)的技术,这时的分区粒度(granularity)是每个系统域至少要有1个CPU/MEM板和一个I/O板。Solaris 10引入了ZONE(也称为Container)的技术,通过此技术,可以在系统上创建多个逻辑上独立的操作系统实例(instance),每个实例可以运行其自己的程序集并且相互之间没有任何干扰。即便是单CPU的系统,也可以创建多个ZONE,只要你的系统资源足够创建并运行这么多实例。

      随着Solaris 10 11/06版的发布,一种新的虚拟化分区技术--逻辑域(Logical Domains以下简称LDOMs)呈现在大家的面前。System Domains、LDOMs和ZONE三者之间有什么关系呢?下面是一个简单的示意图:

 Zone(Container)
LDOMs
System Domains
Operating System
   
Firmware Level
   
Harware Platform




       上面的示意图简化了很多细节,主要是为了突出LDOMs与Zone和System Domains之间的关系。我们可以看到LDOMs是建立在Firmware至上的,即LDOMs不光需要操作系统的支持,也需要Firmware的支持。那么需要什么样的Firmware支持的?

      LDOMs是靠在操作系统和硬件层之间的Firmware(flash PROM)中加入一个叫做hypervisor的软件来实现虚拟化分区的。目前支持这种hypervisor软件的平台只有Sun Fire[TM] T1000Sun Fire[TM] T2000系统(即sun4v平台体系架构服务器)。这就是为什么现在LDOMs只能用于Sun Fire[TM] T1000Sun Fire[TM] T2000系统的原因。

        为了能够正确的与hypervisor通信,操作系统必须有相关的支持。目前只有Solaris 10 11/06才能支持hypervisor(还需要相关补丁),对于Solaris 8和Solaris 9,并没有计划对sun4v的支持(Solaris 10功能如此强大,为什么强扭着Solaris 8和Solaris 9不放呢),因此在LDOMs虚拟分区安装的Guest OS也必须是Solaris 10 11/06(之前可能有很多朋友以为LDOMs支持不同版本的Solaris,现在看来是不行的)。

       Sun Fire[TM] T1000Sun Fire[TM] T2000服务器有8个core,每个core有4个thread,LDOMs技术可以将每个thread划分到一个虚拟分区。

       为了实现LDOMs,我们需要以下的条件:

       当系统满足以上条件后,就可以配置LDOMs。为了管理LDOMs,必须要先建立一个控制域Control Domain(也称为Primary Domain),有点类似于一些服务器的控制器。只有控制域建立好之后,你才能够开始其它逻辑域的创建。

        LDOMs按照其角色可以分为以下几类:

  1. Control domain -- 上面已经提到,用来创建并管理其它的逻辑域和服务,及与hypervisor的通信
  2. Service domain --  为其它逻辑域提供虚拟网络交换、虚拟磁盘服务等的逻辑域
  3. I/O domain --  具有对输入/输出设备直接的物理链接,比如PCI-E卡或者网络设备等。
  4. Guest Domain --  使用Service domain和I/O domain提供的服务,并受Control domain的管理。

       LDOMs支持对CPU的动态配置(Dynamic Reconfiguration),对Memory或者其它部件,LDOMs提供延迟配置(Delayed Reconfiguration),即要等到下一次重启才生效。

        几点说明:

  1. 所有LDOM的操作系统必须是Solaris 10 11/06,并且已经安装了相关补丁
  2. 如果Control domain出现故障,则会影响到其它所有LDOM。Control domain是SPOF(Single-Point-Of-Failure)
  3. 如果提供服务的LDOM出现故障,则所有使用其服务的LDOM都会受到影响。Service LDOM是SPOF。

 

更多信息,请参见《What's New in the Solaris 10 11/06 Release》 和 SUN BLUEPRINTS《BEGINNERS GUIDE TO LDOMS: UNDERSTANDING AND DEPLOYING LOGICAL DOMAINS


     
 

☆业界领先 - Sun Multithreaded Networking Card ☆

    SUN公司已经发布了业界领先的10Gigabit Ethernet多线程网卡

    Sx8ED10GEFXFPLPA

      通过多线程TOE(TCP Offload Engine)技术,以及与Solaris 10的Crossbow项目的配合,可以使你的网络性能得到空前的提高。

      根据 theinquirer 的报告:

---------------------------------------------
With a bit of tweaking, a Sun Fire T2000 on Solaris 10 got 8.75Gbps of transmit and 9.40 Gbps receive bandwidth (MTU of 1500 if you care). Linux on an Dual Opteron at 2.8GHz was at 7.7 and 7.3Gbps respectively reflecting the state of tuning more than anything else. Windows numbers will have to wait a few months for drivers.
----------------------------------------------

       看看我们的CEO Jonathan在其博客上的描述     

星期四 三月 08, 2007

☼ 什么是DST以及它对IT设备、软件的影响 ☼

      这一阵子老是看到网上提到 Daylight Saving Time (DST),那么到底DST是什么呢?

      DST翻译成中文好像是叫“日光节约时制”,也可以叫“夏时制”,是美国以及其它一些国家实行的时间调整制度。其实施方法就是在3月份的第二个礼拜日(在2007年以前是4月份的第一个礼拜日)凌晨2点将时间提前一小时,然后在11月份的第一个礼拜日(在2007年以前是10月份的最后一个礼拜日)凌晨2点将时间推迟一小时。

     下表是美国1990年至2015年使用的“夏时制”。简单讲,就是在春天,将时间提前一小时,然后在秋天,将时间推迟一小时。

      http://www.energy.ca.gov/daylightsaving.html
 

Year DST Begins 2 a.m.
(First Sunday in April)
DST Ends 2 a.m.
(Last Sunday in October)
1990 April 1 October 28
1991 April 7 October 27
1992 April 5 October 25
1993 April 4 October 31
1994 April 3 October 30
1995 April 2 October 29
1996 April 7 October 27
1997 April 6 October 26
1998 April 5 October 25
1999 April 4 October 31
2000 April 2 October 29
2001 April 1 October 28
2002 April 7 October 27
2003 April 6 October 26
2004 April 4 October 31
2005 April 3 October 30
2006 April 2 October 29
DST Start and End date changes beginning March 2007
Year DST Begins 2 a.m.
(Second Sunday in March)
DST Ends 2 a.m.
(First Sunday in November)
2007 March 11 November 4
2008 March 9 November 2
2009 March 8 November 1
2010 March 14 November 7
2011 March 13 November 6
2012 March 11 November 4
2013 March 10 November 3
2014 March 9 November 2
2015 March 8 November 1

      为什么要这么作呢?因为在这段时间里面,太阳出来得较早,同时日照时间也较长,如果把时间提前一个小时,就可以充分利用日光,减少因照明消耗的能源。不要小看这区区一小时,据说可以为美国节约1%的能源消耗

      http://www.house.gov/upton/press/press-07-21-05.html

      -------------------------------------------------------------
Extending daylight in the 1970's saved the equivalent of 100,000 barrels of oil a day, or one percent of the nation's energy consumption. Taking the savings figure from the mid 1970s - 100,000 barrels of oil a day - and multiplying that by $60 a barrel for 30 days, the savings amounts to at least $180 million for the extended weeks.
     --------------------------------------------------------------


      人可以通过调整手表或者时钟来实现,那么IT设备呢?不能说到时候你才去调整吧,那样会出大问题的。所以需要相应的补丁程序来完成这个任务,有点像Y2K的解决。

       由于这个“夏时制”只与时区TIMEZONE有关,对于没有实行“夏时制”的国家和地区,就没有这个顾虑。那么对于需要实现“夏时制”的地区,SUN公司是如何在其产品中实现的呢?

       在Solaris操作系统中,有两个东西与时区有关,一个是libc库,一个是zoneinfo库。这两个库都是在程序运行之初才读取的,因此安装了相应的补丁后,需要重新启动这些受影响的应用程序。为了保证所有程序都以及采用了新的“夏时制”,因此建议在安装补丁后,要进行重启。对于有控制器的服务器或者存储阵列,也需要升级相关的补丁来支持新的“夏时制”。

        对于已经支持新的“夏时制”的设备,以美国为例,在2007年3月11日和11月4日,将发生以下事件:

 

  • 此刻是2007年3月11日1:59AM EST(Eastern Standard Time),1分钟后,时间是2007年3月11日3:00 AM EDT(Eastern Daylight Time)
  • 此刻是2007年11月4日1:59AM EDT(Eastern Daylight Time),1分钟后,时间是2007年11月4日1:00 AM EST(Eastern Standard Time)

         注意上面EST和EDT之间的转变。

        我记得小时候中国也采用过这种制度,为什么现在不用了呢?现在不是提倡建设节约型社会嘛,我觉得挺好的。

        为什么不直接将作息时间调整了,比如上班从9:00AM调整为8:00AM,看来折腾机器还是比折腾人容易 \^_\^


 

  
 

SUN Microsystems真是免费到家了!

    试问还有哪一家商业公司能够像SUN公司一样免费开放这么多资源,IBM行吗?微软行吗?

    看看在这里,你都能免费得到什么!

     Download Solaris 10 For Free
     Download Sun Studio For Free
     Download Solaris Cluster For Free

    还需要犹豫什么吗?是时候转向SUN的阵营了!

    http://www.sun.com/software/solaris/hatsoff/index.html?cid=251017

星期三 三月 07, 2007

今天你“动态跟踪”了吗?

      SUN公司的动态跟踪工具DTRACETM真是一个伟大的创举,它使得你可以在Solaris 10及其以上版本的Solaris操作系统中对整个核心的运行情况进行“偷窥”。从此以后,你对系统的运行情况不会再是一头雾水,你可以清晰地知道哪怕是每一条指令的来龙去脉。而且其实现的效率是如此之高,以至于你在没有激活(enable)任何探测点(probe)的时候,你根本不会发现它与之前的Solaris操作系统版本有任何不同。实际上,只要你不是激活了非常多的探测点,其影响也是可以忽略不计的。难怪DTRACE能够脱颖而出荣获《华尔街杂志》2 006技术创新大奖中的金奖

      目前在UNIX/Linux领域,还没有像DTRACE功能如果强大的跟踪技术。Linux有一个仍处于开发阶段的SystemTap项目,主要成员有Red Hat, IBM, Intel, 和Hitachi。但是SystemTap的功能是有限的,它不能跟踪用户程序(至少目前是这样)。下面是IBM中国研发中心一个工程师写的《使用 SystemTap 调试内核》的文章, http://www.ibm.com/developerworks/cn/linux/l-systemtap/index.html

      文章中只提到“SystemTap是遵循GPL的开源软件项目”,其实dtrace也已经随着opensolaris的开源而开放出来。 网上还有很多其它的对比DTRACE和SystemTap的文章,比如: http://uadmin.blogspot.com/2006/09/systemtap-vs-dtrace-chart.html

      到底DTRACE怎么样,说得太多就会有打广告之嫌,还是自己自己动手用一下。不需要你懂C程序,不需要你读完整个Dtrace Guide,你只需使用DTraceToolkit中oneliners.txt提供的例子就会对它深深着迷!

http://opensolaris.org/os/community/dtrace/ 这是DTRACE的社区

http://docs.sun.com/app/docs/doc/819-6959?l=zh&q=dtrace&a=load 这里有中文版的《Solaris动态跟踪指南》

http://docs.sun.com/app/docs/doc/819-5488?l=en&q=dtrace+guide 这是英文版的

http://www.sun.com/bigadmin/content/dtrace/

      还没有安装OpenSolaris?没关系,SUN公司现在正在免费赠送OpenSolaris光盘套件(OpenSolaris Starter Kit)。赶紧去注册吧,机不可失!

      明天就是“国际妇女节”,在此预祝全天下的女性朋友们节日快乐,并借此机会感谢我的母亲,我的妻子

About

samwan

Search

Categories
Archives
« 四月 2014
星期日星期一星期二星期三星期四星期五星期六
  
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
   
       
今天