Skip to content

Latest commit

 

History

History
135 lines (70 loc) · 13.4 KB

File metadata and controls

135 lines (70 loc) · 13.4 KB

运维的日子

我之前不是做运维的, 在逃离上海的时候意外做了数据库运维, 一做做了两年半. 先前以为是挺无聊的事情, 却意外地遇到了很多有趣的情况, 想来必须要做个总结, 不然以后忘了也颇为遗憾. 总体上说, 遇到的这些事, 我相信对"二线及以下"互联网公司, 应该都挺实用的.

上云

现在的故事多是发生在云上, 作为一个大公司, 没有私有云那是说不过去的. 我去做运维的时候, 正好碰上数据库上云这事.

开头我遇到的是Couchbase, 一个内存数据库, 可以理解为memcache的集群版. 用内存的系统, 套了个虚机, 以我体系结构实验室的知识, 理应一切正常, 然而一上来就遇到下马威. 我们当时要搭建一个1T内存的Couchbase集群, 用4台3X0G内存的服务器, 每个服务器上开3个100G内存的虚机--请不要问我为什么要这样起虚机, 反正就是要--于是开起来了. 很顺利的装上Couchbase, 搭建好集群, 交给业务使用.

image

半个小时之后, 被找上门了: "缓存性能不稳定, 100ms还没拿到数据". 我直接傻眼了. 100ms? 这怎么可能呢. 然后就自己写个程序测试, 的确很慢, 而且很不稳定. 有一些请求是1ms, 有一些慢到150ms. 是不是机器有问题? 于是请IAAS组帮我们看机器正常不正常. 一切都很正常. 于是重装软件, 重启虚机. 别说, 重启之后的确会好一些. 虽然也就好一会. 就这么折腾了一阵, 突发奇想, 宿主机网络和虚机网络都测一下. 竟然发现诡异的地方: 宿主机的延迟在0.1ms, 虚机在0.5ms到20ms不等. 那至少确定是虚拟化出了问题. 就继续交给给IAAS组. 结果没等到答案.

于是就比较尴尬了, 于是很悲催地悬在那里空想怎么办. 东搞搞西搞搞弄了两天, 灵光闪现google了一下vmware latency. 神奇地收获了一份专门讲vmware延迟调优的文档! 心里感叹真是专业的公司啊. 于是就按图索骥, 第一条: BIOS设置. 忽略, 服务器当然都是标配啊. 跳到第二条. 结果都做了一遍, 还是没帮助. 只能回过头来再试图看看BIOS. 不看不知道, 一看吓一跳: 当前处于省电模式. =.=!!! 线上服务器开着省电模式. 实在是惊喜啊. 改成性能优先, 世界清净了.

PS. 上图这种集群拓扑是很危险的, 引以为戒.

隔离

互联网么, 关键就是"要快". 比如说上云这事, 说上就上, 上了再说. 前面说到我是搞缓存服务器, 那自然还有其他的很多服务器啊, 比如说FTP. FTP也上云了, 就放在咱们缓存服务器的虚拟机边上.

image

万兆服务器带宽啊, 我都不知道这个问题当时是怎么找出来的了. 我们去找FTP的owner, 说你的机器得迁走. 小伙还说"不行, 这个服务很重要的不能停". 我只记得当时直想飙脏话. 一个FTP服务器还不能停了, 咱A股都能熔断好吗.

幸好和IAAS的哥们铁, 我就开始嚷嚷让他们上隔离. 终于有一天, 哥们说有隔离了, 最大不超过宿主机的30%. 我就盯着他看, 我不说话. 后来么总是说了, 终究也没有在我离开之前看到结果.

我想说的是: 隔离必须是弹性隔离, 在没有竞争的时候, 应该让guest vm尽情的用, 性能最大化; 有竞争的时候, 再做限制性的隔离. 私有云和公有云不一样, 公有云是故意隔离了收费的, 私有云没法收费肯定是提高利用率优先. 实现其实很简单, 写个百八十行的脚本就能搞定吧, 每秒钟check一下各个虚机的带宽, 调整一下配置. 都不用和openstack有关系啊.

Zabbix

我在做开发的时候, 从来没听说过监控系统(咱们代码写得好啊:). 第一次接触zabbix的时候, 觉得真心难用. 不过总得用, 感谢同事搭了雏形, 还带我入门. 然后发现, 简直太好了啊. 估计有很多人要说我没见识, 还有这个那个更好的. 那都没有用! 我就觉得, 开始用一个东西, 就要用好它. 什么叫用好它呢? 就像学英语, 要Think in English; 学Java, 要Think in Java; 用Zabbix的时候, 就要想"怎么用Zabbix来满足当前需求", 而不是"这个需求能不能用Zabbix实现". 直到实在遇到无法跨越和忽略的鸿沟, 再考虑更换或者创新. 这样的创新才有意义.

