Archive for August, 2014

作者:AngryFox 分类: Uncategorized August 26th, 2014 暂无评论

公司装了域,天天提示自动更新,并经常要求重启,不胜其烦,以下关闭自动更新

如果你运行的是Windows 7专业版,企业版或者旗舰版,我建议你做以下操作。

1. 点击开始,在搜索条中运行Gpedit.msc,然后按回车键。
2. 依次展开本地计算机策略、计算机配置、管理模板、Windows组件、Windows Update。
3. 双击配置自动更新,选择为配置,然后点击确定。

如果你运行的是Windows 7家庭基础或者家庭高级版,你可以尝试以下步骤。

1. 点击开始,在搜索条中运行Regedit,然后按回车键。
2. 展开以下注册表,右键点击WindowsUpdate然后导出作为备份,接着删除WindowsUpdate。

HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\WindowsUpdate

妈的,没效果,公司的域的权限更改,可以还原的

作者:AngryFox 分类: Uncategorized August 25th, 2014 暂无评论

用户态线程和核心态线程。用户态线程指不在内核中实现线程,只在用户态中模拟出多线程,内核完全不知道。
  而核心态线程是由内核创建的。类Unix系统中一般通过修改进程的实现方式来完成,可以使用不完全的进程创建方式创建共享数据空间的进程,在 Linux下这种系统调用为clone(),而在FreeBSD下它为rfork()。
  在许多类Unix系统中,如Linux、FreeBSD、Solaris等,进程一直都是操作系统内核调用的最小单位。程序开发也都采用多进程模型。
  后来引入了线程这一概念,由于这些系统本身不存在线程这一概念,那么出现以下几种常见的线程模型:
N∶1用户线程模型:N条用户线程只由一条内核进程/线程调度,即以用户态线程实现。内核不干涉线程的任何生命活动,用户态线程工作在“进程竞争范围”。因此,线程的创建、删除和环境切换都很高效。

但是缺点同样明显,因为一个进程同一时间只能在一个CPU中执行。所以在SMP中,无论系统有多少CPU,同一进程中的所有线程都只能由一个CPU去执行。
另外,如果其中某条线程执行了一个“阻塞”操作,比如read和write,那么整个进程中的其它线程都会被阻塞,这也违背了线程的概念。
目前,采用这种模型的线程库大概有,FreeBSD下的libc_r
1∶1 核心线程模型:1条用户线程对应一条内核进程/线程来调度,即以核心态线程实现。应用程序创建的每一个线程都由一个核心线程直接管理,内核将每一个核心线程都调度到系统CPU上。
所有线程都工作在“系统竞争范围”。这种方式也是现在大多线程库采用的模式。它完全克服了N:1模型的缺点,但较之在线程的创建、删除、切换的代价更昂贵。
目前,采用这种模型的线程库大概有,FreeBSD下的libthr,Linux下的LinuxThreads,NPTL。
N∶M 混合线程模型:即N∶1和1∶1模型的组合形式,支持用户态线程和核心态线程同时存在。在创建线程时可以指明这个线程应该工作在哪一种模式。
这个模型比较灵活和强大,并且在实现N∶1模型中,加入了算法来克服这个模型会被阻塞的缺点。但是这种模型也较复杂。
目前,solaris提供了这种模型。Linux下可选的NGPT(已不再维护,NPTL已成为Linux下默认的线程库)

线程有自己的私有数据:程序计数器,栈空间以及寄存器。
Why Thread?(传统单线程进程的缺点)
1. 现实中有很多需要并发处理的任务,如数据库的服务器端、网络服务器、大容量计算等。
2. 传统的UNIX进程是单线程的,单线程意味着程序必须是顺序执行,不能并发;既在一个时刻只能运行在一个处理器上,因此不能充分利用多处理器框架的计算机。
3. 如果采用多进程的方法,则有如下问题:
a. fork一个子进程的消耗是很大的,fork是一个昂贵的系统调用,即使使用现代的写时复制(copy-on-write)技术。
b. 各个进程拥有自己独立的地址空间,进程间的协作需要复杂的IPC技术,如消息传递和共享内存等。

