云涛名苑2018物业服务满意度调查结果分析

本次调查为本人个人发起,非官方组织,因此参与度较低人数较少,但也有43份问卷完成填写,小区一共400多户也有差不多10%的比例了,可以算是一次抽样调查,基本上可以代表了业主们共同的观点,问卷地址:https://www.wenjuan.in/s/umiqAn/(结果查看:https://www.wenjuan.com/r/b6F7Zn?pid=5a6eb5c3a320fc9c419edbcc&vcode=b612080b039b4e2f055c5ad5ffc05d34),针对每个问题的分析如下:

Q1是填写房间号,没有可以分析的。

Q2表明绝大部分业主都已经入住2年以上,对物业的过往服务情况是有了解和对比的,正是有对比,才有发言权和真实度。刚交付的时候物业管理相对还是比较到位的,现在是有点每况愈下的感觉。

Q3表明大部分业主还是关心业委会的成立进展的,实际是在筹建中,大家也希望业委会成立后能切实维护业主利益,在跟物业公司沟通时有更多的主动权和法律效力。

Q4表明大部分业主还是习惯用电话和去物业中心与物业沟通交流。物业是组建了一个QQ群的,当然后面也有业主反馈说希望物业能建立一个微信群,毕竟当下QQ已经在70~80~90这几代人中不如微信流行了。

 

Q5问了一个比较贴近生活的问题,大部分业主还是了解物业的通知情况的,因为物业通知停水停电信息,一般都是在QQ群,尤其是临时停水停电,所以应该是加了物业的业主沟通QQ群,并且经常打开QQ查看信息的那部分业主会相对容易收到通知。

Q6是车辆管理相关的,绝大部分业主都反馈有乱停车问题,并且还有消防通道被堵住的情况(应该是指11栋前面的消防通道),自从上次10栋业主家失火后,大家对消防通道的畅通情况就比较关注了,消防通道是生命线,必须保证任何情况下都畅通无阻。

Q7是关于公共建筑的用途变更的,大部分业主都不清楚是否有,就算没有吧,毕竟我们也没有掌握真凭实据,当然如果有业主有证据,也可以公布在业主微信群、QQ群,让其他业主也了解下相关情况。或许等业委会成立后,大家应该可以向他们询问相关情况。

Q8是关于保安人员和安保情况的,这点也是大部分业主都对保安人员不太满意,也对小区治安情况不太满意,不过今天早上看到小区保安队已经更换了,据说是外聘的,看来物业也受不了自家招聘的保安了,对新的保安队伍的表现我们拭目以待吧。

Q9是保洁人员和小区卫生环境的,总体来说大部分业主还算满意,尤其是对保洁人员的服务态度,很多业主都单独反馈好评,我本人也感受到了保洁人员的良好态度,每次去地下车库出电梯口,保洁大姐都会主动打招呼致意,卫生情况也算很好。究其原因,我认为还是因为保洁是外聘的队伍,而不是物业自己的,对业主的评价更加重视,我猜测如果有投诉,会扣他们的工资或奖金,而物业公司自己的人员,相关的投诉估计都被压下来了。至于有部分业主反应地下车库有业主遛狗并且随地大小便,这个也不能全怪保洁人员,我亲眼见过几次保洁人员发现有宠物大小便都是立即清理的,毕竟保洁也不是24小时随时清理,要怪也只能怪部分养宠物的业主不道德(当然我也见过有业主用宠物粪便袋清理宠物大小便,也不是全部),但物业本身应该还是可以做更多的事情的,比如贴告示禁止在地下车库遛狗等,加强监控,如发现有此类现象及时制止等。公共区域的蚊虫消杀,也经常在电梯里看到相关的通知,还是定期执行了的。我个人感觉小区整体清洁程度也是可以的。

Q10是绿化相关的,总体也算满意,可能绿化养护的及时性稍差,我个人感觉还是可以的,没发现有大面积枯死情况,草坪也没有疯长,至于说小区商铺前面的那部分草坪,被人车踩踏碾压导致干枯死亡,这部分也只能怪保安、物业不作为,不及时制止导致的,个人感觉与绿化养护人员关系不大。绿化人员应该也是外聘的,所以表现也不差。当然也有个别业主表示,8点之前就有修剪草坪的工人在作业,影响他们休息(与之对比的是8点之前不准装修),这点也可以跟物业沟通反馈,调整作业时间应该问题不大,可能因为我住的楼层比较高,所以没有发现有此类问题。

Q11是维修人员和公共设施维护相关的,大家对维修的及时性和公共设施的维护满意度都很低,我个人也感觉如此,比如电梯、走廊灯等,一般都是等到业主反馈后过一段时间才会去修理,并且还容易再次损坏。而公共设施的维护就更差了,刚开始小区里的儿童游乐设施还可以用,现在已经基本都报废了,小区的长椅、公共区域的桌椅也都报废了,很多业主对此都有很大意见。电梯故障管理的问题就更大了,整个小区才20部左右电梯,但基本上每天都有电梯出故障,并且维修耗时也比较长,短的一两天、长的要好几周,在维修期间也没有相关告示之类的贴出来告知业主故障原因、故障处理方案、故障处理预估时间等,缺乏与业主的沟通,业主也只能每次询问,而客服也只是机械的回复正在处理了,更加造成了业主和物业之间的矛盾。我希望物业能公示设施设备故障的处理流程、预案,并在故障发生后能主动告知业主更多细节,尤其是预计修复时间,能让业主心中有数,而不是一脸懵逼,加重对物业的误解,认为物业不作为。

Q12是关于物业客服的评价,总体来说,客服态度还可以,毕竟是做客服的,专业素养还是有一些的,但是处理投诉问题的结果就不怎么样了,比如我就电话里和去前台投诉过地下车库通道乱停车问题,至今这个现象还是存在,我所看到的处理方式就是,在地下车库拉了2条横幅,提醒不要停在过道,还有就是我在QQ群里还反馈能否在转弯处贴上提示语,这个也贴了,不过貌似也没啥用,有些业主就是不在乎,依然我行我素。而客服多次收到类似投诉,也没有进一步的动作。