很多公司喜欢自己做监控系统, 我其实比较迷惑, 为什么不把时间放在更有意义的事情上去.

有半年多的时间, 我都是逢人就推荐Zabbix. 做了运维再回头看开发, 真的好多项目, 都是盲操啊. 后面我会说到, 我最有成效的一次推荐. 虽然人家上了nagios, 然而精髓在于"知道监控的重要性"嘛, 后来他们监控的详细程度, 让运维都汗颜.

没有监控系统, 日常工作很多是像下图的.

image

在推荐zabbix的过程中, 我遇到很多人以为它只能监控CPU, 磁盘, 内存, 不能对app server做监控. 不知道他们是怎么了解这一点的, 但是很多好的东西, 就是这样被略过去的. 二手烟可恶, 二手信息有毒, 看书要看原著, 调研要上官网.

使用Zabbix的时候, 也发生过一件有趣的事. 因为Couchbase是集群系统, 而Zabbix是按server监控的, 有很多报警, 会每台server都报一次. 比如我们有10台server组成集群, 数据是分散存储的, 像数据超出内存这种问题, 10台server都报一遍. 而实际上, 我们只需要知道"这个集群数据超出容量". 那要怎么办呢? Zabbix提供了一种Calculated item, 可以把收集到的数据聚合成一个新的metrics, 用它来报警, 而不是设定在每个Server的metrics上.

开始我也是这么想的, 后来发现维护太复杂. 于是用了个技巧: 我不需要每个机器都报, 也不需要一个聚合项, 只要让这个集群中的一台机器负责集群metrics的报警就可以了啊. 那要怎么来确定谁来报警呢? 我增加了一个fakemaster的metrics, 每台机器按照集群机器列表, 计算一下自己是不是fakemaster. 只有fakemaster负责报警.

然后, 记得要用Screen.

应用对监控的支持

说到监控, 其实还没完, 很重要的一部分是应用怎么去支持监控. 最近看到一些应用的监控, 采用侵入式的框架, 在中间件上实现. 我是不大喜欢啦. 侵入式这个名词就惹人烦.

我接触到的情况, 现在的开发, 多能用日志. 开发更喜欢"做监控的人"能从日志中提取metrics, 这样他们就什么也不用做. 所以ELK流行是很有道理的. 然而监控和日志绝对不是一回事, 日志记录的是事件, 监控的metrics描述的是状态. 应用和监控系统的接口, 就应该是一个metrics列表.

在折腾tigase的时候, 看到它有个statistics list, 唯一的问题是通过继承实现的, 添加起来不怎么方便. 所以我就改了一个使用注册的.

interface Statistics {
	List<Pair<String, Object>> getStatistics();
}

class Office {
	public void register(Statistics s){...}
	public List<Pair<String, Object>> getStatistics(){...}
}

想法很简单, 需要metrics列表的时候, 调用Office.getStatistics就可以获取所有注册了的模块的信息. 本来要参考一下logger的实现, 让它看起来更好一点. 不过么, 比没有已经好太多了!

我觉得, 把metrics留给开发是很重要的, 就像review code一样, 开发得考虑可能的瓶颈和故障点, 知道自己的代码脆弱的地方.

YCSB性能测试

为了能了解不同数据库的性能, 我们开始对Couchbase, MongoDB还有Redis做性能测试, 后面两个比较容易, 但是用YCSB对Couchbase做性能测试的时候, 就有点感觉不大靠谱. 因为YCSB是线程模型, 所以, 很长一段时间里, 我们以为Couchbase的性能差不多就那个样子. 挺长一段时间之后, 为了排查问题在服务端还是客户端, 我写了个异步的benchmark, 才发现Couchbase很有潜力.

因为用Java比较方便, 当时用Java写的客户端, 单线程轻松上30kqps. 我就多找了几台机器用来加压力, 顿感深不见底啊! 于是我搞了个Hadoop帐号, 非要测个结果出来.

当时正好有3台机器空着, 24核N多内存千兆带宽. 因为主要是测软件性能, 所以内存没关系. 经过多轮测试, 服务器还是2.1版本, 用异步调用的情况下, 15个Hadoop线程, 能把3台Couchbase压满, 接近1Mqps的读. 写减半. 是怎么知道压满了呢? 因为15个线程和50个线程的结果是一样的.