支持多线程的程序(进程)可以取得真正的并行(parallelism),且由于共享进程的代码和全局数据,故线程间的通信是方便的。它的缺点也是由于线程共享进程的地址空间,因此可能会导致竞争,因此对某一块有多个线程要访问的数据需要一些同步技术。
三种线程——内核线程、轻量级进程、用户线程

内核线程

内核线程就是内核的分身,一个分身可以处理一件特定事情。这在处理异步事件如异步IO时特别有用。内核线程的使用是廉价的,唯一使用的资源就是内核栈和上下文切换时保存寄存器的空间。支持多线程的内核叫做多线程内核(Multi-Threads kernel )。

轻量级进程[*]

轻量级线程(LWP)是一种由内核支持的用户线程。它是基于内核线程的高级抽象,因此只有先支持内核线程,才能有LWP。每一个进程有一个或多个LWPs,每个LWP由一个内核线程支持。这种模型实际上就是恐龙书上所提到的一对一线程模型。在这种实现的操作系统中,LWP就是用户线程。
由于每个LWP都与一个特定的内核线程关联,因此每个LWP都是一个独立的线程调度单元。即使有一个LWP在系统调用中阻塞,也不会影响整个进程的执行。
轻量级进程具有局限性。首先,大多数LWP的操作,如建立、析构以及同步,都需要进行系统调用。系统调用的代价相对较高:需要在user mode和kernel mode中切换。其次,每个LWP都需要有一个内核线程支持,因此LWP要消耗内核资源(内核线程的栈空间)。因此一个系统不能支持大量的LWP。
注:
1. LWP的术语是借自于SVR4/MP和Solaris 2.x。
2. 有些系统将LWP称为虚拟处理器。
3. 将之称为轻量级进程的原因可能是:在内核线程的支持下,LWP是独立的调度单元,就像普通的进程一样。所以LWP的最大特点还是每个LWP都有一个内核线程支持。

用户线程

LWP虽然本质上属于用户线程,但LWP线程库是建立在内核之上的,LWP的许多操作都要进行系统调用,因此效率不高。而这里的用户线程指的是完全建立在用户空间的线程库,用户线程的建立,同步,销毁,调度完全在用户空间完成,不需要内核的帮助。因此这种线程的操作是极其快速的且低消耗的。进程中包含线程,用户线程在用户空间中实现,内核并没有直接对用户线程进程调度,内核的调度对象和传统进程一样,还是进程本身,内核并不知道用户线程的存在。用户线程之间的调度由在用户空间实现的线程库实现。
这种模型对应着恐龙书中提到的多对一线程模型,其缺点是一个用户线程如果阻塞在系统调用中,则整个进程都将会阻塞。
加强版的用户线程——用户线程+LWP

这种模型对应着恐龙书中多对多模型。用户线程库还是完全建立在用户空间中,因此用户线程的操作还是很廉价,因此可以建立任意多需要的用户线程。操作系统提供了LWP作为用户线程和内核线程之间的桥梁。LWP还是和前面提到的一样,具有内核线程支持,是内核的调度单元,并且用户线程的系统调用要通过LWP,因此进程中某个用户线程的阻塞不会影响整个进程的执行。用户线程库将建立的用户线程关联到LWP上,LWP与用户线程的数量不一定一致。当内核调度到某个LWP上时,此时与该LWP关联的用户线程就被执行。

作者:AngryFox 分类: Uncategorized August 21st, 2014 暂无评论

http://wiki.apache.org/lucene-java/ImproveSearchingSpeed

1.使用最新的solr版本
2.使用本地文件系统
3.可以的话,使用flash 卡,ssd 等高速IO设备
4.调整操作系统,最大限度的使用物理内存 将swappiness设置成0
5.打开indexReader的时候,只使用 readOnly =true
6.在非windows 的平台,使用 NIOFSDirectory 代替 FSDirectory
7.增大内存
8.只使用一个 IndexSearcher
9.当需要测试性能时,忽略第一次的查询时间
10.当有必要时,才重开IndexSearcher
11.调小 mergeFactor
12.尽量小数据存储字段
13.只需要获取你想要的hits,不需要全部循环整个hits
14.当使用模糊查询时,使用最小的前缀长度
15.考虑使用filters

