shaonbean

shaonbean 查看完整档案

上海编辑滁州学院  |  计算机科学与技术 编辑平安医保科技  |  SRE 编辑 www.itdevops.me 编辑
编辑

Focus on Cloud,Cloud Native,SRE,Kubernetes and so on.

个人动态

shaonbean 发布了文章 · 8月7日

第1讲:第一堂“云原生”课

摘要:欢迎大家来到阿里云与 CNCF 共同推出的“云原生”技术公开课。本文整理自“云原生”技术公开课的开篇:第一堂“云原生”课。在本文中,阿里巴巴高级技术专家、CNCF 官方大使张磊为大家介绍了“云原生”技术的发展历程,本门课程的简介与预备知识以及“云原生”的定义和技术要点,精彩不容错过。

本节课程要点

  1. 云原生技术发展历程(为什么要学习这门课)
  2. 课程简介与预备知识(这门课到底教什么)
  3. 云原生的定义与技术要点(本节正式内容)

一、为什么要开设云原生技术公开课?

云原生技术发展简史

首先从第一个问题进行分享,那就是“为什么要开设云原生技术公开课?”云原生、CNCF 都是目前非常热门的关键词,但是这些技术并不是非常新鲜的内容。

  • 2004 年— 2007 年,Google 已在内部大规模地使用像 Cgroups 这样的容器技术;
  • 2008 年,Google 将 Cgroups 合并进入了 Linux 内核主干;
  • 2013 年,Docker 项目正式发布。
  • 2014 年,Kubernetes 项目也正式发布。这样的原因也非常容易理解,因为有了容器和 Docker 之后,就需要有一种方式去帮助大家方便、快速、优雅地管理这些容器,这就是 Kubernetes 项目的初衷。在 Google 和 Redhat 发布了 Kubernetes 之后,这个项目的发展速度非常之快。
  • 2015 年,由Google、Redhat 以及微软等大型云计算厂商以及一些开源公司共同牵头成立了 CNCF 云原生基金会。CNCF 成立之初,就有 22 个创始会员,而且 Kubernetes 也成为了 CNCF 托管的第一个开源项目。在这之后,CNCF 的发展速度非常迅猛;
  • 2017 年,CNCF 达到 170 个成员和 14 个基金项目;
  • 2018 年,CNCF 成立三周年有了 195 个成员,19 个基金会项目和 11 个孵化项目,如此之快的发展速度在整个云计算领域都是非常罕见的。

云原生技术生态现状

因此,如今我们所讨论的云原生技术生态是一个庞大的技术集合。CNCF 有一张云原生全景图(https://github.com/cncf/landscape),在这个全景图里已经有 200 多个项目和产品了,这些项目和产品也都是和 CNCF 的观点所契合的。所以如果以这张全景图作为背景,加以思考就会发现,我们今天所讨论的云原生其实主要谈论了以下几点:

  1. 云原生基金会 —— CNCF;
  2. 云原生技术社区,比如像 CNCF 目前正式托管的 20 多个项目共同构成了现代云计算生态的基石,其中像 Kubernetes 这样的项目已经成为了世界第四活跃的开源项目;
  3. 除了前面两点之外,现在全球各大公有云厂商都已经支持了 Kubernetes。此外,还有 100 多家技术创业公司也在持续地进行投入。现在阿里巴巴也在谈全面上云,而且上云就要上云原生,这也是各大技术公司拥抱云原生的一个例子。

我们正处于时代的关键节点

2019 年正是云原生时代的关键节点,为什么这么说?我们这里就为大家简单梳理一下。

从 2013 年 Docker 项目发布开始说起,Docker 项目的发布使得全操作系统语义的沙盒技术唾手可得,使得用户能够更好地、更完整地打包自己的应用,使得开发者可以轻而易举的获得了一个应用的最小可运行单位,而不需要依赖任何 PaaS 能力。这对经典 PaaS 产业其实是一个“降维打击”。

2014 年的时候,Kubernetes 项目发布,其意义在于 Google 将内部的 Borg/Omega 系统思想借助开源社区实现了“重生”,并且提出了“容器设计模式”的思想。而 Google 之所以选择间接开源 Kubernetes 而不是直接开源 Borg 项目,其实背后的原因也比较容易理解:Borg/Omega 这样的系统太复杂了,是没办法提供给 Google 之外的人使用,但是 Borg/Omega 这样的设计思想却可以借助 Kubernetes 让大家接触到,这也是开源 Kubernetes 的重要背景。

这样到了 2015 年到 2016 年,就到了容器编排“三国争霸”的时代,当时 Docker、Swarm、Mesos、Kubernetes 都在容器编排领域展开角逐,他们竞争的原因其实也比较容易理解, 那就是 Docker 或者容器本身的价值虽然大,但是如果想要让其产生商业价值或者说对云的价值,那么就一定需要在编排上面占据一个有利的位置。

Swarm 和 Mesos 的特点,那就是各自只在生态和技术方面比较强,其中,Swarm 更偏向于生态,而 Mesos 技术更强一些。相比之下, Kubernetes 则兼具了两者优势,最终在 2017 年“三国争霸”的局面中得以胜出,成为了当时直到现在的容器编排标准。这一过程的代表性事件就是 Docker 公司宣布在核心产品中内置了 Kubernetes 服务,并且 Swarm 项目逐渐停止维护。

到了 2018 年的时候,云原生技术理念开始逐渐萌芽,这是因为此时 Kubernetes 以及容器都成为了云厂商的既定标准,以“云”为核心的软件研发思想逐步形成。

而到了 2019 年,情况似乎又将发生一些变化。

2019 年——云原生技术普及元年

为什么说 2019 年很可能是一个关键节点呢?我们认为 2019 年是云原生技术的普及元年。

首先大家可以看到,在 2019 年,阿里巴巴宣布要全面上云,而且“上云就要上云原生”。我们还可以看到,以“云”为核心的软件研发思想,正逐步成为所有开发者的默认选项。像 Kubernetes 等云原生技术正在成为技术人员的必修课,大量的工作岗位正在涌现出来。

这种背景下,“会 Kubernetes”已经远远不够了,“懂 Kubernetes”、“会云原生架构”的重要性正日益凸显出来。 从 2019 年开始,云原生技术将会大规模普及,这也是为什么大家都要在这个时间点上学习和投资云原生技术的重要原因。

二、“云原生技术公开课”是一门怎样的课程?

基于上面所提到的技术趋势,所以阿里巴巴和 CNCF 联合开设了云原生技术公开课。

那么这样的公开课到底在讲什么内容呢?

公开课教学大纲

第一期云原生公开课的教学大纲,主要以应用容器和 Kubernetes 为核心,在后面几期将会陆续上线 Service Mesh、Serverless 等相关课程。

在第一期公开课中,我们首先将课程分为两部分——基础知识部分和进阶知识部分,总共有 17 个知识点。

  • 首先,我们希望通过第一部分的课程讲解帮助大家夯实基础。然后,对于更高阶的内容展开更深入的代码级别的剖析。希望通过这样循序渐进的方式帮助大家学习云原生技术;
  • 其次,在每个课程后面我们的讲师都会设置对应的课后自测考试题,这些考试题实际上是对本节课程最有效的归纳,我们希望能够通过课后评测的方式来帮助大家总结知识点,打造出属于自己的云原生知识体系;
  • 最后,我们的讲师在每个知识点的背后都设计了云端实践,所谓“实践出真知”,学习计算机相关的知识还是需要上手来实际地进行操作才可以。 因此在云端实践部分,讲师会提供详细的实践步骤供大家课后自我联系。并且在这个环节,阿里云还会赠送了定量的阿里云代金券帮助大家更好地在云上进行实践。

以上三个部分就构成了阿里云和 CNCF 联合推出的云原生技术公开课的教学内容。

公开课授课计划(第一期)

在授课计划方面,初步这样安排:第一堂课在 2019 年 4 月的第三周上线,此后将会每周更新一课,对于部分比较重要的知识点将会每周更新两次,总共 25 个课时。每个知识点后面都提供了课后自测和云端实践。

对于讲师阵容而言,也是本次公开课最引以为傲的部分。我们的公开课将会主要由 CNCF 社区资深成员与项目维护者为大家讲解,很多课程讲师都是阿里云容器平台团队的专家级工程师。同时,我们也会邀请云原生社区的资深专家和外部讲师为大家讲解部分内容。因此在课程进行过程中,我们会不定期地安排大咖直播、课程答疑和落地实践案例。

我们希望将这些内容都集成在一起,为大家呈现一个中国最完整、最权威、最具有影响力的云原生技术公开课。

课程预备知识

大家可能存在这样的疑惑,就是想要学习云原生基础知识之前需要哪些预备知识呢?其实大致需要三部分预备知识:

  1. Linux 操作系统知识:主要是一些通识性的基础,最好具有一定的在 Linux 下开发的经验;
  2. 计算机和程序设计的基础:这一点到入门工程师或者高年级本科生水平就足够了;
  3. 容器的使用基础:希望大家具有容器的简单使用经验,比如 docker run 以及 docker build 等,最好有一定 Docker 化应用开发的经验。当然,我们在课程中也会讲解相关的基础知识。

三、什么是“云原生”?云原生该怎么落地?

在介绍完课程之后,我们再来详细的聊一聊“云原生”:什么是“云原生”?云原生该怎么落地?这两个问题也是整个课程的核心内容。

云原生的定义

很多人都会问“到底什么是云原生?”

实际上,云原生是一条最佳路径或者最佳实践。更详细的说,云原生为用户指定了一条低心智负担的、敏捷的、能够以可扩展、可复制的方式最大化地利用云的能力、发挥云的价值的最佳路径。

因此,云原生其实是一套指导进行软件架构设计的思想。按照这样的思想而设计出来的软件:首先,天然就“生在云上,长在云上”;其次,能够最大化地发挥云的能力,使得我们开发的软件和“云”能够天然地集成在一起,发挥出“云”的最大价值。

所以,云原生的最大价值和愿景,就是认为未来的软件,会从诞生起就生长在云上,并且遵循一种新的软件开发、发布和运维模式,从而使得软件能够最大化地发挥云的能力。说到了这里,大家可以思考一下为什么容器技术具有革命性?

其实,容器技术和集装箱技术的革命性非常类似,即:容器技术使得应用具有了一种“自包含”的定义方式。所以,这样的应用才能以敏捷的、以可扩展可复制的方式发布在云上,发挥出云的能力。这也就是容器技术对云发挥出的革命性影响所在,所以说,容器技术正是云原生技术的核心底盘。

云原生的技术范畴

云原生的技术范畴包括了以下几个方面:

  • 第一部分是云应用定义与开发流程。这包括应用定义与镜像制作、配置 CI/CD、消息和 Streaming 以及数据库等。
  • 第二部分是云应用的编排与管理流程。这也是 Kubernetes 比较关注的一部分,包括了应用编排与调度、服务发现治理、远程调用、API 网关以及 Service Mesh。
  • 第三部分是监控与可观测性。这部分所强调的是云上应用如何进行监控、日志收集、Tracing 以及在云上如何实现破坏性测试,也就是混沌工程的概念。
  • 第四部分就是云原生的底层技术,比如容器运行时、云原生存储技术、云原生网络技术等。
  • 第五部分是云原生工具集,在前面的这些核心技术点之上,还有很多配套的生态或者周边的工具需要使用,比如流程自动化与配置管理、容器镜像仓库、云原生安全技术以及云端密码管理等。
  • 最后则是 Serverless。Serverless 是一种 PaaS 的特殊形态,它定义了一种更为“极端抽象”的应用编写方式,包含了 FaaS 和 BaaS 这样的概念。而无论是 FaaS 还是 BaaS,其最为典型的特点就是按实际使用计费(Pay as you go),因此 Serverless 计费也是重要的知识和概念。

云原生思想的两个理论

在了解完云原生的技术范畴之后你就会发现,其所包含的技术内容还是很多的,但是这些内容的技术本质却是类似的。云原生技术的本质是两个理论基础。

  • 第一个理论基础是:不可变基础设施。这一点目前是通过容器镜像来实现的,其含义就是应用的基础设施应该是不可变的,是一个自包含、自描述可以完全在不同环境中迁移的东西;
  • 第二个理论基础就是:云应用编排理论。当前的实现方式就是 Google 所提出来的“容器设计模式”,这也是本系列课程中的 Kubernetes 部分所需主要讲解的内容。

基础设施向云演进的过程

首先为大家介绍一下“不可变基础设施”的概念。其实,应用所依赖的基础设施也在经历一个向云演进的过程,举例而言,对于传统的应用基础设施而言,其实往往是可变的。

大家可能经常会干这样一件事情,比如需要发布或者更新一个软件,那么流程大致是这样的,先通过 SSH 连到服务器,然后手动升级或者降级软件包,逐个调整服务器上的配置文件,并且将新代码直接都部署到现有服务器上。因此,这套基础设施会不断地被调整和修改。

但是在云上,对“云”友好的应用基础设施是不可变的。

这种场景下的上述更新过程会这么做:一旦应用部署完成之后,那么这套应用基础设施就不会再修改了。如果需要更新,那么需要现更改公共镜像来构建新服务直接替换旧服务。而我们之所以能够实现直接替换,就是因为容器提供了自包含的环境(包含应用运行所需的所有依赖)。所以对于应用而言,完全不需要关心容器发生了什么变化,只需要把容器镜像本身修改掉就可以了。因此,对于云友好的基础设施是随时可以替换和更换的,这就是因为容器具有敏捷和一致性的能力,也就是云时代的应用基础设施。

所以,总结而言,云时代的基础设施就像是可以替代的“牲口”,可以随时替换;而传统的基础设施则是独一无二的“宠物”,需要细心呵护,这就体现出了云时代不可变基础设施的优点。

基础设施向云演进的意义

所以,像这样的基础设施向“不可变”演进的过程,为我们提供了两个非常重要的优点。

  • 1、基础设施的一致性和可靠性。同样一个镜像,无论是在美国打开,在中国打开,还是在印度打开都是一样的。并且其中的 OS 环境对于应用而言都是一致的。而对于应用而言,它就不需要关心容器跑在哪里,这就是基础设施一致性非常重要的一个特征。
  • 2、这样的镜像本身就是自包含的,其包含了应用运行所需要的所有依赖,因此也可以漂移到云上的任何一个位置。

此外,云原生的基础设施还提供了简单、可预测的部署和运维能力。由于现在有了镜像,应用还是自描述的,通过镜像运行起来的整个容器其实可以像 Kubernetes 的 Operator 技术一样将其做成自运维的,所以整个应用本身都是自包含的行为,使得其能够迁移到云上任何一个位置。这也使得整个流程的自动化变得非常容易。

应用本身也可以更好地扩容,从 1 个实例变成 100 个实例,进而变成 1 万个实例,这个过程对于容器化后的应用没有任何特殊的。最后,我们这时也能够通过不可变的基础设施来地快速周围的管控系统和支撑组件。因为,这些组件本身也是容器化的,是符合不可变基础设施这样一套理论的组件。

以上就是不可变基础设施为用户带来的最大的优点。

云原生关键技术点

当我们回过头来看云原生关键技术点或者说它所依赖的技术理论的时候,可以看到主要有这样的四个方向:

  1. 如何构建自包含、可定制的应用镜像;
  2. 能不能实现应用快速部署与隔离能力;
  3. 应用基础设施创建和销毁的自动化管理;
  4. 可复制的管控系统和支撑组件。

这四个云原生关键技术点是落地实现云原生技术的四个主要途径,而这四个技术点也是本门课程的 17 个技术点所主要讲述的核心知识。

本节总结

  • “云原生”具备着重要的意义,它是云时代技术人自我提升的必备路径;
  • “云原生”定义了一条云时代应用从开发到交付的最佳路径;
  • “云原生”应用生在云上,长在云上,希望能够将云的能力发挥到极致。

讲师点评:

“未来的软件一定是生长于云上的”这是云原生理念的最核心假设。而所谓“云原生”,实际上就是在定义一条能够让应用最大程度利用云的能力、发挥云的价值的最佳路径。在这条路径上,脱离了“应用”这个载体,“云原生”就无从谈起;容器技术,则是将这个理念落地、将软件交付的革命持续进行下去的重要手段之一。

而本期云原生公开课重点讲解的 Kubernetes 项目,则是整个“云原生”理念落地的核心与关键所在。它正在迅速成为连通“云”与“应用”的高速公路,以标准、高效的方式将“应用”快速交付到世界上任何一个位置。如今”云原生应用交付“,已经成为了 2019 年云计算市场上最热门的技术关键词之一。希望学习课程的同学们能够学以致用,持续关注以 K8s 为基础进行“云原生应用管理与交付”的技术趋势。

查看原文

赞 0 收藏 0 评论 0

shaonbean 赞了文章 · 7月13日

救火必备!问题排查与系统优化手册

简介: 软件工程领域存在一个共识:维护代码所花费的时间要远多于写代码。而整个代码维护过程中,最惊心动魄与扣人心弦的部分,莫过于问题排查(Trouble-shooting)了。特别是那些需要 7x24 小时不间断维护在线业务的一线服务端程序员们,大大小小的问题排查线上救火早已成为家常便饭,一不小心可能就吃成了自助餐 —— 竖着进躺着出,吃不了也兜不住。本文分享作者在服务端问题排查方面的一些经验,包括常见问题、排查流程、排查工具,结合实际项目中发生过的惨痛案例进行现身说法。

image.png

一 问题排查

1 常见问题

Know Your Enemy:知己知彼,百战不殆。

日常遇到的大部分问题,大致可以归到如下几类:

  • 逻辑缺陷:e.g. NPE、死循环、边界情况未覆盖。
  • 性能瓶颈:e.g. 接口 RT 陡增、吞吐率上不去。
  • 内存异常:e.g. GC 卡顿、频繁 FGC、内存泄露、OOM
  • 并发/分布式:e.g. 存在竞争条件、时钟不同步。
  • 数据问题:e.g. 出现脏数据、序列化失败。
  • 安全问题:e.g. DDoS 攻击、数据泄露。
  • 环境故障:e.g. 宿主机宕机、网络不通、丢包。
  • 操作失误:e.g. 配置推错、删库跑路(危险动作,请勿尝试..)。

上述分类可能不太完备和严谨,想传达的点是:你也可以积累一个这样的 checklist,当遇到问题百思不得其解时,耐心过一遍,也许很快就能对号入座。

2 排查流程

医生:小王你看,这个伤口的形状,像不像一朵漂浮的白云?

病人:...再不给我包扎止血,就要变成火烧云了。

image.png

快速止血

问题排查的第一步,一定是先把血止住,及时止损。如何快速止血?常见方式包括:

  • 发布期间开始报错,且发布前一切正常?啥也别管,先回滚再说,恢复正常后再慢慢排查。
  • 应用已经稳定运行很长一段时间,突然开始出现进程退出现象?很可能是内存泄露,默默上重启大法吧。
  • 只有少数固定机器报错?试试隔离这部分机器(关闭流量入口)。
  • 单用户流量突增导致服务不稳定?如果不是惹不起的金主爸爸,请勇敢推送限流规则。
  • 下游依赖挂了导致服务雪崩?还想什么呢,降级预案走起。

保留现场

血止住了?那么恭喜你,至少故障影响不会再扩大了。卸下锅,先喘口气再说。下一步,就是要根据线索找出问题元凶了。作为一名排查老手,你需要有尽量保留现场的意识,例如:

  • 隔离一两台机器:将这部分机器入口流量关闭,让它们静静等待你的检阅。
  • Dump 应用快照:常用的快照类型一般就是线程堆栈和堆内存映射。
  • 所有机器都回滚了,咋办?别慌,如果你的应用监控运维体系足够健全,那么你还有多维度的历史数据可以回溯:应用日志、中间件日志、GC 日志、内核日志、Metrics 指标等。

定位原因

OK,排查线索也有了,接下来该怎么定位具体原因?这个环节会综合考验你的技术深度、业务熟悉度和实操经验,因为原因往往都千奇百怪,需要 case by case 的追踪与分析。这里给出几个排查方向上的建议:

  • 关联近期变更:90% 以上的线上问题都是由变更引发,这也是为什么集团安全生产的重点一直是在管控“变更”。所以,先不要急着否认(“肯定不是我刚加的那行代码问题!”),相信统计学概率,好好 review 下近期的变更历史(从近至远)。
  • 全链路追踪分析:微服务和中台化盛行的当下,一次业务请求不经过十个八个应用处理一遍,都不好意思说自己是写 Java 的。所以,不要只盯着自己的应用不放,你需要把排查 scope 放大到全链路。
  • 还原事件时间线:请把自己想象成福尔摩斯(柯南也行),摆在你面前的就是一个案发现场,你需要做的是把不同时间点的所有事件线索都串起来,重建和还原整个案发过程。要相信,时间戳是不会骗人的。
  • 找到 Root Cause:排查问题多了你会发现,很多疑似原因往往只是另一个更深层次原因的表象结果之一。作为福尔摩斯,你最需要找到的是幕后凶手,而不是雇佣的杀人犯 —— 否则 TA 还会雇人再来一次。
  • 尝试复现问题:千辛万苦推导出了根因,也不要就急着开始修 bug 了。如果可以,最好能把问题稳定复现出来,这样才更有说服力。这里提醒一点:可千万别在生产环境干这事(除非你真的 know what you're doing),否则搞不好就是二次伤害(你:哈哈哈,你看,这把刀当时就是从这个角度捅进去的,轨迹完全一样。用户:...)。

解决问题

最后,问题根因已经找到,如何完美解决收尾?几个基本原则:

  • 修复也是一种变更,需要经过完整的回归测试、灰度发布;切忌火急火燎上线了 bugfix,结果引发更多的 bugs to fix。
  • 修复发布后,一定要做线上验证,并且保持观察一段时间,确保是真的真的修复了。
  • 最后,如果问题已经上升到了故障这个程度,那就拉上大伙好好做个故障复盘吧。整个处理过程一定还有提升空间,你的经验教训对其他同学来说也是一次很好的输入和自查机会:幸福总是相似的,故障也是。

3 排查工具

手里只有锤子,那看什么都像钉子。作为工程师,你需要的是一整套工具箱。

image.png

image.png

问题排查其实就是一次持续观测应用行为的过程。为了确保不遗漏关键细节,你需要让自己的应用变得更“可观测(Observable)。

提升应用可观测性有三大利器:日志(Logging)、监控(Metrics)、追踪(Tracing)。在我之前所做的项目中,这三块能力分别是由 SLS、Alimonitor / AliMetrics / Tsar、EagleEye 提供的,这里就不再展开描述了。

另外也很推荐 Arthas 这个工具,非常实用和顺手,相信很多同学都已经用过。

二 系统优化

只学会了问题排查还远远不够(当然技能必须点满,shit always happen),再熟练也只是治标不治本。如果想从根源上规避问题,必须从系统本身出发:按照性能、稳定性和可维护性三个方向,持续优化你的系统实现,扼杀问题于摇篮之中,让自己每天都能睡个安稳觉。

老板:既要快,又要稳,还要好。哦,工资的事你别担心,下个月一定能发出来。

image.png

系统优化的三个基本方向:性能(Performance)、稳定性(Stability)、可维护性(Maintainability)。三者之间并不是完全独立的,而是存在着复杂的相互作用关系,有时甚至会此消彼长。

最优秀的软件系统,并非要把这三个方向都做到极致,而是会根据自己实际的业务需求和场景合理取舍,在这三者之间达到一个综合最优的动态平衡状态,让各方面都能做到足够好即可。

所以,优化不只是一门科学,也是一门艺术。

1 性能优化

问:要跑出最快的圈速,是车手重要,还是赛车重要?

答:全都重要。

image.png

没有哪个男人会不喜欢高性能跑车,也没有哪个女人会希望在看李佳琦直播时突然卡顿。

性能,是各行各业工程师们共同追求的终极浪漫。

性能指标

指标(Indicators)是衡量一件事物好坏的科学量化手段。对于性能而言,一般会使用如下指标评估:

  • 吞吐率(Throughput):系统单位时间内能处理的工作负载,例如:在线 Web 系统 - QPS/TPS,离线数据分析系统 - 每秒处理的数据量。
  • 响应时间(Response Time):以 Web 请求处理为例,响应时间(RT)即请求从发出到收到的往返时间,一般会由网络传输延迟、排队延迟和实际处理耗时几个部分共同组成。
  • 可伸缩性(Scalability):系统通过增加机器资源(垂直/水平)来承载更多工作负载的能力;投入产出比越高(理想情况是线性伸缩),则说明系统的可伸缩性越好。

此外,同一个系统的吞吐率与响应时间,一般还会存在如下关联关系:吞吐率小于某个临界值时,响应时间几乎不变;一旦超出这个临界值,系统将进入超载状态(overloaded),响应时间开始线性增长。对于一个有稳定性要求的系统,需要在做性能压测和容量规划时充分考虑这个临界值的大小。

注:其实按更严谨的说法,性能就是单指一个系统有多“快”;上述部分指标并不纯粹只代表系统快慢,但也都与快慢息息相关。

性能分析

古人有句老话,If you can't measure it, you can't improve It.

要优化一个系统的性能(例如Web请求响应时间),你必须首先准确地测量和分析出,当前系统的性能究竟差在哪:是请求解析不够快,还是查询 DB 太慢?如果是后者,那又是扫描数据条目阶段太慢,还是返回结果集太慢?或者会不会只是应用与 DB 之间的网络延迟太大?

任何复杂请求的处理过程,最终都可以拆解出一系列并行/串行的原子操作。如果只是逮住哪个就去优化哪个,显然效率不会太高(除非你运气爆棚)。更合理的做法,应该是坚持 2/8 原则:优先分析和优化系统瓶颈,即当前对系统性能影响最大的原子操作;他们很可能就是 ROI 最高的优化点。

具体该如何去量化分析性能?这里列出了一些工具参考:

  • 系统层面:tsar、top、iostat、vmstat
  • 网络层面:iftop、tcpdump、wireshark
  • 数据库层面:SQL explain、CloudDBA
  • 应用代码层面:JProfiler、Arthas、jstack

其中很多工具也是问题排查时常用的诊断工具;毕竟,无论是性能分析还是诊断分析,目的都是去理解一个系统和他所处的环境,所需要做的事情都是相似的。

优化原则

你应该做的:上面已经提了很多,这里再补充一点:性能优化与做功能需求一样,都是为业务服务的,因此优化时千万不要忙着自嗨,一定要结合目标需求和应用场景 —— 也许这块你想做的优化,压根线上就碰不到;也许那块很难做的优化,可以根据流量特征做非通用的定制优化。

你不应该做的:即老生常谈的提前优化(Premature-optimization)与过度优化(Over-optimization) —— 通常而言(并不绝对),性能优化都不是免费的午餐,优化做的越多,往往可维护性也会越差。

优化手段

常用的性能优化手段有哪些?我这里总结了 8 个套路(最后 1 个是小霸王多合一汇总套路)。

1)简化

有些事,你可以选择不做。
  • 业务层面:e.g. 流程精简、需求简化。
  • 编码层面:e.g. 循环内减少高开销操作。
  • 架构层面:e.g. 减少没必要的抽象/分层。
  • 数据层面:e.g. 数据清洗、提取、聚合。

2)并行

有些事,你可以找人一起做。

方式:单机并行(多线程)、多机并行(分布式)。

优点:充分利用机器资源(多核、集群)。

缺点:同步开销、线程开销、数据倾斜。

  • 同步优化:乐观锁、细粒度锁、无锁。
  • 线程替代(如协程:Java WISP、Go routines、Kotlin coroutines)。
  • 数据倾斜:负载均衡(Hash / RR / 动态)。

3)异步

有些事,你可以放手,不用死等。

方式:消息队列 + 任务线程 + 通知机制。

优点:提升吞吐率、组件解耦、削峰填谷。

缺点:排队延迟(队列积压)。

  • 避免过度积压:Back-pressure(Reactive思想)。

4)批量

有些事,你可以合起来一起做。

方式:多次单一操作 → 合并为单次批量操作。

案例:TCP Nagel 算法;DB 的批量读写接口。

优点:避免单次操作的固有开销,均摊后总开销更低。

缺点:等待延迟 + 聚合延迟。

  • 减少等待延迟:Timeout 触发提交,控制延迟上限。

5)时间空间互换

游戏的本质:要么有闲,要么有钱。
  • 空间换时间:避免重复计算、拉近传输距离、分流减少压力。

案例:缓存、CDN、索引、只读副本(replication)。

  • 时间换空间:有时候也能达到“更快”的效果(数据量减少 → 传输时间减少)。

案例:数据压缩(HTTP/2 头部压缩、Bitmap)。

6)数据结构与算法优化

程序 = 数据结构 + 算法
  • 多了解一些“冷门”的数据结构 :Skip list、Bloom filter、Time Wheel 等。
  • 一些“简单”的算法思想:递归、分治、贪心、动态规划。

7)池化 & 局部化

共享经济 & 小区超市

池化(Pooling):减少资源创建和销毁开销。

  • 案例:线程池、内存池、DB 连接池、Socket 连接池。

局部化(Localization):避免共享资源竞争开销。

  • 案例:TLB(ThreadLocalBuffer)、多级缓存(本地局部缓存 -> 共享全局缓存)。

8)更多优化手段

  • 升级红利:内核、JRE、依赖库、协议。
  • 调参大师:配置、JVM、内核、网卡。
  • SQL 优化:索引、SELECT *、LIMIT 1。
  • 业务特征定制优化:e.g. 凌晨业务低峰期做日志轮转。
  • Hybrid 思想(优点结合):JDK sort() 实现、Weex/RN。

2 稳定性优化

稳住,我们能赢。—— by [0 杀 10 死] 正在等待复活的鲁班七号

维持稳定性是我们程序员每天都要思考和讨论的大事。

什么样的系统才算稳定?我自己写了个小工具,本地跑跑从来没出过问题,算稳定吗?淘宝网站几千人维护,但双十一零点还是经常下单失败,所以它不稳定喽?

稳定是相对的,业务规模越大、场景越复杂,系统越容易出现不稳定,且带来的影响也越严重。

image.png

衡量指标

不同业务所提供的服务类型千差万别,如何用一致的指标去衡量系统稳定性?标准做法是定义服务的可用性(Availability):只要对用户而言服务“可用”,那就认为系统当前是稳定的;否则就是不稳定。用这样的方式,采集和汇总后就能得到服务总的可用/不可用比例(服务时长 or 服务次数),以此来监测和量化一个系统的稳定性。

可是,通过什么来定义某个服务当前是否可用呢?这一点确实跟业务相关,但大部分同类业务都可以用类似的方式去定义。例如,对于一般的 Web 网站,我们可以按如下方式去定义服务是否可用:API 请求都返回成功,且页面总加载时间 < 3 秒。

对于阿里云对外提供的云产品而言,服务可用性是一个更加需要格外重视并持续提升的指标:阿里云上的很多用户会同时使用多款云产品,其中任何一款产品出现可用性问题,都会直接被用户的用户感知和放大。所以,越是底层的基础设施,可用性要求就越高。关于可用性的更多细节指标和概念(SLI / SLO / SLA),可进一步参考云智能 SLA 了解。

可用性测量

有了上述可用性指标定义后,接下来该如何去准确测量系统的可用性表现?一般有如下两种方式。

1)探针模拟

从客户端侧,模拟用户的调用行为。

  • 优点:数据真实(客户端角度)
  • 缺点:数据不全面(单一客户数据)

2)服务端采集

从服务端侧,直接分析日志和数据。

  • 优点:覆盖所有调用数据。
  • 缺点:缺失客户端链路数据。

对可用性数据要求较高的系统,也可以同时运用上述两种方式,建议结合你的业务场景综合评估选择。

优化原则

你应该做的:关注 RT 的数据分布(如:p50/p99/p999 分位点),而不是平均值(mean) —— 平均值并没有太大意义,更应该去关注你那 1%、0.1% 用户的准确感受。

你不应该做的:不要尝试承诺和优化可用性到 100% —— 一方面是无法实现,存在太多客观不可控因素;另一方面也没有意义,客户几乎关注不到 0.001% 的可用性差别。

优化手段

常用的稳定性优化手段有哪些?这里也总结了 8 个套路:

1)避免单点

父母:一个人在外漂了这么多年,也该找个人稳定下来了。

如何避免?

  • 集群部署
  • 数据副本
  • 多机房容灾

只堆量不够,还需要具备故障转移能力(Failover)。

  • 接入层:DNS、VipServer、SLB。
  • 服务层:服务发现 + 健康检查 + 剔除机制。
  • 应用层:无状态设计(Stateless),便于随时和快速切换。

2)流控/限流

计划生育、上学调剂、车牌限号、景区限行... 人生处处被流控。
  • 类型:QPS 流控、并发度流控。
  • 工具:RateLimiter、信号量、Sentinel。
  • 粒度:全局、用户级、接口级。
  • 热点流控:避免意料之外的突增流量。

3)熔断

上午买的股票熔断,晚上家里保险丝熔断... 淡定,及时止损而已。
  • 目的:防止连锁故障(雪崩效应)。
  • 工具:Hystrix、Failsafe、Resilience4j。
  • 功能:自动绕开异常服务并检测恢复状态。
  • 流程:关闭 → 打开 → 半开。

4)降级

没时间做饭了,今天就吃外卖吧... 对于健康问题,还是得少一点降级。

触发原因:流控、熔断、负载过高。

常见降级方式:

  • 关闭非核心功能:停止应用日志打印
  • 牺牲数据时效性:返回缓存中旧数据
  • 牺牲数据精确性:降低数据采样频率

5)超时/重试

钉钉不回怎么办?每 10 分钟 ping 一次,超过 1 小时打电话。

超时:避免调用端陷入永久阻塞。

  • 超时时间设置:全链路自上而下规划
  • Timeout vs. Deadline:使用绝对时间会更好

重试:确保可重试操作的幂等性。

  • 消息去重
  • 异步重试
  • 指数退避

6)资源设限

双 11 如何避免女友败家?提前把自己信用卡额度调低。
  • 目的:防止资源被异常流量耗尽
  • 资源类型:线程、队列、DB 连接
  • 设限方式:资源池化、有界队列
  • 超限处理:返回 ServiceUnavailable / QuotaExceeded

7)资源隔离

双 12 女友还是要败家?得嘞刷你自个的卡吧,别动我的。
  • 目的:防止资源被部分异常流量耗尽;为 VIP 客户提供服务质量保证(QoS)。
  • 隔离方式:队列划分、独立集群;注意处理优先级和资源分配比例。

8 )安全生产

女友哭着说再让我最后剁一次手吧?安全第一,宁愿心疼也不要肉疼。

程序动态性:开关、配置、热升级。

  • Switch:类型安全;侵入性小。

审核机制:代码 Review、发布审批。

灰度发布;分批部署;回滚预案。

  • DUCT:自动/手动调整 HSF 节点权重。

可维护性优化

前人栽树,后人乘凉。

前人挖坑,后人凉凉。

维护的英文是 maintain,也能翻译成:维持、供给。所以软件维护能有多重要?它就是软件系统的呼吸机和食物管道,维持软件生命的必要供给。

系统开发完成上线,不过只是把它“生”下来而已。软件真正能发挥多大价值,看的是交付后持续的价值兑现过程 —— 是不断茁壮成长,为用户发光发热?还是慢慢堕落,逐渐被用户所遗忘?这并不是取决于它当下瞬时是否足够优秀(性能)和靠谱(稳定),而是取决于未来 —— 能否在不断变化的市场环境、客户需求和人为因素中,始终保持足够优秀和靠谱,并且能越来越好。

相比性能和稳定性而言,可维护性所体现的价值往往是最长远、但也最难在短期内可兑现的,因此很多软件项目都选择了在前期牺牲可维护性。这样决策带来的后果,就跟架构设计一样,是几乎无法(或者需要非常高的成本)去弥补和挽回的。太多的软件项目,就是因为越来越不可维护(代码改不动、bug 修不完、feature 加不上),最后只能慢慢沦落为一个谁都不想碰的遗留项目。

衡量指标

相比性能和稳定性而言,可维护性确实不太好量化(艺术成分 > 科学成分)。这里我选取了几个偏定性分析的指标:

1)复杂度(Complexity):是否复杂度可控?

  • 编码:简洁度、命名一致性、代码行数等。
  • 架构:组件耦合度、层次清晰度、职责单一性等。

2)可扩展性(Extensibility):是否易于变更?

  • 需要变更代码或配置时,是否简单优雅、不易出错。

3)可运维性(Operability):是否方便运维?

  • 日志、监控是否完善;部署、扩容是否容易。

重要性

这里给了几个观点,进一步强调可维护性的重要性。

  • 软件生命周期:维护周期 >> 开发周期。
  • 破窗效应、熵增定律:可维护性会趋向于越来越差。
  • 遗留系统的危害:理解难度,修改成本,变更风险;陷入不断踩坑、填坑、又挖坑的循环。

优化原则

你应该做的:遵循 KISS 原则、DRY 原则、各种代码可读性和架构设计原则等。

你不应该做的:引入过多临时性、Hack 代码;功能 Work 就 OK,欠一堆技术债(出来混总是要还的)。

优化手段

常用的可维护性优化手段有哪些?这里我总结了 4 个套路:

1)编码规范

无规矩,不成方圆。
  • 编码:推荐《Java 开发手册》,另外也推荐 The Art of Readable Code 这本书。
  • 日志:无盲点、无冗余、TraceID。
  • 测试:代码覆盖度、自动化回归。

2)代码重构

别灰心,代码还有救。
  • 何时重构:任何时候代码中嗅到坏味道(bad smell)。
  • 重构节奏:小步迭代、回归验证。
  • 重构 vs. 重写:需要综合考虑成本、风险、并行版本维护等因素。
  • 推荐阅读:Refactoring: Improving the Design of Existing Code。

3)数据驱动

相信数据的力量。
  • 系统数据:监控覆盖、Metrics 采集等,对于理解系统、排查问题至关重要。
  • 业务数据:一致性校验、旧数据清理等;要相信,数据往往比代码要活得更久。

4)技术演进

技术是第一生产力。
  • 死守阵地 or 紧跟潮流? 需要综合评估风险、生产力、学习成本。
  • 当前方向:微服务化、容器化。

三 结语

Truth lies underneath the skin - 真理永远暗藏在表象底下。

对,就在这句话底下。

欢迎各位技术同路人加入阿里云云原生应用研发平台 EMAS 团队,我们专注于广泛的云原生技术(Backend as a Service、Serverless、DevOps、低代码平台等),致力于为企业、开发者提供一站式的应用研发管理服务,内推直达:pengqun.pq # alibaba-inc.com,有信必回。

查看原文

赞 4 收藏 3 评论 0

shaonbean 发布了文章 · 3月22日

最有用的Linux命令行技巧

最有用的Linux命令行技巧

将输出显示为表格

mount | column –t

使用-s参数指定分隔符,如下

cat /etc/passwd | column -t -s:

重复执行命令,直到命令成功运行

使用while true循环,>/dev/null 2>&1 将程序的输出重定向到/dev/null,同时包括标准错误和标准输出。

按内存使用情况对进程进行排序

ps aux | sort -rnk 4 | head -10

按CPU使用率对进程进行排序

ps aux | sort -nk 3 | head -10

同时观看多个日志文件

yum install multitail -y

自动对任何命令回答是或否

yes | yum update

记录您的命令行会话

如果要记录在shell屏幕上键入的内容,可以使用script命令将所有键入的内容保存到名为typescript的文件中

用制表符替换空格

cat geeks.txt | tr ':[space]:' 't' > out.txt

将文件转换为大写或小写

cat myfile | tr a-z A-Z > output.txt

强大的Xargs命

find. -name *.png -type f -print | xargs tar -cvzf images.tar.gz
cat urls.txt | xargs wget
ls /etc/*.conf | xargs -i cp {} /home/likegeeks/Desktop/out

常用的20个linux命令

ls
cp
cd
mv
rm
mkdir
rmdir
chown
chmod
locate
updatedb
date
tar
cat
less
grep
awk
sed
passwd
du
df

本文由博客群发一文多发等运营工具平台 OpenWrite 发布
查看原文

赞 0 收藏 0 评论 0

shaonbean 发布了文章 · 2019-08-30

promerheus+grafana+node_exporter 配置

docker start prometheus

pull prometheus images

  • docker pull prom/prometheus
  • docker pull prom/node-exporter
  • docker pull grafana/grafana

start prometheus & grafana & node_exporter

  • start node_exporter
docker run -d --name=node-exporter -p 9100:9100 -v "/proc:/host/proc:ro" -v "/sys:/host/sys:ro" -v "/:/rootfs:ro" --net="host" prom/node-exporter
  • config prometheus
# mkdir /etc/prometheus ,add prometheus.yml
# vim prometheus.yml
global:
  scrape_interval:     15s
  evaluation_interval: 15s

scrape_configs:
  - job_name: 'prometheus'

    static_configs:
      - targets: ['127.0.0.1:9090', '127.0.0.1:9100']
        labels:
          group: 'prometheus'
  • start prometheus
docker run -d --name=prometheus -p 9090:9090 -v /etc/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml  prom/prometheus

start influxdb

docker volume create vol-influxdb
docker run -d --name=influxdb -p 8083:8083 -p 8086:8086 -v vol-influxdb:/var/lib/influxdb influxdb
  • config influxdb
# docker exec -it 4362fc6a166a /bin/bash        
root@4362fc6a166a:/# influx
Connected to http://localhost:8086 version 1.7.7
InfluxDB shell version: 1.7.7
> create database telegraf
> use telegraf
Using database telegraf
> create user telegraf with password 'telegraf'
> show databases
name: databases
name
----
_internal
telegraf
> show users
user     admin
----     -----
telegraf false
> quit
root@4362fc6a166a:/# 

install telegraf

  • start telegraf
查看原文

赞 0 收藏 0 评论 0

shaonbean 发布了文章 · 2019-08-30

使用InfluxDB,Grafana和Telegraf监控Docker环境

使用InfluxDB,Grafana和Telegraf监控Docker环境

安装Grafana

  • 创建持久存储卷,确保在销毁并重新创建grafana docker以进行升级时,将保留应用的配置
# 挂在本地目录
mkdir /data/grafana-storage 
docker run -d --name=grafana -p 3000:3000 --name=grafana -v /data/grafana-storage:/var/lib/grafana grafana/grafana
  • 安装插件
# 根据需要自行安装
# grafana-cli plugins ls | grep -v Restart | grep -v installed | awk '{print $1}' (查看配置好已安装的插件,全新安装的grafana需要安装)           
alexanderzobnin-zabbix-app
grafana-clock-panel
grafana-kubernetes-app
grafana-piechart-panel
grafana-simple-json-datasource
grafana-worldmap-panel
michaeldmoore-annunciator-panel
  • 登录访问grafana
http://hostip:3000/login
# 默认:admin:admin

安装influxdb

mkdir /data/influxdb
docker run -d --name=influxdb -p 8083:8083 -p 8086:8086 -v /data/influxdb/influxdb.conf:/etc/influxdb/influxdb.conf:ro -v /data/influxdb:/var/lib/influxdb influxdb -config /etc/influxdb/influxdb.conf
  • 创建influxdb用户和数据库
# docker exec -it 7a717ccf97e1 /bin/bash
root@7a717ccf97e1:/# influx
Connected to http://localhost:8086 version 1.7.7
InfluxDB shell version: 1.7.7
> create user "telegraf" with password 'password'
> show users;
user     admin
----     -----
telegraf false
> create database telegraf
> show databases;
name: databases
name
----
_internal
telegraf
> exit

安装telegraf

mkdir /data/telegraf
docker run --rm telegraf telegraf config > /data/telegraf/telegraf.conf
docker run -d --name telegraf -v /data/telegraf/telegraf.conf:/etc/telegraf/telegraf.conf:ro telegraf -config /etc/telegraf/telegraf.conf
  • 配置telegraf.conf
# 参照更改
[[outputs.influxdb]]
  urls = ["http://hostip:8086"]

  database = "telegraf"

  retention_policy = ""

  write_consistency = "any"

  timeout = "5s"

  username = "telegraf"
  password = "password"
  • telegrafa连接influxdb成功显示如下
2019-08-30T00:25:48Z I! Starting Telegraf 1.11.5
2019-08-30T00:25:48Z I! Loaded inputs: mem processes swap system cpu disk diskio kernel
2019-08-30T00:25:48Z I! Loaded aggregators: 
2019-08-30T00:25:48Z I! Loaded processors: 
2019-08-30T00:25:48Z I! Loaded outputs: influxdb
2019-08-30T00:25:48Z I! Tags enabled: host=f0aa64ca61d8
2019-08-30T00:25:48Z I! [agent] Config: Interval:10s, Quiet:false, Hostname:"f0aa64ca61d8", Flush Interval:10s

grafana配置influxdb datasource

查看原文

赞 0 收藏 0 评论 0

shaonbean 发布了文章 · 2019-08-29

docker 常用命令速查

  • info
## List Docker CLI commands
docker
docker container --help

## Display Docker version and info
docker --version
docker version
docker info

## Execute Docker image
docker run hello-world

## List Docker images
docker image ls

## List Docker containers (running, all, all in quiet mode)
docker container ls
docker container ls --all
docker container ls -aq
  • container
docker build -t friendlyhello .  # Create image using this directory's Dockerfile
docker run -p 4000:80 friendlyhello  # Run "friendlyhello" mapping port 4000 to 80
docker run -d -p 4000:80 friendlyhello         # Same thing, but in detached mode
docker container ls                                # List all running containers
docker container ls -a             # List all containers, even those not running
docker container stop <hash>           # Gracefully stop the specified container
docker container kill <hash>         # Force shutdown of the specified container
docker container rm <hash>        # Remove specified container from this machine
docker container rm $(docker container ls -a -q)         # Remove all containers
docker image ls -a                             # List all images on this machine
docker image rm <image id>            # Remove specified image from this machine
docker image rm $(docker image ls -a -q)   # Remove all images from this machine
docker login             # Log in this CLI session using your Docker credentials
docker tag <image> username/repository:tag  # Tag <image> for upload to registry
docker push username/repository:tag            # Upload tagged image to registry
docker run username/repository:tag                   # Run image from a registry
  • services
docker stack ls                                            # List stacks or apps
docker stack deploy -c <composefile> <appname>  # Run the specified Compose file
docker service ls                 # List running services associated with an app
docker service ps <service>                  # List tasks associated with an app
docker inspect <task or container>                   # Inspect task or container
docker container ls -q                                      # List container IDs
docker stack rm <appname>                             # Tear down an application
docker swarm leave --force      # Take down a single node swarm from the manager
  • Swarms
docker-machine create --driver virtualbox myvm1 # Create a VM (Mac, Win7, Linux)
docker-machine create -d hyperv --hyperv-virtual-switch "myswitch" myvm1 # Win10
docker-machine env myvm1                # View basic information about your node
docker-machine ssh myvm1 "docker node ls"         # List the nodes in your swarm
docker-machine ssh myvm1 "docker node inspect <node ID>"        # Inspect a node
docker-machine ssh myvm1 "docker swarm join-token -q worker"   # View join token
docker-machine ssh myvm1   # Open an SSH session with the VM; type "exit" to end
docker node ls                # View nodes in swarm (while logged on to manager)
docker-machine ssh myvm2 "docker swarm leave"  # Make the worker leave the swarm
docker-machine ssh myvm1 "docker swarm leave -f" # Make master leave, kill swarm
docker-machine ls # list VMs, asterisk shows which VM this shell is talking to
docker-machine start myvm1            # Start a VM that is currently not running
docker-machine env myvm1      # show environment variables and command for myvm1
eval $(docker-machine env myvm1)         # Mac command to connect shell to myvm1
& "C:\Program Files\Docker\Docker\Resources\bin\docker-machine.exe" env myvm1 | Invoke-Expression   # Windows command to connect shell to myvm1
docker stack deploy -c <file> <app>  # Deploy an app; command shell must be set to talk to manager (myvm1), uses local Compose file
docker-machine scp docker-compose.yml myvm1:~ # Copy file to node's home dir (only required if you use ssh to connect to manager and deploy the app)
docker-machine ssh myvm1 "docker stack deploy -c <file> <app>"   # Deploy an app using ssh (you must have first copied the Compose file to myvm1)
eval $(docker-machine env -u)     # Disconnect shell from VMs, use native docker
docker-machine stop $(docker-machine ls -q)               # Stop all running VMs
docker-machine rm $(docker-machine ls -q) # Delete all VMs and their disk images
查看原文

赞 0 收藏 0 评论 0

shaonbean 发布了文章 · 2018-07-16

shell批量设置免密认证

shell批量设置免密认证

实验背景:笔者想使用ansible同步一批虚拟机的配置,需要对这些虚拟机进行免密设置
  • 实验所需文件及脚本如下图

这里写图片描述

生成ip列表

#!/bin/bash
####################################
# Function: generate ip list for use
####################################
# auther: shaobean@qq.com
# Changelog:
# 2018-07-11 wanghui initial
####################################
# set -x

# define ip Subnet

SUBNET=192.168.10.

for ip in `seq 20 25`;
  do
  echo "$SUBNET$ip" >> /root/ip.txt
  done

[ $? -eq 0 ] && echo "Generate Ip List Complete."

生成密码文件

#!/bin/bash
##########################################
# Function: generate password list for use
##########################################
# auther: shaobean@qq.com
# Changelog:
# 2018-07-11 wanghui initial
##########################################
# set -x

# define ip Subnet

PASSWORD=password

for pd in `seq 20 25`;
  do
  echo "$PASSWORD$pd" >> /root/password.txt
  done

[ $? -eq 0 ] && echo "Generate Password List Complete."
  • 合并ip文件和密码文件
/usr/bin/paste -d: /root/ip.txt /root/password.txt > /root/ip-password.txt
  • 笔者ip-password文件格式:
[root@wanghui ~]# cat ip-password.txt
192.168.10.20:211212
192.168.10.21:211212
192.168.10.22:211212
192.168.10.23:211212
192.168.10.24:211212
192.168.10.25:211212
# 由于笔者虚拟机初始密码都一样,这里为了实验方便,建议使用不同的密码

创建批量设置ssh免密认证脚本

#!/bin/bash  
#########################################################
# Functions: batch ssh free secret login
#########################################################
# Author: shaonbean@qq.com
# Changelog:
# 2018-07-11 wanghui initial create
#########################################################
# set -x

# generate ip-password.txt for paste_ip_password.sh

IP_PASSWORD=/root/ip-password.txt

# if expect exists

rpm -qa | grep expect >> /dev/null

if [ $? -eq 0 ];then
  echo "expect already install."
  else
  yum install expect -y
fi

# batch ssh Certification
for IP in $(cat $IP_PASSWORD)
  do
  ip=$(echo "$IP" | cut -f1 -d ":") 
  password=$(echo "$IP" | cut -f2 -d ":")
     
  # begin expect 
  expect -c "   
  spawn ssh-copy-id -i /root/.ssh/id_rsa.pub root@$ip  
        expect {   
                  \"*yes/no*\" {send \"yes\r\"; exp_continue}   
                  \"*password*\" {send \"$password\r\"; exp_continue}   
                  \"*Password*\" {send \"$password\r\";}   
        }   
    "   
  done   
     
# use ssh batch excute command
     
for hostip in $(cat $IP_PASSWORD | cut -f1 -d ":")  
    do  
    ssh root@$hostip 'uptime'    
    done  
  • 本地重新生成ssh私钥公钥
[root@wanghui ~]# rm -rf .ssh/
[root@wanghui ~]# ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): 
Created directory '/root/.ssh'.
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
Your identification has been saved in /root/.ssh/id_rsa.
Your public key has been saved in /root/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:+QrZGBOpZciJqG9QnDmT2d5wLDoJiuXLmob7avcWYFk root@wanghui.io
The key's randomart image is:
+---[RSA 2048]----+
|                 |
| o O E .         |
|o % X B          |
|+= X O . .       |
|= * + + S        |
| + o . * .       |
|. =   = . .      |
|.* . . . .       |
|B+o o.  .        |
+----[SHA256]-----+

执行脚本、批量设置免密认证

[root@wanghui ~]# bash batch_set_ssh_secret.sh 
expect already install.
spawn ssh-copy-id -i /root/.ssh/id_rsa.pub root@192.168.10.20
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
The authenticity of host '192.168.10.20 (192.168.10.20)' can't be established.
ECDSA key fingerprint is SHA256:WV7KiVaITK4NnnYC1ebdmXg+QEmUAKtpD4bH0To7uPU.
ECDSA key fingerprint is MD5:f3:c9:59:14:cd:b1:bf:08:9e:cf:3a:cc:63:02:46:8b.
Are you sure you want to continue connecting (yes/no)? yes
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@192.168.10.20's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'root@192.168.10.20'"
and check to make sure that only the key(s) you wanted were added.

spawn ssh-copy-id -i /root/.ssh/id_rsa.pub root@192.168.10.21
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
The authenticity of host '192.168.10.21 (192.168.10.21)' can't be established.
ECDSA key fingerprint is SHA256:WV7KiVaITK4NnnYC1ebdmXg+QEmUAKtpD4bH0To7uPU.
ECDSA key fingerprint is MD5:f3:c9:59:14:cd:b1:bf:08:9e:cf:3a:cc:63:02:46:8b.
Are you sure you want to continue connecting (yes/no)? yes
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@192.168.10.21's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'root@192.168.10.21'"
and check to make sure that only the key(s) you wanted were added.

spawn ssh-copy-id -i /root/.ssh/id_rsa.pub root@192.168.10.22
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
The authenticity of host '192.168.10.22 (192.168.10.22)' can't be established.
ECDSA key fingerprint is SHA256:WV7KiVaITK4NnnYC1ebdmXg+QEmUAKtpD4bH0To7uPU.
ECDSA key fingerprint is MD5:f3:c9:59:14:cd:b1:bf:08:9e:cf:3a:cc:63:02:46:8b.
Are you sure you want to continue connecting (yes/no)? yes
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@192.168.10.22's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'root@192.168.10.22'"
and check to make sure that only the key(s) you wanted were added.

spawn ssh-copy-id -i /root/.ssh/id_rsa.pub root@192.168.10.23
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
The authenticity of host '192.168.10.23 (192.168.10.23)' can't be established.
ECDSA key fingerprint is SHA256:DDyxtC8wq06dGmngNcX7xU4XprZ/WCz7vfVikiSUix8.
ECDSA key fingerprint is MD5:97:32:a0:7c:5a:59:06:f5:cf:f3:87:df:e0:e0:fb:b6.
Are you sure you want to continue connecting (yes/no)? yes
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@192.168.10.23's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'root@192.168.10.23'"
and check to make sure that only the key(s) you wanted were added.

spawn ssh-copy-id -i /root/.ssh/id_rsa.pub root@192.168.10.24
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
The authenticity of host '192.168.10.24 (192.168.10.24)' can't be established.
ECDSA key fingerprint is SHA256:DDyxtC8wq06dGmngNcX7xU4XprZ/WCz7vfVikiSUix8.
ECDSA key fingerprint is MD5:97:32:a0:7c:5a:59:06:f5:cf:f3:87:df:e0:e0:fb:b6.
Are you sure you want to continue connecting (yes/no)? yes
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@192.168.10.24's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'root@192.168.10.24'"
and check to make sure that only the key(s) you wanted were added.

spawn ssh-copy-id -i /root/.ssh/id_rsa.pub root@192.168.10.25
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/root/.ssh/id_rsa.pub"
The authenticity of host '192.168.10.25 (192.168.10.25)' can't be established.
ECDSA key fingerprint is SHA256:DDyxtC8wq06dGmngNcX7xU4XprZ/WCz7vfVikiSUix8.
ECDSA key fingerprint is MD5:97:32:a0:7c:5a:59:06:f5:cf:f3:87:df:e0:e0:fb:b6.
Are you sure you want to continue connecting (yes/no)? yes
/usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
root@192.168.10.25's password: 

Number of key(s) added: 1

Now try logging into the machine, with:   "ssh 'root@192.168.10.25'"
and check to make sure that only the key(s) you wanted were added.

 17:33:26 up 5 days, 23:55,  0 users,  load average: 0.15, 0.05, 0.06
 09:33:23 up 5 days, 23:56,  0 users,  load average: 0.00, 0.01, 0.05
 17:33:28 up 5 days, 23:56,  1 user,  load average: 0.00, 0.01, 0.05
 09:33:22 up 5 days, 23:38,  1 user,  load average: 0.08, 0.08, 0.10
 09:33:24 up 5 days, 23:38,  1 user,  load average: 0.01, 0.02, 0.05
 09:33:23 up 5 days, 23:38,  1 user,  load average: 0.00, 0.01, 0.05
查看原文

赞 0 收藏 0 评论 0

shaonbean 发布了文章 · 2018-03-05

CentOS7 安装并使用Ovirt 4.2

CentOS7 安装并使用Ovirt 4.2

Ovirt 4.2 安装

参考:http://blog.csdn.net/wh211212...
参考:http://blog.csdn.net/wh211212...(需要使用)
  • 环境准备,两台主机
禁用selinux,关闭防火墙
10.1.1.2 (ovirt-engine+GlusterFS)
10.1.1.3 (GlusterFS+nfs)
  • hosts设置
10.1.1.2 ovirt.aniu.so server1
10.1.1.3 nfs.aniu.so docker.aniu.so server2
  • Ovirt官网文档:
http://www.ovirt.org/document...
  • oVirt安装
yum install http://resources.ovirt.org/pub/yum-repo/ovirt-release42.rpm
yum -y install ovirt-engine
安装过程全部使用默认,建议使用默认
  • 在两台主机server1,server2上安装ovirt node
#
yum install http://resources.ovirt.org/pub/yum-repo/ovirt-release42.rpm
yum -y install vdsm

配置Ovirt

这里写图片描述

  • 登录ovirt UI,用户名 admin,密码是安装过程中设置的密码

这里写图片描述

使用Ovirt创建虚拟机

  • 创建数据中心

这里写图片描述

存储类型选择共享的,类型选择本地,每个数据中心下面只能添加一个主机,不采用这种方式
  • 创建集群

这里写图片描述

假如有多个数据中心,创建集群的时候选择在那个数据中心下面创建,根据使用选择CPU架构,其他默认即可
  • 添加主机

这里写图片描述

添加主机时注意关闭自动配置防火墙选项,在高级设置里面,使用root账号 密码即可,添加主机过程可以查看,事件查看安装过程
  • 查看添加完成的主机

这里写图片描述
这里写图片描述

添加存储

  • 添加nfs data存储域,用于创建虚拟机

这里写图片描述

标注的地方都需要修改,注意根据自己的配置填入对应的
  • 添加iso存储域,用于存放镜像文件

这里写图片描述

  • 添加glusterfs data 存储域,高可用 用于创建虚拟机

这里写图片描述

  • 添加系统镜像文件
# 使用命令
先把镜像文件上传到服务器上,执行上传命令
engine-iso-uploader --nfs-server=nfs.aniu.so:/export/iso upload /usr/local/src/CentOS-7-x86_64-Minimal-1611.iso
# 或者通过filezilla上传到服务的 data存储域目录下。然后到移动到正确的位置

这里写图片描述

创建虚拟机

这里写图片描述

这里写图片描述

添加硬盘的时候可以选择不同的data存储域
  • 运行虚拟机
这里笔者安装ovirt-engine的服务器安装了桌面环境,然后通过VNC远程进行虚拟的安装,不安装系统桌面时,笔者配置完虚拟机运行后,通过console不能连上去,会让下载vv格式的文件,很烦,安装桌面配置VNC笔者这里不过多赘述

这里写图片描述
这里写图片描述

  • 虚拟机在线迁移

这里写图片描述

迁移的时候选择要迁移到的主机,注意:不同数据中心下面的虚拟机不能迁移

ovirt备份

参考:https://www.ovirt.org/documen...
engine-backup --scope=all --mode=backup --file=ovirt-backup.txt --log=/var/log/ovirt-engine/ovirt-engine.log
笔者安装配置遇到的问题:
  • 存储域添加完成后不知道如何删除
查看原文

赞 0 收藏 0 评论 0

shaonbean 发布了文章 · 2017-12-13

Cloudera Manager 安装 CDH5.x 心得

Cloudera Manager 安装 CDH5.x 心得

废话不多说,先展示下这几天捣鼓的成果

  • Cloudera Manager 管理配置界面

这里写图片描述

  • Hbase 管理界面及Hbase Web UI

[站外图片上传中...(image-1c6abb-1513138023093)]

这里写图片描述

  • HDFS 管理界面 及 NameNode Web UI

[站外图片上传中...(image-82c66f-1513138023093)]

这里写图片描述

  • Hive 管理界面 及 HiveServer2 Web UI

这里写图片描述
这里写图片描述

  • Hue 管理界面 及 Web UI

这里写图片描述

这里写图片描述

首次登录会提示让创建管理员账号和密码,笔者 admin admin

这里写图片描述

  • Oozie 管理界面 及 Oozie Web UI

这里写图片描述

# Oozie  Web UI 报错,后期修复

Oozie web console is disabled.
To enable Oozie web console install the Ext JS library.

参考:http://cdh01.aniu.so:11000/oozie/docs/DG_QuickStart.html
  • YARN (MR2 Included) 管理界面 及 Web UI

这里写图片描述

  • ResourceManager Web UI

这里写图片描述

  • HistoryServer Web UI

[站外图片上传中...(image-47c126-1513138023093)]

  • Zookeeper 管理界面

这里写图片描述

笔者这里zookeeper安装的时候选择的默认,因此只安装了一个zookeeper,但个人感觉后期应该需要增加zookeeper的界面数量

下面开始说安装的注事事项

  • 1、配置环境要符合要求,要纯净的系统环境
# 笔者环境
# CM env
192.168.1.137 cdh01.aniu.so CentOS6.9 16G Memory 100G LVM卷 (Manger 节点)
192.168.1.148 cdh02.aniu.so CentOS6.9 4G Memory 70G LVM卷
192.168.1.149 cdh03.aniu.so CentOS6.9 4G Memory 70G LVM卷
192.168.1.150 cdh04.aniu.so CentOS6.9 4G Memory 70G LVM卷

建议小白参考笔者的环境配置,主机名可以自定义

#对四个节点的系统进行更新,安装开发工具包
yum update -y && yum -y groupinstall "Development Tools"
  • 2、关闭防火墙、禁用Selinux
# 关闭防火墙
/etc/init.d/iptables stop && /etc/init.d/ip6tables stop
chkconfig iptables off && chkconfig ip6tables off

# 建议采用修改内核参数的方式关闭ip6tables 
vim /etc/modprobe.d/dist.conf # 编辑此文件,在最后加入:

# Disable ipv6
alias net-pf-10 off
alias ipv6 off

# 禁用selinux
sed -i 's/SELINUX=enforcing/SELINUX=disabled/g' /etc/selinux/config
setenforce 0  # 不重启临时生效
  • 3、内核参数调整
# 内存参数调整
sysctl -w vm.swappiness=10 或者 编辑vim /etc/sysctl.conf,在最后加入:

vm.swappiness = 10

编辑启动项vim /etc/rc.local,最后加入:
echo never > /sys/kernel/mm/transparent_hugepage/defrag 
echo never > /sys/kernel/mm/transparent_hugepage/enabled

注:上面所有操作在所有节点都需要执行

  • 4、所有节点间配置免密认证
# CM节点执行
ssh-keygen -t rsa -b 2048 # 有确认提示,一直按回车即可
cat ~/.ssh/id_rsa.pub > ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys
# 笔者 hosts.conf
# CM node
192.168.1.137 cdh01.aniu.so
192.168.1.148 cdh02.aniu.so
192.168.1.149 cdh03.aniu.so
192.168.1.150 cdh04.aniu.so

# 同步密钥
for ip in $(awk '{print $1}' hosts.conf );do scp ~/.ssh/authorized_keys root@$ip:/root/.ssh ;done
或者使用
ssh-copy-id root@cdh01.aniu.so
ssh-copy-id root@cdh02.aniu.so
ssh-copy-id root@cdh03.aniu.so
ssh-copy-id root@cdh04.aniu.so
# 上面操作也需要在所有节点执行
  • 5、使用cloudera-manger repo安装CM
# 在CM节点执行
wget http://archive.cloudera.com/cm5/redhat/6/x86_64/cm/cloudera-manager.repo -P /etc/yum.repos.d
wget https://archive.cloudera.com/cdh5/redhat/6/x86_64/cdh/cloudera-cdh5.repo -P /etc/yum.repos.d
# 
yum clean all && yum makecache # 建议执行不强制
yum install oracle-j2sdk1.7 -y
yum install cloudera-manager-daemons cloudera-manager-server -y

# 在其他节点执行
wget http://archive.cloudera.com/cm5/redhat/6/x86_64/cm/cloudera-manager.repo -P /etc/yum.repos.d
yum install oracle-j2sdk1.7 -y

# 配置JAVA_HOME
编辑vim /etc/profile
export JAVA_HOME=/usr/java/jdk1.7.0_67-cloudera
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar
保存退出执行:
source /etc/profile 使更改的环境变量生效

# 在所有节点执行配置JAVA_HOME的操作
  • 6、CM节点安装数据库,或使用已有的数据
# 笔者使用mysql57-community.repo,安装的mysql
[mysql57-community]
name=MySQL 5.7 Community Server
baseurl=http://repo.mysql.com/yum/mysql-5.7-community/el/6/$basearch/
enabled=1
gpgcheck=0
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-mysql
#
yum install mysql-community-embedded  mysql-community-server  mysql-community-devel mysql-community-client -y

# 笔者my.cnf
[root@cdh01 yum.repos.d]# cat /etc/my.cnf
[client]
port        = 3306
socket      = /var/lib/mysql/mysql.sock

[mysqld]
datadir     = /opt/mysql
socket      = /var/lib/mysql/mysql.sock
#skip-grant-tables 
skip-ssl
disable-partition-engine-check
port        = 3306
skip-external-locking
key_buffer_size = 16M
max_allowed_packet = 1M
table_open_cache = 64
sort_buffer_size = 512K
net_buffer_length = 8K
read_buffer_size = 256K
read_rnd_buffer_size = 512K
myisam_sort_buffer_size = 8M
thread_cache_size = 8
query_cache_size = 8M
tmp_table_size = 16M
performance_schema_max_table_instances = 500

explicit_defaults_for_timestamp = true
max_connections = 500
max_connect_errors = 100
open_files_limit = 8192

log-bin=mysql-bin
binlog_format=mixed
server-id   = 1
expire_logs_days = 10
early-plugin-load = ""

default_storage_engine          = InnoDB
innodb_file_per_table           = 1
innodb_data_home_dir            = /opt/mysql
innodb_data_file_path           = ibdata1:1024M;ibdata2:10M:autoextend
innodb_log_group_home_dir       = /opt/mysql
innodb_buffer_pool_size         = 16M
innodb_log_file_size            = 5M
innodb_log_buffer_size          = 8M
innodb_flush_log_at_trx_commit  = 1
innodb_lock_wait_timeout        = 50
innodb_log_files_in_group       = 3 
innodb_buffer_pool_size         = 12G
innodb_log_file_size            = 512M
innodb_log_buffer_size          = 256M
innodb_flush_log_at_trx_commit  = 2
innodb_lock_wait_timeout        = 150
innodb_open_files               = 600
innodb_max_dirty_pages_pct      = 50
innodb_file_per_table           = 1

[mysqldump]
quick
max_allowed_packet = 16M

[mysql]
no-auto-rehash

[myisamchk]
key_buffer_size = 20M
sort_buffer_size = 20M
read_buffer = 2M
write_buffer = 2M

[mysqlhotcopy]
xinteractive-timeout

symbolic-links=0
slow_query_log
long_query_time = 5
slow_query_log_file = /var/log/mysql-slow.log
log-error = /var/log/mysqld.log
pid-file = /var/run/mysqld/mysqld.pid

# 初始化mysql,并设置启动数据库设置root密码
/usr/sbin/mysqld --initialize --user=mysql --socket=/var/lib/mysql/mysql.sock # 先执行
mysql_secure_installation # 再执行

# 创建CM启动用到的数据库
mysql -u root -pAniuops123. -e "create database cmf DEFAULT CHARACTER SET utf8;"
mysql -u root -pAniuops123. -e "GRANT ALL PRIVILEGES ON `cmf`.* TO 'cmf'@'localhost' IDENTIFIED BY 'Aniunas123.'";"
  • 启动cloudera-scm-server,并配置parcel
# 生成db配置文件
/usr/share/cmf/schema/scm_prepare_database.sh mysql cmf cmf Aniucmf123.

# 启动cloudera-scm-server
/etc/init.d/cloudera-scm-server start # 查看启动日志

# 配置parcel离线
cd /opt/cloudera/parcel-repo/ # 然后下载

wget http://archive.cloudera.com/cdh5/parcels/latest/CDH-5.13.1-1.cdh5.13.1.p0.2-el6.parcel
wget http://archive.cloudera.com/cdh5/parcels/latest/CDH-5.13.1-1.cdh5.13.1.p0.2-el6.parcel.sha1
wget http://archive.cloudera.com/cdh5/parcels/latest/manifest.json

# 注:读者根据cloudera当前CDH最新版本更改下载用到的URL
mv CDH-5.13.1-1.cdh5.13.1.p0.2-el6.parcel.sha1 CDH-5.13.1-1.cdh5.13.1.p0.2-el6.parcel.sha # 强制执行、默认使用本地的parcels包,不更改sha1,cloudera-scm-server启动安装时会去cloudera官网找匹配的parcel安装包

重启cloudera-scm-server,查看实时日志
/etc/init.d/cloudera-scm-server restart
tailf /var/log/cloudera-scm-server/cloudera-scm-server.log 
  • 通过CM管理界面安装CDH,注意事项
# CM server启动成功即可通过http://192.168.1.137:7180访问,默认账户密码:admin admin

# **重点内容** 下面的话很重要:


不要勾选:单用户模式 ,笔者在此模式下安装多次都没成功,有心人可以测试
  • 能一次性安装成功的最好,安装不成功建议多试几次,对初始化完成的虚拟机进行快照操作,便于恢复
查看原文

赞 1 收藏 6 评论 0

shaonbean 回答了问题 · 2017-12-08

svn每次update,都会改变目录所属用户和用户组,怎么避免?

  1. 使用git好吗?

关注 3 回答 3

认证与成就

  • 获得 20 次点赞
  • 获得 14 枚徽章 获得 0 枚金徽章, 获得 2 枚银徽章, 获得 12 枚铜徽章

擅长技能
编辑

开源项目 & 著作
编辑

  • 运维手册

    企业实际运维中技术栈安装、使用及维护

注册于 2016-09-28
个人主页被 595 人浏览