云平台监听及性能优化
- 云平台监听及性能优化
- Monitoring
- 对象
- 资源
- 意义
- 目前大规模部署下遇到的问题
- 优化方案
- 虚拟机的监听
- 6以前版本的监听机制
- 针对上面的问题目前的解决方案
- 改进监测程序
- 处理方法
- 大批量读取数据库的数据
- 处理方法
- 平台代码流程
- 平台初始化过程
关于oVirt云平台的介绍可以参考我的另一篇文章’oVirt架构’
Monitoring
对象:
- 虚拟机,主机,存储域
资源:
- 内存,CPU,磁盘…
意义:
- 以此来观察平台的运行状态,提高平台的稳定性,给某些操作提供必要的数据,例如高可用,负载均衡…
目前大规模部署下遇到的问题:
- 在大规模的情况下,会有很多的数据,监听这些数据包括对数据的搜集,处理,存储起来,这是一个很耗时的过程
- 监听必须是要持续不断的进行,运行在后端,牵动着engine和nodes
优化方案
虚拟机的监听
- 包含的属性:虚拟机状态,异步数据,设备信息,静态数据
3.6以前版本的监听机制
- 基于定时任务polling机制的
- 每三秒钟向每一台主机拉取运行着的虚拟机的信息,然后engine再在获取数据库内保存的信息,对比两者的信息,找出改变的虚拟机,然后保存到数据库,这样静态的数据也是每次都更新,就会多耗资源
- 每5个周期才统计改变的数据, 虚拟机devices另外操作当他们的hash值改变了
- 基于这种机制大规模部署会出现的问题,虚拟机不经常变的属性还是有很多的,这就会导致CPU高消耗和数据库的高负载
针对上面的问题,目前的解决方案:
- 添加一个全局的缓存层(可以减少和数据库的互动操作,但是CPU高消耗没有解决)
- 分发监控流程(解决了CPU的高消耗问题,但是没有减少数据库的高负载问题)
NOTE:以上这两种方案都太复杂了
改进监测程序
静态数据不监听
devices很少的改变,通过hash值判断
每一个周期内都统计改变的数据
异步数据脱离出来进行判断,例如虚拟机的IP就是需要实时报告的,但是虚拟机关机reason就不需要了
处理方法:
减少往数据库里面写的属性,引入了@UnchangeableByVdsm装饰器,用来标志属性不需要从后端返回。在文件VmDynamic.java内
@UnchangeableByVdsm
private String vmHost;
@UnchangeableByVdsm
private Date lastStartTime;
@UnchangeableByVdsm
private Guid runOnVds;
@UnchangeableByVdsm
private String stopReason; //等一系列的属性
将频繁更改的字段移动到统计数据
例如虚拟机的内存cached/buffered/free,频繁改变的属性分到另一个表里面的保存
分离虚拟机devices监听
vdsm层会返回Hash值和engine数据库内保存的上一次的匹配,这样只要保存hash就可以了,当Hash值变了才会去更新表vm_device
大批量读取数据库的数据
- 会导致大量的数据库连接
- 长时间的数据库查询
- 即使没有数据改变也会读数据库
处理方法:
优化代码消除不需要的数据进程
例如根据虚拟机获取numa节点上的cpu,这个就不用通过每台虚拟机都去获取下
Memorization
提供memorization机制反复查询
启用较轻的专用查询
1: narrow down ‘vms’ view
explain analyze select * from vms where …
Planning time: 2.947 ms
Execution time: 765.774 ms
explain analyze select * from vms_monitoring_view where …
Planning time: 0.387 ms
Execution time: 275.600 ms2: query only dynamic data
explain analyze select * from vms_monitoring_view where …
Planning time: 0.405 ms
Execution time: 275.850 ms
explain analyze select * from vm_dynamic where …
Planning time: 0.109 ms
Execution time: 2.703 ms
不同属性分表保存,分表查询
平台代码流程
平台初始化过程
- 创建数据中心->集群->添加主机(创建网络)->附加存储->创建虚拟机
- 这一套动作下来生成了一个资源池,ResourceManager.java,里面包含HostMonistoring/VmMonistoring
- 当往平台加入一台主机的时候,就会建立和这台主机相关的监听机制(主机和主机上虚拟机的监听),在VdsManager.java里面实现的
vmsRefresher = getRefresherFactory().create(this);
vmsRefresher.startMonitoring();
- RefresherFactory.java
private VmStatsRefresher getRefresherForVds(VdsManager vdsManager) {
Version version = vdsManager.getCompatibilityVersion();
VDS vds = vdsManager.getCopyVds();
if (FeatureSupported.jsonProtocol(version)
&& VdsProtocol.STOMP == vds.getProtocol()
&& FeatureSupported.vmStatsEvents(version)
&& FeatureSupported.events(version)) {
return new EventVmStatsRefresher(vdsManager);
}
return new PollListAndAllVmStatsRefresher(vdsManager);
}
- EventVmStatsRefresher.java
public void startMonitoring()里面有allVmStatsOnlyRefresher.startMonitoring(); //文件PollVmStatsRefresher.java
public void startMonitoring() { //启动定时任务poll,
vmsMonitoringJobId =
scheduler.scheduleAFixedDelayJob(
this,
"poll",
new Class[0],
new Object[0],
0,
refreshRate,
TimeUnit.MILLISECONDS);
}
@OnTimerMethodAnnotation("poll")
public void poll() { //定时的去后台获取主机上的虚拟机的信息
if (vdsManager.isMonitoringNeeded()) {
VmsListFetcher fetcher = getVmsFetcher();
long fetchTime = System.nanoTime();
if (fetcher.fetch()) {
getVmsMonitoring(fetcher, fetchTime).perform();
} else {
log.info("Failed to fetch vms info for host '{}' - skipping VMs monitoring.", vdsManager.getVdsName());
}
}
public boolean fetch() {
VDSReturnValue getList =
getResourceManager().runVdsCommand(
VDSCommandType.List,
new VdsIdAndVdsVDSCommandParametersBase(vdsManager.getCopyVds()));
if (getList.getSucceeded()) {
vdsmVms = (Map<Guid, VmInternalData>) getList.getReturnValue();
onFetchVms(); //里面会有filterVms();函数过滤出符合的虚拟机
return true;
} else {
onError();
return false;
}
}
protected void filterVms() {
for (VmInternalData vdsmVm : vdsmVms.values()) {
VM dbVm = dbVms.get(vdsmVm.getVmDynamic().getId());
gatherChangedVms(dbVm, vdsmVm); //通过状态来判断是否更新虚拟机信息 if (statusChanged(dbVm, vdsmVm.getVmDynamic()))
gatherVmsWithChangedDevices(dbVm, vdsmVm); 根据返回的devices相关的信息来判断是否更新虚拟机isDevicesChanged()
}
//这里面的Hash值设置很巧妙
public static boolean isDevicesChanged(VM dbVm, VmInternalData vdsmVm) {
// Update only running VMs
VmDynamic vdsmVmDynamic = vdsmVm.getVmDynamic();
return
vdsmVmDynamic != null &&
vdsmVmDynamic.getStatus() != VMStatus.MigratingTo &&
vdsmVmDynamic.getHash() != null &&
dbVm != null &&
!Objects.equals(dbVm.getHash(), vdsmVmDynamic.getHash());
}
final String hostname = vdsManager.getVdsHostname();
resourceManager.subscribe(new EventSubscriber(hostname + "|*|VM_status|*") { //VM_status和vdsm里面的字段一致,在这里订阅这个消息,当遇到虚拟机属性或状态发生改变时,vdsm层就会发布相关的消息出来,这里就能接受到消息然后进行相关的操作
@Override
public void onSubscribe(Subscription sub) {
subscription = sub;
subscription.request(1);
}
@Override
public void onNext(Map<String, Object> map) {
try {
printEventInDebug(map);
List<Pair<VM, VmInternalData>> changedVms = new ArrayList<>();
List<Pair<VM, VmInternalData>> devicesChangedVms = new ArrayList<>();
convertEvent(changedVms, devicesChangedVms, map);
if (!changedVms.isEmpty() || !devicesChangedVms.isEmpty()) {
getVmsMonitoring(changedVms, devicesChangedVms).perform();
}
} finally {
subscription.request(1);
}
}
}
- 平台已经在大力推广使用STOMP传输协议,
- 当添加主机的时候会创建一系列的相关监听事件