您的足迹: DevOps的八荣八耻

DevOps的八荣八耻

DevOps的八荣八耻

今天我要讲的是DevOps的八荣八耻。DevOps这个思想提出来已经五六年了,一直都是呼声很高,落地很难,为什么呢?

这可能与各个公司的业务情况和技术发展路线有或多或少的关系,

  1. 比如说创业的最早技术合伙人是运维出身或者技术出身,但是水平不高,为了公司持续发展,引入新鲜血液时,就会存在技术的先进性跟解决遗留烂摊子的矛盾;
  2. 又或者业务本身偏向于用户,导致技术被边缘化,产品又没有好的架构,限制了快速发展等;

所以,DevOps的推进一定要自上而下,凭借挑战自我,颠覆传统的勇气才能去落实。

devops的落地还是带有一些机遇和巧合的。当然,如果老司机创业,就会执行的更好。

一、 以可配置为荣,以硬编码为耻

重点是学着用开发的思想去理解运维工作,做过开发的程序员朋友都知道,程序中所需的变量分离会出现单独的配置文件,所以运维要像开发学习,学会把软件和配置参数分离。(其实编程语言也是为了屏蔽底层硬件的一种统一编码)

举个例子,我们公司第一个版本自动化运维时,把所有需要用到参数集中配置到upyun.cfg,如上图。它的好处在于,不同的程序只要编写一个config函数,就可以把这种文本的运行方式,变成右边nginx所能运行的格式。并且可以用同样一份配置去适用不同的后端软件,如用haproxy替换nginx,只要重新写一下config函数即可,运维和开发仍然可以使用同一份参数。

本地配置的文本格式有txt、ini、cfg,但是这些格式都没有没有硬性要求,如ini在php里用的多一点,cfg在mysql里用的多一些。一般配置的文件里面会包括开关变量,调试参数、可变参数、权重,以及关联上下游的参数,这些都可以放在配置里面,通过程序生成程序的方式完成。

第二代就不再使用它了。我们现在使用Yaml来定义配置文件,通过它动态生成配置文件,这两者的思路是相同的,都是通过程序生成程序。配置文件的好处是可读性更像文本,不是程序员,或者专业的运维工程师,也可以看懂和理解不过,现在有一些新的技术开始流行,比如通过etcd或者是consul来实现服务的自动发现、自动注册。老实说,是对我们现在的运维配置带来了很大的便利。

  1. 使用kubernetes中的configmap和secret,用volume挂载到容器中,达到无侵入和语言无关性
  2. 比如通过etcd或基于Consul服务自动发现和注册 配合coredns性能优化实现服务的自动发现、自动注册。

二、 以互备为荣,以单点为耻

  • 互容互备一直是优良架构的设计重点
  • 互容互备一直是优良架构的设计重点
  • 互容互备一直是优良架构的设计重点

重要的事情说三遍!只有做好互灾互备,才能让运维不像救火队员那么累死累活。

负载均衡:

我们早期做架构设计,使用了LVS+Keeplived+VRRP做转换,这样可以方便负载均衡,动态升级,隔离故障。

现在第二代,已经在部分大节点使用OSPF和Quagga做等价路由的负载均衡和冗余保障。

Nginx可以加Haproxy或LVS做负载均衡。MySQL可以做主从切换,或者是MMM的高可用成熟解决方案。

  1. kube-router使用ipvs和bgp广播做负载均衡
  2. 应用容器高可用部署,如galera-mysql,redis-cluster

消息队列:

我们的消息队列之前用rabbitmq做,现在主要是redis和kafka集群化,其中kafka已经迁到了Mesos容器平台里。

我们要善用消息队列,这个后面在分布式环节还会再提到。

平滑扩容:

服务的自动发现、注册,我们可以使用consul、etcd、nomad(Heroku公司产品),还有zookeeper。主要区别是算法不一样,zookeeper用的是paxos算法,而consul用的是raft算法。目前看来consul比较流行,因为consul的自动发现和自动注册更加容易使用。

etcd主要是CoreOS在主推,CoreOS本身就是一个滚动发布的针对分布式部署的操作系统,大家可以去关注一下它。还有一个是hadoop和elk,大数据平台的可扩展性是标配,很容易互备。

上面是举了一些常见互备的软件组件的选型,那我们应该如何设计一个无单点的架构呢?

主要掌握以下几点:

1、无状态

无状态意味着没有竞争,很容易做负载均衡,负载均衡的方式有很多种,F5,LVS,Haproxy,总能找到一种适合你的方式。现在最新的nginx不光可以做 HTTP代理,还可以支持tcp,udp的反向代理, 但haproxy不能做udp反向代理。

