技术流 | 运维平台大型“生产事故”录播和实战重现

【本文作者:擎创科技 资深专家禹鼎侯】

本文写于2021年,最近重读觉得特别有现场感。这也是运维人面对生产环境时遇到的各种惊心动魄的事件之一。惊险,但又顺利解决。是最好的结果。


事情是酱紫的。
那天上午,轻轻松松完成了一个新功能的开发,原本计划着混到中午吃个饭,美美的午个觉,下午跑跑测试,摸摸鱼,划划水,愉快的一天就过去了。
正当我在为我的完美计划自豪不已的时候,微信群闪过一条消息,有人艾特我。
特么的!!!
这个时候!居然有人艾特我!!!
当时我就不乐意了。指名道姓的艾特我,指定没好事。

图片

划开手机一看,果然,生产出事故了。而且看起来事情还比较紧急严重。

图片


我给大家简单描述一下事情的经过。
我们(咳咳,请把"们"字去掉,说的就是你,别想甩锅)开发了一个可以采集宿主机硬件指标的这么一个功能。其中有一项是获取IPV6的地址,然后这个IPV6地址获取的时候出问题了,本来不应该获取fe80开头的地址(fe80开头的地址类似于IPV4的192.168,是局域网的地址,这个是应该pass掉的),却获取成了一串乱七八糟的数字。

图片

当时的情况是这样的。客户提交了升级单,他们也怕出问题,就先升级了两千台设备,并打算当天晚上升级剩余的两万多台。
然后到了快中午的时候,发现这两千台中,有那么一百台的样子,获取的地址不对。
如果嫌我说的啰嗦的话,请我师爷来翻译翻译。

图片


简单来说,就是客户中午的时候发现了程序有问题,但是由于晚上要升级所有生产环境,所以下午必须给他们搞定。不能耽误他们晚上的升级。此诚危急存亡之秋也。
什么情况啊?
劳资特么一脸懵逼啊!
没办法啊,谁让咱是吃这碗饭的呢?于是乎,简单收拾一下,连午觉都不顾上了,背上我的蓝色小书包,坐上公交车,直接奔赴客户现场。


当时我心里是一点底都没有,这问题咱也没碰到过啊,于是脑中快速过了一遍当时的代码逻辑,看看能不能找到可以甩锅的地方。嗯,测试!一定是测试没测好!带着问题就上线了!
于是乎:

图片


人家很明确的告诉我,测试没有发现问题。
这就尴尬了。公司环境没有发现问题,pit环境也没有发现问题(备注:该pit环境是客户提供的一套无限接近生产环境的机器)。也就是说,这个问题似乎是生产环境独有的。
这特么就扯了。。。
这都什么鬼啊?
没办法了,去现场看吧。

图片


经过了冗长而复杂的客户园区入场手续后,终于来到了生产机房。客户找出两台有问题的机器,说,你调试吧!然后也不管我,忙他自己的工作去了。
生产的机器,如果玩过的大家都应该了解,客户不让做的事情千万别做,千万别想着删库跑路,然后坐船去新加坡,越南,柬埔寨。
特别是我当时拿到的是root权限。客户更是慎之又慎,就连重启程序都得经过他们同意。危险的命令想都不要想。
那还调试个鸡儿啊。

图片


但这个时候我可不能怂啊,老夫一世英名能否保住,就看在此一举了。
首先我给客户强调,这个问题百年难得一遇,肯定不是那么好解决的,今天下午就算能找到根因,回去还要修改代码,测试,晚上升级估计有点来不及。
打了这个预防针,客户也知道问题棘手,就有心里准备了。说,你先查原因吧,实在难解决的话今晚就暂缓升级,周五之前能搞定就行。
这样我就放心大胆的搞了。

图片


先说一下我们这个程序获取IPV6的逻辑。
我们这个程序是用C语言开发的,为了支持跨平台,我们引入了一个叫sigar的第三方库。这个sigar库是专门用来获取机器硬件指标的,而且对不同的平台操作系统都有实现。
Linux下,获取IPV6的逻辑是读取/proc/net/if_net6的配置文件。这个文件的第一项就是IPV6的地址。
简单来说,获取ipv6的地址,就是读取文件中指定字符串的内容的实现。听起来剁么简单的事情。就这破逻辑,还能出啥问题?
sigar库里这段逻辑在 src/os/linux/linux_sigar.c 中的sigar_net_interface_ipv6_config_get函数中。当然我们做了一些调整,最终的样子是这样的:

while (fscanf(fp, "%32s %02x %02x %02x %02x %16s\n",addr, &idx, &prefix, &scope, &flags, ifname) != EOF){if (strEQ(name, ifname) && addr != strstr(addr, "fe80")) {status = SIGAR_OK;break;}}

说一下/proc/net/if_net6这个文件,这个文件里存放的是接口和单播地址。其内部格式如下:
|addr(32位)|

addr(32位)if_index(一般2位十六进制数字)prefix(一般2位十六进制数字)scope(一般2位十六进制数字)flags(一般2位十六进制数字)ifname(16位)
ipv6地址接口ID前缀长度地址适用范围标志位网卡名称

这样一看,上面的代码解析,似乎没有什么问题嘛。
但,等等,这都是什么鬼?

图片


我嗅到了一丝犯罪的气息,虽然说不上哪里不对,但我感觉这里会有问题。第二位,也就是if_index,为啥出现了这么多三位的?
一个三位的字符串,却用%02x,这是会出问题的呀。
可是,为什么会出现3位的呢?

图片


咱也不知道啊。没办法,祭出百度吧!
然鹅,一上百度,是这个样子的:

图片


众所周知,大天朝的技术文章,百分之八十被号称吃屎都(D)难(N)的某网站给劫持了,只要一搜索,千篇一律的出来的都是该网站的链接,而且内容重复率之高,含金量之低,令人咋舌。
既然度娘不助我,我就只能寻求谷嫂的帮助了。
可是!

图片


完犊子了,这可咋办?
我忽然想到我一个高中同学发小是做海外竞价的,自己创业当了老板,咱要不去试试白嫖一波?

图片


嗯。。。弄起来还是挺麻烦的,但好歹是弄到了。
谷歌一游,大多数也只是告诉你if_net6文件是啥含义的,没有告诉我这个if_index到底应该有几位。
然后我在if.h头文件里发现了这个if_index的定义:

struct if_nameindex{unsigned int if_index;  /* 1, 2, ... */char *if_name;      /* null terminated name: "eth0", ... */};

int类型,理论上可以有8位啊,汗~
得,不管了。为了验证我这一猜想是对的,确实是if_index有三位导致的,我让测试的同事在pit环境找if_net6文件中有三位的测试,很快:

图片

然后就是愉快的修改代码的过程了。咱也不管有的没的,搞什么位数啊,代码一旦hard code了,下次有变动还是得出问题,不如一把搞定:

while (fscanf(fp, "%s %s %s %s %s %s\n",addr, idx, prefix, scope, flags, ifname) != EOF){if (strEQ(name, ifname) && addr != strstr(addr, "fe80")) {status = SIGAR_OK;break;}}

事实上,fscanf函数处理这种带固定宽度的解析时,如果字符串有三位,但只解析了两位,并不会把第三位丢弃,而是把第三位挤到了下一个域。
举个例子。

图片


上图中第二条记录,if_index321,按照上述代码逻辑处理时,会将32当做if_index,剩下的1当做prefix40当做scope20flags80ifname, veth1ffa1a8本来是网卡名,它会将其认为是第二条的ipv6地址,导致后面的全部错位。
嗯。。。接下来就是把代码改好,重新发布补丁,让客户更新测试。
虽然过程是曲折的,但结果是好的。

图片


至此,故事划一段落,可惜了了我的午觉啊。嘤嘤嘤~

———— THE END ————

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/861665.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

昇思MindSpore基本介绍

昇思MindSpore是一个全场景深度学习框架,旨在实现易开发、高效执行、全场景统一部署三大目标。 其中,易开发表现为API友好、调试难度低;高效执行包括计算效率、数据预处理效率和分布式训练效率;全场景则指框架同时支持云、边缘以…

C语言之进程学习

进程打开的文件列表:就是0 1 2 stdin stdout stderro等 类似于任务管理器是动态分ps是静态的 Zombie状态: 在Linux进程的状态中,僵尸进程是非常特殊的一种,它是已经结束了的进程,但是没有从进程表中删除。太多了会导…

轻量级仿 SpringBoot 程序

但凡 Java 程序,想必就是 Spring 程序;但凡 Spring 程序,想必就是 SpringBoot 程序——且慢,当今尚有不是 SpringBoot 即 SpringMVC 的程序不?有——老旧的遗留系统不就是嘛~——不,其实只要稍加“调教”&a…

TikTok网页版使用指南:如何登录TikTok网页版?

海外版抖音TikTok,已成为连接全球观众的重要平台。据统计,在美国,TikTok的用户数量已达到近1.3亿,并且在国外的95后用户群体中很受欢迎。 TikTok网页版也提供了一个广阔的平台,让品牌和创作者在电脑端与全球观众互动&…

智能语音抽油烟机:置入WTK6900L离线语音识别芯片 掌控厨房新风尚

一、抽油烟机语音识别芯片开发背景 在繁忙的现代生活中,人们对于家居生活的便捷性和舒适性要求越来越高。传统的抽油烟机操作方式往往需要用户手动调节风速、开关等功能,不仅操作繁琐,而且在烹饪过程中容易分散注意力,增加安全隐…

大数据处理引擎选型之 Hadoop vs Spark vs Flink

随着大数据时代的到来,处理海量数据成为了各个领域的关键挑战之一。为了应对这一挑战,多个大数据处理框架被开发出来,其中最知名的包括Hadoop、Spark和Flink。本文将对这三个大数据处理框架进行比较,以及在不同场景下的选择考虑。…

ubuntu篇---添加环境变量并且在pycharm中使用

ubuntu篇—添加环境变量并且在pycharm中使用 一. 添加环境变量 vim ~/.bashrc 在文件末尾加上 保存退出 source ~/.bashrc二. 在pycharm中添加环境变量 1.打开pycharm,并打开你的项目 2.点击菜单栏中的“Run”, 选择“Edit Configurations” 3.在弹…

pytorch为自己的extension backend添加profiler功能

pytorch为自己的extension backend添加profiler功能 1.参考文档2.your-extension-for-pytorch需要增加的代码3.pytorch demo及如何调整chrome trace json文件4.[可视化](https://ui.perfetto.dev/) 本文演示了pytorch如何为自己的extension backend添加profiler功能 背景介绍 …

Taro +vue3 中的微信小程序中的分享

微信小程序 右上角分享 的触发 以及配 useShareAppMessage(() > {return {title: "电影属全国通兑券",page: /pages/home/index,imageUrl: "http:///chuanshuo.jpg",};}); 置 就是Taro框架中提供的一个分享Api 封装好的

项目经理必读:三步走实现项目高效管理

一个项目的成功往往取决于项目管理能力的高低。若管理不当,易导致团队成员间的推诿和抱怨,且项目团队还可能面临成员对目标不明确、信息不透明、进度难以跟踪等问题。作为项目经理,掌握有效的项目管理策略至关重要。 一、精细化的目标拆解 …

数据库逻辑结构设计-实体和实体间联系的转换、关系模式的优化

一、引言 如何将数据库概念结构设计的结果,即用E-R模型表示的概念模型转化为关系数据库模式。 E-R模型由实体、属性以及实体间的联系三个要素组成 将E-R模型转换为关系数据库模式,实际上就是要将实体及实体联系转换为相应的关系模式,转换…

【EtherCAT】TwinCAT3通过PLC修改SDO数据

目录 1、打开twincat3, 左边PLC右键->添加新项,建立PLC工程 2、->References右键添加库 3、找到Tc2_EtherCAT库,点确定。 4、PLC程序ST语言就可以调用下面的功能块函数 5、PLC编程界面右键->输入助手 1、打开twincat3, 左边PLC右键->添…

数据恢复篇:如何恢复丢失的Android短信?

许多用户发现自己处于重要短信意外从Android手机中删除的情况。幸运的是,有一些行之有效的方法可以在没有root的情况下恢复已删除的短信Android,这可以成为救命稻草。这些技术不需要深厚的技术知识,也不需要损害设备的安全性。为了帮助您摆脱…

jieba--《红楼梦》章节分卷并计算TF-IDF值(超详细)

目录 大致步骤: 任务1: 将红楼梦 根据卷名 分隔成 卷文件 红楼梦txt: 红楼梦卷头: 红楼梦章节分卷: 任务2:对每个卷进行分词,并删除包含停用词的内容 1.遍历所有卷的内容,并添…

Python26 Lambda表达式

1.什么是lambda表达式 lambda 是 Python 中的一个关键字,用于定义简单的匿名函数。与 def 关键字定义的标准函数不同,lambda 函数主要用于需要一个函数对象作为参数的简短操作。lambda 函数的设计哲学是简洁,因此它只能包含一条表达式&#…

7km远距离WiFi实时图传模块,无人机海上无线传输方案,飞睿智能WiFi MESH自组网技术

在浩瀚无垠的海洋上,无人机正在开启一场前所未有的技术创新。它们不再只是天空的舞者,更是海洋的守望者,为我们带来前所未有的视野和数据。而这一切的背后,都离不开一项创新性的技术——飞睿智能远距离WiFi实时图传模块与无线Mesh…

java必知必会-java IO

系列文章目录 java必知必会-java环境搭建 java必知必会-java开发工具安装与使用 java必知必会-java关键字、变量和常量 java必知必会-java数据类型和变量定义 java必知必会-java类和对象 java必知必会-java面向对象的三大特性 java必知必会-java继承与重写、重载 java必知必会…

昇思25天学习打卡营第1天|快速入门-Mnist手写数字识别

学习目标:熟练掌握MindSpore使用方法 学习心得体会,记录时间 了解MindSpore总体架构 学会使用MindSpore 简单应用时间-手写数字识别 一、MindSpore总体架构 华为MindSpore为全场景深度学习框架,开发高效,全场景统一部署特点。 …

Verilog进行结构描述(三):Verilog模块实例化

目录 1.模块实例化(module instantiation)2.实例数组(Array of Instances) 微信公众号获取更多FPGA相关源码: 1.模块实例化(module instantiation) 模块实例化时实例必须有一个名字。使用位置映射时,端口次序与模块的说明相同。使用名称映射时&#x…

搭建大型分布式服务(四十)SpringBoot 整合多个kafka数据源-支持生产者

系列文章目录 文章目录 系列文章目录前言一、本文要点二、开发环境三、原项目四、修改项目五、测试一下五、小结 前言 本插件稳定运行上百个kafka项目&#xff0c;每天处理上亿级的数据的精简小插件&#xff0c;快速上手。 <dependency><groupId>io.github.vipjo…