1 服务器端整体概览图

概览图

ServerCnxnFactory:负责与client之间的网络交互,支持NIO(默认)以及Netty

SessionTrackerImpl:会话管理器

DatadirCleanupManager:定期清理存在磁盘上的log文件和snapshot文件

PreRequestProcessor,SyncRequestProcessor,FinalRequestProcessor:请求处理流程,责任链模式

LearnerHandler:Leader与Learner之间的交互

FileTxnSnapLog:存储在磁盘上的日志文件

DataTree:体现在内存中的存储结构

Sessions:Session的相关信息存储

2 单机版服务器启动流程

执行QuorumPeerMain的main方法,其中先创建一个QuorumPeerMain对象

调用initializeAndRun方法

protected void initializeAndRun(String[] args)

throws ConfigException, IOException

{

QuorumPeerConfig config = new QuorumPeerConfig();

if (args.length == 1) {

config.parse(args[0]);

}

// Start and schedule the the purge task

DatadirCleanupManager purgeMgr = new DatadirCleanupManager(config

.getDataDir(), config.getDataLogDir(), config

.getSnapRetainCount(), config.getPurgeInterval());

purgeMgr.start();

if (args.length == 1 && config.servers.size() > 0) {

runFromConfig(config);

} else {

LOG.warn("Either no config or no quorum defined in config, running "

+ " in standalone mode");

// there is only server in the quorum -- run as standalone

ZooKeeperServerMain.main(args);

}

}

2.1

args实际上就是zoo.cfg中的配置,如下

2.2

创建DatadirCleanupManager实例,参数有snapDir,dataLogDir,snapRetainCount(要保存snapshot文件的个数),purgeInterval(定期清理的频率,单位为小时),snapRetainCount与purgeInterval在zoo.cfg中均可以配置

调用DatadirCleanupManager的start方法,里面主要依赖PurgeTask,这也是一个线程,其run方法

PurgeTxnLog的purge方法:

public static void purge(File dataDir, File snapDir, int num) throws IOException {

// snapshot文件保存的数量小于3,抛异常

if (num < 3) {

throw new IllegalArgumentException(COUNT_ERR_MSG);

}

// 根据dataDir和snapDir创建FileTxnSnapLog

FileTxnSnapLog txnLog = new FileTxnSnapLog(dataDir, snapDir);

// 根据给定数量获取最近的文件

List snaps = txnLog.findNRecentSnapshots(num);

// 获取数目

int numSnaps = snaps.size();

if (numSnaps > 0) {

// 第二个参数是最近的snapshot文件

purgeOlderSnapshots(txnLog, snaps.get(numSnaps - 1));

}

}

找最近n个snapshot文件:

public List findNRecentSnapshots(int n) throws IOException {

List files = Util.sortDataDir(snapDir.listFiles(), SNAPSHOT_FILE_PREFIX, false);

int count = 0;

List list = new ArrayList();

for (File f: files) {

if (count == n)

break;

if (Util.getZxidFromName(f.getName(), SNAPSHOT_FILE_PREFIX) != -1) {

count++;

list.add(f);

}

}

return list;

}

purgeOlderSnapshots:

static void purgeOlderSnapshots(FileTxnSnapLog txnLog, File snapShot) {

// 从snapshot文件名中获取zxid

final long leastZxidToBeRetain = Util.getZxidFromName(

snapShot.getName(), PREFIX_SNAPSHOT);

/**

* 我们删除名称中带有zxid且小于leastZxidToBeRetain的所有文件。

* 该规则适用于快照文件和日志文件,

* zxid小于X的日志文件可能包含zxid大于X的事务。

* 更准确的说,命名为log.(X-a)的log文件可能包含比snapshot.X文件更新的事务,

* 如果在该间隔中没有其他以zxid开头即(X-a,X]的日志文件

*/

final Set retainedTxnLogs = new HashSet();

//获取快照日志,其中可能包含比给定zxid更新的事务,这些日志需要保留下来

retainedTxnLogs.addAll(Arrays.asList(txnLog.getSnapshotLogs(leastZxidToBeRetain)));

/**

* Finds all candidates for deletion, which are files with a zxid in their name that is less

* than leastZxidToBeRetain. There's an exception to this rule, as noted above.

*/

class MyFileFilter implements FileFilter{

private final String prefix;

MyFileFilter(String prefix){

this.prefix=prefix;

}

public boolean accept(File f){

if(!f.getName().startsWith(prefix + "."))

return false;

if (retainedTxnLogs.contains(f)) {

return false;

}

long fZxid = Util.getZxidFromName(f.getName(), prefix);

if (fZxid >= leastZxidToBeRetain) {

return false;

}

return true;

}

}

// add all non-excluded log files

List files = new ArrayList();

File[] fileArray = txnLog.getDataDir().listFiles(new MyFileFilter(PREFIX_LOG));

if (fileArray != null) {

files.addAll(Arrays.asList(fileArray));

}

// add all non-excluded snapshot files to the deletion list

fileArray = txnLog.getSnapDir().listFiles(new MyFileFilter(PREFIX_SNAPSHOT));

if (fileArray != null) {

files.addAll(Arrays.asList(fileArray));

}

// remove the old files

for(File f: files)

{

final String msg = "Removing file: "+

DateFormat.getDateTimeInstance().format(f.lastModified())+

"\t"+f.getPath();

LOG.info(msg);

System.out.println(msg);

if(!f.delete()){

System.err.println("Failed to remove "+f.getPath());

}

}

}

