1.General description
我们知道,使用日志系统是为了使系统变得更健壮,能够应对各种错误并能从错误中较快地恢复。一个大型的分布式系统生成的日志数量是巨大的,所以需要一个有效的工具对其进行管理。Scribe就是这样一个日志收集服务器,使用它可以对大型的系统进行监控。它是Facebook的一个开源组件,使用的是Facebook另一个框架—Thrift。Thrift 在我的理解就是一个高效的跨语言 rpc 框架,所以它可以支持通过 C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, Smalltalk, and OCaml 给服务器汇报。
总的来说,Scribe由两部分组成:central Scribe server 和 local Scribe server。在分布式系统中,每个结点都会有一个local Scribe server运行在上面,收集此结点的日志信息,并将其发送给central Scribe server。这里的central和local是相对的,是针对一个组内的。
2. Download and Install
Scribe并不大,但其安装是一个非常繁琐的过程。通过我不断的努力,最终还是没有安装成功(源代的example不能正常运行)。虽说没有产出的劳动是徒劳的,但这也不是绝对的,至少对其具体的安装过程倒是耳熟能详了。
Scribe运行于Linux系统下,试验中我所使用的是Ubuntu 9.10,通过虚拟机安装的。Scribe安装前需要很多Environment Dependency,具体如下所示:

(1)安装ruby:
install: sudo apt-get install ruby-full build-essential
test: ruby -v 显示 版本 号
which ruby 显示安装的位置
新建一个test.rb文件,里面输入如下内容:
#!/usr/bin/env ruby
puts "hello world!"
然后进入该目录,输入如下命令:./test.rb。如果ruby安装成功则会
输出hello world!
(2)安装python:
一般来讲,Ubuntu系统里已经安装了python。查看是否已经安装,使用如下
命令:python 显示安装的版本号
which python 显示安装的位置
系统自带的,其安装目录是在/usr/bin下。如果是自安装的,则会在
/usr/local/bin下。就如接下来要安装的Thrift和Scribe。
(3)安装libevent:
下载http://www./linux/accidence/20100218/22428.html
tar xzfv libevent-1.4.8-stable.tar.gz
cd libevent-1.4.8-stable
./configure
make
make install
(4)安装剩下的dependency:
sudo apt-get install libboost-dev=1.38.1 flex bison libtool automake autoconf pkg-
config && wget -O thrift.tgz
"http://gitweb./?p=thrift.git;a=snapshot;h=HEAD;sf=tgz"
&& tar -xzf thrift.tgz && cd thrift &&./bootstrap.sh && ./configure && make
&& sudo make install
&& cd contrib/fb303/ && ./bootstrap.sh && sudo make && sudo make install
实际上是将多条命令合为一条而已。
至此为止,所有的依赖已经安装完成。
(5 )安装Scribe
首先下载Scribe,这里我所使用的是Scribe2.2。接下来的安装就非常简单了:
./bootstrap.sh
make
make install
至此为止,Scribe就成功安装上了。接下来就可以跑Example内的例子了。
3. Example:
网上关于Scribe的资料较少,所以阅读源代码是一个很有效的途径。在此之前先运行Example内的例子。
源代码里所给的example很简单,但大体上了模拟了其运行的过程,分三个部分。可参考里面的README文件:
Configurarion(配置)、Running Scribe Server(运行服务器)、Logging messages(记录日志)
3.1 配置:
Scribe Server是通过配置文件启动的。

null:丢弃所有消息
multi:给所有multi类型的store传递消息
file:将消息写入文件
thriftfile:类似于file,但写入的文件类型为thrift TfileTransport文件
network:将消息转发给另外一个scribe server
buffer:包含两个子store(主、次),在主store工作时,直接使用主store记录日志,只
有当主store不可用时,才使用次store记录。而且一旦主store恢复工作,次
stroe记录的日志将转移到主store。
bucket:包含一系列的其他类型的stroe,具体使用哪个是由所定义的Hash函数决定的
3.2 运行Scribe Server:

1)启动:进入到Scribe源码中的根目录,执行如下命令
scribed examples/example1.conf
如果scribe安装成功的话,则会出现如下提示信息:

2) 查看状态:在另外一个终端执行如下命令:
./scribe_ctrl status
ALIVE
3)停止:开启另外一个终端,执行如下命令:
./scribe_ctrl stop
在另外一个终端会看到状态信息:
“STATUS: STOPPING"
3.3 记录日志:
1)Example1:向已经启动的Server发送消息,验证是否被记录下来。
Server启动后,开启另外一个终端向Server发送信息:使用scribe_cat
mkdir /tmp/scribetest
echo "hello world"| ./scribe_cat test
这时你很可能会出现如下错误提示:

也就是说python导入模块scribe失败,但我们打开/usr/lib/python2.6/site-packages,发现里面是有scribe的模块的,所以很可能是PYTHONPATH没有配置正确。使用如下命令进行配置:
进入到/etc目录,然后输入命令gedit profile(profile文件为系统的每个用户设置环境信息,当用户第一次登录时,该文件被执行),在此文件中添加如下内容:
export PYTHONPATH= ”/usr/lib/python2.6/site-packages”
然后注销重新登录。
输入echo $PYTHONPATH命令进行测试。
再次执行echo命令,查看结果:
cat /tmp/scribetest/test/test_current
或者直接打开查看。—hello world!
2) Example2:启动中心服务器和客户端服务器,然后开启一个终端并输入三条命令,并查看结果:
mkdir /tmp/scribetest2
scribed examples/example2central.conf
scribed examples/example2client.conf
echo "test message" | ./scribe_cat -h localhost:1464 test2
echo "this message will be ignored" | ./scribe_cat -h localhost:1464 ignore_me
echo "123:this message will be bucketed" | ./scribe_cat -h localhost:1464 bucket_me
查看结果:
cat /tmp/scribetest/test2/test2_current
cat /tmp/scribetest/bucket*/bucket_me_current
./scribe_ctrl status 1463
./scribe_ctrl status 1464
./scribe_ctrl counters 1463 #查看中心服务器的统计数据
./scribe_ctrl counters 1464 #查看客户端服务器的统计数据

当客户端服务器讲收到的信息发送给中心服务器后,会删除本地的存储。
结果显示:客户端收到三条消息,发送了三条消息;
服务器端收到三条消息,忽略了一条消息。
3) Example3:如同Example2启动中心服务器和客户端服务器,但本例测试的是在中心服务器突然down掉的情况下,客户端服务器的缓冲存储功能。
echo "test message 1" | ./scribe_cat -h localhost:1464 test3 #发送消息1
cat /tmp/scribetest/test3/test3_current #结果:test message 1
./scribe_ctrl stop 1463 #down掉中心服务器
./scribe_ctrl status 1463 #结果:Failed to get status
echo "test message 2" | ./scribe_cat -h localhost:1464 test3 #发送消息2
./scribe_ctrl status 1464 #结果:WARNING - Failed to connect
echo "test message 3" | ./scribe_cat -h localhost:1464 test3 #发送消息3
scribed examples/example2central.conf #重新启动中心服务器
./scribe_ctrl status 1463 #结果:ALIVE
./scribe_ctrl status 1464 #结果:ALIVE
cat /tmp/scribetest/test3/test3_current
#结果:
test message 1
test message 2
test message 3
全部正常接收
4.Source Analyse:
4.1 整体类图:

4.2 store 和 storeConf

4.3 scribeHandler和storeQueue

4.4 配置文件的解析
在server启动的过程中,会调用StoreConf中的parseConfig函数,具体实现是先调用readConfig函数将配置文件的内容逐行读入到一个队列中,然后再调用parseStore函数从队列中逐行解析,并将解析的内容存入StoreConf中的两个Map变量: values和stores。
|
类型
|
解释
|
values
|
std::map<std::string, std::string>
|
每个store里的<参数,值>对
|
stores
|
std::map<std::string, pStoreConf>
|
存放所有的store
|
4.5 Server的启动过程的流程图:
Main函数是入口点,端口号port和配置文件config_file作为声明一个server实例:
new scribeHandler(port, config_file);然后执行一系列的初始化工作,初始化的流程图如下:

4.6 Log过程的流程图:
客户端调用Log(messages)函数发送消息,通过thrift框架的实现,远程方法
scribeHandler:: Log(const vector<LogEntry>& messages)函数被调用,过程如下:

Reference:
http://github.com/facebook/scribe
http://hi.baidu.com/you5a_com/blog/item/ed62ee3fd1228d0bbba167d5.html
http://snippets./2009/07/29/howto-install-scribe-the-facebook-log-system-on-debian/
http:///product-scribe-facebooks-scalable-logging-system
http:///posts/facebook-scribe-server-documentation-and-tutorials#comments