和睦家初诊,协和国际确诊,取了一颗乳腺纤维瘤

今年 12 月的,XXM 经历了从和睦家初诊,到协和国际建议手术以及最终术后病理分析确认为乳腺纤维腺瘤的紧张揪心的过程,术后恢复的不错,分享一些亲身经历的医疗事件细节, 从个人的角度谈谈中国的私立医疗,网上公开的不多,给后人一些有用的参考。

医疗资源在中国是典型的稀缺资源,既然是稀缺资源,就一定存在供需不平衡的严重畸形,如果去北京三甲医院挂专家号,可能纸面价格是 50-100,由于价格的管制违背了市场的规律,导致了黄牛这一类群体的出现,「人为炒高」了挂号费,其实,上过大学的应该都明白,这不过是纸面不合理价格的无形补偿而已,只要有管制,这种现象将一直存在,无非是从大家通宵排队变成了更加隐蔽的资源竞争而已,类似的现象数不胜数,春运抢车票,早晚高峰的三环四环。

目前我们家基本形成了小病去和睦家,专病大病去协和国际的就医方式,所以我主要对比协和国际跟和睦家的优劣,普通公立医院大家基本都体验过,我不会过多的总结,文中会分享一个最近去协和普通门诊拿药遇到的事情,发人省心。

⚠️,以下大部分为主观对比(就医本身就是一个很主观的体验),少部分为客观事实,仅供参考。

如果要以一句话对比和睦家跟协和国际的区别,那就是,服务流程规范度远超协和国际,医疗质量效果大概率不及后者。下面我会按照患者就医的整个生命周期分别对比。

挂号预约

微信还未普及之前,和睦家只有电话挂号的方式,通常是身体出现异常后,拨打电话告知接诊护士,描述清楚状况后,护士会根据你的状况给你分配医生以及时间,如果护士没法判断病情,通常会将你分配到全科。拨打电话很少会出现占线的情况,基本都是次日或者本周就能看诊,除非你指定医生则需要根据医生来协调时间,通常也不会等待太久。

这几年和睦家上了微信挂号系统后,我也很少打电话,而是通过微信来预约,微信最大的优点是,能看到该科室下所有医生的可预约时间,以及最重要的,每个医生的专长简介,不夸张的讲,和睦家的医生简介是目前见到过的最专业的描述,比如最近给 XXM诊断的翟梦瑶大夫的简介,仔细阅读一遍,你就知道她适不适合你,相比之下,京医通包括协和 app 上面的医生简介文案就潦草太多了,不是说医生水平水,而是通过看医生的简介,无法比较准确快速的确定这个医生能不能解决我的问题,显然这不是京医通自身的问题,这需要各个医院门诊部门的用心来提升。

翟梦瑶医生2009年毕业于北京协和医学院8年制临床医学专业,获医学博士学位。之后于2011年在北京安贞医院完成了外科住院医师规范化培训,熟练掌握各类普外科及乳腺外科疾病的诊治。

在加入北京和睦家医院之前,翟医生于2011年起在北京安贞医院任血管外科医生,在血管开放手术和腔内介入治疗方面积累了丰富的经验。并于工作期间负责执行腹主动脉瘤开放手术与腔内修复、急性下肢深静脉血栓新型口服抗凝药治疗,以及颈动脉内膜剥脱术中止血技术等大型临床研究工作。翟医生擅长下肢静脉曲张、皮肤毛细血管扩张症、下肢深静脉血栓、颈动脉狭窄、锁骨下动脉窃血综合征、下肢缺血、肾动脉狭窄、腹主动脉瘤、周围动脉瘤等周围血管及大血管疾病的诊治;以及乳腺肿物、乳腺纤维瘤、乳房疼痛、乳头溢液、乳腺炎等乳腺疾病的诊治。

协和,不管是国际医疗部还是普通特需门诊,目前都可以通过 App 实现挂号预约,用户的交互体验,跟和睦家以及京医通差了不是一个档次。另外一个问题,号确实比较难抢,最近给 XMM 做手术的主治医生张燕娜大夫就是在放号当天尝试了很多次才挂上的,那天我记得是下午 16 点放号,放号的时候协和的 App 直接崩溃,与此同时,我们也跟保险公司联系让帮忙走他们的渠道看看能不能挂上,幸运的是尝试到晚上终于挂上了号。

顺便说一句,挂号其实是很有讲究的,比如以协和国际为例,并不是挂号费越贵就越好。在和睦家初诊的时候,B 超判断为 BI-RADS4a,翟梦瑶大夫建议观察,因为即使是最悲观的情况乳腺癌,由于其惰性的特质(类似的还有甲状腺癌,前列腺癌,这也是为什么重疾险将其列为轻度重疾的原因之一),现在治疗跟三个月治疗的效果并不会有很大的差异,我们回去立即 Google 了很多资料,4a 是一个尴尬的分界线,往前是良性往后是恶性的概率越来越大,所以我们决定去协和征求第二诊疗意见,协和的 App 上专家很多,正常情况下,一般诊疗费用越贵的代表着医生的职级以及水平越高,能处理的疑难杂症越多,相应的也越难预约的上,所以结合和睦家的建议,我们选择相对年轻的张燕娜大夫,简介不多

张燕娜,女,博士。2004年毕业于中国协和医科大学临床医学系,获医学博士学位,留任北京协和医院外科医师。自2007年开始乳腺外科工作,从事乳腺外科疾病的诊断、治疗和临床与基础研究工作,负责多项乳腺癌相关国际多中心临床试验在北京协和医院乳腺外科的开展。

07 年开始从事乳腺工作,博士毕业,十来年的一线经验,解决常见的问题应该不在话下,所以最终选择预约了这位医生。

和睦家是明确区分首诊跟非首诊的,区别就是首诊会跟你做一些体温血压的测量,确认生命体征状态,其次首诊的时间平均在半小时左右,这个时间我觉得已经是相当长的了,同时挂号费也更高,平均在 1200 左右。而非首诊不需要进行生命体征的测量也就减少了这部分的服务,同时时间稍短控制在 20 分钟左右,其实这个时间我认为对于绝大多是人来说是相当充足的了,当然挂号费用会更便宜平均在 800 左右。协和如果通过 App 的花是无法区分这两项的,这个通常是由你的首诊大夫,比如我们的张燕娜大夫代为预约。

在挂号预约这一步,整体来说,不管是协和国际还是和睦家,差别不是很大。

看诊

先说和睦家,按照预约的时间,提前五到十分钟到了医院后,找到分诊台报道,告知一下预约的医生,休息区等待,周围普遍比较安静,应该除了妇产科(和睦家是做产科起家),很少会看到休息区坐满的情况。到了预约的时间点,会有护士带你进去,有一半的概率是主治医生会出来简单介绍一下自己带你进入诊室,之前还遇到个别医生主动跟你握手的。

进去后关门,不需要担心有患者突然敲门进来的情况,因为是严格按照预约时间表来进行看诊。跟医生描述病况,目前遇到的所有医生都是慢条斯理的跟你平等的对话,不会居高临下不耐烦,没交流几句话就问「还有别的问题吗」,催着滚蛋,「尊重」的问题认为在就医体验中非常的重要。

与之相比的协和国际在这块有很大的提升空间,在这个就诊过程中,我是全程陪同,由于协和国际不是严格的预约制,最小时间段只精确到了半天,所以就造成了每个人不想等待,都想尽快见到医生问诊的情况,造成的现象就是大家都在下午两点左右来到门诊室,而到了普通门诊,问题应该是及其的普遍,几年之前看普通门诊不好的经历就不提了,说说最近亲自遇到的,XXM 复查的那个下午,张燕娜大夫问我们是否需要处理疤疤痕贴,我们表示需要,她回复说这个只有普通门诊有,国际部这边没有,所以帮我联系了当时在普通门诊看诊的大夫,具体名字就不提了以 S 代指,让我直接去找她开一个处方拿药就好了,我从国疗走到五号楼中楼五层乳腺外科,进去之后找到 S 所在的诊室,门大开,门口排队站了五个患者,诊室里面用帘子隔开分成两个空间,两个医生在看诊,我象征性的敲了下门,厚着脸皮进去,站在她桌子对面说「S 大夫您好,张燕娜大夫刚刚联系过您让您帮忙开个疤痕贴」,她眼睛一直盯着屏幕回复「等下」,看旁边有张椅子,我索性坐了下来等待。紧靠她旁边坐着一中年妇女在跟她交流,从她跟 S 的对话结合我之前恶补的相关知识,应该是左臂刚作为腋窝淋巴切除手术(到这一步病情通常比较严重了),看上去很虚弱。

患者「我左臂以后是不是不能拎重物了」,S 回复「不能」,患者「是不是也不能甩胳膊了」,S 回复「不能」,患者「那我走路正常手臂甩动了?」,看 S 脸色明显不耐烦了「不行,都不能,还有问题吗?」,患者很小心的问「大夫,我再咨询您个问题,是不是修养一段时间就能恢复正常了?」,S 语气明显不耐烦了音调也提高了「我不是说了吗不行,一辈子都不行,你这个手臂以后都不能动」,患者「那我如果不小心动了话会有什么问题吗」,S 「肿啊,你想肿吗?」紧接着低声怨气道「真是的」。接着 S 对我说「你先去门口挂个号然后报道,我再给你开药」,经历了上面这这场景,感觉真的得跪着跟她说「好的,谢谢大夫」。挂号报道后拿到 S 的处方,交完费在分诊台等疤痕修复贴,突然一个老人跪在地上大哭,后来知道是因为挂不上号,一个医生的把她带到了 S 的诊室,几分钟后出来了对她说「这次就给你加个号,下次不加了啊」,心里顿时非常的复杂,说不出的感受,类似的情况在国疗也遇到一次。

大部分情况下,和睦家走的是保守治疗的路线,不会过度治疗,说几个深刻印象的事情。

前几年去体检,拿到报告后说肛门息肉,决定去复检,搜了下发现中日友好肛肠科比较有名,于是预约了他们家范学顺的特需,跟协和类似,门大敞,门口排着几个人,进去后,坐着的,一看就是范学顺,气场十足,三四个白大褂的年轻学徒站着围成了一个小半圈,我描述了下病情告知体检有息肉来确诊下,范学顺指着窗帘隔开的一个简陋的床,大概率是上面的一次性床垫没有换「脱裤子侧躺」,我先过去脱了裤子按照他的指示侧躺,学徒跟着他紧接着过来围着床站,范学顺说「双腿弯曲」,我刚做完还没来得及深呼吸一口,啊的一声就感觉一个异物伸了进去,手指在里面转了两圈,拿了出来脱掉了手套,跟学徒说「肛乳头瘤」,我起身走到他桌子旁,他递给我一张名牌「这是个瘤得切,这是我好大夫上面的联系方式,你什么时候准备好了来预约我,手术」,我还没来得及缓过神,下一个人已经进来了。

