记2017-03-16 9:20将一台数据库节点关机进行硬件升级造成公司核心业务不能访问的事故
公司数据库使用sql server 2014 AlwaysOn+硬件LB做读写分离,有好几个AlwaysOn集群,此次事故由多个条件共同发生造成的。事故相关有两个集群,这两个集群节点结构如下:
主集群A(核心集群)结点结构如下:
写:DB-01
读:DB-02(同步)
DB-06(异步)
DB-09(异步)
DB-03(异步)
DB-10(异步)
集群A的只读负载均衡节点为DB-02 DB-06 DB-09
集群B(日志、BI分析结果数据)结点结构如下:
写:DB-05
读:DB-03(同步)
DB-10(异步)(事故前在节点在事故中,但不在只读列表中)
注:DB-03和DB-10是所有集群共同的读节点,为的是备份和必不可少的跨集群JOIN以及数据分析(BI),但尽量不做单集群的读操作(除非集群没有多余的读节点,如集群B)
每个AlwaysOn集群本来都做到了≧3个节点的备份,由于DB-10是后来加的,集群B的读就少了一个节点。而开发环境只有一个数据库实例,所有库都在这一个实例上,这是不能在开发时就将问题发现的主要原因。
由于所有集群的帐户都一致,造成可以在集群共同的节点(DB-03和DB-10)可以访问所有数据库,而出事故的Sql竟然是一个跨集群的JOIN,数据库字符串连接的是集群B的只读节点(DB-03)。由于集群B的只读节点包含所有数据库且能访问,因此在正常的情况下SQL不会有任何问题。当DB-03不能服务时这段SQL就会出错(当时DB-10不在集群B的只读列表中,alwayson自动将读节点切换到写节点上)——xxx对象不存在,从而造成核心业务不能访问。
此次事故问题出现在开发环境所有数据库在一个实例上,在生产环境时代码连接的实例也包含所有数据库造成的,当出现问题时就会出错
此次事故的后续解决方案如下:
1.将开发环境的数据库做实例上的隔离
2.每个应用在每个集群有不同的帐户名,在共同节点上对应集群帐户只能访问对应集群的数据库,防止意外的跨集群查询