如果是nginx + lua,则可以做更多的事,神器组合。

2、无共享

以前我们很喜欢用内存来保持临时信息,如进程间的交换,这种方式虽然效率很高,但是对程序的扩展性没什么好处,尤其是现在的互联网体量,光靠单机或者高性能机器是明显玩不转的,所以架构考量的重点会转移到水平扩容和伸缩性上。

所以我们现在就需要使用类似消息队列的组件,把数据共享出去,利用多台机器把负载给承担下来。

3、松耦合/异步处理

以前我们用Gearman这样的任务框架,有了这样的异步解耦框架,大家可以把任务丢进任务池里,生成多个消费者去取任务。当我的消费不够用时,可以平滑增加我的work资源,让他从更快的去拿任务。

还有一个优点在于,通过框架,可以把公司内部各种语言的开发人员都可以统一起来,大家可以用自己喜欢的语言,只要输入和输出是一样的就行。

当然,我也推荐用 python/celery的组合,也是非常不错的选择。

三、 以随时重启为荣,以不能迁移为耻

虽然我们运维是要求服务器轻易不下火线,但是如果服务器能够做到随时重启,随时添加,那说明架构真的设计得很牛逼。首先:

1、Pet到Cow观念的转变

以前我们说机器是pet,也就是宠物模式,然后花了几万块钱去买的服务器,当宝一般供奉。但事实上却并不是这样,任何电子设备、服务器只要一上线,便开始了一个衰老的过程。

你根本不知道在运行过程中会发生什么事

  1. 比如说质量差的电容会老化爆浆;
  2. 电子元器件在机房的恶劣环境里会加速损坏;
  3. 防火防水防电这些物理因素是我们无法参与控制的;

所以无论我们怎么努力,都无法保障机器有多么的牢靠。谷歌指出的Cow模式就是指农场模式。就是要把机器发生故障当做常态,打个比方,比如说这头牛死了,那我就不要了,因为我有很多这样的牛,或者是再拉一头新的牛。

这就是我们软件开发和运维需要做的转变,去适应这种变化。

所以,运维如果没有做好提前的准备,背锅侠肯定是跑不掉了,因为东西总是会坏的。我们要积极的学习新技术。

2、OpenStack虚拟机的编排

虚拟化是个好东西,通过OpenStack我们很容易就可以做出一些存储或者迁移的操作,但是在实施的过程中,也是一波三折的。

我们从2014年开始在内部推动OpenStack,当然我们也踩过OpenStack网络的坑。那时候我们用双千兆的卡做内网通讯,因为使用OpenStack实现虚拟化后,一切都变成了文件,在网络上传输的话,对网络的压力会非常大,结果就导致部分服务响应缓慢。因为本身就是实验性质,所以在硬件上没有足够投入,内测时也没有推广,所以影响不大。

2015年我们再上的OpenStack,全部都用双万兆的网卡做bonding,交换机也是做了端口聚合和堆叠。

目前来说,只有云存储没有上线,其它云处理,云网络的使用还是能够满足要求。

3、Docker的导入导出

Docker是更轻量级的资源隔离和复用技术,从2016年开始,又拍云同时也在尝试使用Mesos/Docker来实现云处理的业务迁移。

四、 以整体交付为荣,以部分交付为耻

以往开发运维要安装一个机器,首先要去申请采购,购买完了还要等待运输,在运输中要花去一天的时间,之后还需要配交换机和网络。在这个过程中你会发现,简单的给开发配台机器,光上架就涉及到运维的很多环节,更不要说系统安装,优化,软件配置等剩余工作了。

所以大多数情况下你只能做到部分交付。部分交付的坏处除了延长工期,还会造成沟通不顺,支持不给力,甚至会因为时间的问题导致项目的流产。

要如何解决这些问题?通过OpenStack可以做到云计算、云网络、云存储这三块搭建完成之后,进行整体交付。

根据一些经验总结,在整个云平台当中,云存储的坑最多,云计算、云网络相对来说比较成熟。现在云计算的硬件基本上是基于英特尔CPU的虚拟化技术来硬件指令穿透的,损耗大概2%~5%,这是可以接受的。至于云网络,胡凯(B站运维总监)提到内网包转发效率,我做过一个测试,在OpenStack的内网中,如果MTU默认是1500,万兆网卡的转发率大概为6.7xxGbps。

后来我在优化的过程中,也翻查一些文档,看到的数据是可以达到9.5xxGbps,通过不断的摸索,对比测试后发现,如果把内网的MTU搞成大包,如9000时,万兆网卡的存储量直接达到了9.72Gbps左右的。

不过,这个MTU需要提前在宿主机上调整好,需要重启生效。所以,这个问题发现得越早越好,这样就可以做到统一调度,分配资源。

云存储目前坑太多,如果公司内没有相应的团队可以hold住这些事,不建议在生产线上使用。虽然OpenStack也可以一站式交付,整体交付,使用时非常方便。但是对开发来说,他还是拿到一台机器,还是需要去安装软件环境,配置,上线,运行,除了得到机器快一些,对上线服务没有什么大的帮助。

Docker的好处是可以做到Build、Shipand Run,一气呵成。

无论是对开发,测试,还是运维来说,Docker都是同一份Dockerfile清单,所以使用Docker在公司里的推动就很顺畅。

所以我们现在的Openstack集群一般对内申请开发测试用,外网生产环境还是以Docker容器化部署为主,这也是大家都喜闻乐见的方式。但前提是开发那边能够适应编写Dockerfile(目前是我在内部推动这种变革,如新的项目就强制要求用docker)。

五、 以无状态为荣,以有状态为耻

状态是指上下文关联的信息,或者需要共享的内容,但凡复杂的应用,肯定会有状态的,这是事实。

但是有状态的服务在面对云时代的应用真的很麻烦,无论是存在数据库、磁盘开销,还有各种锁等资源的竞争,还是面对瞬间而止的访问量,如果横向扩展能力很差,不能重启,也不能互备的情况,有状态的服务对于扩展原则来说,就是一场恶梦。

如何解决我们说的这个问题,那就要使用解耦和负载均衡的方法去解决问题。要把有状态分解成无状态是指方法手段,比如说利用消息队列,中间件,把要共享的状态内容放到公共的地方去分享,不过,这需要团队所有的人都能达成一致。怎么做?

1、使用可靠的中间件

中间件其实最早出现在金融公司、证券公司,后来随着互联网行业不断壮大以后,就出现了一些高可靠性的号称工业级的消息队列出现,如RabbitMQ,一出来以后,就把中间件拉下神坛。随着中间件民用化,互联网蓬勃发展,是可以把一些服务变成无状态,方便扩展。

2、公共资源池

我们可以通过各种云,容器云、弹性云,做计算单元的弹性扩展。比如说阿里云,AWS云,弹性使用,弹性收费,弹性扩容……

3、能够被计算

如果你不想存状态,那也可以被计算,比如说Ceph存储,它的创新在于每个数据块都是可计算出来的,这就类似无状态的,每次都算,反正现在的cpu都这么强悍了。

所以,无状态就像是一个命题作文,大家在做架构的时候,脑海里一定要提前有这个理念,然后再看你用什么样的方式开动脑筋,预先的跟开发,运维沟通好,把应用拆分成一种无状态的最佳组合。

这样做的还有一个好处,就是能够区分运维工作中哪些是重点资源,哪些是需要更多的人去监控后端的服务,当知道这是重中之重的时候,就可以把有限的运维力量投到上面去。运维的人力和精力是有限的,要区分出关键场景,关键组件,然后再投入主要精力,这是策略。

  1. 利用k8s的CSI定义,使用Ceph/GlusterFS提供统一存储和分布式高可靠性的冗余

六、以标准化为荣,以特殊化为耻

在标准化方面,我们在这几个方面改良:

1、统一输入输出

统一入口是我加入公司后做的第一件事情,我们用一个统一的文本,到现在也在用,然后推送到所有的边缘,服务器上面的组件,要用到的参数,都能从配置里读出来。

现在我们用yaml的格式在重新定义配置文件。代码管理方面我们也使用git,git wiki,批量部署我们用ansible(早在2012年,我做了一些比较后,就在公司里推行ansible,看来还是很明智的决定)。

2、统一的流程管理

运维中使用python最多,所以我们使用了yaml和playbook来做统一的自动化部署,配置,升级,回退,发布。

我们也有自己的跳板机,通过VPN登陆,目前我们也在试用一个带有审计功能的堡垒机,可以把每个人的操作录制下来,然后再去回放观察,改进我们的工作流程。

3、抽象底层设计和复用组件

如果是开发者的话,就会写很多的复用函数,如各种class, function……对于优秀的运维人员来说,也要有优秀的抽象业务的能力,也要去做一些重复工作的复用准备,如频繁的,繁琐易出错的手工操作抽象成若干运维的脚本化。

最后是巧妙的利用虚拟化、容器服务、server-less微服务,这些服务是可以被备份,还原的,可以保持一个相对稳定的状态,我们要拒绝多的特殊管理操作。