当时的Couchbase, 最多能用到4核. 现在应该更厉害了.

经此一役, 我的感受是, 现在的大型互联网服务, 真需要Hadoop来做压力测试, 用来模拟百万用户在线什么的. AB得升级成HadoopAB, 不知道这个有人做了没. 以及, 单纯说每天几十亿的访问, 真不算什么压力.

部署拓扑

因为多机房的缘故, 遇到了好几次因为部署拓扑带来的性能和稳定性的问题.

这是第一个问题: 需要为电信和联通的用户都提供好服务, 就必须在电信和联通机房都部署服务. 所以可能会这样安排服务器:

image

或者

image

技术上说, 这两种部署, 在正确地处理数据一致性的情况下, 都是能工作的. 那么它们不好的地方在哪里呢?

首先, 最重要的一点 , 可以和前面说的服务器开省电模式一样致命: 开发这部分代码的程序员真的了解这种拓扑会带来什么样的影响吗? 正确地处理cache脏数据和数据库写冲突, 是多线程开发的基础, 却是业界开发的软肋. 我接触到的几个外企一线大公司, 很多j2ee的程序员, 只是写顺序的业务逻辑, 多线程中典型的TOCTTOU, 都不能立刻解释明白, 所以要做到正确是很难的; 互联网行业, 代码质量估计也是这样的. 原来我做Java开发的时候, 以为至少findbug是必须要跑一下的, 直到遇见我的前公司.

然后就是一些技术性的东西, 很容易讲明白:

  1. 在第一种部署下, 联通机房的Server访问Cache和db的速度比电信机房的慢, 并且可能经常出点小问题, 超时什么的, 要注意处理, 加上错误重试. 加重试的时候, 一定要把逻辑写好, 别因为重试逻辑把db或者cache给压垮了...这都是遇到过的悲剧啊.
  2. 第二种部署, 应该是比较好的, 访问cache和读db都是同机房访问, 速度快. 在电信机房故障的时候, 还能提供读服务. 要注意的是, 数据库同步延迟, 很可能导致cache脏数据变多, 两个机房的cache数据不一致. 我记得哪一年, 有个公司分享了他们的"两次删除技术". 第一次写入的时候, 删除cache, 同时发送一个第二次删除缓存的请求给消息队列; 可能因为主从延迟cache被写入脏数据; 第二次删除的消息触发脏数据删除. 针对这个小技巧, 我想说: "千万别这么干, 干了千万别说...".

我个人是比较喜欢另一种部署方式:

image

这个方式的优势呢, 就是简单嘛, 把多机房的问题reduce到单机房, 同一个机房里出现cache脏数据的可能性就小多了, 而且这个是肯定要debug的. 唯一的问题就是, 记得买一个跨机房提速的服务, 确保用户走这个代理比直接跨运营商访问的速度快就行, 现在大的云服务商应该都会想办法解决这种互联问题的.

后端跨机房多次访问的性能问题脏数据处理主机房故障存活模型简单远近适用
部署1不能跨地区机房不适用, 高延迟的cache和db访问很糟糕
部署2写主库时有降级为只读部署成本高
部署3不能越远越好

我觉得, 这三种部署模型需要了解. 绝对不是IAAS给分配了哪些服务器就用哪些服务器. 很多次开发部找上门, 怀疑是db和cache性能问题, 就是调整下部署解决了. 现在还记得的有4个case:

  1. 用了部署1, 实际上更糟糕, 因为涉及到3个机房, 并且请求到后台的放大比有20倍以上. 就是一次对AppServer的请求, 会变成20+的对cache和db的访问. 后来把AppServer和cache,db放在一个机房, 另外两个都是nginx代理. 同时降低了请求延迟和跨机房流量(注意:减少跨机房流量对稳定性提高有很大帮助).
  2. 在上海的APP Server, 需要访问北京的另一个服务. 结果上海的服务几乎无法使用. 改用nginx proxy, 完美运作, 还省了一堆机器.
  3. 需要为海外市场提供服务. 北美的amazon机房, 还得和国内机房组成cluster. Cluster内部通信不畅的教训都是很惨痛的. 后来用LVS把北美的数据包直接带到国内, 把原计划两星期搞定的事情一个下午就完成了.
  4. 内部用户用了公网域名走了公网链路. 我只是意外地发现了...

我想真实存在的拓扑导致的"性能低", "资源浪费", 肯定还有很多. 了解一下拓扑, 这些其实都是很简单的问题, 意识要到位.