Q13这个问题我本意是询问大家对物业的收费服务比如更换、维修业主家的水电设施,或者其他不在物业免费服务范围内的业务的满意程度,但我估计有很多回答该问题的业主都没搞清楚是什么意义,误以为是缴纳物业费后物业提供的免费服务也算收费服务,因此这题就不分析了,毕竟如果不满意物业的收费服务,可以自己动手或者找外面的服务人员处理,简单来说就是选择度比较高,市场调节即可。

 

Q14不交物业费的原因,这个很多人都是说物业服务不到位,当然我也有同感,但这不能作为不交物业费的理由,毕竟如果你只简单的用不交物业费来表达对物业服务不满意的抗议和不满,最终吃亏的还是你自己,最终都是要交的,也就是延迟一段时间而已,买房的时候 有签订物业服务协议的,每个业主肯定都签字同意了的,凭这一点,物业就可以把不交物业费的业主告上法庭,并且违约业主几乎没有胜算,一旦判决败诉,就可能对个人的信用履约情况会产生不良影响(以后贷款、子女从事部分职业等都可能受影响),这在新闻报道里是有很多先例的,并且即使你后续要卖房子,也得先把物业费补齐了才能交接。所以我觉得业主们不积极给物业反应问题,要求物业改进,而是通过不交、缓交物业费来表达抗议,这么做只会便宜物业,让他们可以有不作为的借口(没人反馈我做的不好,就说明我做的挺好的),就算最终换了物业,换之前这段时间还是让物业占了大便宜,而吃亏的还是自己。更合适的办法是,在业委会成立之前,业主们联合起来,把物业做的不到位的事项列出来,统一交给物业解决,如果不给满意答复,就可以据此投票更换物业公司,毕竟业委会早晚都会成立的,物业也不会永远无视业主的诉求而肆意妄为(除非他们想激起民愤,不想干下去了),这也是我组织这次调查的初衷。正好业委会这几天正在进行选举,我本人都业委会的积极作用还是抱有一定的期望的,至少他们的话语权比较大,也更有法律意义,中国已经逐步进入法治社会(虽然还有很多人治的领域),在民事合同相关领域还是比较尊重法律法规的。

至少得让大家了解情况物业哪方面做的不好,也让物业知道自己哪方面做的不好,业主们是有动作的,不是一味忍让的。

Q15这个没啥分析的,各占3分之1,反正肯定不能物业公司自己定。我倾向于市场调节,服务业市场已经非常开放没有垄断壁垒,性价比高的公司就应该得到更多的发展空间。但就怕招标过程有猫腻。

Q16群众的眼睛是雪亮的,做的好就是好,做的不好就是不好,物业收发快递等便民服务确实给业主带来了很多便利(虽然现在小区里有很多快递柜了),卫生绿化这些方面,上面已经分析过,是外聘的保洁绿化公司在做,服务质量更高一些,大家明显都能感觉到,还有好几位邻居在其他里专门填写了保洁人员的服务态度很好,物业监督他们,关联到工资,还是有效果的,而物业本身谁来监督呢?只能是业主了,所以我们要监督起来,积极反馈意见。

Q17不满意的点比较分散,但大头是在小区的外来人员和车辆管理,车库和停车管理这两个大方向,其次就是电梯故障管理了,这个也是非常让邻居们心烦的,毕竟电梯时天天都在用的东西,为啥没排在第一位,我个人感觉是因为小区每个单元都有两部电梯,一般情况下都不会同时出故障,所以还不至于要经常爬楼梯上下楼,最多也就是多等几分钟,很大程度上弱化了故障的影响程度,如果只有一部并且时不时出故障,邻居们就要疯了。目前看起来小区的外来人员和车辆管理基本处于无人管理状态,大门常开门禁失效或谁来都给开门,车辆方面地面停车也是来了就抬杆,随意无序停放,连11栋前面的消防通道都经常被占,而物业却没有任何实质性的动作来制止(最多就是贴一张禁止停车的通知单,没有任何实际作用),还是那句话,消防通道是生命线,必须保证任何时间都不被堵塞。地下车库的门禁也是一直常开的,不管有没有车库出入卡都能随意进出,另外众所周知,射频卡方式的门禁很容易被复制或借用,这也进一步导致地下车库通道乱停车的现象十分严重。要解决上述问题,必须要求物业做到如下几点:

  1. 加强外来人员管理,严格执行无卡登记、门禁刷卡流程,防止推销、诈骗等人员进入小区(清洗油烟机的骗子已经来我家至少3次了),并接受业主的监督和测试(我也希望业主们能理解和自觉遵守,如果有业主违反,邻居们可以进行批评谴责,并支持保安的做法,我也相信绝大部分邻居都是通情达理的)
  2. 加强非机动车停车管理,这点物业已经做了很多事情,至少9栋门口已经很少有电瓶车、自行车乱停放了(当然也跟公安部门的强力推动有很大关系),10栋下面的,如果没有飞线充电并且不影响出行的(比如走道旁边的角落里),可以以劝说为主,如果有占道或者飞线充电的,可以采取强制措施。之前业主们反应电瓶车不好推到地下车库,坡太陡太窄,物业已经改进加宽,太陡的问题因为是开发商建设就这样,不好整改,所以在小区最北面建设了非机动车停车场并安装了充电设施,我记得调查的时候还说要在7栋那边也建一个,有部分业主认为会占用绿化用地没有同意
  3. 加强机动车管理,包含3个部分,地面停车场和地下车库。地面部分,严格限制停车场进入车辆总量(不能超过总停车位数量),并规范停车秩序防止乱停乱放、碾压草坪等行为;地下车库,改进闸机设备,采用更加安全的车牌识别方案替换射频卡方案,一个车位同时只能有一辆车进入车库(多辆车的家庭要么买多个车位、要么租赁车位,要么只能同时进入购买或租赁的车位数量相等的车辆),非同时进入的不限制车辆牌号(比如只有1个车位但有2辆车,可以轮换进入,但不能同时都在地下车库停放),这么做可以提高地下车库的租赁比例,对物业没有坏处(当前的情况是,很多空着的租赁车位,但就是没人租,都想免费停车),当然这么做的前提是得保证闸机不能常开,只能识别通过的车辆进入;第3个部分是地下车库里泽园楼饭店购买的车位,我个人认为11栋地下车库出口开放就是因为这部分车位,物业的理由是一个出口不够用(我是没发现),我的问题是,物业是如何管理这部分车位的?怎么做到只允许泽园楼的顾客按需停放,而不会放入其他无关车辆?如果物业不加甄别,那就算更新了车牌识别闸机,也仍然不能避免地下车库无车位车辆的乱停放问题(我说我是来泽园楼吃饭的,保安敢不放我下车库?下了车库我还不是想停哪停哪?反正停多久都不收费,停哪里都没人管),我个人认为超时收费方案是个不错的选择(免费停放几个小时,或者只要不过夜都不收费,一旦过夜了就收费),就看物业愿不愿意做了
  4. 加强电梯故障管理,电梯出现故障,我个人认为大部分情况都不是物业的错,电梯质量不好,也只能怪开发商(我买房的时候就知道这个牌子的电梯不怎么样,因此还问过售楼员,他肯定说还可以的,但毕竟也没啥好说的,谁让咱明知道用的这个电梯的牌子还要买这个小区呢?)。但这不能说物业就可以不管不顾,我认为物业能做的就是在电梯出现故障的时候,及时联系维修人员进行处理,并督促尽快修复,另外就是及时张贴相关进展情况通知,毕竟有些故障不是一时半会能修好的。我建议的故障处理流程如下:1)定期巡检(这部分是电梯维护公司在做),2)24小时接受业主故障反馈(这部分有消控中心24小时值班),3)故障后及时通知维修人员(这部分对物业来说也没啥成本),4)与维修人员沟通故障情况和预估修复时间(这个也不难做到),5)及时张贴故障情况通报(包括故障情况、维修方案、预计修复时间等),让业主做到心中有数,减少与物业的沟通成本,也可在很大程度上缓解业主的焦虑情绪和抵触情绪,6)维修中有新的情况需要说明的,也建议及时更新通报(比如备件到货延期、发现新的故障等导致的预计修复时间后延)。

Q18这个问题表明大家都不知道该去哪投诉,很多人选了找业委会,但我们小区业委会还没成立,所以这部分人也可以算作是投诉无门那部分,我这边建议可以先找物业公司领导,如果找不到或者不给解决,可以投诉到中粮地产物业杭州分公司,然后继续投诉到中粮地产物业的深圳总公司,再不行可以投诉到市长热线、1818黄金眼等,最终方案是找律师起诉物业公司。我也专门网上搜索了中粮物业杭州分公司的联系方式:0571-85317296(本人未核验),非官方网址:http://hzzhongl.5858.com/contact/,中粮地产集团联系方式:集团呼叫中心电话0755-23999000(本人未核验),中粮地产集团深圳物业管理有限公司联系电话0755-23999114(本人未核验),官方网址:http://www.cofco-property.com/category.aspx?NodeID=18(本人已在工信部域名备案系统核验)。

Q19我挑选了杭州市面上声誉比较好的几家物业公司,大部分邻居还是比较相信这些公司的,把其他选项排第一的很少。

Q20大部分邻居还是可以接受更换物业可能导致物业费上涨的情况的,大家都想有好的服务,也有极个别的不能接受,估计是认为当前的物业费已经比较高,不能再涨价了,其实如果已经比较高,那么更换物业公司一般也不会涨价的。

Q20、21这两个问题可以归位一类来分析,这两个问题里面反馈的很多问题在上面已经分析过了,我大概整理了下,主要包含如下几类问题(按反馈数量排序):

  1. 门禁、保安、外来人员管理
  2. 电梯问题
  3. 乱停车
  4. 监控问题(数量不够、有死角)
  5. 公共设施维护
  6. 其他(顶楼漏水、楼顶种植蔬菜等、小区内烧纸、楼梯口杂物堆放、房屋质量等等)非共性问题

除了第6项,其他几项我都会整理好改进建议,交给物业处理。

 

keystone revocation event (part)

问题症状

在虚拟机里部署OpenStack环境,遇到一个问题,openstack token issue可以正常生成token,但nova list等命令都报401错误,用curl GET请求验证生成的token也都401错误。

解决方法先讲下,最终发现是因为虚拟机的时间不同步导致的,用ntpdate命令同步下时间之后就可以了。虚拟机时间不同步,应该是做快照过程中pause虚拟机导致其时间停止,从而发生时间延后,因为延后的时间比较长,有好几个小时,所以才导致这个问题。

分析过程

keystone日志看到如下告警:

但明明是刚生成的token,怎么会不可用?

直接加断点调试,调到最后发现token invalid的原因在:

头一次听说还要检查token的生成时间,以前看老版本keystone代码,貌似只有对expires_at过期时间的检查。

继续看为啥要检查生成时间,找到了revoke event,在更新用户、revoke token等操作过程中就会执行相关检查,event的注册代码:

以revoke token为例说明相关流程:

token内容类似(有audit_ids,但没看到audit_chain_id):

数据库更新记录:

 

再以更新用户为例:

之后执行注册好的回调:

之后就与上面的revoke token流程类似了,数据库更新记录:

 

补充知识

为啥要有revoke流程?(以下内容为个人猜测,未经验证)

之前用uuid格式的token,都存在token表里面,有个valid字段标识是否可用,删掉或者更新用户导致失效的,就把这个字段改成0,表示已失效,但是fernet格式token没有数据库记录,没办法做这种操作,只能改为把revoke相关记录保存在单独的表中,也就是revocation_event表。

这只是revocation event相关流程的一部分,所以本文的标题加了part,其他部分还没研究,等后面有机会看明白了再补充。

 

neutron resource notifications

对neutron各种资源操作时,如果配置了oslo_messaging_notifications的dirver,如下所示:

则会发送消息到Queue notifications.info,例如更新port属性:

neutron-server日志可以看到(需要打开debug级别):

消息队列中信息为:

加入断点调试,bt看调用栈如下:

找到发送notification的位置:

上面的self._resource就是neutron的资源之一,如network、subnet、port、router等(也可以是各种extension资源如vpnaas、lbaas、fwaas等)。

发送notification使用的是oslo.messaging库,因为功能单一,所以文档比较简单,有需要可以考虑使用:https://docs.openstack.org/oslo.messaging/latest/

nova extension api原理与实现

注意:新版本已经移除在主流程之前插入自定义扩展api的功能,但在主流程之后加扩展继续保留,参考:https://review.openstack.org/#/c/332436/(remove support for legacy v2 generator extensions),去掉的原因在nova.api.openstack.wsgi.Resource#pre_process_extensions方法上面的注释里有写,说是nova里面已经没有api在用这个功能了,但我还要用啊:<。后面要升级版本的话,在主流程之前做操作只能采用在源码上添加装饰器的方式了,虽然恶心了点,但至少不用在主流程里面插入代码。下面是正题:


这几天要重构一个功能,系统盘的配额管理,之前是在web后端实现的,没有写在nova里,主要是为了减少对社区代码的侵入,对OpenStack原版无代码侵入是我当前实现产品功能的首要条件,目前看来基本算是实现了的,当前我们VisionStack产品开发的这么多功能,只有在线扩容云主机的代码还在nova里面,这个后续也考虑移出来(除了设置maxcpu和maxmemory这两个xml参数的代码目前没想到好办法移出来,其他操作代码都考虑移走)。

这次的系统盘配额功能,需要改到nova代码里,否则用命令行创建、删除云主机,配额就不准了。

即使是要加代码到nova,也要尽量做到不改动主流程,做到插件化。幸好nova支持扩展api,nova show接口返回keypairs等额外信息就是通过这种方式实现的,而我们要做到在API主流程之前执行配额检查流程(只检查不保存usage,usage直接统计instances表,符合官方新版本的配额管理逻辑,配额管理功能介绍可参考之前的这篇文章,还有这篇)。

老版本的扩展api很好实现,新版本更简单,并且改动也很小,只不过之前一直没搞清楚实现的原理,这次同事在开发的时候,顺便让她研究了下原理,当然还是靠田田专家指点的入口在哪(虽然田田专家已经跳出云计算OpenStack的坑了,但H版本的OpenStack代码居然还保存在他的博客服务器上,肯定是真爱粉)。

下面的源码部分是根据同事的实现截取的其中一部分,实现原理分析也是参考她整理的。

实现

 

原理

大概介绍下,反正已经被删掉了,代码位置在nova.api.openstack.wsgi.Resource#_process_stack,里面调用了nova.api.openstack.wsgi.Resource#pre_process_extensions,这个方法里会遍历所有包含generator的extension,并执行,之后才执行到主流程nova.api.openstack.wsgi.Resource#dispatch,最后执行nova.api.openstack.wsgi.Resource#post_process_extensions,主流程之后的extension。

 

云主机创建、删除、关机、重启过程ovs tap网卡相关流程

写这篇的起因是前段时间同事处理了一个打开基于ovs的安全组功能后,重启云主机后ovs流表刷新太慢导致云主机网络不通的问题,这个问题最终定位是neutron已经修复的bug:https://bugs.launchpad.net/neutron/+bug/1645655(没有backport到M版本),但由于对整个云主机tap网卡的创建、清理生命周期流程不清楚,所以走了一些弯路,因此决定整体分析下相关流程。

nova相关流程

基于nova Mitaka版本源码

创建云主机

创建云主机的整个nova流程比较复杂,要全部介绍的话得把nova代码翻一遍了,这里只描述跟libvirt相关的部分。

之前创建云主机整理的流程图(基于ceph系统盘),很多细节没考虑比如nova-conductor、neutron、MQ、DB等,供参考吧:

 

nova准备好云主机启动所需的全部资源后,就调用libvirt接口(通过libvirt-python api调用C库最后转到libvirtd),正式进入libvirt的create流程:

重启云主机

重启分为两种类型,soft和hard,区别是soft调用的libvirt接口是virDomainShutdownFlags+virDomainCreateWithFlags(virsh命令对应shutdown+start),hard是virDomainDestroyFlags+virDomainCreateWithFlags(virsh命令对应destroy+start)。

这里仅分析soft类型,hard类似:

删除过程主要是destroy并清理资源,就不多介绍了。

上述流程分析可以看到,nova里面其实是不管理tap设备的,只是通过查询neutron接口,找到云主机上绑定的port信息,用来生成libvirt所需的xml文件,tap设备的生命周期管理交给libvirt维护。

libvirt相关流程

基于libvirt v3.2.0版本源码

nova创建、重启过程中的启动过程,类似virsh start vm,会执行add-port命令,libvirtd的debug日志如下:

gdb debug调用栈如下,流程比较清晰,没有回调之类的,因此不再分析:

 

nova删除、关机、重启过程中的关机流程,类似virsh shutdown/destroy vm(shutdown的话,还分为使用qemu guest agent关机和使用ACPI接口关机两种,优先使用前一种),会删除ovs tap设备执行del-port命令,libvirtd的debug日志如下:

调用栈如下:

qemuProcessEventHandler发现qemu monitor退出,执行processMonitorEOFEvent,qemuProcessEventHandler为回调函数,负责处理qemu进程状态变更事件,回调函数的流程一般分为注册和执行两部分,

  • 注册流程:libvirtd.c:main–>libvirtd.c:daemonInitialize(VIR_DAEMON_LOAD_MODULE(qemuRegister, “qemu”))–>src\qemu\qemu_driver.c:qemuRegister–>libvirt.c:virRegisterStateDriver(完成注册);
  • 执行流程:main–>daemonStateInit–>daemonRunStateInit–>virStateInitialize–>qemuStateInitialize(qemu_driver->workerPool = virThreadPoolNew(0, 1, 0, qemuProcessEventHandler, qemu_driver))(遍历所有注册的state driver并执行完成初始化调用)

processMonitorEOFEvent事件回调函数的处理流程的另一个分支是结束qemu进程,libvirt发现qemu monitor socket关闭就会kill qemu主进程(monitor是libvirtd跟qemu进程的通信通道,通道断了libvirtd就无法控制qemu进程了,也就无法响应用户的各种查询、热插拔等操作,因此libvirtd选择杀死qemu进程,一了百了,不留后患),正常情况下都是qemu进程退出导致的monitor socket关闭,所以这种情况下会打日志“2018-01-08 07:38:18.427+0000: 1560: debug : qemuProcessKill:5897 : VM ‘instance-0000000e’ not active”,提示vm已关机,return 0返回不执行任何操作;异常退出情况下会kill掉qemu进程:

gdb调试调用栈如下:

 

 

调用qemu monitor回调,shutdown/destroy时执行(发现qemu monitor服务退出调用eofNotify,发现异常调用errorNotify,其他monitor事件则调用对应的回调,比如qemu进程发送的SHUTDOWN事件会调用qemuMonitorJSONHandleShutdown回调,):