作者:AngryFox 分类: Uncategorized August 21st, 2014 暂无评论

Updates and Commit Frequency Tradeoffs
如果从机太经常从主机更新的话,从机的性能是会受到影响的。为了避免,由于这个问题而引起的性能下降,我们还必须了解从机是怎样执行更新的,这样我们才能更准确去调节一些相关的参数(commit的频率,spappullers,autowarming/autocount),这样,从机的更新才不会太频繁。
执行commit操作会让solr新生成一个snapshot。如果将postCommit参数设成true的话,optimization也会执行snapShot.
slave上的Snappuller程序一般是在crontab上面执行的,它会去master询问,有没有新版的snapshot。一旦发现新的版本,slave就会把它下载下来,然后snapinstall.
每次当一个新的searcher被open的时候,会有一个缓存预热的过程,预热之后,新的索引才会交付使用。
这里讨论三个有关的参数:
number/frequency of snapshots —-snapshot的频率。
snappullers 是 在crontab中的,它当然可以每秒一次、每天一次、或者其他的时间间隔一次运行。它运行的时候,只会下载slave上没有的,并且最新的版本。
Cache autowarming 可以在solrconfig.xml文件中配置。
如果,你想要的效果是频繁的更新slave上的索引,以便这样看起来比较像“实时索引”。那么,你就需要让snapshot尽可能频繁的运行,然后也让snappuller频繁的运行。这样,我们或许可以每5分钟更新一次,并且还能取得不错的性能,当然啦,cach的命中率是很重要的,恩,缓存的加热时间也将会影响到更新的频繁度。
cache对性能是很重要的。一方面,新的缓存必须拥有足够的缓存量,这样接下来的的查询才能够从缓存中受益。另一方面,缓存的预热将可能占用很长一段时间,尤其是,它其实是只使用一个线程,和一个cpu在工作。snapinstaller太频繁的话,solr slave将会处于一个不太理想的状态,可能它还在预热一个新的缓存,然而一个更新的searcher被opern了。
怎么解决这样的一个问题呢,我们可能会取消第一个seacher,然后去处理一个更新seacher,也即是第二个。然而有可能第二个seacher 还没有被使用上的时候,第三个又过来了。看吧,一个恶性的循环,不是。当然也有可能,我们刚刚预热好的时候就开始新一轮的缓存预热,其实,这样缓存的作用压根就没有能体现出来。出现这种情况的时候,降低snapshot的频率才是硬道理。
Query Response Compression
在有些情况下,我们可以考虑将solr xml response 压缩后才输出。如果response非常大,就会触及NIc i/o限制。
当然压缩这个操作将会增加cpu的负担,其实,solr一个典型的依赖于cpu处理速度的服务,增加这个压缩的操作,将无疑会降低查询性能。但是,压缩后的数据将会是压缩前的数据的6分之一 的大小。然而solr的查询性能也会有15%左右的消耗。
至于怎样配置这个功能,要看你使用的什么服务器而定,可以查阅相关的文档。
Embedded vs HTTP Post
使用embeded 来建立索引,将会比使用xml格式来建立索引快50%。
RAM Usage Considerations(内存方面的考虑)
OutOfMemoryErrors
如果你的solr实例没有被指定足够多的内存的话,java virtual machine也许会抛outof memoryError,这个并不对索引数据产生影响。但是这个时候,任何的 adds/deletes/commits操作都是不能够成功的。
Memory allocated to the Java VM
最简单的解决这个方法就是,当然前提是java virtual machine 还没有使用掉你全部的内存,增加运行solr的java虚拟机的内存。
Factors affecting memory usage(影响内存使用量的因素)
我想,你或许也会考虑怎样去减少solr的内存使用量。
其中的一个因素就是input document的大小。
当我们使用xml执行add操作的时候,就会有两个限制。
document中的field都是会被存进内存的,field有个属性叫maxFieldLength,它或许能帮上忙。
每增加一个域,也是会增加内存的使用的。

作者:AngryFox 分类: Uncategorized August 21st, 2014 暂无评论