回家后立即预约了和睦家,记得当时预约的是肖海涛大夫,进诊室后区别就看出来了,当然该屈膝侧躺还是照做,肖大夫带上手套抹了些润滑油「我会慢慢的进去指检,可能会有些疼,有不舒服的告诉我」。检查完了之后,大夫很耐心的讲解了这种情况的病因以及需要注意的地方「这个是肛乳头瘤,良性肿瘤,如果日常生活中没有不舒服的感觉就不需要理会」,听到这话我立马放心了很多。前年买重疾,主动告知之前体检的结果,保险公司需要出具肛乳头瘤恢复健康的证明,我找到肖海涛,帮忙开了一份「恢复健康,不会造成癌变」的证明,他笑着说「医学上从没有看到这种良心肿瘤会恶化的案例,放心吧」。

公立医院的治疗有些时候就是简单粗暴,如果当时按照范学顺的建议,除了挨了一刀以及几天的生活不便外,后续并不会有特别大的影响,这个瘤是留着没关系,切了也没关系的良性肿瘤,但是和睦家的医生更多的是从患者的角度出发,给出了更加综合的意见。有的时候,治病不是只需要将生理疾病治疗好这么简单,上文提到的 S 大夫给刚做完手术的中年妇女的故事,女性普遍来说情绪比较敏感加上刚做完手术,更是需要精神上呵护的时候,如果 S 大夫语气态度能够稍微耐心点,国内的医患矛盾可能会缓解那么一点点,当然医患这事,不是态度温和这么简单的事情,本质还是供需的矛盾,只不过最终由医生的高负荷高压力的工作以及患者来承担了最终的结果。

再来说一下本月的这件事,月初 XXM 说左胸难受,感觉长了什么,于是预约去和睦家看翟梦瑶大夫的号,翟大夫先是指检,给出的结论是左胸没有结节,右胸有一个。

说个后话,翟大夫是唯一一个在诊室可以准确定位到右胸有一个结节的医生, 这个在后面协和医生的指检中并没有出现,反而告知的是特征不明显。我认为越是一线的医生应该对于常见疾病的诊断越是高超,尤其是中国这种典型的人口红利国家,对于医疗体系更是如此,医生的医术进步与老练很大程度依靠每天大量的患者标本的提供,说的难听点,患者就是活靶子。我之前看和睦家从不挑医生,基本上预约的护士给我安排哪个我就选哪个,所以经常会给我安排到外籍的医生,这类外籍医生普遍有非常好的背景,有很好的理论知识,但是医学是一门实践科学,所以造成的结果就是,一个简单的疾病能墨迹大半天都查不出原因。去年年初我咳嗽的厉害全身无力,当时和睦家主院呼吸内科最近一周的都预约满了,我就去他们朝外诊所看了个全科,医生应该是 ABC,结果检查了一圈外加开药,回去过了春节都没好,过完年去主院搜医生找到了曹菊,

曹菊医生2003年毕业于北京大学医学部,2005年在北京大学第一医院获得呼吸内科硕士学位, 2008年获得肾脏内科博士学位。同年,曹医生在北大医院完成了内科住院医师规范化培训,并在各临床科室轮转实习,熟练掌握从呼吸道感染到疑难杂症等各类呼吸内科疾病的诊治。曹医生拥有9年的临床实践经验。在加入北京和睦家医院之前,曹医生在北京大学第一医院呼吸和危重症医学科工作,擅长肺部感染、哮喘、间质性肺病等。

北大医院出来的,九年经验,应该能治好,给我开了可待因吃了几天才好了。这事的教训就是后续看医生都得先把简历拿出来好好看一眼,看看能不能治,不能治也别瞎逼看。

回到指乳腺结节这事,后来通过 B 超也验证了翟大夫的判断,确实是右胸出现了一个 2cm 不到的结节,而左胸没有任何的问题。由于整体边界比较清晰也没有明显的血流,所以被诊断为 BI-RADS4a,翟大夫建议「4a 有比较低的恶性风险,由于乳腺具有惰性的特征,所以是现在手术还是三个月手术,区别并不会太大,所以建议观察三个月复检」。回去搜资料,大部分是良性结果,由于我们这个边界不是特别的清晰,所以还是存在一定的可能性,《早期乳腺癌可能伪装成纤维瘤,针灸按摩适得其反》这篇文章也解释了可能的发展方向。香港乳癌基金会的一份调查指出,有很大一部分人决定手术是出于心里的煎熬,你想,你被诊断了一个瘤,不确定是良性还是恶性,有大概 10% 或者更高的概率会变恶性,你可以选择三个月后复诊,因为三个月并不会恶化太多,复诊的结果跟你当前进行手术并不会有太大的差别,你会怎么选择?我们选择把瘤给取出来。

这就有了上文去协和国际挂号的事情了,看到 B 超结果后,张燕娜问我们「你们是倾向观察还是手术」,所以我跟 XXM 商量后,为了避免心里的折磨,最终选择了手术,张大夫帮我们预约一周后的手术,这可能是我们感觉到的国际医疗除了物理环境稍好之外,其他为数不多的优势,几乎不需要排队,这个其实蛮重要的,尤其对于确定手术的病人来说,越早手术越心里负担越少。本来这事我的心态还好,也没那么紧张,毕竟发现的早,早发现早治疗嘛,我们提前一天办理住院手续,整个流程给我们的感觉比较杂乱同时也很仓促,比如当天早上住院后只能在病房干等,完全不知道接下来需要做什么,以及何时做,大概九点多来了个目测是实习或者很 junior 的医生,来问了一些过敏之类的问题;快吃午饭的时候一个男医生喊我们去病房旁边的一个诊室,问了一下既往史以及过敏之类的问题,然后尝试指触,竟然没摸到。吃完午饭突然出现一个住院大夫以下以 M 代替,跟张大夫一起,站在病房门口给我们简单讲了一下手术事项,因为 M 要赶着手术,所以为数不多的交流显得十分匆忙。等到下午三点多,M 手术完了,把我们跟另外一个病房的患者拉到一个屋子,左右同时开工,给我们讲手术风险以及措施,并且另外一个患者跟我们要做的还不是同一个手术,我当时心里真的是「还可以这么操作???」,我们坐她左边,另外一个病房的坐她右边,屋子里还有别的在办公的医生,完全没有隐私,另外一个病房的因为非哺乳期溢乳也需要手术治疗。讲到一半突然接了一个电话,电话那头应该是她丈夫,说话声音很清晰,大致就是儿子发烧,高烧几天了,什么时候能来照顾之类的,挂了电话之后,继续给我们讲解手术操作以及风险。先给隔壁病房的讲解完,开始给我们制定手术方案以及可能的风险,听的我真的全身都不好了:

手术前先进行超声定位,肿物切除活检术;若术中冰冻病理为恶性,则进行局部扩大切除+右腋窝前哨淋巴结切除活检术;若术中发现前哨淋巴结冰冻病理为转移癌或者前哨淋巴结活检失败或不符合保乳条件或保乳不成功(如切缘阳性等),则暂不进行手术,待石蜡病理结果回归后,根据石蜡病理结果决定下一步治疗方案;术中根据具体情况,决定最终手术方案。术后石蜡病理结果可能与术中冰冻病理结果不符合,有二次手术的可能,【省略若干风险】,术中可能使用美兰和/或荧光造影剂,造成局部皮肤组织染色的可能。

这些风险 M 给我们粗略快速的过了一遍,很多专有术语我们并不是很明白意味着什么,只能通过字面意思判断个大概,既然已经到这一步了,也没有退缩的可能了。讲完扶着 XMM 回病房。在之前一直以为是个很简单的手术,再加上这是协和,还是国际部,很久没吃到这种少油少盐的饭菜了,所以午饭吃的特别香,但是晚饭上来的时候已经没什么胃口了。第二天早上导医通知我们去 B 超室,不专业的地方又体现出来了,病房里面竟然忘记给病服了,导医出去转了一圈才找了套新的,做完钼靶超声定位就开始焦虑的等待,没人能告诉我手术时间点,只是说在中午左右。当天中午我在病房吃完饭不到一刻钟,护士通知准备手术,12:19,XXM 进了手术室,我在外面休息室等到了两点多,看还没做完,就下楼问护士,护士说已经做完回病房休息了,我赶紧跑回去见到了 XXM,因为绷带特别紧,只能坐在椅子上,告诉我冰冻病理是良性的纤维腺瘤,终于松了口气。

下午大概三点多的样子,负责三餐的服务员过来说「你们明天没有预定,就不给你们送餐了啊」。我一脸懵逼,不是之前沟通好一共住两晚的吗,跑过去跟护士确认,告知,已经给我们开出院证明了,就这样,当天下午四点多,我们被赶出了医院,只能安慰自己不占用公共资源吧。

另外一个很大的差别,和睦家是全程电子病例,所以你能跟踪到在该院就诊的所有疾病以及用药检查,可以让护士打印副本或者发送邮件,对患者以及医生都很方便。协和国际目前依然是手写病例,我知道的京医通下面的医院也都是纸质病例,他们应该有电子的记录,但是不对患者开放,之前还在职的时候也调研过技术上的实现方式,并没有什么什么难度,不清楚是何阻力一直没有实现。

说到这里,基本也算通过一些亲身经历的事例对比了协和国际,协和普通以及和睦家之间的就诊过程的利弊了,总的来说,协和国际完爆协和普通,这个完全没有可比性,但是协和国际跟和睦家之间就各有千秋了,当初选择在协和做手术,还是看中的是医术,相信协和这块招牌,所以环境包括服务也就没那么的重要了。张燕娜大夫全程也蛮尽心,医术这个东西我作为非专业人士不好评价,对患者以及家属来说,能以最小的代价,安全的做完手术并且尽快的恢复,这就是高水平医术的表现,在这点上,协和国际做的还是不错的,和睦家还有很长的路要走。

经历了乳腺纤维腺瘤这事,感觉我也成了半个业余医生,能够通过看 B 超能判断出 BI-RADS 等级,是否是恶性,要不要立即手术😄

门诊跟进,诊后

这一块没有可比性,和睦家完爆协和国际,和睦家所有当天无法拿到的检查都是事后主治大夫会电话告知你结果以及后续的治疗方案,同时,患者跟医生在后期是一个双向的互动,比如我们会给医生邮件,向其咨询疾病方面的问题,通常都能得到很满意的回复,同时我们也可以通过分机号主动联系到医生以确定疾病的相关细节。这点协和没有自身的闭环,更多的是依赖于第三方好大夫,实现患者跟医生的互动。

至于拿药这块,协和跟和睦家两者差的不是很多,个人感觉和睦家有更加专业的药剂师,典型的就是冀连梅药师,曾经出过中国人应该这样用药的书,后者通常会更耐心的跟你解释如何用药,同时会有非常明显的用药周期标签以及注意事项贴在药盒上,协和药房肯定也是正规药师,但是毫无存在感,仅仅是毫无表情的说几句话而已,这个我也能理解,每天接诊那么多人,嘴都要说破了。

快新年了,祝读到这篇文章的人身体健康,如果你是乳腺结节患者,看完结节立马消失。

博客复活

回头一看两年多没更新了。

技术相关的这些年并没有太大的发展的,那些所谓风口浪尖、炒得来炒得去的新技术底层的还是那一套,并么有很大的创新,鉴于此加上搜索引擎的强大,单独分享或者为此花一两个小时写博客记录一些日常工作中的技术性问题意义就不大了。再者,对于绝大多的商业来说,在没有达到技术瓶颈之前就已经死掉了,很少听过某个公司某个产品因为工程性的问题导致流产的。

索性就不谈技术,给大家分享今年潜水遇到的一些有趣的事情。

18 年年底在 Cebu 潜水,把 AOW 给学完了,途径 Olango 去 Cabilao 一天三潜,跟几个成都人一起包船,有趣的事情来了,下潜到二十多米的深度,一个成都女同志拿出一张刺瞎人双眼的银箔,插到了珊瑚里,目测祈福相关的,这年头还有人迷信这个,不多见。下午上船的时候腿抽筋,只顾着拉伸,把潜水表给丢海里了,深海,看不到底的那种。

说到这里,在这之前去 moalboal 看沙丁鱼,浮潜,上船的时候 gopro 带子断了,导游帮忙确认到 gopro 丢的具体位置,二十米深,当地人听到这个消息,一个个跃跃欲试,土方子自由潜一个接着一个下去,最后一个老哥帮忙捡起来了,穿上一阵鼓掌欢呼,给了 2000 php 小费。

圣诞节的前夕去 SM City 看了部中途睡着了的电影,Aqua man,水王,起初我以为是电影院设备屏幕太落后导致的视觉效果,回来后 Google 了下发现真的就是那么烂,对不起,冤枉菲律宾了。

在离新年还剩 3 天的时候突然决定要跨年,热门的地方全部给订光了,于是跟 xxm 去了一个离 Cebu 大概两小时船程叫 Camotes 的岛,岛的形状很特别,可以类比雄性的一组蛋,中间通过一座桥连接两个圆形的岛,岛上最好的酒店 Mangodlong Paradise 已经预定出去了,只能住在隔壁的一个酒店,没有海景,只有一个花园,这都是后来才知道的事。很神奇的是,我们住了 3 晚,一共就遇到三四个房客,早上吃早饭,从未碰到过其他房客,冷清的很,尤其是晚上,有点恐怖,去的时候船晚点,入住的时候接近零点了,在前台等服务员可能等了有一刻钟,周围什么吃的都没有,酒店也没有,睡觉的时候下雨,据说 xxm 被吓醒了,当然我是一如既往的睡死过去。

Camotes 岛太小了,我们包了两天车把整个岛绕了几圈,再加上整个岛上饭馆少的实在可怜,网络信号差的得站在某个特定的地方对着特定的角度才能接收到信号,索性剩下的时间就都呆在隔壁的酒店了,也算是因祸得福,在那里,完成了目前最有趣的浮潜体验,倒不是说水下的生态有多棒,相反的是水下有很多的塑料酒瓶垃圾,之前所有的浮潜其实多少都是有时间限制的,但是,这个酒店,或者说这个岛,是真的感觉不到时间的存在,当你完全不用考虑时间的时候,很多事情就变得不一样了。所以每天中午吃完饭,就穿上水母服,静静的漂在海上,仔细的欣赏水下的每一个生物,看到了海星在缓慢的爬行,螃蟹左右钳交替着吃东西,小丑鱼在快白化的海葵离东躲西藏,有时候为了让 gopro 拍出最好的视频,会重试好多次而乐此不疲,一飘就是一个小时,上午潜,下午潜,每次都能看到不一样的东西。

不管如何,如果在 Cebu 呆的时间比较长可以专程去趟 Camotes,但是休闲放松绰绰有余,有几个沙滩尤其是 Mangodlong 不比长滩差。

新年就这么过去了,接下来直杀 Coron, Palawan,世界级的沉船之潜,在 Chindonan 呆了三天,Resort 有自己的船,去沉船很方便,3 潜沉船,1 潜珊瑚。

前一天晚上入住,工作人员很专业,大家一起吃完饭瞎逼扯,最后跟丹麦的潜导 Julius 讨论制定潜水计划,计划八点开船出发,结果第二天,新加入了一对环游世界的 switzerland 小情侣入住酒店,等他们收拾一下吃完早饭相互聊了会,最终十点出发,这都没什么,毕竟潜水安全开心最重要嘛。科隆  morazan 船,第一次下这边的海域能见度不高。我跟 Julius 一组,小情侣一组,开始下潜到 20m 深的时候,Julius 停留点名确定大家状况,在水底我都是死死跟着潜导的,结果发现男的没了,而他女朋友跟着我???我们三一脸懵逼相互对视,原地找了一分钟没人,上潜,结果在 10m 的地方发现了那男的,瑞士男朋友忘带 gopro 防水壳,10m 的地方 gopro 在哔哔哔叫,不忍心继续下潜。关了 gopro,继续下潜。当天的第二潜是 olympia maru sangat wreck,看到了 stone fish,lion fish 以及各种生物,穿越了半个船,呆了 44 分钟。第三潜岸潜,各种 nudibranch, sea horse。

第二天,早上 7:30 一潜。因为酒店很小第一天入住的时候认识了一对荷兰的夫妻,四十多岁刚结婚,特别黏超级秀恩爱,FB 上各自拿对方头像做封面(后来知道的),不大像我对西方人士的即往感受,一个劲要跟我学中文,他们前一天去 Irako,40M+,难度太大,我胆小没跟着一起去,跟荷兰老夫妻以及瑞士小情侣一起潜了 kogyo maru,水域超级平静,没有浪,下水后悲剧的是 gopro 死机了,索性专心潜水观察,Julius 指了看了好多的有趣的鱼,并且用那个丁丁棒挑逗他们(这样是不对的),长得像蜘蛛的螃蟹在绳索上爬行,穿了一整艘船,特别磅礴,Kogyo 是二战日本 cargo ship,里面水泥袋,绳索啥的都完整的留在了船上,进去之后真的感觉是在读历史。荷兰老夫妻回国后还专门给制作了一个视频剪辑配上震撼的 BGM 表达对我的感谢。

早上潜完这一潜就结束在 Chindonan 之旅了,因为在酒店的吃喝包括潜水都是单独收费的,结账的时候,竟然少算了几百 RMB,不知道是打折的了,还是真的是菲律宾服务人员的数学不行,不得而知。

下午去 Coron 市区,呆了五天,迫于 xxm 的压力,只潜了一天 3 潜。

第一潜, barrucuda lake,传说中的冷热湖,其实是自由潜的胜地,能见度很高,冷热分层肉眼可见。第二潜 east sangat gunboat,以为就是个小破船,但是跟着潜导在船里面左绕右绕,穿越不同的舱室,真是锻炼中性的好地方。

第三潜,跟在 Chindonan 的第一潜一样,morazan 沉船,跟一个 61 岁的美国佬一起,第一次穿越的大多为大空间舱室,可以同时穿越几个人的洞口,这次明显跟上次不同,比第一次难度大多了,很多都是一人大小的洞口,超级锻炼中性,气瓶被卡了几次,好在不慌都慢慢下沉回退一点重新穿越。在做潜水计划的时候潜导跟我们说了有这么一个舱室,水特别清澈,14m 深的地方可以伸头出去,大概水平往上一米的高度没有水,可以头伸出水面,但是不能摘掉面镜以及说话,担心里面有有毒气体,当真的见到这一幕的时候,还是被这场景震撼住了,我们三人头同时伸出水面发出嗯嗯的声音,声音反弹到舱壁产生微弱的回音,墙壁爬满了红色的虾跟黄色的螃蟹。大部分的舱室都是手电达不到光的地方一片漆黑,有次手电往下瞎晃,看到一条死的大鱼躺在地上,尸体被蚕食了一半,一群小鱼围着啃噬,不由得倒吸凉气。

科隆这个地方真的是太小太无聊了,我们把科隆镇上看上去还行的餐馆咖啡店都消费过一遍,徒步绕了市区 N 圈,逛街的时候跟 Chinadonan 老板碰了几次面(Chinaonan 距离镇上船程一小时)。。。

菲律宾的潜水到此结束,总结起来就是,菲律宾这地方真的是自然风光无限美,其他的就没太多要求了。

xxm 爱吃菠萝,这次就是靠菲律宾有好吃的菠萝哄骗过来的。在北京吃到的菠萝都写着原产地菲律宾都乐,包括之前在香港 Hysan 楼下超市吃到过大为惊叹的菠萝都写着源自菲律宾,这次来,从地摊到超市尝了若干,没一个口味对劲的。推荐大家吃吃他们的 lechon,就是烤乳猪,以及 sisig,可以理解为菲律宾版的老干妈,超级下饭。在 Camotes 上的 Mangodlong Paradise 里面,我们就是靠 sisig 填饱肚子的,后面去 Coron 市区,在 Westown Resort 也是每餐必点 Sisig。之前出去玩从没吃过中餐,都是吃当地的食物,这次实在没办法,最后的几天,连续吃了两天中餐,西红柿蛋汤,鲜美。

八月份的时候去新加坡,时间比较紧,只有一天,就去了圣淘沙水族馆,前一天晚上发现可以潜水还邮件预约了下,第二天去的时候人家说要提前一周预约才可以,作罢。

十月份再去新加坡的时候,提前半个月就预约了潜水,价格跟东南亚肯定不好比,但是环境包括服务很一流的,体验了一次水族馆的潜水,在 Adventure Cove Waterpark 里面,最深 12m,呆了半个小时,在圆柱型的封闭水箱里面潜,然后被一群人看猴子,看到了鲨鱼的卵鞘,之前一直以为鲨鱼是产的那种圆的透明的卵,直到潜导拣了一个给我看才发现不是这样的,还有掉落的 manta ray 的牙齿,白色的,除此之外并没有特别的,可能是好久没有练习了,五米停留的时候竟然差点飘上去。

本来第二天还预约了一个 shark dive,上面潜完后去场地看了下,面积比上面的还小,但是鲨鱼的密度倒是很大,不是很有意思,取消了。

年初的时候买了块 Garmin Descent MK1,一直没用上,这次潜水特意用了下,真的是除了时间是准的,其他都不准,两个字,垃圾。

由 rc_mksid 引起 pppd 奔溃的一个 bug

最近手贱想把手头的几台玩具机器统一下标准,其中一个标准是将 kernel.pid_max 增加到了 512000,结果就在当天的凌晨,一台跑着 pptp 的 VPS 崩溃了:

Jun 20 22:53:09 jaseywang vps pptpd: ======= Backtrace: =========
Jun 20 22:53:09 jaseywang vps pptpd: /lib64/libc.so.6(__fortify_fail+0x37)[0x7fdba6416047]
Jun 20 22:53:09 jaseywang vps pptpd: /lib64/libc.so.6(+0x10d200)[0x7fdba6414200]
Jun 20 22:53:09 jaseywang vps pptpd: /lib64/libc.so.6(+0x10c709)[0x7fdba6413709]
Jun 20 22:53:09 jaseywang vps pptpd: /lib64/libc.so.6(_IO_default_xsputn+0xbc)[0x7fdba637f60c]
Jun 20 22:53:09 jaseywang vps pptpd: /lib64/libc.so.6(_IO_vfprintf+0xb0d)[0x7fdba634ec3d]
Jun 20 22:53:09 jaseywang vps pptpd: /lib64/libc.so.6(__vsprintf_chk+0x88)[0x7fdba6413798]
Jun 20 22:53:09 jaseywang vps pptpd: /lib64/libc.so.6(__sprintf_chk+0x7d)[0x7fdba64136ed]
Jun 20 22:53:09 jaseywang vps pptpd: /usr/lib/../lib64/pppd/2.4.5/radius.so(rc_mksid+0x43)[0x7fdba4272763]
Jun 20 22:53:09 jaseywang vps pptpd: /usr/lib/../lib64/pppd/2.4.5/radius.so(+0x48f0)[0x7fdba426d8f0]
Jun 20 22:53:09 jaseywang vps pptpd: /usr/sbin/pppd(notify+0x27)[0x562eaeb64847]
Jun 20 22:53:09 jaseywang vps pptpd: /usr/sbin/pppd(+0x1cfff)[0x562eaeb6cfff]
Jun 20 22:53:09 jaseywang vps pptpd: /usr/sbin/pppd(fsm_input+0x671)[0x562eaeb669a1]
Jun 20 22:53:09 jaseywang vps pptpd: /usr/sbin/pppd(main+0xbe7)[0x562eaeb63317]
Jun 20 22:53:09 jaseywang vps pptpd: /lib64/libc.so.6(__libc_start_main+0xf5)[0x7fdba6328b35]
Jun 20 22:53:09 jaseywang vps pptpd: /usr/sbin/pppd(+0x1393d)[0x562eaeb6393d]
Jun 20 22:53:09 jaseywang vps pptpd: ======= Memory map: ========
Jun 20 22:53:09 jaseywang vps pptpd: 562eaeb50000-562eaeba6000 r-xp 00000000 fd:01 1510143                    /usr/sbin/pppd
Jun 20 22:53:09 jaseywang vps pptpd: 562eaeda6000-562eaeda7000 r–p 00056000 fd:01 1510143                    /usr/sbin/pppd
Jun 20 22:53:09 jaseywang vps pptpd: 562eaeda7000-562eaedad000 rw-p 00057000 fd:01 1510143                    /usr/sbin/pppd
Jun 20 22:53:09 jaseywang vps pptpd: 562eaedad000-562eaedf9000 rw-p 00000000 00:00 0
Jun 20 22:53:09 jaseywang vps pptpd: 562eb07ef000-562eb0810000 rw-p 00000000 00:00 0                          [heap]
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba28a0000-7fdba28af000 r-xp 00000000 fd:01 1508183                    /usr/lib64/libbz2.so.1.0.6
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba28af000-7fdba2aae000 —p 0000f000 fd:01 1508183                    /usr/lib64/libbz2.so.1.0.6
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba2aae000-7fdba2aaf000 r–p 0000e000 fd:01 1508183                    /usr/lib64/libbz2.so.1.0.6
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba2aaf000-7fdba2ab0000 rw-p 0000f000 fd:01 1508183                    /usr/lib64/libbz2.so.1.0.6
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba2ab0000-7fdba2ad5000 r-xp 00000000 fd:01 1507951                    /usr/lib64/liblzma.so.5.2.2
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba2ad5000-7fdba2cd4000 —p 00025000 fd:01 1507951                    /usr/lib64/liblzma.so.5.2.2
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba2cd4000-7fdba2cd5000 r–p 00024000 fd:01 1507951                    /usr/lib64/liblzma.so.5.2.2
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba2cd5000-7fdba2cd6000 rw-p 00025000 fd:01 1507951                    /usr/lib64/liblzma.so.5.2.2
Jun 20 22:53:09 jaseywang vps charon: 05[KNL] interface ppp1 deactivated
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba2cd6000-7fdba2ceb000 r-xp 00000000 fd:01 1508207                    /usr/lib64/libelf-0.163.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba2ceb000-7fdba2eea000 —p 00015000 fd:01 1508207                    /usr/lib64/libelf-0.163.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba2eea000-7fdba2eeb000 r–p 00014000 fd:01 1508207                    /usr/lib64/libelf-0.163.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba2eeb000-7fdba2eec000 rw-p 00015000 fd:01 1508207                    /usr/lib64/libelf-0.163.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba2eec000-7fdba2ef0000 r-xp 00000000 fd:01 1508224                    /usr/lib64/libattr.so.1.1.0
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba2ef0000-7fdba30ef000 —p 00004000 fd:01 1508224                    /usr/lib64/libattr.so.1.1.0
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba30ef000-7fdba30f0000 r–p 00003000 fd:01 1508224                    /usr/lib64/libattr.so.1.1.0
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba30f0000-7fdba30f1000 rw-p 00004000 fd:01 1508224                    /usr/lib64/libattr.so.1.1.0
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba30f1000-7fdba3106000 r-xp 00000000 fd:01 1510624                    /usr/lib64/libgcc_s-4.8.5-20150702.so.1
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba3106000-7fdba3305000 —p 00015000 fd:01 1510624                    /usr/lib64/libgcc_s-4.8.5-20150702.so.1
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba3305000-7fdba3306000 r–p 00014000 fd:01 1510624                    /usr/lib64/libgcc_s-4.8.5-20150702.so.1
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba3306000-7fdba3307000 rw-p 00015000 fd:01 1510624                    /usr/lib64/libgcc_s-4.8.5-20150702.so.1
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba3307000-7fdba334c000 r-xp 00000000 fd:01 1508259                    /usr/lib64/libdw-0.163.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba334c000-7fdba354b000 —p 00045000 fd:01 1508259                    /usr/lib64/libdw-0.163.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba354b000-7fdba354d000 r–p 00044000 fd:01 1508259                    /usr/lib64/libdw-0.163.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba354d000-7fdba354e000 rw-p 00046000 fd:01 1508259                    /usr/lib64/libdw-0.163.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba354e000-7fdba3555000 r-xp 00000000 fd:01 1507938                    /usr/lib64/librt-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba3555000-7fdba3754000 —p 00007000 fd:01 1507938                    /usr/lib64/librt-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba3754000-7fdba3755000 r–p 00006000 fd:01 1507938                    /usr/lib64/librt-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba3755000-7fdba3756000 rw-p 00007000 fd:01 1507938                    /usr/lib64/librt-2.17.so
Jun 20 22:53:09 jaseywang vps charon: 14[KNL] 10.8.0.1 disappeared from ppp1
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba3756000-7fdba3856000 r-xp 00000000 fd:01 1507916                    /usr/lib64/libm-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba3856000-7fdba3a56000 —p 00100000 fd:01 1507916                    /usr/lib64/libm-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba3a56000-7fdba3a57000 r–p 00100000 fd:01 1507916                    /usr/lib64/libm-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba3a57000-7fdba3a58000 rw-p 00101000 fd:01 1507916                    /usr/lib64/libm-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba3a58000-7fdba3a5c000 r-xp 00000000 fd:01 1508228                    /usr/lib64/libcap.so.2.22
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba3a5c000-7fdba3c5b000 —p 00004000 fd:01 1508228                    /usr/lib64/libcap.so.2.22
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba3c5b000-7fdba3c5c000 r–p 00003000 fd:01 1508228                    /usr/lib64/libcap.so.2.22
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba3c5c000-7fdba3c5d000 rw-p 00004000 fd:01 1508228                    /usr/lib64/libcap.so.2.22
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba3c5d000-7fdba3c62000 r-xp 00000000 fd:01 1507924                    /usr/lib64/libnss_dns-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba3c62000-7fdba3e61000 —p 00005000 fd:01 1507924                    /usr/lib64/libnss_dns-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba3e61000-7fdba3e62000 r–p 00004000 fd:01 1507924                    /usr/lib64/libnss_dns-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba3e62000-7fdba3e63000 rw-p 00005000 fd:01 1507924                    /usr/lib64/libnss_dns-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba3e63000-7fdba3e64000 r-xp 00000000 fd:01 1517634                    /usr/lib64/pptpd/pptpd-logwtmp.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba3e64000-7fdba4063000 —p 00001000 fd:01 1517634                    /usr/lib64/pptpd/pptpd-logwtmp.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4063000-7fdba4064000 r–p 00000000 fd:01 1517634                    /usr/lib64/pptpd/pptpd-logwtmp.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4064000-7fdba4065000 rw-p 00001000 fd:01 1517634                    /usr/lib64/pptpd/pptpd-logwtmp.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4065000-7fdba4066000 rw-p 00000000 00:00 0
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4066000-7fdba4067000 r-xp 00000000 fd:01 1565616                    /usr/lib64/pppd/2.4.5/radattr.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4067000-7fdba4267000 —p 00001000 fd:01 1565616                    /usr/lib64/pppd/2.4.5/radattr.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4267000-7fdba4268000 r–p 00001000 fd:01 1565616                    /usr/lib64/pppd/2.4.5/radattr.so
Jun 20 22:53:09 jaseywang vps charon: 08[KNL] interface ppp1 deleted
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4268000-7fdba4269000 rw-p 00002000 fd:01 1565616                    /usr/lib64/pppd/2.4.5/radattr.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4269000-7fdba4275000 r-xp 00000000 fd:01 1565617                    /usr/lib64/pppd/2.4.5/radius.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4275000-7fdba4474000 —p 0000c000 fd:01 1565617                    /usr/lib64/pppd/2.4.5/radius.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4474000-7fdba4475000 r–p 0000b000 fd:01 1565617                    /usr/lib64/pppd/2.4.5/radius.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4475000-7fdba4476000 rw-p 0000c000 fd:01 1565617                    /usr/lib64/pppd/2.4.5/radius.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4476000-7fdba4478000 rw-p 00000000 00:00 0
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4478000-7fdba4484000 r-xp 00000000 fd:01 1507926                    /usr/lib64/libnss_files-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4484000-7fdba4683000 —p 0000c000 fd:01 1507926                    /usr/lib64/libnss_files-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4683000-7fdba4684000 r–p 0000b000 fd:01 1507926                    /usr/lib64/libnss_files-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4684000-7fdba4685000 rw-p 0000c000 fd:01 1507926                    /usr/lib64/libnss_files-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4685000-7fdba468b000 rw-p 00000000 00:00 0
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba468b000-7fdba46eb000 r-xp 00000000 fd:01 1508069                    /usr/lib64/libpcre.so.1.2.0
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba46eb000-7fdba48ea000 —p 00060000 fd:01 1508069                    /usr/lib64/libpcre.so.1.2.0
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba48ea000-7fdba48eb000 r–p 0005f000 fd:01 1508069                    /usr/lib64/libpcre.so.1.2.0
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba48eb000-7fdba48ec000 rw-p 00060000 fd:01 1508069                    /usr/lib64/libpcre.so.1.2.0
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba48ec000-7fdba4910000 r-xp 00000000 fd:01 1508068                    /usr/lib64/libselinux.so.1
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4910000-7fdba4b0f000 —p 00024000 fd:01 1508068                    /usr/lib64/libselinux.so.1
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4b0f000-7fdba4b10000 r–p 00023000 fd:01 1508068                    /usr/lib64/libselinux.so.1
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4b10000-7fdba4b11000 rw-p 00024000 fd:01 1508068                    /usr/lib64/libselinux.so.1
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4b11000-7fdba4b13000 rw-p 00000000 00:00 0
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4b13000-7fdba4b2a000 r-xp 00000000 fd:01 1507934                    /usr/lib64/libpthread-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4b2a000-7fdba4d29000 —p 00017000 fd:01 1507934                    /usr/lib64/libpthread-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4d29000-7fdba4d2a000 r–p 00016000 fd:01 1507934                    /usr/lib64/libpthread-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4d2a000-7fdba4d2b000 rw-p 00017000 fd:01 1507934                    /usr/lib64/libpthread-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4d2b000-7fdba4d2f000 rw-p 00000000 00:00 0
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4d2f000-7fdba4d45000 r-xp 00000000 fd:01 1507936                    /usr/lib64/libresolv-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4d45000-7fdba4f45000 —p 00016000 fd:01 1507936                    /usr/lib64/libresolv-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4f45000-7fdba4f46000 r–p 00016000 fd:01 1507936                    /usr/lib64/libresolv-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4f46000-7fdba4f47000 rw-p 00017000 fd:01 1507936                    /usr/lib64/libresolv-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4f47000-7fdba4f49000 rw-p 00000000 00:00 0
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4f49000-7fdba4f4c000 r-xp 00000000 fd:01 1508495                    /usr/lib64/libkeyutils.so.1.5
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba4f4c000-7fdba514b000 —p 00003000 fd:01 1508495                    /usr/lib64/libkeyutils.so.1.5
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba514b000-7fdba514c000 r–p 00002000 fd:01 1508495                    /usr/lib64/libkeyutils.so.1.5
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba514c000-7fdba514d000 rw-p 00003000 fd:01 1508495                    /usr/lib64/libkeyutils.so.1.5
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba514d000-7fdba515a000 r-xp 00000000 fd:01 1508745                    /usr/lib64/libkrb5support.so.0.1
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba515a000-7fdba535a000 —p 0000d000 fd:01 1508745                    /usr/lib64/libkrb5support.so.0.1
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba535a000-7fdba535b000 r–p 0000d000 fd:01 1508745                    /usr/lib64/libkrb5support.so.0.1
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba535b000-7fdba535c000 rw-p 0000e000 fd:01 1508745                    /usr/lib64/libkrb5support.so.0.1
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba535c000-7fdba5377000 r-xp 00000000 fd:01 1508093                    /usr/lib64/libaudit.so.1.0.0
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba5377000-7fdba5577000 —p 0001b000 fd:01 1508093                    /usr/lib64/libaudit.so.1.0.0
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba5577000-7fdba5578000 r–p 0001b000 fd:01 1508093                    /usr/lib64/libaudit.so.1.0.0
Jun 20 22:53:09 jaseywang vps pppd[88951]: Exit.
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba5578000-7fdba5579000 rw-p 0001c000 fd:01 1508093                    /usr/lib64/libaudit.so.1.0.0
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba5579000-7fdba5583000 rw-p 00000000 00:00 0
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba5583000-7fdba5585000 r-xp 00000000 fd:01 1507867                    /usr/lib64/libfreebl3.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba5585000-7fdba5784000 —p 00002000 fd:01 1507867                    /usr/lib64/libfreebl3.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba5784000-7fdba5785000 r–p 00001000 fd:01 1507867                    /usr/lib64/libfreebl3.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba5785000-7fdba5786000 rw-p 00002000 fd:01 1507867                    /usr/lib64/libfreebl3.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba5786000-7fdba579b000 r-xp 00000000 fd:01 1507927                    /usr/lib64/libz.so.1.2.7
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba579b000-7fdba599a000 —p 00015000 fd:01 1507927                    /usr/lib64/libz.so.1.2.7
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba599a000-7fdba599b000 r–p 00014000 fd:01 1507927                    /usr/lib64/libz.so.1.2.7
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba599b000-7fdba599c000 rw-p 00015000 fd:01 1507927                    /usr/lib64/libz.so.1.2.7
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba599c000-7fdba59cb000 r-xp 00000000 fd:01 1508733                    /usr/lib64/libk5crypto.so.3.1
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba59cb000-7fdba5bca000 —p 0002f000 fd:01 1508733                    /usr/lib64/libk5crypto.so.3.1
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba5bca000-7fdba5bcc000 r–p 0002e000 fd:01 1508733                    /usr/lib64/libk5crypto.so.3.1
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba5bcc000-7fdba5bcd000 rw-p 00030000 fd:01 1508733                    /usr/lib64/libk5crypto.so.3.1
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba5bcd000-7fdba5bce000 rw-p 00000000 00:00 0
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba5bce000-7fdba5bd1000 r-xp 00000000 fd:01 1508119                    /usr/lib64/libcom_err.so.2.1
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba5bd1000-7fdba5dd0000 —p 00003000 fd:01 1508119                    /usr/lib64/libcom_err.so.2.1
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba5dd0000-7fdba5dd1000 r–p 00002000 fd:01 1508119                    /usr/lib64/libcom_err.so.2.1
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba5dd1000-7fdba5dd2000 rw-p 00003000 fd:01 1508119                    /usr/lib64/libcom_err.so.2.1
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba5dd2000-7fdba5ea8000 r-xp 00000000 fd:01 1508743                    /usr/lib64/libkrb5.so.3.3
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba5ea8000-7fdba60a8000 —p 000d6000 fd:01 1508743                    /usr/lib64/libkrb5.so.3.3
Jun 20 22:53:09 jaseywang vps pptpd[88950]: GRE: read(fd=6,buffer=55afa3981480,len=8196) from PTY failed: status = -1 error = Input/output error, usually caused by unexpected termination of pppd, check option syntax and pppd logs
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba60a8000-7fdba60b6000 r–p 000d6000 fd:01 1508743                    /usr/lib64/libkrb5.so.3.3
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba60b6000-7fdba60b9000 rw-p 000e4000 fd:01 1508743                    /usr/lib64/libkrb5.so.3.3
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba60b9000-7fdba6104000 r-xp 00000000 fd:01 1508729                    /usr/lib64/libgssapi_krb5.so.2.2
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba6104000-7fdba6304000 —p 0004b000 fd:01 1508729                    /usr/lib64/libgssapi_krb5.so.2.2
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba6304000-7fdba6305000 r–p 0004b000 fd:01 1508729                    /usr/lib64/libgssapi_krb5.so.2.2
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba6305000-7fdba6307000 rw-p 0004c000 fd:01 1508729                    /usr/lib64/libgssapi_krb5.so.2.2
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba6307000-7fdba64bd000 r-xp 00000000 fd:01 1507908                    /usr/lib64/libc-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba64bd000-7fdba66bd000 —p 001b6000 fd:01 1507908                    /usr/lib64/libc-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba66bd000-7fdba66c1000 r–p 001b6000 fd:01 1507908                    /usr/lib64/libc-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba66c1000-7fdba66c3000 rw-p 001ba000 fd:01 1507908                    /usr/lib64/libc-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba66c3000-7fdba66c8000 rw-p 00000000 00:00 0
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba66c8000-7fdba6706000 r-xp 00000000 fd:01 1508723                    /usr/lib64/libpcap.so.1.5.3
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba6706000-7fdba6905000 —p 0003e000 fd:01 1508723                    /usr/lib64/libpcap.so.1.5.3
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba6905000-7fdba6907000 r–p 0003d000 fd:01 1508723                    /usr/lib64/libpcap.so.1.5.3
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba6907000-7fdba6908000 rw-p 0003f000 fd:01 1508723                    /usr/lib64/libpcap.so.1.5.3
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba6908000-7fdba6909000 rw-p 00000000 00:00 0
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba6909000-7fdba690b000 r-xp 00000000 fd:01 1507914                    /usr/lib64/libdl-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba690b000-7fdba6b0b000 —p 00002000 fd:01 1507914                    /usr/lib64/libdl-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba6b0b000-7fdba6b0c000 r–p 00002000 fd:01 1507914                    /usr/lib64/libdl-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba6b0c000-7fdba6b0d000 rw-p 00003000 fd:01 1507914                    /usr/lib64/libdl-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba6b0d000-7fdba6b1a000 r-xp 00000000 fd:01 1508738                    /usr/lib64/libpam.so.0.83.1
Jun 20 22:53:09 jaseywang vps pptpd[88950]: CTRL: PTY read or GRE write failed (pty,gre)=(6,7)
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba6b1a000-7fdba6d1a000 —p 0000d000 fd:01 1508738                    /usr/lib64/libpam.so.0.83.1
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba6d1a000-7fdba6d1b000 r–p 0000d000 fd:01 1508738                    /usr/lib64/libpam.so.0.83.1
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba6d1b000-7fdba6d1c000 rw-p 0000e000 fd:01 1508738                    /usr/lib64/libpam.so.0.83.1
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba6d1c000-7fdba6d24000 r-xp 00000000 fd:01 1507912                    /usr/lib64/libcrypt-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba6d24000-7fdba6f23000 —p 00008000 fd:01 1507912                    /usr/lib64/libcrypt-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba6f23000-7fdba6f24000 r–p 00007000 fd:01 1507912                    /usr/lib64/libcrypt-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba6f24000-7fdba6f25000 rw-p 00008000 fd:01 1507912                    /usr/lib64/libcrypt-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba6f25000-7fdba6f53000 rw-p 00000000 00:00 0
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba6f53000-7fdba7113000 r-xp 00000000 fd:01 1508751                    /usr/lib64/libcrypto.so.1.0.1e
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba7113000-7fdba7313000 —p 001c0000 fd:01 1508751                    /usr/lib64/libcrypto.so.1.0.1e
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba7313000-7fdba732d000 r–p 001c0000 fd:01 1508751                    /usr/lib64/libcrypto.so.1.0.1e
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba732d000-7fdba7339000 rw-p 001da000 fd:01 1508751                    /usr/lib64/libcrypto.so.1.0.1e
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba7339000-7fdba733d000 rw-p 00000000 00:00 0
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba733d000-7fdba73a1000 r-xp 00000000 fd:01 1508753                    /usr/lib64/libssl.so.1.0.1e
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba73a1000-7fdba75a0000 —p 00064000 fd:01 1508753                    /usr/lib64/libssl.so.1.0.1e
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba75a0000-7fdba75a4000 r–p 00063000 fd:01 1508753                    /usr/lib64/libssl.so.1.0.1e
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba75a4000-7fdba75ab000 rw-p 00067000 fd:01 1508753                    /usr/lib64/libssl.so.1.0.1e
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba75ab000-7fdba75ad000 r-xp 00000000 fd:01 1507942                    /usr/lib64/libutil-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba75ad000-7fdba77ac000 —p 00002000 fd:01 1507942                    /usr/lib64/libutil-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba77ac000-7fdba77ad000 r–p 00001000 fd:01 1507942                    /usr/lib64/libutil-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba77ad000-7fdba77ae000 rw-p 00002000 fd:01 1507942                    /usr/lib64/libutil-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba77ae000-7fdba77ce000 r-xp 00000000 fd:01 1507901                    /usr/lib64/ld-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba7998000-7fdba79a5000 r-xp 00000000 fd:01 1512314                    /usr/lib64/libnss_myhostname.so.2
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba79a5000-7fdba79a8000 r–p 0000c000 fd:01 1512314                    /usr/lib64/libnss_myhostname.so.2
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba79a8000-7fdba79a9000 rw-p 0000f000 fd:01 1512314                    /usr/lib64/libnss_myhostname.so.2
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba79b5000-7fdba79c0000 rw-p 00000000 00:00 0
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba79c9000-7fdba79ca000 rw-p 00000000 00:00 0
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba79ca000-7fdba79cc000 rw-s 00000000 00:16 19496                      /run/ppp/pppd2.tdb
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba79cc000-7fdba79cd000 rw-p 00000000 00:00 0
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba79cd000-7fdba79ce000 r–p 0001f000 fd:01 1507901                    /usr/lib64/ld-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba79ce000-7fdba79cf000 rw-p 00020000 fd:01 1507901                    /usr/lib64/ld-2.17.so
Jun 20 22:53:09 jaseywang vps pptpd: 7fdba79cf000-7fdba79d0000 rw-p 00000000 00:00 0
Jun 20 22:53:09 jaseywang vps pptpd: 7ffc6d3db000-7ffc6d3fc000 rw-p 00000000 00:00 0                          [stack]
Jun 20 22:53:09 jaseywang vps pptpd: 7ffc6d3fc000-7ffc6d3fe000 r–p 00000000 00:00 0                          [vvar]
Jun 20 22:53:09 jaseywang vps pptpd: 7ffc6d3fe000-7ffc6d400000 r-xp 00000000 00:00 0                          [vdso]
Jun 20 22:53:09 jaseywang vps pptpd: ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
Jun 20 22:53:09 jaseywang vps pptpd[88950]: CTRL: Client 117.73.146.179 control connection finished

现象就是 pptp VPN 连接失败,每次连接都会报上面的错误,寻着关键词找到了这个 15 年发现的 bug:
https://nvd.nist.gov/vuln/detail/CVE-2015-3310

简而言之就是 2.4.6 版本之前的 ppp 进程每次 fork 的时候产生 PID 的时候,一旦大于 65535,plugins/radius/util.c 里面的函数 rc_mksid 就 overflow 了,只能重启机器解决。最坑的是,Ubuntu/Debain/OpenSuse 都更新了相应的补丁,但是 RedHat 没有,没有,并且对于 5/6/7 三个大版本都不会修复

这么大的影响,尤其对于一台生产的服务器,pid_max 设置超过 65535 是件很正常的事情,不知道 Redhat 是怎么考虑这件事情的。
临时的解决办法要将 pid_max 设置成 65535 以下,要么定期设置 /proc/sys/kernel/ns_last_pid 的值,指定接下来新生成的 PID 获得比较低的值,后者在 3.3 以上的内核才支持。

全网统一账户实践

分享下目前我们全网的账号管理体系。

整体的账户管理思路是分而治之。主要分为下面三类账户:
1. 办公网账户,也就是大家熟悉的域账户。对于办公网账户,全网用户一人一账户,在 OpenLDAP 的基础上做了一些开发,这是进入公司内部的大门,所有新入职的员工都会分配一个该账号,不管是在办公室连接 Wi-Fi 还是在家连接 anyconnect VPN,访问 confluence/jira 等基础办公设置,都需要通过此账户进行登录认证。
2. 生产网账户,主要用来访问线上、线下机器资源。工程师访问线上生产、测试机器,登录线下自助机树莓派(raspberry) 均需要通过此账户认证,整个 user/group 的分配、HBAC/sudo 的控制、密码/公钥的管理均在 freeIPA/IDM 上实现,freeIPA 是 RedHat 支持的一整套集成安全信息管理解决方案系统,又称 IDM。
3. 数据库账户,这块比较小众,简单带过。
下面会针对上面两大块分别介绍。

办公网账户

该账号与所有人息息相关,从入职第一天起到你的 lastday,都需要登录该账户才可以访问办公资源,包括常见的 Wi-Fi/Gitlab/Jira/Confluence/Jenkins/Cisco Anyconnect VPN/Zabbix/Grafana/跳板机(intermediate host) 以及自己开发的各种内部系统。

这里面需要先简单描述下目前我们的多网分离的架构,多网是指办公网(包含国际线路)、生产网、测试网、专线网(到医院 HIS/LIS 等信息系统)、OOB(带外管理网),这五张大网是处于「部分」分离的状态的,比如,办公网到生产网/测试网/专线网/OOB 是完全分离的状态,除非通过跳板机(后面全部以 ih 代指)登录之后再访问;生产网跟测试网也是几乎分离的,除了极个别的公共服务。以办公网登录生产、测试网为例,在进入用户验证这步之前,会先通过 IP <-> MAC <-> 用户身份的一一映射绑定,先通过最基本 IP:PORT 的 ACL 方式来控制住大部分的请求。所以在你能通过网页打开 git,通过 ssh 协议 pull/push git 仓库的时候,说明已经通过 TCP/IP 层面的验证机制以及用户级别的验证机制,具体如何实现的会在后面的博客中说明。

默认情况下,OpenLDAP 支持的 schema 非常有限;另外不同应用接入方式都不大一样,需要逐一尝试。

比如 LDAP 跟 Anyconnect 的对接,官方提供的 schema 仅仅基本可用,离生产还有一段距离,默认只支持添加一组 IP/Netmask,以及一条 IP 层面的 ACL,为此需要自行扩展维护一套 cisco.ldif 文件,这个是我们自行维护的一个 schema 文件,根据我们业务的情况,新增了一组 IP/netmask 以及若干的 ACL。下面是一个普通用户的数据文件示例:

从 slapcat 导出的字段数据可以看到,为了实现 Wi-Fi 账号跟 OpenLDAP 的共享,加入了 samba 相关的 schema,具体的可以看这个文件

再比如,对于 anyconnect/ih 的认证,需要增加两步验证机制,这里引入 OTP(privacyIDEA) 以及 Radius 作为跟 OpenLDAP 的桥梁例,具体的交互图可以看这里:

最终实现了用户的 CRUD 在 OpenLDAP 层面控制。用户的两步验证,下图可以看到,privacyIDEA 支持十余种的 token,包括 hOTP/mOTP/sms/email/Yubikey 等等:

privacyIDEA 不仅仅支持我们使用的 ldapresolver,sql/passwd/scim 的 resolver 都有很好的支持。目前我们使用 Google Authenticator 是基于事件的 HOTP(RFC4226):

用来管理 OpenLDAP 的工具有不少,包括我们使用的经典的 phpldapadmin,除此之外,fusiondirectoryweb2ldap 都是不错的选择。同时为了支持用户的自助修改、重置密码,定期修改用户密码,我们引入了 LTB,一个非常神奇的 LDAP 工具箱集合,目前仅支持通过邮件找回密码的链接来重置密码:

除了自助机服务,LTB 还支持 LDAP 性能、用户使用数据的监控等若干非常实用的脚本。
这么重要的基础服务稳定性肯定是需要保障的,通过 syncprov 模块实现双 master 的写的高可用,通过多个 slave 同步 master,前端挂 Haproxy 实现读的高可用:

对用户来说,他们看到的是下面这个样子:

PACKT 出版的 Mastering OpenLDAP 是本通俗易懂的书,浏览一遍之后应该能轻松应对上面的内容。 

生产网账户

这里的生产网泛指包含线上生产测试服务器线下自助机树莓派等在内的所有 *nix 系统。所有需要登录如上机器的用户都需要获得该账户的权限之后,才能访问基于 HBAC 机制的主机以及颗粒度更细致的用户执行权限。

整个系统基于 freeIPA/IDM 实现,默认情况下,每台机器有一个专门用来运行进程(我们所有的 JVM 进程都跑在 vm 上,不会出现混跑的状态)的 worker 用户,所有的相关的 bin/, log/, lib/ 等目录文件都通过 Jenkins 统一打包到 ~/worker/ 下面,实现跟系统文件的隔离。/home/worker/ 的权限如下:

worker/ 下面所有的目录文件权限都如上所示。这样,只要用户在 bm_be_sre 这个组下面,就能实现 worker/ 下面也即 JVM 相关服务的读取权限:

下图可以看到,appCenter 这个服务是跑在 worker 下面的:

类似的,如果想实现 worker/ 下面的写操作,比如执行 bin/ 下面的脚本,将用户加到 30002(sre) 这个组即可,这里完全可以各自的需求自定义。所有的 sudo/su 相关权限设置全部在 IPA 的 Policy 操作即可,比如下面这个赋予的是 sre 这个组的用户可以执行 /bin/su – worker、/bin/su worker 这两个单独的比较危险的命令以及 sre_allow 命令行组里面基础命令(/bin/chmod, /bin/chown, /bin/cp 等等):

目前单台 8G/4core 的 IPA 支撑着 1000+ 的线上生产测试的物理虚拟机以及线下 100+ 的树莓派,应付起来绰绰有余,CPU 平均 1% 利用率、disk IO 平均 10%。

对我们的用户来说,在经过办公网/VPN 的 IP ACL 过滤之后,通过办公网账号结合 OTP 登录线上的任意一台跳板机(ih),然后通过 ih 再登录线上的机器,跟办公网账户类似的是,需要定期修改密码。对有权限看到的用户来说,他们看到的是下面这样

以上的两块账户体系算是把当年在阿里的基础核心账户体系复制了一遍,对最终用户来说,体验相对来说会更好些,当然我们没法也暂时没必要实现类似阿里郎那种监控每台入网设备所有操作的系统。

需要注意的是,在 IPA 上新增的用户,或者新增 sudo 权限,由于 sssd 的缓存,不会立即生效,可以通过 sss_cache 或者删除缓存文件可以让规则立即生效,这部分可以以类似 hook 的方式触发,每次修改用户权限的时候自动触发该操作。

freeIPA 结尾的 A 表示 audit,实际情况是目前还不支持 audit 功能,所以这块功能我们通过 snoopy 结合 rsyslog 方式进行收集审计

对于办公网账户,目前通过 python-ldap 实现了多个层次的自助以及服务的打通,freeIPA 还未进行这块的开发工作,最终的效果类比阿里内外,一个 portal 实现不同用户的自助服务。

数据库账户

第三块,或者说非常小众的一块账户是 DB 的账户,这里面主要涉及 MySQL 以及 NoSQL(Redis/ElasticSearch) 的账户划分管理审计。

MySQL 的账户管理我们通过 saltstack 的 mysql_user 进行管理,我们用的saltstack 是 2015.8.7,对 MySQL 5.7 的支持有不少 bug,2016 开头的版本对此都修复了,嫌麻烦的不妨直接把 salt 给升级了或者做 diff 给 2015.8.7 打 patch,主要原因是 5.7 之前存储用户表的密码字段是 password 而 5.7 之后变成了 authentication_string。

目前所有的 MySQL 账户用户通过 git 管理而密码通过 salt pillar 管理,审计则使用了 Percona 的 Audit Log Plugin 通过 rsyslog 打到中心服务器收集分析。

对于 Redis/ES 来说,由于上面存储的数据为非敏感数据,所有的都通过 IP 层面的 ACL 进行控制访问。

一张复杂网络的生长过程

虽然不是网络出身,但是对于我们全网架构的「生长」过程还是比较了解的,分几个重要的时间点讲讲里面有意思的事情。

15 年下旬

公司业务还没起飞,全网架构简单,应付一天 1k+ 的订单了(有效挂号单)绰绰有余,机房跟第三方的卡管机构通过一根 10M 的 SDH 专线打通,所有到院方的请求先经过第三方的卡管机构,由其转发再进行业务层面的处理,实际的带宽峰值不到 500kbps。

16 年初

正式开始批量接入三甲医院,同时跟医院数据打通的方式也由原先的经过第三方卡管机构的非直连方式变成了直连方式,所有接入的院区通过两根双活的专线跟我们机房打通,两根专线的意义很重大,一旦一根专线被挖掘机挖断,可以在 1s 之内切换到另外一根,上层业务通过重试机制可以做到几乎无感知。新闻上报道的某某地区由于光纤被挖掘机挖断造成网络中断的问题在后来专线数量增加的情况下时有发生,但是到目前为止对于这种双主的架构并无影响,考虑到成本等因素,暂时不会做 N + 2。

为了控制 IP 地址的分配以及部分安全性的考虑,跟院方接入全部采用双向 nat 的方式,双向 nat 的问题之前的博客有过介绍,只不过之前是通过 iptables 实现,本次通过专业的路由设备实现。经过双向的 IP 地址转后,我们对院方的地址全部隐藏,另外由于院内自助机的 IP 全部由我们自行分配,通过双向 nat 之后,我们有更大的自主权。下面这张图演示了 IP 地址转换的过程:

与此同时,为了快速实现新接入医院的稳定上线,保守采用了双防火墙双路由器的策略,通过 BGP/BFD 协议实现单条线路失败的快速收敛,总成本控制在 20K 左右:

医院的数据通过一根 2M 的专线,一根 10M 的专线汇聚到我们的核心机房,核心机房通过主流的三层结构互联。

对于办公网来说,为了实现访问 google 等国际联路,我们通过在办公网的路由器上设立 GRE 隧道的方式连接到国内的专线服务商,再由该服务商进行国际流量的转发,由于跨了国内的公网环境,会出现偶尔的延时增高以及中断的问题。

16 年中

随着接入院区的爆发式增长,成本成了很大的一个问题,原先所有院区接入同一个核心机房的方式不仅成本无法得到控制,单点也成为了一个迫在眉睫的问题。原先三层的简单架构也无法满足日后的水平横向扩展。为了解决上面的问题,花了大量时间跟北京具有运营商资质的公司进行了大量的商务沟通,实现了专线、带宽资源的大幅度下降。在保证稳定性的前提下,2M 的专线做到了平均 450RMB/m,10M 的 1500RMB/m,50M 的 4000RMB/m,100M 的 6000RMB,同时引入了阶梯价格的策略,量大会更加具有竞争力,当然三大运营商的价格会比鹏博士、天地祥云的高些,毕竟稳定性也高的多(这个后来验证确实如此)。最终跟北京三大运营商以及几家准运营商达成了友好的合作,实现了双方的共赢。上面的问题谈妥了,接下来自然引入了下面几个核心思想:
1. 链路类型,优先选用 SDH/MSTP 协议的,G.703 次之。
2. 运营商,成本跟稳定性下的权衡,优先选用电信/电信通,联通/天地祥云次之。
3. 专线接口类型,优先选用双绞线电口,光纤单模次之,方便排查问题,同时默认接入千兆全双工,百兆全双工作为备选。
4. 建立中立的中转机房,所有院区的专线先通过中转机房再进入核心机房,实现了跨区域专线的成本以及稳定性的大幅提升。
5. 在上条的基础上,全网引入骨干网 msr(metropolitan small router)、核心网 csr(core small router)、汇聚网 csw (core switch),专线 dll(dedicated leased line),边界路由器 edr(edge router),边界交换机 esw(edge switch)。优先选择中低端廉价设备,比如 msr 使用 Cisco2921/K9,csw 使用 WS-C3750X-24T-F,esw 使用 WS-2960X-24TS-L 等型号,通过 HSRP/BFD 等协议实现分而治之。

着重说下最后的两点,对于第 4 点,其架构图如下:

可以看到,这一阶段引入了 msr/csw 等角色,将运营商的专线接入诸如鹏博士、天地祥云等中立机房的进行中转,最终汇聚到核心的机房。每一台中转机房的 msr 承载 20 条左右的专线,通过上方的 csw 进行线性扩展,目前每条专线的带宽在 2~10M 左右,所以不会给机器造成很大的压力。

对于第 5 点,在核心骨干汇聚分成之后,一方面是实现了多网分离,即生产网、测试网、OOB 网,办公网以及到院方的专线网的分离,极大的方便了 tcp/ip 层面的访问控制,在这个阶段,所有对人的访问控制(人访问线上线下)全部通过在网络设备上加白名单的方式实现,算是实现了基础的访问控制,虽然比较繁琐。另外一方面全网由之前的树根结构扩展到了树根枝干末梢叶子的网状结构,扩展性以及冗余性都有了很大的提高,下面这张图是相对比较成型的网络拓扑:

这个阶段,除了院内、机房的大幅度改造之外,办公网尤其是国际网络也做了优化,从原先的 GRE 隧道方式一步到位成了专线直连方式,办公网通过专线直接到服务商节点,节点直接到第一线的香港节点,同时,为了避免所有流量都走国际网络,我们在内网通过 DNS view 的方式,将主要被墙的域名解析丢给 Google DNS,其余则解析丢给国内 DNS,DNS 层面解析结束之后,TCP/HTTP 的流量则通过在路由层面通过不同的 ACL 规则实现国内国际流量的划分。下图是日常访问 Google 的 ICMP 延时:

16 年底

为了进一步控制成本,响应国产化的号召,原先一家院区 4 台设备(2 台防火墙、2 台路由器)的架构,在保证稳定性不变的情况下,优化成了由 2 台带路由功能的防火墙(USG 6306)组成的专线网络:

在同样秒级切换的情况下,成本降低到了原先的一半不到。同时,考虑到后续接入非三甲院区的特殊性,目前正在调研舍弃大型物理硬件,通过 4G 网卡配套 VPN 的方式来进行网络层面的直连。

在优化成本以及性能的基础上,还进行了下面几点的优化:
1. 通过 PowerDNS 的 API 实现了上千条内网的 DNS 正反向解析,这对于使用 mtr 细颗粒度的排查定位问题提供了很大的帮助
2. QoS 的优化,优先走生产上的业务流量,其次生产上的非核心(日志、监控等),在 msr 上通过 CoPP 实现
3. 全网设备的配置备份问题,所有设备的配置每日自动备份到内网的 gitlab 上
4. 为了实现生产网访问被墙的资源,在办公网搞了两套 tinyproxy,生产的机器通过 http_proxy,访问前端的 Haproxy 实现了网络资源的自由访问
5. 办公网无线的 LDAP 认证,这块在全网统一账户实践有所涉及

从 15 年底到 16 年底的一年多时间,通过不断的演变,一个相对比较完善有很强冗余性的大网基本建设完成,该架构支撑目前每天的 100k 订单(有没有发现一年期间增长了多少倍),40k 的有效挂号量没有任何瓶颈。

在建设初期遇到不少跟院方通信的网络中断问题,起初做贼心虚以为是自身的问题,后来通过监控不断的完善,实现了分钟级别的问题发现与诊断。

下面列一些有趣的问题:
最常见的,某院区由于专线被挖断,单条专线中断,平均一个月一次。院方机房全部或者部分掉电,导致所有专线中断;院方机房制冷设备故障,导致专线设备罢工死机。院方线下自助机网络设备故障,导致该区域自助机全部脱网,类似的事情不一而足。再比如我们的 RPC 服务访问某院区 HIS,凡是下一跳为 10.222.0.45 均能够访问终点 IP,凡是下一跳为 10.222.0.41 则无法访问同样的的终点 IP,经过抓包发现由于院方的两台核心路由故障导致。最喜剧的性的事,某院区偷懒将我们跟 HIS 直连的 IP 划分到他们的核心网络,由于 arp-proxy 的问题导致全院 HIS 宕机数个小时。当然医院 HIS 宕机其实是件很频繁的事,之前仅仅因为处在一个封闭落后并且无知的环境,很多时候重启应用重启机器问题就算是绕过去了,现在一下子暴露在了一支「正规军」面前,一下子露馅了。

树莓派(raspberrypi)、saltstack 在线下自助机运维上的应用

