An-Accident-Triggered-by-a-String
今天下午健身回来想着注册线上的search server到zk,让prometheus去拉metrics,然后由于申请机器权限的系统经常性的抽风,申请登录机器一直不成功(老牛鼻子问题了,他们就是不修),然后就想直接更新zk的数据,反正脚本也是这样,然后就到了consule的UI上(我也不知道为啥consul的UI跟ZK的数据是连着的),直接创建对应的key。
创建完成之后发现并没有卵用,过了一会儿就被打岔喊道了楼上去(现在想起来,如果不上去的话会不会自己就把key给删了?但大概率会忘掉!),说了一会儿之后正巧他们出故障了,隐隐约约听到了我们组的名字,妈的瞬间就精神了,这不是我刚才建的key吗,卧槽我是不是闯祸了?
仔细听下去,果真。日。
事情的起因是我想注册我们的search server到ZK,让prometheus去拉数据。
经过是没有登录到注册zk的机器上,然后就手工写错了注册的path和value。
结果导致平台组负责服务发现的程序崩溃?
程序期待一个JSON,我写了一个string,然后程序就崩溃了。贰叁叁。
最终导致订单系统停止服务五十分钟。(讲道理五十分钟才解决这种故障也是……)
然后群里领导们就在讨论如何避免以后类似问题的发生,说如何限制zk的写入,如何提交ticket,如何更新服务发现等等等等。
我就想,这难道没有work flow和programer的责任吗,每个人都能写线上的ZK不太好吧?这么简单的异常,程序没有正确处理而是直接崩溃不好吧?花费五十分钟还顺带回滚服务(当然没卵用了也)才解决问题也不好吧?最终我(导火索)如果没有恰好站在旁边背锅,也发现不了是怎么引起的bug也不太对吧?
洋洋洒洒都在讨论auth的问题,真是,醉了。
服务发现用ZK本来就值得吐槽了,而且各种服务都写ZK,不区分国家和服务类型,把ZK当银弹用,还是一颗,这么明显的问题都没人提出来,也没人说程序写的有问题,(这么关键的程序,感觉像是随便写写的),深深的觉着领导层有点本末倒置。
普林西普的刺杀引发了一战,但讲道理,让普林西普背一战的锅就说不过去。当然也没人让我背锅,我只是觉着导火索就不应该存在,把潜在的问题扼杀在摇篮中是最好的。因为这次可能是我写string,下次可能就是程序写int,在下次可能就是黑客直接递归删key了,暴露出这么多问题,一个auth能解决?一个disable能解决?
服务发现本来就很复杂,etcd都能被打挂,zk也不是万能钥匙啊,况且还不分区。这么关键的核心服务连这种异常都hold不住,也难怪天天修bug。
我肯定是要被批评的,因为我写的key嘛,就像上次99时候DNS挂了,一个更改防火墙的DBA背锅一样。
几点经验教训:
- 对核心数据的权限控制:什么样的人能干什么样的事儿,该干什么样的事儿要有明确的划分。
- 对数据的隔离和分区:不要把鸡蛋放在一个篮子里,老生常谈了。
- 核心程序的code review和至少80%的单元测试:不要让这么低级的异常把整个系统搞挂。
- 关键数据的备份要做好:实在解决不了问题咱回滚数据行不行?
- 还是告警,还是日志,错误处理不是说说那么简单的。
- 服务发现是个大事儿:别用zk,用etcd。
- 哪怕是内部服务,也不能完全可信,尤其是带有网络调用的,数据验证是基本操作。
- 出问题是好事儿,跌倒也是好事儿,但出了问题不总结就不是好事儿,总结不到位也不是好事儿,就像明明是脚上扎了钉子,却一直想办法如何修路。早点暴露问题就能早点修复,以免在更严重的时期触发问题;早点跌倒就会早点反思,而不是拖着一只被扎穿的脚彳亍。
- 最重要的一点也是针对我的一点,没事儿别瞎搞,对于不了解的东西要如履薄冰,如坐针毡,没准你就是最后一块被抽掉的积木。