Schema Design Considerations
indexed fields
indexed fields 的数量将会影响以下的一些性能:
索引时的时候的内存使用量
索引段的合并时间
优化时间
索引的大小
我们可以通过 将 omitNorms=“true” 来减少indexed fields数量增加所带来的影响。
stored fields
Retrieving the stored fields 确实是一种开销。这个开销,受每个文档所存储的字节影响很大。每个文档的所占用的空间越大,文档就显的更稀疏,这样从硬盘中读取数据,就需要更多的i/o操作(通常,我们在存储比较大的域的时候,就会考虑这样的事情,比如存储一篇文章的文档。)
可以考虑将比较大的域放到solr外面来存储。如果你觉得这样做会有些别扭的话,可以考虑使用压缩的域,但是这样会加重cpu在存储和读取域的时候的负担。不过这样却是可以较少i/0的负担。
如果,你并不是总是使用 stored fields 的话,可以使用stored field的延迟加载,这样可以节省很多的性能,尤其是使用compressed field 的时候。
Configuration Considerations
mergeFactor
这个是合并因子,这个参数大概决定了segment(索引段)的数量。
合并因子这个值告诉lucene,在什么时候,要将几个segment合并成为一个segment, 合并因子就像是一个数字系统的基数一样。
比如说,如果你将合并因子设成10,那么每往索引中添加1000个文档的时候,就会创建一个新的索引段。当第10个大小为1000的索引段添加进来的时候,这十个索引段就会被合并成一个大小为10,000的索引段。当十个大小为10,000的索引段生成的时候,它们就会被合并成一个大小为100,000的索引段。如此类推下去。
这个值可以在 solrconfig.xml 中的 *mainIndex*中设置。(不用管indexDefaults中设置)
mergeFactor Tradeoffs
较高的合并因子
会提高索引速度
较低频率的合并,会导致 更多的索引文件,这会降低索引的搜索效率
较低的合并因子
较少数量的索引文件,能加快索引的搜索速度。
较高频率的合并,会降低索引的速度。
Cache autoWarm Count Considerations
当一个新的 searcher 打开的时候,它缓存可以被预热,或者说使用从旧的searcher的缓存的数据来“自动加热”。autowarmCount是这样的一个参数,它表示从旧缓存中拷贝到新缓存中的对象数量。autowarmCount这个参数将会影响“自动预热”的时间。有些时候,我们需要一些折中的考虑,seacher启动的时间和缓存加热的程度。当然啦,缓存加热的程度越好,使用的时间就会越长,但往往,我们并不希望过长的seacher启动时间。这个autowarm 参数可以在solrconfig.xml文件中被设置。
详细的配置可以参考solr的wiki。
Cache hit rate(缓存命中率)
我们可以通过solr的admin界面来查看缓存的状态信息。提高solr缓存的大小往往是提高性能的捷径。当你使用面搜索的时候,你或许可以注意一下filterCache,这个是由solr实现的缓存。
详细的内容可以参考 solrCaching这篇wiki。
Explicit Warming of Sort Fields
如果你有许多域是基于排序的,那么你可以在”newSearcher”和”firstSearcher”event listeners中添加一些明显需要预热的查询,这样FieldCache 就会缓存这部分内容。
Optimization Considerations
优化索引,是我们经常会做的事情,比如,当我们建立好索引,然后这个索引不会再变更的情况,我们就会做一次优化了。
但,如果你的索引经常会改变,那么你就需要好好的考虑下面的因素的。
当越来越多的索引段被加进索引,查询的性能就会降低, lucene对索引段的数量有一个上限的限制,当超过这个限制的时候,索引段可以自动合并成为一个。
在同样没有缓存的情况下,一个没有经过优化的索引的性能会比经过优化的索引的性能少10%……
自动加热的时间将会变长,因为它依赖于搜索。
优化将会对索引的分发产生影响。
在优化期间,文件的大小将会是索引的两倍,不过最终将会回到它原来的大小,或者会更小一点。
优化,会将所有的索引段合并成为一个索引段,所以,优化这个操作其实可以帮助避免“too many files”这个问题,这个错误是由文件系统抛出的。

作者:AngryFox 分类: Uncategorized August 6th, 2014 暂无评论

1.源代码编译安装
1)获得文件
US VPS使用源

