最后更新2022/03/16
忘记更新对应的学习笔记,补上。这一科有9节,加上0章简介
google cloud的好多功能有点相似,这科内容是介绍应该选什么产品,怎么选择,怎么规划,怎么设计等等。首先,你要有个软件产品的设计思想,包括对需求和用户的定义,这个没人能帮你,要你自己解决,google cloud只是个辅助的实现工具,要拿这个工具干什么,你自己决定。
有了这个核心设计思想之后,就要对实现过程进行解构,例如将大目标——10个亿,变成10个1个亿的小目标。。。在现代设计中,基于云架构的系统,最佳的实现方案是采用微服务的模式,换句话说,10个一个亿的小目标并非10个单一一亿目标重复10次,如果这样,和1个10亿目标没什么区别,他们之间的关联太密切了。这10个一个亿的目标是完全独立的10个不同目标,只是恰好他们各是1亿而已,实际上,可能是3亿,5千万,1亿2等等10个各不相同的目标,只是他们之和恰好10亿而已,任何两个小目标之间,最好没有任何联系。当然,作为复杂的软件体系,子目标之间不可避免要互相关联,以上说明的目的只是在于尽力求简,简化到每个目标只依赖于最简单的某个google云服务既可实现。(其实,跟没说一样。。。到底要怎么办,还得以后具体分析)
然后,还要有存储,去恰当地保存以上目标在实现过程中的数据,当然也要包括承载实现目标的一切,代码,参数等等。
请从下面选择出你需要的产品,每个一个图标,有没有搞错?!美式幽默而已。
当然,还要有安全,还要有监控等等。下面就具体介绍设计的详细过程:
在实操之前,咱们要现有个假设的需求,这个例子里是一个叫做ClickTravel的旅游代理公司,想要建立一个全球规模的电子商务网站为客户服务。主要功能包括:
该系统的用户包括:
定义服务首先要了解需求,也就是我们要干什么。
现要搞清requirements,需求概括起来是5个W,11项:
需求可以用user story进行描述。那么什么是用户?在定义用户,user的时候,有一个关键词:角色
确切来说,用户并非一个物理人,它应该是持有特定行为的系统使用者的分类,这个分类则是为了分析系统而设定,特定行为也不见得是人类动作、操作,例如一个微服务客户端访问另一个微服务提供者,这个微服务客户端的访问行为也具有角色的特点,会根据具体设计而进行归类设计。
在设计时,要对role进行多次发散、合并(除重、归类)的过程,尽力做包含所有动作要求且不交叠重复。同时,使用用户故事(user story)的方式来表达这个需求功能特征:
下面是一句话的user story:
账户查询
作为一个账户拥有者(角色),我需要随时可以检查账户余额(动作)以避免我的账户透支(价值)。
可以以这个为模板:
As [ type of user] I want to [ do something ] so that I can [ get some benefit ]
或者:
Given [ some context ] When I [ do something ] Then [ this should happen ]
User story是进行(程序)系统设计的关键,可以用INVEST模型去确定user story:
这是对需求进行评估的一组参数或规则。
上一节说过对user story(及完成结果)要能测试和评估,例如在给定的限定条件下(时间、资金、人员),能达到什么样的结果?
KPI就是对这些结果进行评估的具体指标的统称,其实,KPI就是把远大理想翻译成人话并且有实际数据可以进行比较:
Goal: 增加网店的转化率
KPI:网络销售额与网络流量的比率
既然KPI是人话,那就是可以达到的,它需要具有SMART特征:
下面是这几个名词之间的关系:
SLI,service level indicator是与server密切相关的KPI
SLO,service level object是基于SLI所要达到的目标,指标
SLA,service level agreement把SLO固化到纸面协议的合同文本,如果供应商没达到,会有罚金付给用户作为补偿;
由于SLI是KPI中的一种,所以必须是measurable且具有time-bound,而目标结果SLO则需要achievable且relevent
SLO设定的标准:
注:前互联网时代或许如此,如今。。。特别是越来越多mission critical的应用被移植到互联网,而且自媒体的信息裂变链式反应能力越来越强大,今后互联网应用估计也会按照任务对重要性进行分类吧?
举例:
SLI: HTTP成功响应延时在200ms之内
SLO:99%的HTTP响应延时<=200ms
SLA: 如果HTTP响应延时大于300ms的百分比超过1%,则用户会收到补偿金
这节介绍如何将单体应用拆分为微服务应用,确定微服务的边界,设计有状态及无状态的服务以优化性能和可靠性,按照12指标进行应用部署,建立松耦合的REST架构,设计一致的、标准的RESTful API服务。
先看什么是微服务
微服务是一种架构模型,是将一个整体的大单体程序拆分为若干很小的、相互独立的服务模块程序。Google提供了若干引擎去支持运行各种微服务模块程序,包括:App Engine,GKE,Cloud Run,Cloud Function,各自有各自不同的颗粒度和承载特点。
微服务和单体应用各有优缺点,具体不写了。
设计微服务的关键点在界定微服务的边界,也就是做拆分时从什么地方下刀,切分功能的同时,还要考虑如何在操作系统层、数据层已经UI表现层进行纵向整合,同时,如果同一微服务模块为多个体系服务,还要研究如何进行服务隔离。
现要区分出有状态和无状态的区别,只要不需要随时间、访问实时变化的数据的服务都属于无状态服务。同时,有状态的服务也往往可以拆分为无状态处理和状态数据保存(处理)两部分,而前者是无状态的。
有状态应用难以扩展(并行),难以升级(需要一致数据导致必须绝对意义的升级中断时间),需要备份(逻辑上数据只有也只能有一份,即使物理层镜像不能保证数据可靠)。
基于以上特点,将业务尽可能由无状态处理完成是设计要点,但由于性能、可靠性、复杂性等等因素,有时又不可避免需要设计有状态服务。下面一些设计要点可以帮助减少有状态服务:
尽力避免在server的内存中保留需要共享的状态信息。因为如果状态信息是需要共享的,而server的内存又显然是非共享的,这就要求同一session访问请求必须始终发送到同一server(只有这个server实例才拥有状态数据),防火墙或者负载均衡设备必须保存session标识(配置为sticky session模式既session affinity),并根据此session标识进行转发,额外负担极大。
解决方案是配置共享的后端存储保存状态信息,可以是firestore或者cloud sql,而如果需要性能,则可以增加memorystore,这些都是google cloud提供的标准服务。
最佳实践是这样的5层结构:
详见:https://12factor.net
以上是12指标?才4个。。。错了,这是12指标应用的特点,下面才是具体的指标:
client别知道太多,干好自己的一点点事就行。通信采用https协议,基于plain text(大白话文字)的。client请求有get,post,put,delete很简单,请求数据采用JSON或XML。可以不中断服务动态添加功能。如果做不到以上这些,实现松耦合,你最终得到的还是一个不伦不类的单体应用。
REST含义是REpresentational State Transfer(表达状态传递),其协议,其实可以随意制定,这只是一种设计思想,但多半采用HTTP,也有采用gRPC等等。支持REST的endpoint被称为RESTful,通信模式是客户机、服务器模式,采用请求、应答的处理方案。当然,也有其它的实现方案,特别是对于某些特殊场景,例如如果需要流数据传送的场景,更可能采用gRPC。
与Web场景结合,URI用来标识资源,返回数据中用被确定保存下来的数据(不会被改变,不是临时的,但实际上也可能是临时,只是这个临时相对于对话session来说是永恒的,足够久了,例如几天)标识对应的资源的相关信息(状态数据)。REST应用提供了一致的、统一的接口,资源信息也可以被缓存。
这里有若干抽象的概念,例如资源其实就是一堆信息,我们需要啥信息,都可以抽象为资源;而REpresentation则是资源信息的表述,复述。例如我想知道你的名字,想知道就可以作为一个请求发送过去,对应的资源就是你的名字,返回的内容呢,可以是包含你名字的表达的资源包。(不似人话。。。你明白就好)
这个HTTP通信协议的基础结构信息,client to server:
verb,可能是get, post, put, delete
uri, 目标资源地址
http version
request head,元数据,包括采用什么协议,JSON,XML?等
request body, 详细的资源状态信息(可能有)
verb中get是取数据(已知元数据),post是生成(元数据)及放数据,put是放(已知元数据)及修改数据,delete是删除数据
server-client返回格式:
http version
response code,2xx OK,4xx client error(你瞎搞,啥请求啊,回答不了),5xx server error(我出问题了,你的请求没问题,但我没法回答)
response header
response body
在设计时,URI标识资源,不要把动作放到里面,例如/path,这个uri不错,/getPath就不好,应该是通过get请求/path,虽然用/getPath也可以实现和get请求/path同样结果,但编程处理容易造成混乱。
最后,我们来看API,作为REST API服务,service function一般会定义成:service.collection.verb这种格式(中间不一定是.,只是表达分割),参数通过URL或者http body传递。这种通用的格式其实是统一命名规则,编写开发者很容易创造出来,使用者很容易记忆或猜测学习。
查看所有的instance就可以用如下URI的get request:
https://compute.googleapis.com/compute/v1/projects/{project}/zone/{zone}/instances
除了HTTP,JSON这一类,还有OpenAPI等API协议标准,google是完全支持OpenAPI的。
当然,google也创造了自己的API,gRPC,gRPC可以由HTTP/2提供负载均衡,这很重要,这意味着能通过普通的http协议直接从外网通过gRPC协议获取gcloud中部署的应用的数据(经由Envoy Proxy)。与JSON,OpenAPI不同,它是binary传送的(高性能),它还支持流。
google提供了两个工具帮助API设计和使用,都支持用户认证,监控,加密安全,OpenAPI和gRPC等
这一节要研究使用CI/DI工具进行流水线自动化的过程,其中包括研究怎么用cloud repository管理源程序,自动构建、云构建、出发构建,使用容器注册管理生成image,使用Terrraform等。
CI是continuity integration,持续集成,要完成如下几个工作:
开发者将代码(开发完成后的代码)登录注册,运行单元测试,创建部属用的资源包image,最后是将生成的资源包保存在容器注册体系中,等待最终部署。
google提供了完整的,全覆盖的,整合的CI工具,由cloud source repositories对源代码资源进行管理,cloud build则根据设定好的步骤完成最终执行包(部署用的image)生成。
build过程还可以通过build trigger进行触发,后台自动完成,例如查看git repository是否有变更(新代码提交)。这个过程由设置cloud build trigger实现。Trigger可以设置为仅对变化影响到的代码或更复杂的判断条件。
容器注册(container registry),最后生成的部署资源包(docker image,deployment package)经由集中的容器管理统一管理,承载image的同时,还可以进行安全(或者叫做弱点)扫描,控制访问授权等等。
下面就不详细介绍细节了,只对一些地方强调一下。
cloud source repositories由IAM统一控制授权,可以经由pub/sub发送事件信息,能够与cloud debugger,logger集成在一起,可以将代码直接部署到app engine,还能与外部github,bitbucket代码管理工具直连,同步。
cloud build则一条命令就可以完成build工作,可以用docker的命令,也可以用gcloud(和docker命令很类似),最后也是一条命令就能提交image到容器注册,例如:
gcloud build submit --tag gcr.io/project-id/image-name .
其中,tag必须与build时设置相同(我觉得这其实就是保存的位置或索引),image名字必须gcr.io开头(更印证了这是个索引,gcr.io就是保存所在微服务定义)。最后,.所在位置(当前目录)必须有Dockerfile做控制完成container image生成,技术上来说google就是用docker实现的。
build可以通过设置trigger触发,每当submit发生,trigger验证触发条件是否满足以执行build。trigger能够基于branch,特定tag(包括对tag进行正则表达验证)触发。而build的控制文件则可以时Dockerfile或者cloudbuild.yaml(如果使用google工具)
container registry其实就是google自己的docker repository,可以直接使用docker push, pull命令操作。
不确定是否是省缺(应该是),google在build和container registry增加了自动签名(发放证明)的过程,注册时会将证明同时附加到image,而部署前需要进行验证。
CI的顶层就是这些,下面要看CI的底层,infrastructure,这个实现技术叫做IaS,Infrastructure as Code
一句关键的总结,这是核心设计基础的转变:
在云上,所有基础设施必须是可抛弃的
具体来说,没时间精力去安装、打补丁、升级、修机器,一切都要自动实现,缺机器,自动生成一个,坏掉了(需要升级),再自动生成一个,有问题的直接干掉(抛弃掉,好残忍!)。
google支持的相关技术、工具:
Terraform
Chef
Puppet
Ansible
Packer
Terraform是IaS工具,特点如下:
Terraform HCL语言大概规则是:
block-type “block-label” “block-label” {
# block body (注释)
identifier = expression # 每个具体参数
}
例如:
resource “google_compute_network” “default” {
name = “${var.network_name}”
auto_create_subnetworks = false
}
一看就大概明白了七七八八:
定义了一个资源,是缺省的google 计算引擎的网络,命名方案是来自network_name变量,不自动创建subnet
先总结一下:
在每一归类下,还有其它维度区分,例如SLA(可用性):
持久性维度(注意,大部分都需要配合手工、额外的备份、快照、导出工作或者设置参数):
可扩展性维度(扩展方案):
水平扩展(一堆小节点,但要手动增加):bigtable, spanner
垂直扩展(用很大,更大的机器,手动添加):cloud sql, memorystore
自动扩展:cloud store, bigquery, firestore
一致性保障维度:
很意外,大部分情况下一致性还是不错的,只要记住bigtable和memory store不保证强一致性就行了(但即使是这两者,也是保证最终一致性的),特别是如果bigquery如果没有replication,则同样有强一致性。
成本维度:
这一页是考试重点,一定要记住:
还有一些没有提到的storage:
filestore,对于需要mount到vm的,这就是某种fs
block storage,直接供vm使用,有disk和ssd两种
有了存储,如何传(原始)数据过去?
cloud网络直传,都在internet,直接传到cloud storage,最好装个transfer agent,这个是在Docker container里面的,只要这个container能看到(mount)上的数据,都可以传到google cloud storage,最多数十亿文件,数百TB数据(要考虑上传网络带宽),在console可以看到状态,有传输log,加密传。
transfer appliance单独硬件,装载最多1PB,运到机房,安装,加密、保存数据到该设备,运回google,解密释放。加解密好像是自动完成,key在你自己手中控制。
从google application,例如yourtube,google ads,以及amazon redshift/S3 直接(定期)下载数据到bigquery。这个可以配置为schedule job
下面研究网络。google当前的网络由21个regions,64 zones构成,一个zone当成一个数据中心吧,一个region呢,算地区?PoP呢?point of presence感觉是某种存在,大概可以说是internet接入点?
google的VPC是全球化的,virtual private cloud,可以理解为给你切分出一块虚拟的,被隔离的网络体系供使用,在同一VPC内部,网络在底层是完全互通的,我理解就是一个单一二层network,甚至可以弄个数据包全球广播。
可以任意配置(subnet)网络和IP子网,但也有些限制,例如不能有地址冲突的两个IP子网,每个IP子网可以自由动态扩展(只要范围不冲突),不会有中断时间,但缩减不是自由的。另外,每个subnet可以有多个ip网段。
关于vm和network(二层网络)和subnet(IP子网)有这样要求:
每个VM至少有连一个subnet,每个VM最多8个interface,每个interface只能连一个network,由于interface是虚拟的,连多个interfaces没啥用,而且容易引起网络数据传输混乱。除此之外,最多interface支持还和vCPU数量有关,vCPU越多,可以支持的interface越多。
每个project可以有一个或多个network(仅被称为VPC?)多个project可以共用同一VPC。
google的全球负载均衡技术由http balancer实现,基于DNS实现,支持任何http, tcp/ssl代理,会根据访问请求所在位置自动发送到最近服务点(解析合适的服务IP)。主要为internet访问提供服务。
google还有区域负载均衡,支持http, tcp, udp,无论是公网IP还是私有IP都可以,(后端设备使用)任何端口都行(可以将负载发送到后端设备的不同端口)。但是后端设备只能在同一区域内,不能跨区域。
如果负载均衡对internet服务,建议开启ssl,google帮你管理ssl认证。
负载均衡配置选项:
如果是HTTP(s),则甚至可以根据请求内容(layer 7)进行负载均衡任务分配。
如果是TCP,则只能到传输层既TCP链路(layer 7, 源、目IP和端口)进行均衡。
如果是UDP,则只能对在同一region(一个subnet)的设备进行均衡(没有session,无法记录时序,跨region就乱套了)。
同时google还有CDN,能cache vm web的静态数据,GKE和cloud storage bucket里的(静态)数据。
网络互联,这也是个重点课题。
现要确定到底用哪种引擎。
首先,把应用限定为非数据库类、非存储类应用,这些都有专门的产品支持。普通应用如果又必须要计算引擎,最好的方案是基于模板创建instance group,这个模板应是能运行该应用的最小资源需求的vm,在启动脚本中绑定从repository安装程序。instance group manager负责生成、启动vm,根据用户负载(例如每分钟平均访问请求数)设置自动扩展,增加健康检查,在多个zone部署以实现高可用。
如果在多个region有部署,则用global loadbalancer,否则只需要region loadbalancer(好像不存在独立设置,会根据配置自动选择),增加CDN,对外服务采用SSL,对内服务(loadbalancer后端访问地址)一定使用内部地址,这样确保数据流不会误走internet
关于app engine:
关于cloud function:
这个可靠性是个统称,具体来说至少包括可用、持久、扩展三个放面,三方面都达到很高的水平。这要求系统必须有容错能力,没有单点故障点,没有相关故障点,没有级联故障点。
对我个人,研究了很久高可用,前面几个概念都有深入理解,后面的的单点故障问题也探讨了很久,相关故障点和级联故障点稍微新奇一点,但也很容易理解,而且类似场景在云,这种单一、海量部署的情况下特别常见。
具体来说,按字面意思correlated failure相关故障可以更准确地翻译为相似故障,也就是类型、架构、模式相近的情况下发生的一种故障,这种故障在某个具体实例爆发具有偶然性,但对于这一类实例却具有内在的必然,有点类似系统性的设计错误,但并不仅仅是错误那么简单,即使是没有错误,但居于现场情况,却一定或者早晚会发生。例如不严查用火安全,管理易燃物,早晚由于疏忽大意等意外偶然事件,导致严重火灾发生,火灾就是correlated failure,而增加用火安全教育、严格易燃物管理、有防火行为规范、使用阻燃物制造等等就属于解决correlated failure的方案。
与correlated failure类似的cascading failure则是另一种情况,可以表达为为了避免或者修复前一个问题,而造成更多、更严重的问题,以至于最终系统崩溃。这样的例子也很常见,特别是在设计避免单点失效系统时,最简单粗暴的方案就是设计冗余,但并非简单的冗余就可以解决问题,如果没能很好地处理故障后通过冗余进行故障规避,如何能自动修复错误,甚至在故障之前如何探测错误,很可能冗余设计会造成业务阻塞,问题越积越多最后还是系统崩溃。连环撞车,剧场火灾逃生口塞死等等,都是没有对单一故障冗余之后的问题进行很好地处理,只简单粗暴地以猛然刹车停车、以多开逃生门来解决。
从某种意义上说,这是一个多样性避免灾难、缓慢延长处理时间(或吞吐量)降低单位时间影响度的时间、空间联合解决方案去应对时间、空间的多样性故障。
还有一种过载(错误)问题,也是需要云架构需要解决的常见问题。解决方案通常是采用过载断路器(circuit breaker)以及指数型回退方案等常用的设计模型。断路器(保险丝)都好理解,就是过载就咔嚓,不对过载部分业务对象提供服务了,那指数回退是什么?这是一种相对柔和一点的断路方案。具体来说,如果发现某部分业务、区域访问量过大,那么就人为(当然是设计成自动实现,而不是真的需要人实时现场操作)强制减少部分访问请求,如果依然过载,那么再将限制增加一倍(或者某个倍数,总之,每次增加幅度是指数级增长的),这样重复,直到系统能够承载这些业务,再逐步恢复,也是指数级逐步恢复,降低时是越降幅度越大,恢复时是越恢复,增加幅度越大。
存储也要有对应的韧性设计,而且要增加被动检测。韧性同样是高可用的概念之一,就是既刚又柔。在强大外力破坏面前,先刚,能撑就撑,而如果撑不住,并不是直接垮掉或者撂挑子不干了,而是做适当规避,勉力支撑最后自己能支撑的部分,这叫柔。
最后的lazy detetion没有合适的翻译,叫做延期清理数据垃圾?先这么写吧。
设计时要考虑到正常工作情况、降级工作情况以及故障工作情况。传统设计一般只考虑正常工作,对其他两点是很少提及的,及时研究,也是研究如何实现对上层透明,既在本设计层,能硬抗故障。随着业务系统越来越复杂,系统内故障越来越无法避免,系统设计无法完全忽视错误、故障的存在,不能把所有事情都由底层系统透明底硬抗,要主动考虑当有故障的时候如何处理,如何降级以避免更长期、更大规模、更严重问题。
分析容灾场景和容灾方案,实施、测试或模拟灾难恢复。
我们这一代人,前几天还在感慨岁月静好,没想到这两三年间,一切活了这么久都没见过的事情都亲眼所见,亲耳所闻,亲身所感,必须亲历而为了,明天就是发生WWIII,需要去住石洞、磨石斧我都毫不惊诧。以上说了很多个人感慨,主要是相关内容撞枪口了。
定义基础单元,以单元为评估基础,每个单元是一个单点失效单元。
单元要实现冗余的冗余,N+2,常见的冗余是N+1,不够,再加一个要做到N+2,这是要保证在测试、升级的时候,依然有冗余保证。
每个单元都能负担额外增加的负载,要有安全系数。
但既不要将单元扩得非常大,例如一个单元涵盖了全系统,把所有一切都作为单元内部组件,黑箱处理,也不要对单元设置非常大的安全系数。
尽力将单元设计成可以用无状态的克隆产品直接替换(也就是要把数据/状态数据存储与单元处理部分分开)。
如果单一机器故障,则由此机器提供支持服务的所有系统都会故障(受影响);
如果机柜中为此机柜服务的交换机(top-of-rack)故障,则全机柜的服务器都无法访问。
如果一个zone甚至一个region出问题,则该zone或region内的所有设备都死翘翘。
软件如果有问题,运行同样软件的所有服务器都面临同样的问题。
如果存在全局配置,那么要是多个系统依赖这个配置体系,则他们可能统统完蛋,无一例外。
一组可能同步发生问题的相关组件被称为failure domain。
想要避免相关故障有什么方法?
最后一句话,简直就是放X。。。。
一句话解释,如果一个系统出问题,导致其它系统过载,然后依次崩溃。这种情况通常出现在负载均衡体系中,如果该体系中任何一个单点都不足以承载某个单点故障之后分散过来的额外业务,那么该体系的设计就存在级联故障。
解决方案不一定必须让一个单点能完全全部业务,有时,缩小单点所能承载的业务量,但增加全部分担节点的数量也是解决方案。因为每个分担节点就是一个单点故障点,当出现故障时,其上业务负载需要其它节点去承担,而如果节点数量多,那么每个节点承载的业务量负载就相对较小,再分散到相对较多的其它节点,每个完好节点所增加的额外负载也就变少了。
这是个比喻,不见得一定是查询操作,但往往都是读操作,其最终现象是耗尽系统资源。由于系统由多个节点提供服务,当出现一例这样的访问,一个节点将被负载耗死,而由于访问请求没能得到回应,该请求(或此类请求)又会被转送到正常节点处理,然后再耗死这个节点,如此逐渐波及到所有节点,直到系统崩溃或者塞死。这是一个典型的多个逃生门依次被人流塞死的现相。究其根本,是业务处理逻辑有问题,过度消耗资源,但大部分时候,所谓过度并不那么显而易见,需要综合分析请求延时、资源使用率(CPU、内存、IO等等),错误率等实时数据来辅助判定,而其也无法在系统层面得以根治,需要转回开发程序员解决。
更典型来说,当你希望系统更加可靠,对失败的访问请求进行了重试,而重试操作恰恰导致系统不稳定,更容易过载。
解决方案是当试图对失败请求进行重试的时候要考虑到正反馈过载的可能,采用若干办法去避免无限重试(设定最大重试次数)或者重试被堆积(达到一定失败数量则进行清里工作或者封闭相应的请求)。更精细的方案是使用指数式的回退重试,例如逐渐(按指数倍数)增加两次失败重试之间的等待时间,设定最大重试次数或者超时时间。
在一开始就考虑到降级状态,当服务偶发中断,造成大量访问请求失败,这些失败请求都会重试,因此会阻塞后端服务。如果在设计之初就想到此问题,可以在前端设置代理体系,并在代理设备设置健康检查判定后端服务状态,如果后端服务节点有问题,则代理设备根本不向后端转发请求。
在GKE,有Istio可以完成此工作。
数据没用了,别着急清理,因为误删除数据是常有的事情,以下延期清理方案被认为是有效的:
先看标准的高可用设计要点:
可用性指标对应的全年(计划内、计划外)业务中断时间
9% 33天,基本不可接受,个人容忍下限
99% 79小时,勉强可接受,个人或者企业正常业务容忍下线
99.9% 8小时,一般可接受,非关键业务正常容忍度,特别是对计划内事件的容忍度
99.99% 47分钟,一般可接受,对关键业务计划内或者非关键业务偶然事故
99.999% <5分钟,极度重要、关键业务要求,超越此要求的情况很少
99.9999% 28秒,更高的可用性对普通商业业务意义不大,但不排除特别场景,例如股票交易、导弹卫星核反应堆控制等
针对容灾,还要进行灾难场景头脑风暴,对不同业务服务定义RTO,RPO以及恢复优先级。灾难不仅仅有自然灾难,而是所有一切包含人工误操作在内的造成数据丢失或不可用,造成服务中断的场景。
下一步根据设定场景和RPO,RTO指标设计不同的组件资源实现方案,制定备份、恢复方案。这个(容灾准备)方案需要与日常操作结合,称为日常操作中的一部分。
规划:
定期实施
先说清楚,你我都有责任,不是google一家负责的。google提供工具,并监视着你运行的服务,google cloud也有提升平台安全的控制手段和各种功能特性。
如果进行了适当的设置,google提供了工具去构建一个安全的环境,同时也支持集成第三方的安全工具,最后还有工具去监视和审计逆的网络及各种资源安全。包括以下各个放面:
这是安全的一项通用准则,用户只能获得完成他的工作的必须授权,不额外提供额外的授权。这同样适用于计算机实例,运行程序。通过IAM可以实施这个原则,通过登录识别用户,通过服务账号确定计算机或者代码,通过将角色赋予用户或者服务账号进行授权,控制他们可以做什么(其它都不可以做)。
这个控制的含义是把一些关键操作赋予不同的操作者,这可以避免目标方向冲突,能检测到控制错误,包括安全缺口或者信息窃贼:
例如,写代码的人不部署代码,部署代码的人不修改代码。如何实现呢?
log包括:
Google Cloud也付合很多第三方或者政府的安全标准,包括:
别担心google cloud是否通过安全认证,只要你的程序OK,google cloud就OK,好好研究如何用google cloud的各种安全功能实现程序通过安全认证对外提供服务吧!(牛皮爆了。。。)
google cloud有security command center一个页面提供对组织和项目的安全统一管理,这是一个安全的dashboard
先要把人user授权给项目project,把user置为项目的成员member,并赋予不同角色。一个人user可以被赋予多个roles。
每个member就是不同的user,通过登录login识别。member可以被加入到组以便于管理。role是一组授权,也是为了便于管理。通过console可以方便地查看不同role具有的授权具体是什么。使用group对人进行分组,使用folder,project对resource进行分组,使用role对授权进行分组。注意最小授权原则,尽力避免分配owerner或者editor授权,对大部分用户,这两者授权都是超限的。
Identity-Aware Proxy(IAP)使得google cloud能很容易地控制对vm或者application(GKE,application engine)授权,即使他们隐藏在负载均衡设备之后。配置后,用户必须登录才能进行下一步操作。Admin控制谁可以访问app。而且用户无需VPN就可以对基于web的application进行相应允许的操作。
授权过程以(internet)联合服务的形式提供(CIAM customer identity access management),与其它很多网络应用整合在一起,何以进行相互授权。例如你可以用facebook账号登录,然后就拥有了与该账号在google cloud捆绑的授权。不仅仅网络账号,包括手机、email/密码等很多种方式都可以完成登录。
与真实用户类似,还可以创建服务账号用于vm,gke,通过对服务账号授权,可以让vm运行进程仅仅具有服务账号所授之权利。
service account无法直接登录,只能用将ServiceAccountUser role赋予某个普通用户的方式让该用户获得此service account的权利。service account代表用户授权的同时也与对应的资源绑定,也就是此service account只能操作对应的资源,完成授权的任务。
创建service account的同时可以(选项)创建并下载key,拥有此key就等同于拥有此service account(owner ),key是json格式。这个key很强,所以要注意安全,key有两种管理模式,google管理或者用户自己管理。如果是google管理,google会定期更新此key,最长周期是2周,这样避免某个用户如果之应当临时拥有授权(拿到此key),而以后一直拥有授权无法被删除。用户管理的key没有自动过期,但一个service account也可以最多创建10对key以便人工进行轮换控制,而且google有cloud KMS系统帮助管理人工key。
key对于CLI操作很有用,这样可以凭借key不登录console就拥有所赋予的权利,使用命令操作完成任务。
不要配置(移除)外部IP以提高vm的安全性(通过防火墙对外暴露service ip)。可以通过google console提供的shell或者vm的ssh连接去登录vm,或者通过堡垒机(一台单独的,特别加强安全的,拥有外部IP的)作为跳板访问内部私有设备。google cloud console也算作堡垒机的一种吧,一些堡垒机(设备)还可以支持NAT功能,允许通过外界直接访问内部地址,或者允许内部设备访问外部。
所有的internet访问应该在负载均衡设备、防火墙(proxy或WAF web application firewall是一种reverse proxy),API gateway,IAP (In Application Programming应用内部与服务端通信的程序规则、协议),其含义是由internet发起的访问请求无法一次、直接地穿透保护层,直达内部,需要通过先建立与以上这些堡垒设备连接之后,二次发起内部请求才能送达内部,而二次请求所能采用的通信协议具有更多的限制,这样使攻击困难度增加了不止一个数量级,保护方案也更多,同时有更多的监视、过滤、跟踪、记录手段,且不会造成过度的资源占用,因为只有与堡垒机建立连接之后(无论是正常访问还是攻击访问)再次发起的二次请求才值得去关注,已经大大缩减了需要关注的数据量。
由于最小授权原则,google的所有资源都是只有被授权才能获得访问权,即使内部资源、设备、服务账号都是如此。以下命令将允许内部网段A访问存储:
gcloud compute networks subnets update subnet-a --enable-private-ip-google-access
对于VM,所有的由外到内的访问请求都是禁止的,除非设置防火墙规则允许它(相反,由内到外的访问缺省是允许的)。
google对API的控制通过cloud endpoints完成,每个call都通过JSON web token或者google API keys授权。授权控制与IAM被整合在一起。
帮助记忆(待确定):一切在google cloud内部的API相关管理,通过cloud endpoints完成,而如果需要部署到外google cloud外部,则需要通过APigee,换句话说,APigee可以被单独下载到任何机器,与任何语言整合。
google endpoints都使用https,但用户应用自己的endpoints根据需要去配置协议,建议HTTPS或者TLS,应用程序级别的安全由用户自己负责,google管不了,只提供工具。
抵御DDoS攻击,google提供了全球负载均衡检测并丢弃(将攻击地址列入黑名单?直接丢弃来自攻击地址的访问请求包)攻击访问;通过CDN保护后方资源(这样就变成攻击者与google比拼财力,看我的cache大,还是你的访问多!)。
google提供了cloud armor来创建网络安全策略:
安全策略支持最高到第7层应用层协议,例如SQL注入攻击等;
本节最后一部分谈加密。google用了一个很有意思的词:at rest。意思就是数据google省缺是加密的,但是并非实时,也就是数据保存后,如果系统不忙,一定、早晚会被加密,但如果保存的时候很忙,那么就只能先写下来,保证数据持久性,然后找空余时间加密。读取呢,实时解密的(或者不需要,因为还没真正加密,但这事就不用你操心了),这样做几乎观察不到有性能下降,
加密采用AES-256方案,key由google KMS管理并且定期轮换。如果由于法规遵从原因,你可以自己管理key(CMEK customer managed encryption keys),自己创建key、设定轮换时间。CMEK基于google KMS实现,可以由KMS创建Key(或者上载key),由KMS完成轮换操作等,在每个API call授权时由KMS完成认证。Key只存在于内存中(不知道是否是全部key,包括公钥)。
避免数据丢失API可以帮助你发现、校验敏感数据,包括email,信用卡号、税号等等,也可以自己定义敏感数据类型(我觉得就是个正则表达,只是可以定期扫描各种类型的存储数据而已),能够对数据进行删除、掩码、令牌化(转换替代),或者只是发现识别所在位置
好长的课程,终于到了最后一节,加油!
三个概念:rolling update(滚动升级),blue/green deployment(红绿部署),canary(金丝雀)发布
微服务架构的一个要点,也是特点是要做到服务升级时不能断开客户,不能中断业务。所以:
具体如何能做到升级时不中断业务呢?一般我们会把服务实例置于复杂均衡器之后,那么就可以每次更新一个后台实例,采用滚动升级的方案可以让两个版本的服务实例同时工作。滚动升级是instance group的特性,只要修改instance模板即可升级新版本。滚动升级也是GKE的缺省设置,只需要修改Docker image既完成升级。App Engine更是全自动完成此滚动升级过程。
如果不想采用滚动升级,同时运行两个版本,那可以采用蓝绿部署的方案。这是两套完整、相互独立的部署。蓝色为当前版本,绿色为新版本。新版本经果严格测试通过后,可以一步将访问由蓝切绿。如果绿版(新)运行中出现问题,可以再马上切回蓝版。DNS能完成vm、负载均衡设备切换,GKE configure service可完成service(label)切换,App Engine则可以通过spliting traffic完成。
在滚动升级之前,还可以增加canary release去降低升级风险。具体来说部署一个单一实例,并发送一小部分访问请求,监视运行中的错误。对于VM,可以创建一个新的instance group,并在loadbalancer上将其设置为“额外的additional”后端设备。在GKE可以采用同样label创建新pod,负载自动会发送过去一部分。App Engine依然可以用splitting traffic实现。个人觉得,这个和滚动升级没啥区别,只是把滚动升级这种连续自动完全升级过程阶段化,只升级其中一个实例,然后看看有没有问题,持续运行一段时间,而不同于滚动升级依次自动连续不断升级过去,中间多加了观望、后悔、思考的时间。滚动升级重在不间断地升级,金丝雀发布重在在小范围实验中尽早发现问题。
接下来,或者不得不,还是谈一下钱。所有的google cloud都是要钱的,创建项目一时爽,月底付费火葬场。容量规划是个连续的,步骤清晰的循环:
优化计算资源成本:
优化磁盘成本:
优化网络成本:
GKE的用量表usage metering可以帮助避免过度预建过大的GKE cluster,实现metering需要从meterics server把PodMeterics数据下载到bigquery的两个表里。与billing export对比,就可以知道是否过度预留了容量。数据可以在Data studio dashboard查看
注意不同存储的价格差距,在决定之前多比较以下,够用即可。例如:1GB firestore免费,而1GB bigtable要1400刀/月
还可以考虑google的其它服务,这些都不需要自备存储。(当然,有其它的收费方案),例如CDN, caching, messaging, queueing
google cloud pricing calculator可以预估成本。
最后billing report能看到最后实际发生的所有费用的细节。(vm sizing recommendation就在这里面)如果想进一步详细分析,可以export到bigquery
google data studio可以将数据变为可视图表。
可以设置预算警报cloud function,通过pub/sub发送给相应的责任人,以便他们及时了解预算使用情况。
关于监控有以下工具,各有专长。具体使用特点以后再补充: