Tags
- Airchina
- Android
- Anti-Spam
- bugs
- ChinaSouthern
- collectd
- Django
- DNS
- Enterprise
- fastcgi
- Hainanair
- HAM
- HongKong
- InnoDB
- iSCSI
- kubernetes
- large-scale
- lighty
- Linux
- Macao
- Meituan
- MM
- MySQL
- nginx
- Oracle
- Outdoor
- Percona
- Photo
- postfix
- Python
- RedHat
- Saltstack
- Sentry
- systemd
- Traffic
- Travel
- UK
- Virtualization
- xtrabackup
- 信用卡
- 奥运
- 美食
- 规范化
- 软件工程
Meta
Blogroll
Mine
Author Archives: admin
列举一下MySQL的身份验证历史发展的几个链接,供参考
4.1之前:mysql_old_passwordhttps://mariadb.com/docs/server/reference/plugins/authentication-plugins/authentication-plugin-mysql_old_password https://dev.mysql.com/doc/mysql-security-excerpt/5.7/en/account-upgrades.html 4.1开始:mysql_native_passwordhttps://mariadb.com/docs/server/reference/plugins/authentication-plugins/authentication-plugin-mysql_native_password 5.7开始:sha2https://dev.mysql.com/doc/mysql-security-excerpt/5.7/en/caching-sha2-pluggable-authentication.html 还有验证协议:https://mariadb.org/history-of-mysql-mariadb-authentication-protocols/
昨天另装了个VPS,迁移系统,遇到了很多问题
感叹,确实啊不能总是本地升级,还是要经常进行全新安装和数据转移的,否则总是停留在兼容模式,见识不到行业的发展。 昨天遇到几个问题,先说自己的责任事故:用rsync传输home目录,把普通用户的home目录搞成owned uid=0了,这用户登录之后进不去自己的目录,就去了根目录。然后我sudo chown了当前目录,把系统bin目录里的文件都chown了,此时应该已经丢失了很多setuid。赶紧用另一个已经sudo的窗口去chown回来,并给su和sudo增加setuid。然后再执行dpkg –verify,却发现没检查出多少结果来,不知道是不是dpkg根本没记录原始的mode信息?我记得以前rpm –verify应该是可以的。折腾了一会总感觉哪里不对劲,比如用vi编辑文件无法存盘,用nano却可以存盘等现象。最后决定重装。 再说几件兼容性问题:我妄图把wordpress的数据库换成Postgres,于是给wordpress安装了pg4wp插件。检查这插件发现它是运行时劫持驱动的,类似于pyMySQL monkey patch的做法,并进行了SQL方言翻译。我用pgloader转移数据的时候发现几个问题:一、字段名字的大小写问题,有些id有些ID二、Ubuntu里pgloader版本太文物了,包版本虽然叫3.6.10但实际上是3.6.4,不支持某些字段类型。搜到2020年的issue说让升级……三、MySQL从8版本开始改用类似于Postgres和Microsoft SQL server的验证方式,从unix domain socket连接的时候直接验证“对方”的用户名;但是pgloader既不支持unix domain socket也不支持mysql新版本的caching sha2 password。于是我又现场学习了30年前学习过一遍的关于mysql身份验证的知识,并成功的把MySQL 8降级到pgloader能够支持的mysql native password…… 然后手工修改大小写,勉强整理到能够显示博客内容,但是登录后直接跳转回登录页,也没错误信息也没错误日志……于是切换回MySQL做了一下WordPress数据库升级,再pgloader到Postgres,这下彻底显示不了了。放弃……
在Python里抑制requests库的日志消息
我自己经常在自己的脚本开头使用logging.basicConfig(level=logging.DEBUG)初始化logging库,但是随之而来的就是requests会输出大量日志,甚至盖过了我自己的内容。所以我打算抑制requests的日志。 综合搜索的资料,和探索源代码,我发现: 所以只需要在basicConfig后面加一句 logging.getLogger(“urllib3”).setLevel(logging.WARNING) 就可以抑制这部分日志了。 另外,logging.Logger.manager.loggerDict是个好东西,可以检查当前到底存在哪些logger。通过检查loggerDict[‘urllib3.connectionpool’].propagate发现其为True,其上层也是True,因此,虽然这两层logger一个没handler,一个NullHandler,但是该logger记录的日志消息仍会逐层上传,最终被basicConfig的root logger处理。
Tencent tlinux的$releasever比Redhat原版更反动
前几年我写过一篇批判$releasever的博客之后,现在工作中又用到了tlinux,而且发现它的$releasevar居然是2.2,是带小数的。但是看了看tlinux-release的主版本号确实是2,不带小数;它provide的centos-release的主版本号也是7,也不带小数。 折腾了一番,发现yum的config.py里,class VersionGroupConf下边的_read_yumvars(yumvars, root) 函数,直接提供了用 /etc/yum/vars/ 下边的文件来设置release属性的方法。
Posted in 默认分类
Leave a comment
supervisor泄漏进程案例分析
起因 前几天使用 salt ‘*’ test.ping 的时候发现响应内容中有一些“某某minion was already deleted from tracker, probably a duplicate key“的提示信息。刚开始误以为是salt-key管理有问题,尝试删除再重新accept,但是依然会出错。到该minion上检查,发现上面运行了两套salt-minion*三层进程树,一共6个进程,其中一套的PPID为1,另一套的Parent是supervisord。 然后就开始研究这种情况是怎么产生的,发现有两种可能: 第一种可能 supervisor本身不被systemd监管,被SIGKILL信号杀死时,因为SIGKILL由内核直接处理,所以并没有机会关闭下属的进程,导致下属salt-minion进程树泄漏。而且不但salt-minion进程树泄漏,连同样被supervisor监管的另一个服务也一并泄漏,二者的PPID都变成了1号。 不过,如果supervisor本身被systemd监管,在其主进程被杀死时,systemd会给整个service slice cgroup里所有进程补刀,所以并不会泄漏进程;如果supervisor是被SIGTERM信号杀死,它也会给下属子进程发信号,一般也不会泄漏进程。 第二种可能 supervisor没有受到影响,正常运行;supervisor监管的salt-minion三层进程树的其中最高层进程(也就是supervisord的直属子进程)被SIGKILL信号杀死,随即,第二层进程exit(1) (不明原因,可能需要看一下salt-minion源码),导致第三层进程变成孤儿。经检查源代码的_spawn_as_child()函数,supervisor针对其监管下的每一个服务,都是采用 fork() + setpgid() +execve() 的方式来启动的,在调用setpgid()改变了process group id之后,第三层进程的孤儿收养关系就不再归属于supervisord进程,而是归属于1号进程。 随后supervisor会重启salt-minion服务,产生新的3个进程,加上之前剩下的,一共4个。 结论 考虑到观察到6个进程而不是4个,实际发生的大概是前一种情况 supervisor虽然有“能力”处理进程退出之后马上重启的工作,但是因为使用了setpgid()把下属服务与自己隔离,没使用cgroup机制把下属服务单独圈起来,又不具备1号的神圣地位,其实它并不知道到底下属了多少、哪些进程,从机制原理上就根本无法保证所有下属的孤儿进程都被其reap。还是建议不要在严肃场合使用 1号进程神圣,所有的服务进程监管工作都应该交给1号进程来处理
Reproducible builds 果然是很重要的
去年10月17日公司出了个事故,“幸好有我“,力挽狂澜。我觉得还是把具体内容脱敏,记录一下吧,免得将来忘了。 早晨test环境某个自研产品组件build成功,但是运行时错误日志里一堆“Broker hostname updated”等等,仿佛孔乙己说的话,让人听不懂。我刚开始没把这个当回事,请Kafka管理员去检查,几个小时都没查出原因来。 到了午后,各自研组件纷纷开始更新Live环境的版本,发布的都是前几天在Test环境已经测试定稿的版本,居然也出现了类似的问题。更狠的是,回滚居然也无效! 最终查实,有不少自研产品的build脚本里,使用wget下载master版本的librdkafka然后编译使用。而librdkafka恰在前一天(10月16日)被提交了很多修改。当时紧急解决的方法是使用librdkafka的上一个被明确标记了tag的v1.2.1版本代替master版本。 事后复盘处理过程,觉得当时的处理过程也有问题:所谓回滚其实并非直接使用旧版本编译出来的docker image,而是重新build了旧版本,而且编译时指定的是branch名字,而不是精确的commit id,这样的问题是无论外部代码(master版本的librdkafka)还是自研代码(注意branch有可能move forward哦),都不一定是原来的版本,这个行为其实并不能称作回滚,而是带有主观回滚意向的一次重新构建。 在这种情况下,讨论自研代码和外部库的质量,都是缺乏讨论基础的。这种讨论应该基于确定的版本。 说实话,我以前对于传说中的“Google把自研代码、外部库和工具链”全都纳入版本化管理,是有点嗤之以鼻的。当时我觉得这种做法,在处理多个自研软件的外部依赖相互冲突时,会带来额外的行政成本,在国内企业的KPI风格下,会导致相互推诿。经过这次力挽狂澜之后,觉得相互推诿其实是KPI至上主义导致的,而不是把所有代码都管起来导致的;不过是否真的要管这么大范围,尚有待商榷。
广东电信IPTV 华为EC6108v9c 的使用经验
前天(3月9日)终于拨乱反正把还剩下近一个月但网络“几乎能通”的垃圾天威视讯给弃用了,换了正经运营商中国电信广东深圳公司的上网服务,并且开通了IPTV。因为今年租的房子是正经居民房,就遭遇到了经典的“弱电箱距离电视机太远”的问题。 本来IPTV盒子可以支持Wi-Fi的,但它很快就强制自动升级,把本来支持的Wi-Fi联网方式给去掉了。 网上找到一个固件,保留了“粤TV”app,并且重新开启了Wi-Fi功能,且开放安装外来安卓软件。刷新说明里写着放在FAT32的U盘里,文件名叫update.zip,开盒子之后在bootloader过程中按左右键进入recovery,然后apply update from external storage即可。但我照做的时候,recovery提示没有找到升级包。 再搜,发现还有一个所谓按待机键进入recovery的,但我按不出来。妄want图to 拆盒子短接跳线,还从盒子里掉出一个虫子尸体,算是给祖师爷致敬了。 我想了想,可能这俩方法是不同时期的。于是我在当前recovery里apply update from backup刷回旧版了,(中间还操作了一步wipe dalvik cache,清除新版的升级包,避免旧版开机之强制刷新新版)然后再按待机键进入旧版recovery,刷了这个update.zip进去。 再说网络。官版固件有线网接入,目前是IPoE(其实就是特殊的DHCP)或者PPPoE认证的;直接DHCP无法获得IP地址。我改了一下光猫,把原来的VLAN 45上联业务,从PPPoE桥接模式(即:客户端自己PPPoE)改为PPPoE路由模式,并开放下行DHCP服务,再关联到SSID1上,用IPTV盒子去连这个Wi-Fi即可。理想情况下应该开多个SSID,但我这个光猫似乎不支持多个,所以这个2.4G only的Wi-Fi就给IPTV用,而自家其他通用设备使用的Wi-Fi,用了额外一个5GHz路由器从有线网口转出来。
经典错误——使用/etc/security/limits.conf配置文件 和 ulimit -n命令
很多以讹传讹的半桶水文章,都教人修改/etc/security/limits.conf配置文件来放宽“打开的文件数量”限制,如果可以再多一滴水的话,还会加一句“重启后生效”。 其实,使用这个配置文件,和使用ulimit -n命令一样,属于很经典的错误。 设置或放宽“打开的文件数量“限制,其本质是调用了setrlimit()函数,设置了RLIMIT_NOFILE资源。在有特权的程序中调用这个函数,可以提高上限(放宽限制),而普通权限的程序只能自己勒死自己和新生的子进程。 而/etc/security/limits.conf这个配置文件是怎么生效的呢?其实用dpkg -S或rpm -qf查一下就很容易知道,这个文件是pam_limits.so的配置文件,而pam_limits.so是在/etc/pam.d/中被login和sshd等多个配置文件声明将要被调用的。 系统开机的时候,1号进程init“自然而然”是root身份运行,其下属的getty/login和sshd进程,也都是root身份。这些程序都可以随意调用setrlimit。当身份认证(部分工作由PAM来做,所以可以读shadow文件)完成之后,login和sshd的子进程会为用户准备好session(网络登录调用pam_mkhomdir建设HOME目录、pam_limits模块设置rlimit、pam_env模块读取/etc/environment设置环境变量,甚至显示motd这种功能也是PAM模块实现的)并将自己降级到登录的用户身份,再启动一个shell给用户使用。 /etc/security/limits.conf 只对“调用过pam_limits.so“的登录过程有效。但并不是所有场景都经过这个过程的。而ulimit命令呢,它本身只是shell是一个内部命令而已,只对“该shell进程”及随后新产生的子进程有效。 但是需要放宽rlimit的程序,往往不是在shell中由用户手工运行的程序,而是提供大规模网络服务的后台进程。它们所需的rlimit,要在init脚本、service unit文件中设置;支持从root身份启动的服务,一般都有自行设置rlimit的能力。 如果不理解上面的内容,就容易引发一些莫名其妙的故障。比如之前我在FreeWheel工作的时候,前辈为后台服务写的的init脚本里没有调用ulimit -n命令,而在root用户的~/.bash_profile里有这个命令。造成的后果,就是开机自动启动该服务的时候,启动的是一个打开文件数量受限,以至于无法保持很多socket的网络服务,而当运维人员登录进去手工重启服务之后,又莫名其妙变好了,以至于没法检查这个故障到底是怎么发生的。
从神州租车更改手机号,看数据库关系设计
我搬来深圳之后,就换了手机号。为了应对一些出行需求,我就打算从神州租车租辆车来用。用新手机号注册之后提交身份证,结果提示该身份证已经被占用。联系客服,说是一个135的北京手机号占住了,还提示我以前在嘉峪关租过车,客服可以帮忙把这个135的登录手机号改成我的新手机号。我检查了一下通讯录,认识,跟他打了招呼之后就同意了客服的做法。 但其实,这个事情暴露了神州租车方面的数据库强关系设计,与实际业务冲突的问题。我和这位朋友之前两次一起租车,因为他当时还不会开车,所以登记了我的证件,但后续他仍有使用此注册名租车的业务需求啊。身份信息应该关联在“一次租车行为”而不是关联在“一个注册用户”身上,也就是每次发生租车行为的时候,把身份信息从注册信息复制过来,或者由门店人工录入身份信息到“一次租车行为”的数据库记录里。 这不是关系范式之间来回迁移,而是正确与错误的区别。 联想到以前在美团我们自制的一个用作软件版本发布的小系统,旧的设计并没有把“发布功能相关设置”关联到“一次发布行为”,而是关联到“要发布的应用”,以至于检查每一次发布行为到底为啥不正确的时候,根本不敢确定设置页面里看到的设置就是当时生效的设置。 这个错误在后面重构中被推翻了。