mariadb:wget https://downloads.mariadb.org/interstitial/mariadb-10.0.12/source/mariadb-10.0.12.tar.gz/from/http://sfo1.mirrors.digitalocean.com/mariadb
查看是否已安装cmake
cmake:http://www.cmake.org/files/v2.8/cmake-2.8.10.2.tar.gz
2)首先安装cmake
tar zxvf  cmake-2.8.10.2.tar.gz
cd cmake-2.8.10.2
./bootstrap
make && make install
然后安装mariadb
tar zxvf mariadb-10.0.12
cd mariadb-10.0.12
cmake . -DCMAKE_INSTALL_PREFIX=/usr/localo/mariadb -DMYSQL_DATADIR=/data/mariadb -DWITH_FEDERATED_STORAGE_ENGINE=1 -DWITH_SSL=system
make && make install

3)三.配置
拷贝配置文件和,启动脚本

cd /usr/localo/mariadb
cp support-files/my-large.cnf /etc/my.cnf
cp support-files/mysql.server /etc/rc.d/init.d/mariad
chmod +x /etc/rc.d/init.d/mariad
chkconfig --add mariad
chkconfig mariad on
初始化数据库
mkdir -pv /data/mariadb
chown -R mysql:mysql /data/
chown -R :mysql /usr/local/mariadb.
scripts/mysql_install_db --user=mysql --datadir=/data/mariadb
修改mariadb配置文件
vim /etc/my.cnf
添加
datadir = /data/mysql
修改
thread_concurrency = 2
然后就可以启动服务了
service mariad start
或者
/usr/local/mariadb、bin/mysqld_safe --user=mysql &

2)二进制安装

https://downloads.mariadb.org/mariadb/+releases/

选择二进制文件,wget
mv mariadb-10.0.12-Linux-i686 /usr/local/mysql
其他操作同上

或者repo安装
cd /etc/yum.repos.d/
vi /etc/yum.repos.d/MariaDB.repo
设置安装源仓库的 具体的地址为: https://downloads.mariadb.org/mariadb/repositories/
如果服务器不支持https协议,或者gpgkey 保错,确保没问题的话,可以将 gpgcheck=1 修改为 gpgcheck=0,则不进行校验.
# yum remove MariaDB-server MariaDB-client
yum -y install MariaDB-server MariaDB-client

测试数据库

>
-- 查看MySQL的状态
status;
-- 显示支持的引擎
show engines;
-- 显示所有数据库
show databases;
-- 切换数据库上下文,即设置当前会话的默认数据库
use test;
-- 显示本数据库所有的表
show tables;
-- 创建一个表
CREATE TABLE t_test (
  id int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
  userId char(36),
  lastLoginTime timestamp,
  PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- 插入测试数据
insert into t_test(userId)
	values
('admin')
,('haha')
;

-- 简单查询
select * from t_test;
select id,userId from t_test  where userId='admin' ;
作者:AngryFox 分类: Uncategorized August 5th, 2014 暂无评论

1.安装java 1.6以上
2.安装zookeeper
wget http://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.4.6/zookeeper-3.4.6.tar.gz
其他版本下载地址(最好使用stable版本):http://zookeeper.apache.org/releases.html
3.解压后,将zookeeper-3.4.6/conf目录下的zoo_sample.cfg文件拷贝一份,命名为为“zoo.cfg”
4.如果配置集群方式,修改zoo.cfg如下

# The number of milliseconds of each tick
tickTime=2000
# The number of ticks that the initial
# synchronization phase can take
initLimit=10
# The number of ticks that can pass between
# sending a request and getting an acknowledgement
syncLimit=5
# the directory where the snapshot is stored.
# do not use /tmp for storage, /tmp here is just
# example sakes.
dataDir=/home/test/zkdir/data
dataLogDir=/home/test/zkdir/log
# the port at which the clients will connect
clientPort=2181
# the maximum number of client connections.
# increase this if you need to handle more clients
#maxClientCnxns=60
#
# Be sure to read the maintenance section of the
# administrator guide before turning on autopurge.
#
# http://zookeeper.apache.org/doc/current/zookeeperAdmin.html#sc_maintenance
#
# The number of snapshots to retain in dataDir
#autopurge.snapRetainCount=3
# Purge task interval in hours
# Set to "0" to disable auto purge feature
#autopurge.purgeInterval=1

server.1=192.168.42.146:2888:3888
server.2=192.168.42.163:2888:3888
server.3=192.168.44.84:2888:3888

其中,2888端口号是zookeeper服务之间通信的端口,而3888是zookeeper与其他应用程序通信的端口
initLimit:用来配置 Zookeeper的Follower 服务器连接到leader,初始化连接时最长能忍受多少个心跳时间间隔数。当已经超过 10 个心跳的时间(也就是 tickTime)长度后 Zookeeper 服务器还没有收到客户端的返回信息,那么表明这个客户端连接失败。总的时间长度就是 5*2000=10 秒。
syncLimit:这个配置项标识 Leader 与 Follower 之间发送消息,请求和应答时间长度,最长不能超过多少个 tickTime 的时间长度,总的时间长度就是 2*2000=4 秒。
配置data和log文件夹
5.编辑“myid”文件,并在对应的IP的机器上输入对应的编号。如在zookeeper上,“myid”文件内容就是1,还需加入server.2=192.168.42.146:2888:3888。那么myid文件在192.168.42.146服务器上的内容就是2。
至此,如果是多服务器配置,就需要将zookeeper-3.4.6目录拷贝到其他服务器,然后按照上述的方法修改myid。
6、在/etc/profile文件中设置PATH
修改profile文件:

vi /etc/profile
export ZOOKEEPER_HOME=/home/test/zookeeper-3.4.6
PATH=$ZOOKEEPER_HOME/bin:$PATH
export PATH

7.启动并测试zookeeper
1)、在所有服务器中执行:zookeeper-3.4.6/bin/zkServer.sh start
2)、输入jps命令查看进程
3)、查看状态:zookeeper-3.4.6/bin/zkServer.sh status
4)、启动客户端脚本:zookeeper-3.4.6/bin/zkCli.sh -server zookeeper:2181
5)、停止zookeeper进程:zookeeper-3.4.6/bin/zkServer.sh stop

