github开源 欢迎一起维护~~
- 之前说到注册中心的设计,zookeeper中的节点部署如下:
- kafkaAppender初始化向zk进行app节点注册,并写入相关的信息
- kafkaAppender发生异常暂停工作会向app节点写入相关信息,以便监控系统能够实时感知并发送报警
- app正常或者异常退出后,zk中的app临时节点会消失,shutdownhook会正常运行,监控系统能够实时感知并发送报警(这里就需要我们在自定义的log appender中写好相应的hook,防止对接系统无法正常释放资源,项目不要用kill -9 pid,应该使用kill pid)
- zk中有永久节点用来记录app的最近一次部署信息
那么我们只需要监控zk节点的变化,即可知道对接的系统上下线情况,以及内嵌的采集器是否存活,具体代码如下(curator框架和zkclient一起混用):
public class
ScrollChildrenChangeListener
implements PathChildrenCacheListener {
private static final Logger LOGGER = LoggerFactory. getLogger( ScrollChildrenChangeListener. class) ;
private RabbitmqService rabbitmqService ;
private ZkClient zkClient ;
private AppInfoService appInfoService ;
public ScrollChildrenChangeListener(RabbitmqService rabbitmqService , ZkClient zkClient , AppInfoService appInfoService) {
this. rabbitmqService = rabbitmqService ;
this. zkClient = zkClient ;
this. appInfoService = appInfoService ;
}
@Override
public void childEvent(CuratorFramework client , PathChildrenCacheEvent event) throws Exception {
switch (event.getType()) {
case CHILD_ADDED:
PathChildrenCache pathChildrenCache = new PathChildrenCache(client , event.getData().getPath() , true) ;
pathChildrenCache.start(PathChildrenCache.StartMode. POST_INITIALIZED_EVENT) ;
pathChildrenCache.getListenable().addListener( new AppChildrenChangeListener( this. rabbitmqService , this. zkClient , this. appInfoService)) ;
LOGGER.info( "app added: " + event.getData().getPath()) ;
break;
case CHILD_REMOVED:
LOGGER.info( "app removed: " + event.getData().getPath()) ;
break;
}
}
}
private static final Logger LOGGER = LoggerFactory. getLogger( ScrollChildrenChangeListener. class) ;
private RabbitmqService rabbitmqService ;
private ZkClient zkClient ;
private AppInfoService appInfoService ;
public ScrollChildrenChangeListener(RabbitmqService rabbitmqService , ZkClient zkClient , AppInfoService appInfoService) {
this. rabbitmqService = rabbitmqService ;
this. zkClient = zkClient ;
this. appInfoService = appInfoService ;
}
@Override
public void childEvent(CuratorFramework client , PathChildrenCacheEvent event) throws Exception {
switch (event.getType()) {
case CHILD_ADDED:
PathChildrenCache pathChildrenCache = new PathChildrenCache(client , event.getData().getPath() , true) ;
pathChildrenCache.start(PathChildrenCache.StartMode. POST_INITIALIZED_EVENT) ;
pathChildrenCache.getListenable().addListener( new AppChildrenChangeListener( this. rabbitmqService , this. zkClient , this. appInfoService)) ;
LOGGER.info( "app added: " + event.getData().getPath()) ;
break;
case CHILD_REMOVED:
LOGGER.info( "app removed: " + event.getData().getPath()) ;
break;
}
}
}
public class AppChildrenChangeListener
implements PathChildrenCacheListener {
private static final Logger LOGGER = LoggerFactory. getLogger(AppChildrenChangeListener. class) ;
private RabbitmqService rabbitmqService ;
private ZkClient zkClient ;
private AppInfoService appInfoService ;
public AppChildrenChangeListener(RabbitmqService rabbitmqService , ZkClient zkClient , AppInfoService appInfoService) {
this. rabbitmqService = rabbitmqService ;
this. zkClient = zkClient ;
this. appInfoService = appInfoService ;
}
@Override
public void childEvent(CuratorFramework client , PathChildrenCacheEvent event) throws Exception {
String node = Constants. EMPTY_STR ;
String app = Constants. EMPTY_STR ;
String host = Constants. EMPTY_STR ;
String info = Constants. EMPTY_STR ;
String[] datas = null;
switch (event.getType()) {
case CHILD_ADDED:
node = event.getData().getPath() ;
app = this.getApp(node) ;
host = this.getHost(node) ;
if (!CacheService. appHosts.contains(node)) {
datas = this. zkClient.readData(Constants. ROOT_PATH_PERSISTENT + Constants. SLASH + app + Constants. SLASH + host).toString().split(Constants. SEMICOLON) ;
info = this.buildMsg(DateUtil. format( new Date(System. currentTimeMillis()) , DateUtil. YYYYMMDDHHMMSS) , app ,
this.getHost(node) , datas[ 1] , Constants. APP_START) ;
// add to the queue
this. rabbitmqService.sendMessage(info , datas[ 0]) ;
LOGGER.info(info) ;
CacheService. appHosts.add(node) ;
this. appInfoService.add(host , app , Constants. ZK_NODE_TYPE_EPHEMERAL , LogCollectionStatus. RUNNING) ;
}
this. appInfoService.add(host , app , Constants. ZK_NODE_TYPE_PERSISTENT , LogCollectionStatus. HISTORY) ;
break;
case CHILD_REMOVED:
node = event.getData().getPath() ;
app = this.getApp(node) ;
host = this.getHost(node) ;
datas = this. zkClient.readData(Constants. ROOT_PATH_PERSISTENT + Constants. SLASH + app + Constants. SLASH + host).toString().split(Constants. SEMICOLON) ;
info = this.buildMsg(DateUtil. format( new Date(System. currentTimeMillis()) , DateUtil. YYYYMMDDHHMMSS) , app ,
this.getHost(node) , datas[ 1] , Constants. APP_STOP) ;
// add to the queue
this. rabbitmqService.sendMessage(info , datas[ 0]) ;
LOGGER.info(info) ;
if (CacheService. appHosts.contains(node)) {
CacheService. appHosts.remove(node) ;
this. appInfoService.delete(host , app , Constants. ZK_NODE_TYPE_EPHEMERAL) ;
}
break;
case CHILD_UPDATED:
node = event.getData().getPath() ;
datas = this. zkClient.readData(node).toString().split(Constants. SEMICOLON) ;
app = this.getApp(node) ;
host = this.getHost(node) ;
info = this.buildMsg(DateUtil. format( new Date(Long. parseLong(datas[ 0])) , DateUtil. YYYYMMDDHHMMSS) , app ,
this.getHost(node) , datas[ 1] , Constants. APP_APPENDER_STOP) ;
// add to the queue
this. rabbitmqService.sendMessage(info , this. zkClient.readData(Constants. ROOT_PATH_PERSISTENT + Constants. SLASH + app + Constants. SLASH + host).toString().split(Constants. SEMICOLON)[ 0]) ;
LOGGER.info(info) ;
this. appInfoService.update(host , app , Constants. ZK_NODE_TYPE_EPHEMERAL , LogCollectionStatus. STOPPED) ;
break;
}
}
/**
* 根据 node 获取 app
* @param node
* @return
*/
private String getApp(String node) {
String tmp = node.substring( 0 , node.lastIndexOf(Constants. SLASH)) ;
return this.getLast(tmp) ;
}
/**
* 根据 node 获取 host
* @param node
* @return
*/
private String getHost(String node) {
return this.getLast(node) ;
}
/**
* 返回末尾字符串
* @param line
* @return
*/
private String getLast(String line) {
return line.substring(line.lastIndexOf(Constants. SLASH) + 1) ;
}
/**
* 构造报警 msg
* @param time
* @param app
* @param host
* @param deploy
* @param msg
* @return
*/
private String buildMsg(String time , String app , String host , String deploy , String msg) {
AlertDto alertDto = new AlertDto(time , app , host , deploy , msg) ;
return alertDto.toString() ;
}
}
private static final Logger LOGGER = LoggerFactory. getLogger(AppChildrenChangeListener. class) ;
private RabbitmqService rabbitmqService ;
private ZkClient zkClient ;
private AppInfoService appInfoService ;
public AppChildrenChangeListener(RabbitmqService rabbitmqService , ZkClient zkClient , AppInfoService appInfoService) {
this. rabbitmqService = rabbitmqService ;
this. zkClient = zkClient ;
this. appInfoService = appInfoService ;
}
@Override
public void childEvent(CuratorFramework client , PathChildrenCacheEvent event) throws Exception {
String node = Constants. EMPTY_STR ;
String app = Constants. EMPTY_STR ;
String host = Constants. EMPTY_STR ;
String info = Constants. EMPTY_STR ;
String[] datas = null;
switch (event.getType()) {
case CHILD_ADDED:
node = event.getData().getPath() ;
app = this.getApp(node) ;
host = this.getHost(node) ;
if (!CacheService. appHosts.contains(node)) {
datas = this. zkClient.readData(Constants. ROOT_PATH_PERSISTENT + Constants. SLASH + app + Constants. SLASH + host).toString().split(Constants. SEMICOLON) ;
info = this.buildMsg(DateUtil. format( new Date(System. currentTimeMillis()) , DateUtil. YYYYMMDDHHMMSS) , app ,
this.getHost(node) , datas[ 1] , Constants. APP_START) ;
// add to the queue
this. rabbitmqService.sendMessage(info , datas[ 0]) ;
LOGGER.info(info) ;
CacheService. appHosts.add(node) ;
this. appInfoService.add(host , app , Constants. ZK_NODE_TYPE_EPHEMERAL , LogCollectionStatus. RUNNING) ;
}
this. appInfoService.add(host , app , Constants. ZK_NODE_TYPE_PERSISTENT , LogCollectionStatus. HISTORY) ;
break;
case CHILD_REMOVED:
node = event.getData().getPath() ;
app = this.getApp(node) ;
host = this.getHost(node) ;
datas = this. zkClient.readData(Constants. ROOT_PATH_PERSISTENT + Constants. SLASH + app + Constants. SLASH + host).toString().split(Constants. SEMICOLON) ;
info = this.buildMsg(DateUtil. format( new Date(System. currentTimeMillis()) , DateUtil. YYYYMMDDHHMMSS) , app ,
this.getHost(node) , datas[ 1] , Constants. APP_STOP) ;
// add to the queue
this. rabbitmqService.sendMessage(info , datas[ 0]) ;
LOGGER.info(info) ;
if (CacheService. appHosts.contains(node)) {
CacheService. appHosts.remove(node) ;
this. appInfoService.delete(host , app , Constants. ZK_NODE_TYPE_EPHEMERAL) ;
}
break;
case CHILD_UPDATED:
node = event.getData().getPath() ;
datas = this. zkClient.readData(node).toString().split(Constants. SEMICOLON) ;
app = this.getApp(node) ;
host = this.getHost(node) ;
info = this.buildMsg(DateUtil. format( new Date(Long. parseLong(datas[ 0])) , DateUtil. YYYYMMDDHHMMSS) , app ,
this.getHost(node) , datas[ 1] , Constants. APP_APPENDER_STOP) ;
// add to the queue
this. rabbitmqService.sendMessage(info , this. zkClient.readData(Constants. ROOT_PATH_PERSISTENT + Constants. SLASH + app + Constants. SLASH + host).toString().split(Constants. SEMICOLON)[ 0]) ;
LOGGER.info(info) ;
this. appInfoService.update(host , app , Constants. ZK_NODE_TYPE_EPHEMERAL , LogCollectionStatus. STOPPED) ;
break;
}
}
/**
* 根据 node 获取 app
* @param node
* @return
*/
private String getApp(String node) {
String tmp = node.substring( 0 , node.lastIndexOf(Constants. SLASH)) ;
return this.getLast(tmp) ;
}
/**
* 根据 node 获取 host
* @param node
* @return
*/
private String getHost(String node) {
return this.getLast(node) ;
}
/**
* 返回末尾字符串
* @param line
* @return
*/
private String getLast(String line) {
return line.substring(line.lastIndexOf(Constants. SLASH) + 1) ;
}
/**
* 构造报警 msg
* @param time
* @param app
* @param host
* @param deploy
* @param msg
* @return
*/
private String buildMsg(String time , String app , String host , String deploy , String msg) {
AlertDto alertDto = new AlertDto(time , app , host , deploy , msg) ;
return alertDto.toString() ;
}
}
@Service
public class AppInfoService {
@Autowired
private ZkClient zkClient ;
@Autowired
private AppInfoRepository appInfoRepository ;
/**
* 保存 appInfo
* @param host
* @param app
* @param type
* @param logCollectionStatus
*/
public void add(String host , String app , int type , LogCollectionStatus logCollectionStatus) {
AppInfo appInfo = new AppInfo() ;
AppInfoPK appInfoPK = new AppInfoPK(host , app , type) ;
appInfo.setAppInfoPK(appInfoPK) ;
appInfo.setStatus(logCollectionStatus.symbol()) ;
if (logCollectionStatus.symbol().equals(LogCollectionStatus. HISTORY.symbol())) {
appInfo.setDeploy( this.getDeploy(Constants. ROOT_PATH_PERSISTENT + Constants. SLASH + app + Constants. SLASH + host)) ;
} else {
appInfo.setDeploy( this.getDeploy(Constants. ROOT_PATH_EPHEMERAL + Constants. SLASH + app + Constants. SLASH + host)) ;
}
this. appInfoRepository.save(appInfo) ;
}
/**
* 修改记录的收集日志状态
* @param host
* @param app
* @param type
* @param logCollectionStatus
*/
public void update(String host , String app , int type , LogCollectionStatus logCollectionStatus) {
AppInfo appInfo = this. appInfoRepository.findOne( new AppInfoPK(host , app , type)) ;
appInfo.setStatus(logCollectionStatus.symbol()) ;
this. appInfoRepository.save(appInfo) ;
}
/**
* 根据 host 和 app 进行删除
* @param host
* @param app
* @param type
*/
public void delete(String host , String app , int type) {
AppInfo appInfo = this. appInfoRepository.findOne( new AppInfoPK(host , app , type)) ;
if ( null != appInfo) {
this. appInfoRepository.delete(appInfo) ;
}
}
/**
* 删除所有的数据
*/
public void deleteAll() {
this. appInfoRepository.deleteAll() ;
}
/**
* 获取 app 的部署位置
* @param path
* @return
*/
private String getDeploy(String path) {
String data = this. zkClient.readData(path) ;
return data.split(Constants. SEMICOLON)[ 1] ;
}
}
public class AppInfoService {
@Autowired
private ZkClient zkClient ;
@Autowired
private AppInfoRepository appInfoRepository ;
/**
* 保存 appInfo
* @param host
* @param app
* @param type
* @param logCollectionStatus
*/
public void add(String host , String app , int type , LogCollectionStatus logCollectionStatus) {
AppInfo appInfo = new AppInfo() ;
AppInfoPK appInfoPK = new AppInfoPK(host , app , type) ;
appInfo.setAppInfoPK(appInfoPK) ;
appInfo.setStatus(logCollectionStatus.symbol()) ;
if (logCollectionStatus.symbol().equals(LogCollectionStatus. HISTORY.symbol())) {
appInfo.setDeploy( this.getDeploy(Constants. ROOT_PATH_PERSISTENT + Constants. SLASH + app + Constants. SLASH + host)) ;
} else {
appInfo.setDeploy( this.getDeploy(Constants. ROOT_PATH_EPHEMERAL + Constants. SLASH + app + Constants. SLASH + host)) ;
}
this. appInfoRepository.save(appInfo) ;
}
/**
* 修改记录的收集日志状态
* @param host
* @param app
* @param type
* @param logCollectionStatus
*/
public void update(String host , String app , int type , LogCollectionStatus logCollectionStatus) {
AppInfo appInfo = this. appInfoRepository.findOne( new AppInfoPK(host , app , type)) ;
appInfo.setStatus(logCollectionStatus.symbol()) ;
this. appInfoRepository.save(appInfo) ;
}
/**
* 根据 host 和 app 进行删除
* @param host
* @param app
* @param type
*/
public void delete(String host , String app , int type) {
AppInfo appInfo = this. appInfoRepository.findOne( new AppInfoPK(host , app , type)) ;
if ( null != appInfo) {
this. appInfoRepository.delete(appInfo) ;
}
}
/**
* 删除所有的数据
*/
public void deleteAll() {
this. appInfoRepository.deleteAll() ;
}
/**
* 获取 app 的部署位置
* @param path
* @return
*/
private String getDeploy(String path) {
String data = this. zkClient.readData(path) ;
return data.split(Constants. SEMICOLON)[ 1] ;
}
}
*/
@Service
public class AppStatusMonitorService implements InitializingBean {
@Autowired
private CuratorFramework curatorFramework ;
@Autowired
private RabbitmqService rabbitmqService ;
@Autowired
private ZkClient zkClient ;
@Autowired
private AppInfoService appInfoService ;
@Override
public void afterPropertiesSet() throws Exception {
PathChildrenCache pathChildrenCache = new PathChildrenCache( curatorFramework , Constants. ROOT_PATH_EPHEMERAL , true) ;
pathChildrenCache.start(PathChildrenCache.StartMode. POST_INITIALIZED_EVENT) ;
pathChildrenCache.getListenable().addListener( new ScrollChildrenChangeListener( this. rabbitmqService , this. zkClient , this. appInfoService)) ;
}
}
@Service
public class AppStatusMonitorService implements InitializingBean {
@Autowired
private CuratorFramework curatorFramework ;
@Autowired
private RabbitmqService rabbitmqService ;
@Autowired
private ZkClient zkClient ;
@Autowired
private AppInfoService appInfoService ;
@Override
public void afterPropertiesSet() throws Exception {
PathChildrenCache pathChildrenCache = new PathChildrenCache( curatorFramework , Constants. ROOT_PATH_EPHEMERAL , true) ;
pathChildrenCache.start(PathChildrenCache.StartMode. POST_INITIALIZED_EVENT) ;
pathChildrenCache.getListenable().addListener( new ScrollChildrenChangeListener( this. rabbitmqService , this. zkClient , this. appInfoService)) ;
}
}
@Service
public class CacheService implements InitializingBean {
private static final Logger LOGGER = LoggerFactory. getLogger(CacheService. class) ;
public static List<String> appHosts = new ArrayList<String>() ;
@Autowired
private CuratorFramework curatorFramework ;
@Autowired
private AppInfoService appInfoService ;
@Autowired
private ZkClient zkClient ;
@Override
public void afterPropertiesSet() throws Exception {
// 将 mysql 数据进行清空
this. appInfoService.deleteAll() ;
List<String> apps = curatorFramework.getChildren().forPath(Constants. ROOT_PATH_EPHEMERAL) ;
// 启动时获取所有的节点数据 , 写入本地缓存和 mysql
for (String app : apps) {
List<String> hosts = curatorFramework.getChildren().forPath(Constants. ROOT_PATH_EPHEMERAL + Constants. SLASH + app) ;
for (String host : hosts) {
appHosts.add(Constants. ROOT_PATH_EPHEMERAL + Constants. SLASH + app + Constants. SLASH + host) ;
this. appInfoService.add(host , app , Constants. ZK_NODE_TYPE_EPHEMERAL , this.calLogCollectionStatus(app , host)) ;
}
}
apps = curatorFramework.getChildren().forPath(Constants. ROOT_PATH_PERSISTENT) ;
for (String app : apps) {
List<String> hosts = curatorFramework.getChildren().forPath(Constants. ROOT_PATH_PERSISTENT + Constants. SLASH + app) ;
for (String host : hosts) {
this. appInfoService.add(host , app , Constants. ZK_NODE_TYPE_PERSISTENT , LogCollectionStatus. HISTORY) ;
}
}
}
/**
* 根据 app 和 host 计算 LogCollectionStatus
* @param app
* @param host
* @return
*/
private LogCollectionStatus calLogCollectionStatus(String app , String host) {
String[] datas = this. zkClient.readData(Constants. ROOT_PATH_EPHEMERAL + Constants. SLASH + app + Constants. SLASH + host).toString().split(Constants. SEMICOLON) ;
if (datas[ 0].equals(Constants. APPENDER_INIT_DATA)) {
return LogCollectionStatus. RUNNING ;
}
return LogCollectionStatus. STOPPED ;
}
}
public class CacheService implements InitializingBean {
private static final Logger LOGGER = LoggerFactory. getLogger(CacheService. class) ;
public static List<String> appHosts = new ArrayList<String>() ;
@Autowired
private CuratorFramework curatorFramework ;
@Autowired
private AppInfoService appInfoService ;
@Autowired
private ZkClient zkClient ;
@Override
public void afterPropertiesSet() throws Exception {
// 将 mysql 数据进行清空
this. appInfoService.deleteAll() ;
List<String> apps = curatorFramework.getChildren().forPath(Constants. ROOT_PATH_EPHEMERAL) ;
// 启动时获取所有的节点数据 , 写入本地缓存和 mysql
for (String app : apps) {
List<String> hosts = curatorFramework.getChildren().forPath(Constants. ROOT_PATH_EPHEMERAL + Constants. SLASH + app) ;
for (String host : hosts) {
appHosts.add(Constants. ROOT_PATH_EPHEMERAL + Constants. SLASH + app + Constants. SLASH + host) ;
this. appInfoService.add(host , app , Constants. ZK_NODE_TYPE_EPHEMERAL , this.calLogCollectionStatus(app , host)) ;
}
}
apps = curatorFramework.getChildren().forPath(Constants. ROOT_PATH_PERSISTENT) ;
for (String app : apps) {
List<String> hosts = curatorFramework.getChildren().forPath(Constants. ROOT_PATH_PERSISTENT + Constants. SLASH + app) ;
for (String host : hosts) {
this. appInfoService.add(host , app , Constants. ZK_NODE_TYPE_PERSISTENT , LogCollectionStatus. HISTORY) ;
}
}
}
/**
* 根据 app 和 host 计算 LogCollectionStatus
* @param app
* @param host
* @return
*/
private LogCollectionStatus calLogCollectionStatus(String app , String host) {
String[] datas = this. zkClient.readData(Constants. ROOT_PATH_EPHEMERAL + Constants. SLASH + app + Constants. SLASH + host).toString().split(Constants. SEMICOLON) ;
if (datas[ 0].equals(Constants. APPENDER_INIT_DATA)) {
return LogCollectionStatus. RUNNING ;
}
return LogCollectionStatus. STOPPED ;
}
}
代码较为简单,不再赘述,主要就是监听zk节点的变化情况,并且将app和host信息采集进入了mysql(同时本项目进程中缓存了一份用来提高速度)。