先获取到那些需要保留的文件,之后再去删除这些不在保留文件之内的文件。

2.3

判断集群是单机启动还是集群启动,集群走runFromConfig(config),单机走ZooKeeperServerMain.main(args)(其实单机版最终走的是ZooKeeperServerMain的runFromConfig,)

runFromConfig方法:

public void runFromConfig(ServerConfig config) throws IOException {

LOG.info("Starting server");

FileTxnSnapLog txnLog = null;

try {

final ZooKeeperServer zkServer = new ZooKeeperServer();

// Registers shutdown handler which will be used to know the

// server error or shutdown state changes.

final CountDownLatch shutdownLatch = new CountDownLatch(1);

zkServer.registerServerShutdownHandler(

new ZooKeeperServerShutdownHandler(shutdownLatch));

// 构建FileTxnSnapLog对象

txnLog = new FileTxnSnapLog(new File(config.dataLogDir), new File(

config.dataDir));

zkServer.setTxnLogFactory(txnLog);

zkServer.setTickTime(config.tickTime);

zkServer.setMinSessionTimeout(config.minSessionTimeout);

zkServer.setMaxSessionTimeout(config.maxSessionTimeout);

// 构建与client之间的网络通信服务组件

// 这里可以通过zookeeper.serverCnxnFactory配置NIO还是Netty

cnxnFactory = ServerCnxnFactory.createFactory();

cnxnFactory.configure(config.getClientPortAddress(),

config.getMaxClientCnxns());

cnxnFactory.startup(zkServer);

// Watch status of ZooKeeper server. It will do a graceful shutdown

// if the server is not running or hits an internal error.

shutdownLatch.await();

shutdown();

cnxnFactory.join();

if (zkServer.canShutdown()) {

zkServer.shutdown(true);

}

} catch (InterruptedException e) {

// warn, but generally this is ok

LOG.warn("Server interrupted", e);

} finally {

if (txnLog != null) {

txnLog.close();

}

}

}

初始化网络服务组件后,cnxnFactory.startup(zkServer);

这里以默认网络服务组件为例NIOServerCnxnFactory

@Override

public void start() {

// ensure thread is started once and only once

if (thread.getState() == Thread.State.NEW) {

thread.start();

}

}

@Override

public void startup(ZooKeeperServer zks) throws IOException,

InterruptedException {

//调用上面的start方法,实际调用thread的start

//也就调用了该类的run方法,启动网络服务

start();

//这是ZooKeeperServer

setZooKeeperServer(zks);

zks.startdata();

zks.startup();

}

2.4

zks.startdata()方法:

public void startdata()

throws IOException, InterruptedException {

//check to see if zkDb is not null

if (zkDb == null) {

zkDb = new ZKDatabase(this.txnLogFactory);

}

if (!zkDb.isInitialized()) {

//loadData进行初始化

loadData();

}

}

ZKDatabase在内存中维护了zookeeper的sessions, datatree和commit logs集合。 当zookeeper server启动的时候会将txnlogs和snapshots从磁盘读取到内存中

ZKDatabase的loadData()方法:

//如果zkDb已经初始化,设置zxid(内存当中DataTree最新的zxid)

if(zkDb.isInitialized()){

setZxid(zkDb.getDataTreeLastProcessedZxid());

}

else {

// 没有初始化,就loadDataBase

setZxid(zkDb.loadDataBase());

}

public long loadDataBase() throws IOException {

long zxid = snapLog.restore(dataTree, sessionsWithTimeouts, commitProposalPlaybackListener);

initialized = true;

return zxid;

}

loadDataBase()内部调用的是FileTxnSnapLog的restore方法

2.5

zks.startup()方法:

public synchronized void startup() {

if (sessionTracker == null) {

// 创建会话管理器

createSessionTracker();

}

// 启动会话管理器

startSessionTracker();

// 设置请求处理器

setupRequestProcessors();

// 注册jmx

registerJMX();

setState(State.RUNNING);

notifyAll();

}