如果出现任何问题,看zookeeper-3.4.6/bin/下的日志,tail -20f zookeeper.out

作者:AngryFox 分类: Uncategorized August 3rd, 2014 暂无评论

连接层
1.异步、简单
2.允许随时重启更新、只允许晚上重启、不允许重启断线

逻辑层
1.用户会话验证
2.消息存取
3.异步队列
4.随时重启

xmpp sip
目标
1.高效 弱网络快速的收发
2.可靠 不会丢消息
3.易于扩展

基于版本号的redis协议
针对弱⺴络的优化协议
• 消息通过版本号维护顺序
• 新消息到达,Server只负责push通知
• Client收到轻量的msg-psh后发出同步
请求
• Server按照版本号连续发送msg
• Client告诉Server收到最后的版本
核心的长连接只用于传输轻量的实时数据
• 图片、语音等都可以开新的TCP或HTTP连接

弹性四准则
 机器故障自动修复
 资源故障自动迁移
 服务故障容灾降级
 业务容量自动调整
如何解决连通性
• 多端口
– 应对网管代理限制端口和http协议
– 80/443/8080/14000
• 终端并发探测,接入点+协议+端口
• tcp协议不通,自动切换到http
• 优先使用最近可用IP
• 客户端侧接入点竞速

内核优化
• TCP拥塞控制
– 调大初始拥塞窗口
– TCP westwood+算法
– 关闭空闲slow-start
• 连通性
– MTU: TCP DF标志,终端动态MSS
– 关闭TCP时间戳选项

soul gut skeleton skin

ECS:全路径IO持续优化,Cache策略的优化,带
SSD的读写缓存,存储与计算分离,万兆纯SSD集
群,动态热点迁移技术,GPU支持,LXC/cgroups
支持等。
• RDS:PostgreSQL支持,更低成本的可容忍一定切
换时间RDS服务等。
• 全链路的监控与分析系统应用到全线云产品。
• 无线网络加速、 AliBench服务质量监测、OCR识别服务、深度学习的CNN/DNN
计算服务等。

作者:AngryFox 分类: Uncategorized August 1st, 2014 暂无评论