上面是destroy操作加的断点调试信息输出。qemuMonitorJSONHandleShutdown会调用注册好的关机事件回调,src\qemu\qemu_monitor_json.c:

src\qemu\qemu_monitor.c(最终调用到mon->cb的domainShutdown回调函数):

 

注册qemu monitor回调过程是在创建vm时执行的,如domainShutdown的回调是qemuProcessHandleShutdown:

全部回调定义在src\qemu\qemu_process.c:

qemu事件处理方法定义在src\qemu\qemu_monitor_json.c:

 

qemu事件定义,在qemu源码的qapi/run-state.json文件中,具体的事件发送流程还没分析,应该是封装好之后通过monitor socket传递的,类似qemu-guest-agent的命令结果传递流程:

 

Centos7 libvirtd gdb调试

简单描述下,有两种方法,一种是通过yum安装debuginfo包,好处是方便快捷,执行 yum install libvirt-debuginfo 即可,但是编译优化没关导致单步调试有些地方跟源码对应不起来,还有就是变量经常被优化掉看不到具体的值,我上面为了方便采用的这种方式。debuginfo的源一般没有镜像,直接使用官方的:

另外一种是自己从编译debug二进制,推荐第二种方式,但是编译依赖有点多,参考:https://libvirt.org/compiling.html

之前记录的debian7环境下老版本libvirt编译方法(应该是1.1.4版本的),可以参考依赖包和编译步骤:

apt-get install gcc  make pkg-config libxml2-dev libgnutls-dev libdevmapper-dev python-dev libnl-dev libyajl-dev libpciaccess-dev build-essential libhal-dev libudev-dev libtool(–with-hal=yes –with-udev=yes用到)
后面这两个用来解决这个问题:sudo virsh nodedev-list
error: Failed to count node devices
error: this function is not supported by the connection driver: virNodeNumOfDevices
./configure –prefix=/usr –libdir=/usr/lib –localstatedir=/var –sysconfdir=/etc –with-hal=yes –with-udev=yes
./configure –prefix=/usr –libdir=/usr/lib –localstatedir=/var –sysconfdir=/etc –with-selinux
######error: failed to get the hypervisor version
######error: internal error Cannot find suitable emulator for x86_64
解决方法:安装libyajl-dev之后重新./configure,make,make install
libvirt-1.1.4编译:
make报错:aclocal-1.13: command not found
解决方法:执行./autogen.sh –system(autoreconf),然后make

neutron相关流程

基于neutron Mitaka版本源码,VLAN type driver+ovs mechanism driver,ovs安全组未开启(所以也没有相关流表的操作)。

主要分析tap设备插入、删除操作后,neutron-openvswitch-agent都做了哪些事情。

在不清楚代码流程的情况下,翻日志是最快的方式,云主机启动tap设备插入操作的neutron-openvswitch-agent debug日志:

从日志可以简单分析出,ovs agent是通过注册ovsdb的回调发现ofport的insert操作的,也就是add-port。之后的流程就是该怎么做怎么做了。

云主机关机tap设备删除操作的neutron-openvswitch-agent debug日志:

 

代码流程分析(neutron-openvswitch-agent启动流程可参考之前写的这篇文章):

start:

使用subprocess.Popen创建进程,通过neutron-rootwrap执行ovsdb monitor命令,然后用eventlet协程执行进程标准输出和标准错误的监听任务:

ovsdb-client monitor功能验证:

参考资料:

 

ovsdb monitor的流程已经分析完了,下面要看下监听到有port变更之后的处理流程,主要是在rpc_loop方法里面进行的:

检查到ovsdb有新增或者删除的port就继续处理,当然条件有好几个,看日志输出可以发现每秒都会执行一次 LOG.debug("Agent rpc_loop - iteration:%d started", self.iter_num) ,但并不是每次都执行 LOG.debug("Agent rpc_loop - iteration:%(iter_num)d - starting polling. Elapsed:%(elapsed).3f", {'iter_num': self.iter_num, 'elapsed': time.time() - start}) ,只有端口变更才会执行。

process_port_info先获取所有port插入、删除事件,然后调用process_ports_events进行处理:

process_ports_events只是分析下哪些port被添加了、哪些port被删除了,然后返回给port_info,并没有执行实际的流表操作,经过调试流表操作是在下面的几个方法里面执行的。