因为香农-信息熵理论里说,变量的不确定性越大,把它搞清楚所需要的信息量也就越大。所以一个孤立的系统,他就会变得越来越乱。这个跟墨菲定律有相近的含义。

“一切皆声明”的软件架构设计模式
  1. Kubernetes 采用了“声明式”的资源管理模式,使用YAML格式声明

七、以自动化工具为荣,以手动和人肉为耻

公司早期,用的是bash、sed、awk,因为我之前有搞嵌入式的背景和经验,对一个十几兆的嵌入式系统来说,上面是不可能有python/perl/nodejs等环境。所以我们把服务器批量安装,部署,上线,做成了嵌入式的系统后,只要点亮以后,运行一个硬件检测的程序,会把机器的CPU、内存、硬盘大小等都打印出来,供货商截图给我看,这个机器是否合格。合格的机器可以直接发到机房去,在机器到了机房通上网线以后会有一个ansibleplaybook的推动。

自从用了这种方法以后,我们在公司里面基本上没有见到服务器,一般直接产线上检测通过后发到机房。然后我们运维人员就可以连上去远程管理,在过去的三年里我们服务器平均每年翻了三倍,节点翻了六倍多,但是人手并没有增加。

关于tgz、rpm、pkg的打包部署,我们用的是tgz的打包及docker镜像。优势在于,我们自有CDN网络,软件通过推动到CDN网络下可以加速下发。

像ELK集中日志的分析、大数据的分析,我们现在使用ELK以后,只要有基础的运维技术知识便可看懂,不需要高深的运维知识和脚本编辑知识,大多数人都可以完成这份工作。好处就是你多了好多眼睛帮你一起来发现问题,定位问题。所以ELK这套东西,我是反复强调,推荐给大家使用。

把握原则就是,不要手工hack,最好是用程序生成程序的方式去完成这个步骤。

八、以无人值守为荣,以人工介入为耻

运维部门要做的事情有三件:

1、 运维自动化

要有一定的业务抽象能力,要有标准化的流程。没有好的自动化,就很难把运维的工作效率提升了,只要做好这些,就可以节省时间,从容应对业务增长。

而且运维自动化的另一个好处就是运维不会因为人的喜怒哀乐而受到影响稳定性,比如说我今天心情不好,你让我装一台机器我还可以忍,你让我装十台一百台就不行了。

但如果公司有了运维自动化的流程,这个事情就可以避免,因为谁做都一样。

2、监控要常态

2016年年初,我们特别成立大数据分析部门,我们把日志做了采样收集和过滤,通过大数据平台做日志的同构数据分析,重点关注4xx/5xx/2xx比例,响应时间分析如100毫秒、200毫秒、500毫秒,还有区域性的速率分布,讲真,这真是一个好东西。

3、性能可视化

数据的有效展示。现在ELK对我们的帮助很大,从监控图上来看相关的数据指标,一目了然。这里就不反复赘述了。

最后,我们谈一谈DevOps的本质,更像是复习提纲。

DevOps的本质

一、弹性

像亚马逊推云时,那个单词叫elastic,意思是,你要能够扩展,如横向扩展;

你要能负载均衡,如果你是基于openstack/docker资源池,你的资源就可以复用,可以编排回滚。

比如说OpenStack有模板,我打一个镜像包,稍微重了一点,Docker的就轻一点,Docker可以做一个滚动发布,可以保留原来的程序、原来的容器,你可以做快速切换,这也是一种变化的弹性。

二、无关性

如果是虚拟化资源,一切都可以在模板里面设置,可以把底层的硬件、系统、网络抚平差异,比如说不管物理磁盘是1T(市面上缺货)/4T/6T的盘,都可以划分100G容量,所以当把一切变成按需申请的服务,无论是开发还是运维,工作都会比较简单,因为它的无关性。 当然 ,无状态也是无关性,可随时重启也是无关性。

三、不可变的基础设施

比如说像CoreOS这个操作系统,你到里面去看一下,真的没什么各种组件,除了最基础的就只有docker/RKT运行环境。当然,这个是很极端的例子,但是我觉得当底层的操作系统,他可以做到自我更新,足够安全的时候,确实不需要你去操心这个事情。

这个对传统运维可能是一种打击,因为基础镜像可能已经做的足够安全,足够完美,足够精干,不需要基础运维过多的人工参与。但我认为恰恰能帮助传统运维减轻工作量,反而有更多的精力去迎接虚拟化、容器化,SDN的挑战,掌握了新技能后,就可以随取随用。我现在是用比较开放的心态去接受这些变革……

wiki/public/speech/devops的八荣八耻.txt · 最后更改: 2025/12/13 03:37