服务器启动文件,[Zookeeper] 服务端之单机版服务器启动相关推荐

  1. 天龙八部服务器列表文件,TLBB服务端目录文件作用

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 TLBB服务端目录文件作用 \tlbb\Public\Config\ShopTable.txt 元宝商店加东西,最后一行178是卖6级宝石,提供参考 \t ...

  2. 天龙八部服务器列表文件,天龙八部服务端server目录脚本说明.doc

    文档介绍: 天龙八部服务端 server 目录脚本说明天龙八部服务端 Server 目录脚本功能说明: /Server/Config Account.txt 测试帐号/Server/Config Al ...

  3. 天龙八部服务器列表文件,天龙八部服务端Server目录脚本功能说明

    天龙八部服务端Server目录脚本功能说明 本文出处:网游动力作者:本站发布时间:2008-11-06阅读次数: tlbbServerConfigNotifyDate.txt 公告 tlbbServe ...

  4. 天龙八部服务器列表文件,天龙八部服务端目录说明

    大师帮我看下怎么不能启动了. Last login: Mon Jul  5 20:26:46 2010 from 192.168.1.2 [[email protected] ~]# cd /home ...

  5. 非零基础自学Golang 第18章 HTTP编程(下) 18.2 HTTP服务端 18.2.2 启动HTTP服务器 18.2.3 启动HTTPS服务器

    非零基础自学Golang 文章目录 非零基础自学Golang 第18章 HTTP编程(下) 18.2 HTTP服务端 18.2.2 启动HTTP服务器 18.2.3 启动HTTPS服务器 第18章 H ...

  6. 冰狼服务器无响应或无网络链接,冒险岛一键端用不了,很纠结, 服务端里面提示正在启动数据库...

    冒险岛一键端用不了,很纠结, 服务端里面提示正在启动数据库0 正在启动数据库 Error initializing loginserverjava.lang.RuntimeException: [EX ...

  7. 后端代码之服务端 - 项目工程化创建目录启动服务 -讲解篇

    文章目录 前言 一. 目录创建 与 应用启动 A. 步骤如下: B. 具体cmd命令执行流,截图如下:(`部分无效,可忽略`) 二. 查看Express的欢迎页 1. 查看欢迎页的 浏览器url地址: ...

  8. 魔兽世界修改服务器配置文件,worldserver.conf 服务端配置文件说明

    worldserver.conf 这个文件是服务端的配置文件,可以在这里做很多个性化修改 注意:修改这个必须重启服务端才能生效 首先这个文件要使用支持 utf-8 格式的文本编辑器,比如 VS cod ...

  9. 物联网系统上位机源码,含服务器和客户端 物联网服务端程序

    物联网系统上位机源码,含服务器和客户端 物联网服务端程序,可以接受市面上大多数透传数据的DTU登录,以及和DTU双向通讯 程序功能:能分组管理,不同的组别用户只可见自己组别的设备,设备和客户端登录掉线 ...

最新文章

  1. android6.0麦克风权限,android 6.0权限检测以及6.0以下,麦克风、相机权限判断
  2. 阿里云“华北5”落地内蒙古,AI数据大战一触即发
  3. 用户请求队列化_分布式消息队列选型分析
  4. gitlab中文_ASP.NET实战010:Visual Studio使用GitLab详解
  5. 常考数据结构和算法:跳台阶
  6. 2012年寒假•青年基金【修改后发表】
  7. Eclipse开发C/C++之使用技巧小结,写给新手
  8. Lucene系列:(9)搜索结果排序
  9. linux jdk环境变量配置
  10. 【经典回放】多种语言系列数据结构算法:队列(C版)
  11. 统计天数(洛谷-P1567)
  12. MTK 驱动开发(28)--6797平台 TP 移植
  13. 【elasticsearch】block.ClusterBlockException: blocked by: SERVICE_UNAVAILA
  14. 为什么 SQL 程序员也要懂 Python?
  15. 我的世界光影Java优化_我的世界7款超级棒的光影包推荐 让你的世界从此变得真实无比...
  16. 图像处理中调用matlab自带均值滤波、高斯滤波和中值滤波函数的案例以及自编均值滤波的案例。
  17. LayUI使用distpicker.js插件实现三级联动
  18. linux 主机管理平台,Linux虚拟主机管理系统directadmin使用中文教程
  19. 科技爱好者周刊(第 163 期):你的城市有多少张病床?
  20. SQL/ORACLE_基础英语词汇

热门文章

  1. 强化学习6——policy gradient的变种State of the Art
  2. boot入门思想 spring_SpringBoot快速入门
  3. wpf 图表控件_LightningChart为外汇衍生品交易商提供数据可视化图表支持
  4. 三维数据平滑处理_你该如何正确的处理思看科技三维扫描仪得到的数据?
  5. 没有add framework support选项_什么?小型机房没有“线”也能很好的管理机房?
  6. strace 命令详解
  7. HEX、DEC、OCT和BIN的解释
  8. 乐鑫代理启明云端分享|ESP32驱动1.54inch(240*240)彩屏
  9. 0402封装ESD二极管选型
  10. CPU方案简介UIS8190 - LTE CAT.1模块