目前每家院区都分布了从数台到近百台规模不等的自助机,覆盖了北京市属 22 家医院的三十多个院区,一千多台的日常变更、升级管理、甚至常人看来很简单的开关机成了摆在眼前的一大问题。下面这篇博客会抛出 4 个问题并且分享下我们线上的实战经验。

1. 开关机,一个看似很幼稚的问题
你去市面上问一个的有点经验的运维,「服务器怎么开关机」,他可能第一反应是,「服务器要关机吗?」如果你接着问,「如果现在就有这么一个需要,需要先关机过段时间再开机,怎么办?」,他很可能会告诉你,「远程卡啊,这不是标配吗,再不行,电话个驻场的帮忙开下呗」。 以上的情况对于机房的服务器是适用的,但是对于自助机,放在院内各个大厅角落,物理环境恶劣,随时断网断电,尘埃飞扬,更别谈恒温空调 UPS 之类的,要实现开关机,真不是一件容易的事情。我们在院内用的自助机,说白了就是一台组装的 PC,仅仅是通过串口并口连接了一些读卡器扫码器等外置设备。既然是消费级别的 PC,就不会有远程卡这么「高端」设备,当然,对于 PC 级别来说,市面上是有跟企业级别 iDRAC/iLO/iMana 类似技术的设备的:Intel 的 AMT,最终的实现效果跟远程卡几乎一样,另外一种能实现开机的方式就是通过 Wake-on-LAN 这种古老的协议。

有开就有关,AMT 能开能关,Wake-on-LAN 就没办法了。但是基本思想很简单,需要在每台机器上安装一个 agent,通过此 agent 来下发关机以及后续的变更操作。

有了上面的思路,我们来对比下 AMT 以及 Wake-on-LAN 这两种方案的优劣,如下图:

对于目前的业务来说,我们最看重的是经济成本以及可扩展性,很明显,Wake-on-LAN 完爆 AMT。

有了大方向,下面是具体的实现,首先是至少有一台常年开机的机器用来唤醒其他的机器,选自助机肯定不行,这些机器本身就会出现白天开机晚上关机的状态,后来想到了树莓派,设备小,可以完全放进一台自助机里面,只要该自助机的电源线不拔,就能保证树莓派的常年开机状态;管理简单,默认使用的 Raspbian 系统,源的同步,账户的管理,监控、变更等等跟我们线上完全打通;经济成本低,一台树莓派配上 SD 卡电源线插座传感器(这个后面会单独提)不到 400。有点需要注意的是,很多情况下院内会有多个 vlan,正常情况下 Wake-on-LAN 不支持跨网段的唤醒,一般来说,放在不同位置的自助机网段会不大一样,加上我们需要监控不同位置的温湿度烟雾的状态,所以最终决定出单家院区 4 台树莓派的标准配置。下图是一套树莓派的配置图:

搞明白了上面的核心问题,接下来要解决的是流程类的问题,每上一个新院区,我们会直接格式化 SD 卡灌装定制的 raspbian 系统,salt 初始化,zabbix/freeipa 注册,实施人员到现场之后插电接网即可。

2. 如何优雅的开关机
上面的话题仅仅覆盖了基本的原理,在我们上线的早期,每个院区仅仅上线了个位数的机器,同时运行的院区在三四个左右。这里需要提到一个背景,每个院区的部分自助机,同一个院区的不同自助机,开关机时间都不同,比如友谊位于门诊大厅的自助机是每天早上 7:00 准时开机对外使用,但是二三楼的自助机则是每天早上 07:10 启用,还有一台位于急诊大厅的机器则是全年 24 小时开机,而对于同仁医院来说,所有的机器都是早上 06:45 开机。

早期,我们通过 saltstack/jenkins/git 在树莓派上维护对应的院区的 crontab 列表来实现自助机的开关机。

另外一个频繁出现的问题是,院方会经常性的提出修改自助机开关机服务时间的需求,每次运营转达给我们再经过 git/jenkins 提交的效率异常的低效。为了彻底的将这部分重复低效的工作从运维手里解放出来,我们为院方开发了一套开放平台(open),除了日常的开发者文档更新、开发接口 API 调用,接口测试用例等之外,一块重要的功能就是为院方开放了自助机服务器时间的自主修改查看权限,这样将日常繁杂的自助机时间管理下移到了院方手里。

目前该平台支持全局、个别自助机的开关机时间:

bangkok 上面的 KioskScheduler 进程定期会向 open 平台同步各个院区所有自助机的开关机时间,将其写入到 MySQL,底层通过 APScheduler 这个任务框架来调度,使用 BackgroundScheduler 调度器,默认的 MemoryJobStore 作业存储。每家院区的规则都分为全局跟单独两种,全局规则针对该院区的所有自助机有效,优先级低;单台自助机规则仅针对单台自助机规则生效,优先级高。KioskScheduler 根据以上优先级的不同,优先执行高优先级的规则。这样「积水潭 2017 年春节期间,除了 10、11 号自助机在每天的 08:00 ~ 16:00 开机之外,其余所有的自助机均关机」的规则就能顺利实现了。

同时,为了确保 KioskScheduler 运行正常,应用层面通过 monit 实现进程的监控,业务层面的规则执行与否以及是否达到预计,我们通过 python-nmap 实现了一个批量扫描的脚本,每次开关机时间点触发后的 5min/10min/15min 三个阶段,对命中规则的自助机进行批量的存活性扫描,对于未达到期望的自助机会触发报警到我们的自助机运维同事那边进行人工处理。

对于开机的方式,部署在院内的 4 台树莓派通过 syndic 机制收到请求后同时向目标机器发起唤醒的请求,根据之前的经验,单台树莓派的唤醒偶尔会出现唤醒失败的情况,另外一点 4 台里面只有保证至少有 1 台存活,那么开机就能成功触发。

3. 如何低成本实现 OOB 的核心功能?
先来看下行业标杆的 Dell 远程卡(OOB)提供的一些核心功能,如下图:

根据我们日常使用频率的统计,80% 以上的操作花在了如下的操作上:

1. 服务器的开关机,尤其是机器 hang 住了/kernel panic 之后的开关机
2. 由于各种原因无法 ssh 之后需要通过虚拟终端进入查看当前机器屏幕的状态
3. 机器主要零部件的硬件状态,健康状况

对于一台自助机来说,其核心是简化后的服务器,没有 raid 等企业功能,除此之外,提供的服务跟服务器并无二异,仅仅是加上了 GUI 而已。对于第一、二两点,上面的话题已经阐述过,比较遗憾的是目前并不能对机器的死机、蓝屏实现脱离系统的开关机重启以及实时屏幕的查看,但是对于日常的开关机,VNC 远程操控,绰绰有余;对于第三点,目前诸如磁盘等底层硬件的监控是放在应用层来监控,对于我们来说,个别自助机硬件层面的宕机并不会影响整个院区的使用,我们及时报修返厂更换即可解决此类问题,众所周知的是,对于绝大多数的医院,其院内的物理环境,比如尘埃浓度(PM10)、温湿度等跟正规的机房比相距甚远,早期,我们发现某院区的部分的自助机经常性的宕机蓝屏,经过若干天系统级别应用级别的排查,都无所发现,后来现场的志愿者提醒我们是不是温度太高导致的,现场勘查后发现,西区的部分自助机直接放在了仅有一顶透明帐篷遮蔽的半室外空间内,6 月市内温度 30 度的情况下,这部分自助机箱体的温度已经接近 40 度了,蓝屏在所难免了。

为了及时发现这类问题,我们后续在所有树莓派上全部引进了温度、湿度以及烟雾的传感器,成本非常低,一个 DHT11 的温湿度传感器加上一个 MQ-2 的烟雾传感器成本在 20RMB 以内,加上现成的 Adafruit_DHT/RPi.GPIO 的库直接调用,完美解决此类问题。通过分散在不同地点的四台树莓派,我们能够推断出当前院内的物理环境,这对改进目前自助机的物理位置有非常重要的意义。

下图是某院区蓝屏故障增大期间周边温度的变化,观察可以发现具备一致性关系:

类似的,我们在院方机房放置的连接专线的路由设备,同样发现多次类似的问题,下图是某院区机房空调设备故障温度升高导致设备丢包增大中断服务的监控:

很多看似简单的问题,一旦场景转变了,需要应对的措施也就随之改变了。

4. 如何有效实现自助机的变更操作
自助机上的变更,主要分为两类,一种是最为频繁的版本升级,包括自助机上挂号缴费程序的版本、第三方依赖的程序升级,这类变更的特点是,每次的程序升级,其升级包都相对较大,小的几兆,大的有上百兆;第二种变更更多的集中在日常的系统变更,比如修改 hosts 以对应不同的 nat 影射、增删改查注册表等系,对于这类变更,最大的特点是占用的带宽小,但是操作频繁。

针对这两种变更,分别设计了两种不完全一样的变更方式,但是底层都是通过 saltstack master/syndic/minion 的架构实现文件的传输。中心端一台 master(存在单点的问题),每家院区 4 台部署了 syndic 的树莓派,同时跑 master/syndic,向中心端注册,底层的自助机部署有 minion 向其中一台 syndic 注册,目前 minion 到 syndic 同样存在单点问题,后续考虑将 syndic 升级成 MultiSyndic。

对于第一种变更方式,我们将要升级的版本库文件打包上传至 git,通过 jenkins 将数据从打包机 git pull 下来之后,在打包机通过 salt 将升级的文件分发到 salt syndic 上,syndic 上会起 http 服务,自助机每次开机的时候会自动的向 http 服务检查是否有最新的版本,如果有的话则会升级,对于回滚,我们将版本号递增内容回滚至上一版本重启机器即可。
对于第二种变更方式,如果是修改注册表之类的变更,我们使用 cmd.run 直接将需要跑的 key 执行结束,类似下面这样:
cmd.run 'reg add "HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\HideDesktopIcons\NewStartPanel" /v "{5399-XXX-CBA0}" /t reg_dword /d 1  /f'

如果是传输文件的变更,跟第一种方式类似,不同的是,文件落地到 syndic 之后,我们会直接通过 master/minion 的方式 push 到每台自助机,而不是主动 pull 的方式。同时为了确认文件的完整,每次从 master 到 syndic,从 syndic 到 minion 的两个关键步骤都会做一次 md5 校验,最终实现的效果可以参考早期的 saltpad 版本,下图是 bangkok 中变更的页面展示:

除了最基本的单次变更外,增加了多次执行的执行步骤以及执行步骤的模版功能,前者对于多合一的操作步骤很适用,后者对于经常使用的诸如修改 hosts 文件等很适用。

在这之前,我们尝试直接通过 salt master/minion 的方式进行日常的变更管理,这种方式对于线下的实施同事来说非常的不友好,其灵活性以及方便性远低于目前的方案,遂未在团队内推广使用。上面介绍的系统是目前在线的稳定系统,使用了一段时间整体反馈还不错,后续会优化版本控制以及更加自动的回滚等操作。