zookeeper c 客户端主要围绕zhandler_t结构进行一系列操作
重点关注其中4个队列:
to_process: 已经接收的网络数据包,准备进行处理;
to_send: 准备发送的网络数据包;
sent_requests: 异步操作时未完成的请求
completions_to_process: 已经完成的异步请求,准备执行(包括watcher回调)
整体流程 包括:
main线程:各种zookeeper api, 在应用中进行调用,用来执行zookeeper节点文件的增、删、改、查(包括watcher、异步回调、acl的设置)
io线程:zookeeper_mt库才有,基于事件循环,进行网络通信;
completion线程:zookeeper_mt库才有,执行异步回调、watcher回调;
main thread即应用开发的主线程,调用各种zookeeper api。
首先要调用zookeeper_init:进行资源初始化(参数的默认设置、host打乱顺序),如果是zookeeper_mt库则启动两个线程:io线程、completion线程, 设置相关参数、线程间通信管道。
接着就是各种zookeeper节点操作api(eg:zoo_create), 完成应用程序预期的功能。
zookeeper c 客户端分别提供了单线程的库与多线程的库,分别叫zookeeper_st 和 zookeeper_mt。
zookeeper_st主要用于不支持pthread 或者支持不完善的系统环境, zookeeper_st只提供异步操作的api, 应用程序需要在自己的事件循环中,调用api进行相关操作。
zookeeper_mt 会启动两个独立线程:io线程与completion线程, 封装了内部的事件循环,分别提供了同步和异步的api, 一般情况下建议使用这个库。
zookeeper_st仅提供异步的api, zookeeper_mt提供同步与异步的api.
先说一下同步api, zookeeper_mt的同步:主线程调用完对应api后等待,io线程完成对应的操作后,通知主线程。
关于异步api, zookeeper_st,zookeeper_mt都提供,但是各自的调用方式不同。zookeeper_mt主线程执行完api调用后立即返回, completion线程完成回调函数的执行;但是zookeeper_st是单线程如果达到异步的效果呢?zookeeper_st提供了对应的事件处理函数: zookeeper_interest、zookeeper_process, 应用程序可以根据这两个api完成对应的事件循环,进行异步api的处理(可参见cli_st的实现)
ZooKeeper提供了可以绑定在znode的监视器。如果监视器发现znode发生变化,该service会立即通知所有相关的客户端。
每个处理(或服务器)紧盯着相邻的那个处理(或服务器)。如果一个已被监视的处理(也即Leader)退出或者崩溃了,监视程序就会查找其相邻(此时最老)的那个处理作为Leader。
在真实的应用程序中,leader会给worker分配任务、监控进程和保存结果。
每个znode都是EPHEMERAL和SEQUENCE的。
EPHEMRAL代表当客户端失去连接时移除该znode。这就是为何PHP脚本会知道超时。SEQUENCE代表在每个znode名称后添加顺序标识。我们通过这些唯一标识来标记worker。

Leader处理:
启动LearnerCnxAcceptor,监听Follower的请求。针对每个链接的Follower,开启一个新线程LearnerHandler进行处理
然后针对所有的LearnerHandler,while(true)进行心跳检查ping。针对每次ping结果,针对有ack响应的结果进行vote统计,如果发现超过半数失败,则退出当前的Leader模式,这样又是发起新一轮的选举
Follower处理:
建立socket,链接到Leader server上
发起一次syncWithLeader同步请求,此时Leader会根据当前的最大的zxid对比客户端的zxid,发送DIFF/TRUNC/SNAP指令给follower上,保证follower和leader之间的数据一致性。
同步完成后,就进入while(true){read , process}的工作模式,开始接受Leader的指令并处理
PING : 响应Ack
PROPOSAL : 记录到自己的缓冲队列pendingTxns中,等待sync指令后刷新到zkDataBase中。有点类似2PC阶段事务
COMMIT : 刷新pendingTxns中的对应记录
SYNC : 客户端的同步request请求
Observer处理:
建立socket,链接到Leader server上
发起一次syncWithLeader同步请求
同步完成后,进入while(true){read , process}的工作模式,和Follower有点不同,主要在于其不处理PROPOSAL/COMMIT等2PC阶段。只接受INFORM,Leader告诉最终的更新结果,Observer直接提交到zkDataBase中。