nova start开机流程(neutron.plugins.ml2.drivers.openvswitch.agent.ovs_neutron_agent.OVSNeutronAgent#_bind_devices执行流表添加操作):

neutron-openvswitch-agent流表操作相关命令行日志:

nova stop关机流程(neutron.plugins.ml2.drivers.openvswitch.agent.ovs_neutron_agent.OVSNeutronAgent#update_stale_ofport_rules方法里面执行流表删除操作):

关机流程的日志就不贴了。

另外上面流表内容我现在也只有个模糊的概念,后面会把每条表项的意义搞清楚,这个会专门写一篇文章。

sqlalchemy在nova中的应用浅析

sqlalchemy介绍

sqlalchemy是一个python ORM框架,使用它的项目很多,官方网站有列出来一部分:http://www.sqlalchemy.org/organizations.html

python作为流行编程语言,开源的ORM框架有很多,这里有一篇对比文档:https://www.pythoncentral.io/sqlalchemy-vs-orms/

对sqlalchemy的个人理解(仅局限于看了一部分入门文档和官方文档,并对比了一部分OpenStack项目和云容科技项目的具体实现,所以并不一定准确),它是python里比较流行的企业级ORM框架,功能全面、性能优良,受到了开发人员的喜爱,也获得了DBA的认可。

它可以通过ORM将一张数据库表映射成一个python对象(一般为class,表的列映射到attributes),之后操作class的attributes就可以实现操作数据库表的字段的目的,对开发人员屏蔽了复杂的数据库裸sql语句,更符合python语言使用者的编码习惯,而且对于不熟悉sql语句的开发人员来说,它还可以做更多性能方面的优化工作。它支持多种数据库后端,比如SQLite, Postgresql, MySQL, Oracle, MS-SQL等,便于后端数据库的切换。它还能配合数据库版本管理工具、数据迁移工具完成数据库表结构的升级、回退工作,让软件版本发布和数据库表结构变更工作集成一起(很多公司是软件由开发部门发布,由sa维护,数据库结构由dba维护,有可能出现程序和数据库变更不一致的情况,而如果集成在程序中,可以全部交给sa维护,在升级程序的后执行一次数据库升级命令即可),防止二者脱钩引起的程序运行异常。

sqlalchemy也不是完美无缺的,我个人认为它最大的问题在于学习曲线比较陡峭,看官方文档就能发现内容比较多,要深入理解并熟练掌握它需要花费一定的时间和一定的实际项目使用,否则很难精通。当然,掌握它的前提是对关系型数据库的原理和使用有一定的了解或者比较熟悉,否则很难精通。我对关系型数据库的理解很浅,甚至可以说入门级都不到,只是会用它的一些简单功能。后续这块也要补上来。所以这篇文章也只能是浅析。

sqlalchemy包含两种架构或者两大模块,ORM和Core(官方全称是SQL Expression Language),前者属于高级抽象方式,后者属于较底层的方式,跟数据库类型强依赖,可移植性比较差。两者的用法有一定的差异,适用场景也不太一样,但整体思路是能用ORM就不要用Core,http://docs.sqlalchemy.org/en/latest/index.html,官方文档区分了两个部分。

In contrast to the ORM’s domain-centric mode of usage, the SQL Expression Language provides a schema-centric usage paradigm.

sqlalchemy相关教程和文档

sqlalchemy在nova中的应用

基于Mitaka版本nova代码进行分析

model

以Service和Instance为例:

BASE:sqlalchemy的ORM base,所有model都应该继承它, from sqlalchemy.ext.declarative import declarative_base  BASE = declarative_base() ,每个介绍sqlalchemy的教程或者文档的示例代码里都能看到它的身影(注意它仅用在ORM模式下,Core模式下不需要),参考:http://docs.sqlalchemy.org/en/latest/orm/mapping_styles.html#declarative-mapping

NovaBase:继承oslo.db的通用基类,重写了__copy__方法,用来在将ORM对象赋值给其他python对象的时候解除与数据库的联系,脱离原有session,保证所有ORM对象中的数据都刷新到数据库,禁用延时加载(获取属性时才从数据库读取出来),如果不这么做就不能安全的把ORM对象赋值给其他变量,注意:前面这些是根据代码注释的个人猜测,仅供参考,并未实际测试验证。

models是oslo.db的模块,models.ModelBase,实现基本crud方法,models.SoftDeleteMixin,实现软删除功能(标记为deleted但并不清理记录);models.TimestampMixin,实现create_at、update_at字段更新功能,参考:http://blog.csdn.net/Bill_Xiang_/article/details/78592389http://blog.csdn.net/happyAnger6/article/details/54772731

nova的mapping方式是Declarative Mapping,官方文档参考上面的BASE类的参考链接。

__tablename__:ORM class对应的数据库表名称;__table_args__:数据库表的一些参数配置,比如索引、约束条件等;

Column,对应数据库表的列:http://docs.sqlalchemy.org/en/latest/core/metadata.html#sqlalchemy.schema.Column

relationship:建立表之间的联系,一对一、一对多、多对一、多对多,参考:http://docs.sqlalchemy.org/en/latest/orm/relationships.html

http://www.cnblogs.com/mrchige/p/6389588.html

backref:是relationship的简化写法,正常要建立表之间的联系,要在两张表的mapping class里面各写一个relationship(),然后用back_populates 指定关联的另外一方的字段名,而使用backref之后,就可以只在一个mapping class里面添加relationship。参考:http://docs.sqlalchemy.org/en/latest/orm/backref.html

uselist:用来标记一对一或者一对多,一对一设置为False,一对多设置为True,也比较容易理解,多了就用list,示例代码http://docs.sqlalchemy.org/en/latest/orm/basic_relationships.html#relationships-one-to-one

primaryjoin:设置表的关联条件,http://docs.sqlalchemy.org/en/latest/orm/join_conditions.html

foreign_keys:外键约束,上面代码里Service的instance relationship的外键host,应该是指instance的host字段受service的host字段约束,参考链接跟上面一样。

query&session

用法说明: http://docs.sqlalchemy.org/en/latest/orm/tutorial.html#creating-a-session

context.session的由来:

首先看下context的由来,可以参考之前的一篇文章:Keystone认证和授权流程分析,里面有提到token验证流程,稍微提及了context的由来, nova.api.auth.NovaKeystoneContext ,然后返回的是 nova.context.RequestContext ,分析这个class发现并没有session的初始化代码,但肯定是在这里初始化的session,因为没有别的地方了,看到了class的装饰器 @enginefacade.transaction_context_provider ,于是继续分析相关代码,确实是在这里添加的session属性:https://github.com/openstack/oslo.db/blob/ea1ec64274475465f35d68b93dc95b643a51830a/oslo_db/sqlalchemy/enginefacade.py#L1101-L1102

update/insert/delete

这部分代码跟上面的查询比较类似,就不一一贴代码流程了,只给出入口:

  • insert:nova.objects.instance.Instance#create
  • delete:nova.objects.instance.Instance#destroy
  • update:nova.objects.instance.Instance#save

API DB

API DB models:nova/db/sqlalchemy/api_models.py

由于我们没有启用Cells,其他几个表都是空的,目前只看到RequestSpec(对应数据库中request_specs表)这个表里面有数据库,记录的是nova-api传递给nova-scheduler的参数,目前看起来意义不大。

需要注意的是,unshelve的时候,会从request_specs这个表的spec字段中获取原始的availability-zone信息,用做解封存云主机时指定的az,所以如果原来的az被删除了,会导致unshelve失败,即使你修改了instances表里面该云主机的az记录,也有这个问题(原因很明显,unshelve过程中读取的是nova_api db request_specs表里面的instance的az,而不是nova db的instances表的az)。

看了下相关提交的commit message和bp,这个nova_api db,就是专门给cells用的,暂时用不到就先不分析了。部分参考资料:

版本管理

nova-manage db {sync, version}

这篇文章写的非常赞,大家直接看它就行了:OpenStack数据库版本控制工具简介

读写分离

nova已经实现了数据库主从读写分离,类似定时任务或者其他查询类请求都可以走slave connection(读从库),从而减轻主库的压力。

配置方法:

搜了下代码,貌似M版本只是修改了部分定时任务的数据库查询请求,master版本(Pike之后Queens之前)好像也没改动多少。

如果没有配置slave_connection,应该是继续使用connection,否则像我们只用connection一个配置就乱套了。

具体实现读写分离这部分功能的代码应该是在oslo.db里面,参考:Use the new enginefacade from oslo_db,以及相关源码,这部分没具体分析。

nova-conductor

为了提升数据库安全性,所有数据库查询操作都改为走nova-conductor服务,在此之前是每个服务各自连接到数据库的,也就意味着每个部署了nova服务(并且需要连接数据库)的节点,都需要被授权访问数据库,可维护性和安全性都比较差(每次扩容节点都要修改数据库授权,每个节点都要配置数据库账户),所以社区增加了nova-conductor服务,集中处理数据库相关操作,通过MQ建立起需要查询数据库的服务和nova-conductor之间的联系(nova-api服务除外,它是直接访问数据库的,不走nova-conductor,因此一般把nova-conductor和nova-api部署在控制节点),这当然牺牲了一部分性能。现在conductor的功能已经越来越完善,比如节点调度相关任务的封装执行(跟nova-scheduler打交道)也都是在nova-conductor里面做的。

这部分也不多做介绍,参考:

sqlalchemy在云容科技的应用

云容科技为了提升云平台性能,也引入了自己的数据库,通过trigger同步OpenStack数据库相关表到自己的库,之后使用sqlalchemy的Core模块进行映射查询,之后对web服务提供查询API,无状态模式可以水平扩容,大大提升了查询响应速度,直观体现为VisionStack云平台web页面的用户响应时间比OpenStack原生horizon快很多(绝大部分页面的后台数据返回时间在毫秒级),用户体验得到了极大改善。

涉及到公司内部代码资产,这里就不分析代码了。

oslo-config-generator和老版本的示例配置生成脚本

基于老版本自己改写的一个sample文件生成脚本

nova老版本(我之前用的是H版本)的nova.conf.sample文件生成使用的是一个shell脚本和几个python脚本,其中python脚本又依赖了common目录下的几个py文件,我这边改写了一下,把依赖提取到统一的py文件里面,形成了一个通用的sample文件生成脚本,可以继续用在基于oslo.config库进行配置管理的代码项目中,但有一个缺点,就是使用到的第三方库比如oslo.log,它也用到了oslo.config管理配置,我的这个脚本不能把里面的配置生成出来(debug=True这种配置就丢了),也懒得改了。

代码在这里:https://github.com/aspirer/scripts/tree/master/generate_sample

为啥要写这个,原因就是折腾了好久的oslo-config-generator都没折腾好,配置模板的内容一直为空,不过后来同事又折腾了一次,参考OpenStack senlin项目,总算折腾好了,下面会介绍问题出在哪里。

oslo-config-generator

参考:https://docs.openstack.org/oslo.config/latest/cli/generator.html

之前一直生成不成功,没有内容,是因为没有实现list_opts方法,貌似之前看官方文档的时候没看到这段,也可能是我忽视了。

也可以用yield来替代return的list,多个opt的话就写多行(参考的senlin项目):

另外还需要注意namespace问题,namespace是用来指定你的list_opts的路径的,一个项目可以有多个namespace,也可以只有一个,看你怎么实现的配置管理了(所有配置项都放在一个py文件里就一个namespace就够了,分开放可能要多个),可以配置在setup.cfg或setup.py的entry_points里面,具体参考官方文档就行了,使用命令生成的时候注意加上所有的namespace,或者加上oslo-config-generator的namespace配置文件。

另外还有一个问题要提示一下,虽然我们实验成功了,但发现它对中文配置项的支持不太友好,举例,两个模块里面定义了两个类似的StrOpt配置项,default、help都有中文(name是英文),生成的配置示例文件中,一个模块的中文配置的default、help都可以正常生成,但另外一个死活不行,把能生成的配置的default和help拷贝到有问题的配置项那里,还是一样无法生成,报编码错误,因此只能继续使用我上面那个改写的脚本,那个是都可以生成的。

写给儿子们<15>

今天小宝半岁,小宝是个很好很乖的小宝,同龄的小宝贝们都没有你乖,就傍晚离不开妈妈,当然爸爸也可以,不然就泪流满面

这段时间俩儿子变化挺大,大儿子懂事了很多,还能帮助妈妈带弟弟,就是早起穿衣服比较磨叽,太贪玩,不过自己刷牙洗脸很熟练了

老师也说中午午睡完起床很慢,扣子扣的不熟练

大儿子懂了很多东西,都不知道怎么学到的

大儿子还是一样贪吃,见到想吃的东西就走不动路,可惜就是吃不胖

小儿子今天体检已经快8公斤了,高66cm,白白胖胖人见人爱

 

小儿子半岁,爸爸在新公司也半年了,时间过的很快,在新公司里还不错,想学什么就可以抽空学,空余时间也相对多一些,爸爸把之前没学过的、学的不太深入的地方,很多都补了一遍,搞清楚之前困惑很久的东西,这种幸福感很强烈

爸爸现在心态可以用“但行好事莫问前程”来描述,好好学,认真干,尽全力做事,至于公司能发展到什么程度,就先不考虑了

另外最近有一件在程序员圈子里比较火的事件,传统通信设备厂商中兴的一家子公司的一个研发中层(40出头,上有二老,下有二宝),由于要被公司变相裁员辞退(或者说劝退),而选择了跳楼自杀

微信朋友圈里的同行们都在议论中年危机(也是个老话题了),连圈外人也有所议论,当然程序员这类人感触更深。

程序员都说是吃青春饭,华为据说35岁劝退42岁强制退休,很多人都在议论35岁之后能干啥?

毕竟这个时间点很尴尬,上有老下有小,压力山大

我唯一想的就是现在多赚点钱,过几年不干了,还能有养家糊口的资本

或者多学点技术,能多干几年。

其实还有一个担心,有人说转行要趁早,不然在老本行里越陷越深,更不容易转出来(学的越多陷得越深)。话虽如此但也无可奈何,毕竟人都愿意活在自己熟悉的环境,做熟悉的工作,况且冒风险去未知行业,全家老小都不得不跟着承担风险。

不管怎么说,爸爸现在想得开,有俩儿子要养,怎么样也得好好活着,留着青山在,不怕儿子多

俩儿子做好吃苦的准备就行了,小时候吃点苦也没啥不好的,一帆风顺的人生经不起风浪。

随便干点啥都饿不死。长大后靠自己吧!

 

 

 

 

Nova quota新方案和shadow表的用途

shadow表的用途

今天本来是在看sqlalchemy的用法(过两天会整理下写一篇文章),刚看完相关教程和部分官方文档,想看一下nova里面怎么用的,看到了nova db这部分的逻辑,偶然想到了nova数据库里面有很多shadow开头的表,比如shadow_instances、shadow_instance_system_metadata等等,基本所有正常使用的表都有一个shadow表对应,就网上找了找这些表的用途,发现了一个官方文档介绍nova-manage命令:https://docs.openstack.org/nova/pike/cli/nova-manage.html,里面提到了一个 nova-manage db archive_deleted_rows ,可以把已经标记为删除的记录,移动到shadow表里面,所以shadow表的用途应该就是archives,用来归档数据的(bp在这里),比如云主机已经删除了很久,与该云主机相关的数据库记录如果一直保存在nova使用的表里面,就会影响数据库操作性能,而用这个命令归档后,就可以彻底从使用的表里面清理掉,而又不会导致后续想查询记录的时候找不到,但是网上又搜到一个bp,貌似想干掉这些shadow表,说是实际生产环境没人这么玩。看了master分支代码,创建shadow表的方法还在(nova.db.sqlalchemy.utils.create_shadow_table),并且bp还处于drafting状态,应该还没动手干掉。

Nova quota新方案

继续回到quota新方案,看nova-manage命令行的时候,看到两个quota相关的命令都被废弃了: nova-manage quota refresh  nova-manage project quota_usage_refresh <project_id> [--user <user_id>] [--key <key>] ,原因是“This command has been deprecated and is now a no-op since quota usage is counted from resources instead of being tracked separately.”。看起来是改了方案了,不再单独统计配额使用量,于是赶紧看了下master分支代码,果然已经都改了,改成了直接从instances表里面统计cores、ram、instances的使用量,而不是在创建、删除、修改规格时都reserve、commit到quota_usages表里面,这正是我很早之前就疑惑的地方,明明可以直接统计数据库为啥还要单独维护一张表?而且neutron项目里面已经这么做了,只不过没有提供查询配额使用量接口而已。现在检查配额也是直接统计instances表或者其他资源的表即可,再也不担心各种异常情况下导致的资源配额使用量统计不准确的各种问题了(之前我们用H版本的时候,是打开了max_age和until_refresh两个选项,强制定期同步配额使用量,同步配额使用量就是查一遍资源记录表,统计一次更新到quota_usages表,既然如此,何必绕一圈到单独的表,而不是直接统计资源记录表?感觉有点多此一举了)。

这是新方案的其中一个commit:https://review.openstack.org/#/c/416521/

相关的bp是:

看bp描述,这个改动是为了更好的支持cell集群才做的,不过也算是给nova配额管理模块做了大贡献了,可以看出改成这种方案之后,配额相关操作就简单了很多,不用在nova/compute/api.py里面reserve资源,在nova/compute/manager.py里面commit或者rollback资源使用量了,完全不需要这部分流程了,创建成功写入instances表就算资源用了一份,检查配额使用量的时候根据project_id sum一下instances表就好了,多简单清晰,再也不怕统计不准了。看下commit的diff就明白了:https://review.openstack.org/#/c/416521/63/nova/compute/api.py

提醒下,新方案是Pike版本merge的。

OpenStack nova修改云主机密码功能及云主机内外部启动时间不一致问题

云主机内外部启动时间不一致问题

最近看了一个问题,症状是云主机过一段时间就无法登陆,怀疑是云主机自动关机或者其他异常,就看了下qemu日志,发现里面有如下日志:

看到这段,以之前的经验判断是云主机被关机了,但感觉很奇怪,这个时间点是在凌晨3点(日志中时间是UTC)平台都没人登录,肯定不是人为操作,刚开始想了半天没明白,于是登录到云主机中查看uptime,看到已经启动了好几周了:

物理机上看qemu进程启动时间:

居然是昨天启动的,就更奇怪了。

看了下nova-compute日志,发现这个时间点是在做备份(nova backup接口),配置的是cold snapshot方式(备份代码流程可参考之前写的这篇文章,以及这篇文章),所以备份过程中会把云主机休眠,于是明白了内部uptime看到的启动时间和外部qemu进程启动时间不一致的原因,休眠并不影响云主机内部时间,休眠唤醒过程中云主机内部并不会执行关机开机流程,云主机的进程状态、系统状态都不发生变化(CPU寄存器、内存数据都不变),类似经历了一次热迁移操作。

手工实验了一下,流程如下:

  1. 关闭openstack-nova-compute服务,防止通过virsh命令休眠云主机后云主机状态被同步成关机状态
  2. 通过vnc客户端登陆到云主机内部,查看uptime,已经启动了好几天
  3. virsh managedsave UUID
  4. ps查看qemu进程,已经不存在
  5. 等待几分钟,执行virsh start UUID
  6. 再次通过vnc客户端登陆云主机内部,查看uptime,发现启动时间还是好几天
  7. ps查看qemu进程启动时间,发现是刚刚启动
  8. date查看云主机内部时间,发现仍然停留在休眠时间点,也就是几分钟之前,所以如果涉及到休眠操作,建议使用ntp服务同步云主机内部时间

修改云主机密码功能

另外为了登录到云主机内部,顺便看了下修改密码功能,之前我们用H版本的时候,是自己修改的nova代码实现的修改密码功能,调用qemu guest agent的guest-set-user-password接口,只支持修改root(Linux系统)和Administrator(Windows系统)两个账户的密码。看了下M版本的nova相关代码流程,已经提供了相关接口,nova libvirt driver的实现是直接调用python libvirt API,

libvirt的最低版本要求是2.0.0,我们用的正好满足。

官方实现还支持自定义修改的用户名,在镜像property里面设置即可,比如–property os_admin_user=admin。

对应的libvirt virsh命令是(至少2.0.0版本):

看了下libvirt源码,qemu driver的实现是调用的qemu guest agent接口,

与我们在H版本自己写代码实现的底层接口是一样的,只是低版本的libvirt没有提供api,是在libvirt agent-command模块实现的(python-libvirt包里面提供了libvirt_qemu模块,可以import进来调用qemu guest agent接口),对应的命令行是: