• 关于

    异常程序一般会出现什么故障

    的搜索结果

回答

今天怎么就配置不起来,PHP配置上就提示在页面上提示 Service Unavailable,自然,ASP也不能正常运行了,后来在IIS中检查PHP的配置,发现php5isapi.dll没有被ISAPI筛选器正常加载,是红色的向下的箭头,正常情况应该是绿色向上的箭头,表示加载成功!于是将其删除后重新启动IIS,结果页面显示正常!于是重新检查PHP的配置,也没有发现什么异常现象,最后想到了有可能是权限问题,于是检查PHP安装文件夹的权限,发现没有EVERYONE权限,不知什么时候把EVERYONE权限给删除了,于是从新给EVERYONE加上了只读权限(只读权限就足够了),重启IIS后,一切正常关于网站出现Service Unavailable的说明原因一:网站超过了IIS连接数解决办法一:增加IIS连接数备注一:Windows 2003的操作系统在提示IIS过多时并非像win2000系统提示“链接人数过多”,而是提示”Service Unavailable”原因二:网站超过了IIS资源限制解决办法二:增加网站的资源备注二:Winodws2003中网站占用了超过IIS对该网站系统资源的限制后直接提示”Service Unavailable”原因三:网站的程序发生太多的错误解决办法三:修改程序错误备注三:Winodws2003中网站错误太多,就会造成该网站所在的应用程序池出错,这个时候可以在Windows2003的日志中看到“应用程序池 ‘xxx’ 被自动禁用,原因是为此应用程序池提供服务的进程中出现一系列错误”,这个时候网站就会直接显示”Service Unavailable”以上三个原因造成的”Service Unavailable”,一般现象是出现”Service Unavailable”后,多刷新几次,就可以打开。原因四:ACCESS引擎错误解决办法四:重启IIS备注四:有一些文件造成了ACCESS数据库出现“灾难性故障”及“未将对象引用设置到对象的实例”的错误原因四造成的”Service Unavailable”,现象是所有该服务器上的使用Access数据库的网站都出现错误,不能访问。以上四个原因是常见的造成了”Service Unavailable”的原因,其他还有一些问题造成了该问题,基本只要IIS重启一下就可以的。有时是IIS6.0的应用池限制,在IIS管理中可以看到应用池管理,点属性,限制内存大小使应池自动回收。这样平衡服务器资源,就不会出现“Service Unavailable

我的中国 2019-12-02 01:33:20 0 浏览量 回答数 0

问题

健康检查常见问题

行者武松 2019-12-01 21:43:15 3573 浏览量 回答数 0

问题

【推荐】Windows系统异常重启以及蓝屏的处理方法是什么

boxti 2019-12-01 22:06:15 1737 浏览量 回答数 0

阿里云试用中心,为您提供0门槛上云实践机会!

0元试用32+款产品,最高免费12个月!拨打95187-1,咨询专业上云建议!

回答

回 楼主(qilu) 的帖子 问题:用户反馈linux下服务器站点打不开,控制台重启服务器后也无法打开。 解决:检查服务器是正常的,80端口测试是可以通的,进入后检查确认nginx进程正常,打开网站显示502 Bad Gateway错误,之后检查发现php进程丢失,找到php目录php/sbin/php-fpm start 启动php进程后网站恢复正常。 ------------------------- 问题:用户反馈debian机器无法远程,通过ECS管理链接终端进入看到如下界面 /etc/ssh/sshd_config: bad configuration option 解决:修改ssh配置文件导致,最直接有效方法是重装安装sshapt-get remove --purge openssh-serverapt-get installl  openssh-server/etc/init.d/ssh restart重装后正常远程 ------------------------- 问题:window2003服务器用户反馈可以远程,但是ip地址ping不通 ip地址ping不通只有可能是主机内部防火墙或者组策略限制。查看主机防火墙开启,但没有设置ICMP包回显。控制面板-防火墙-高级-ICMP设置。 ------------------------- 问题:用户反馈两台ECS Linux云服务器内网ip有丢包,提示ping: sendmsg: Operation not permittedping: sendmsg: Operation not permittedping: sendmsg: Operation not permitted使用同时dmesg发现很多nf_conntrack: table full, dropping packet. 解决:IP_conntrack表示连接跟踪数据库(conntrack database),代表NAT机器跟踪连接的数目,连接跟踪表能容纳多少记录是被一个变量控制的,它可由内核中的ip- sysctl函数设置,建议用户修改增大/etc/sysctl.conf中加net.ipv4.ip_conntract_max的值后解决,相关优化可以参考网上文章。 ------------------------- 问题:用户反馈修改php.ini配置文件不生效nginx+php环境下,需要重启php服务,php.Ini配置文件才会生效 ------------------------- 问题:用户使用自己的脚本安装了vpn,使用vpn账号,密码可以登陆但是无法上网。解决方法:开启linux转发功能命令:   #sed -i 's/net.ipv4.ip_forward = 0/net.ipv4.ip_forward = 1/' /etc/sysctl.conf#/sbin/sysctl -p ------------------------- 问题:突然发现访问网站很慢,服务器的cpu、内存和磁盘使用率都正常解决:该问题的主要解决方法参考:http://help.aliyun.com/manual?helpId=1724,但是根据该方法部分系统会报error: "net.ipv4.ip_conntrack_max" is an unknown key ,因此可尝试将方案中的语句修改成:net.ipv4.nf_conntrack_max = 1048576主要部分系统是nf_conntrack 而不是 ip_conntrack 模块。具体可以使用命令确认具体使用了什么模块:modprobe -l|grep conntrack ------------------------- 问题:用户反馈无法远程访问,无法ssh解决:1.ping云服务器ip地址可以ping通 2.使用ECS连接管理终端查看sshd服务是否正常运行,重启sshd服务提示有错误,并且在/var/empty/sshd 目录权限有错误,导致sshd服务无法正常运行 3. 使用命令chown –R root:root /var/empty/sshd 和chmod 744 /var/empty/sshd即可,测试恢复正常可以远程。 ------------------------- 问题:用户反馈客户反馈安装桌面环境失败,执行yum groupinstall "GNOME Desktop Environment"报如下错误:Warning: Group GNOME Desktop Environment does not exist. No packages in any requested group available to install or update。解决:从错误提示中可以看出,不存在GNOME Desktop Environment执行yum grouplist查询发现 GNOME Desktop Environment 已经是 Desktop整理了以下安装步骤:          1、yum groupinstall "X Window System"          2、yum groupinstall "Desktop"          3、安装VNC SERVER yum install tigervnc-server          4、修改配置文件 vi /etc/sysconfig/vncservers添加如下内容:          VNCSERVERS="1:root"             VNCSERVERARGS[1]="-geometry 1024x768"           5、给vnc加密  vncpasswd 输入两次密码           6、重新启动服务 service vpnserver restart完成以上步骤,我们就可以使用VNC客户端连接了 ------------------------- 问题:用户反馈ECS云服务器做域控制器,其他外部服务器无法加入该域中,反之可以解决:将客户ECS服务器开启RemoteRegistry服务,安装域控制器使用外部云服务器加入域中,发现能够解析成功,且能够弹出用户名密码授权界面,但是确定后报网络错误,经过多次尝试,发现最终问题在DNS上,由于ECS服务器有2块网卡公网和内网,因此安装后会有2条A记录分别指向公网和内网所以测试PING域名会解析到公网上,产生了DNS缓存因此很难看到内网地址出现,但是加入域请求时用解析到的是公网地址,验证身份时很可能请求到的就是内网地址,因此造成网络不通从而无法验证。将客户端HOSTS绑定域名到公网地址问题解决。 ------------------------- 问题:用户反馈windows server 2008无法远程,主机内部通信正常解决过程:1、  检查内部是否能够远程,发现服务器内部网络正常,远程localhost也正常2、  检查防火墙配置,发现防火墙无法打开3、  启动防火墙服务器,报错4、  检查防火墙注册表信息,发现丢失,将相同系统的注册表键值导入5、  再次启动防火墙,报错没有权限,错误代码70246、  选择注册表HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SharedAccess将其权限修改添加NT SERVICE\mpssvc并赋予完全控制权限7、启动防火墙服务,远程恢复正常 ------------------------- 问题:用户反馈微软雅黑, sans-serif]服务器网络不通,无法远程,报错情况见下图。网上搜索方法无外乎都是安装glibc.i686,原因一般是64位系统下安装了32位程序,但是没有对应的版本的glibc库导致 这种情况下下虽然service无法启动网卡,但是ifup是可以激活网卡的处理方法如下:sed -i '/exclude/ s/^/#/g' /etc/yum.conf&&ifup eth1&&yum install glibc.i686 -y#修改 /etc/yum.conf 找到包含exclude的行在行首插入#注释(我们64位镜像默认排除了*i?86的包,所以这里要修改一下)#启动eth1网卡,安装32位glibc库,执行后一般即可搞定 ------------------------- 问题:服务器上的Cisco VPN客户端拨入远端VPN服务器网络无法通信,其他外地客户端拨入远端VPN服务器均正常解决:1)查看客户VPN连接成功,但是无数据通信,PING包无法到达远端内网地址2)检查VPN客户端拨号日志,发现添加远端路由失败3)关闭服务器安全狗,重新连接VPN依旧失败。4)检查系统路由表,发现客户VPN段内网地址与VM内网地址段冲突,造成路由表添加失败;询问客户无使用我方SLB\RDS等内网产品后将内网网卡禁用,重新拨号连接,依旧发现路由表添加失败。5)手动添加路由后,VPN网络正常 ------------------------- 问题:服务器上的Cisco VPN客户端拨入远端VPN服务器网络无法通信,其他外地客户端拨入远端VPN服务器均正常解决:1)查看客户VPN连接成功,但是无数据通信,PING包无法到达远端内网地址2)检查VPN客户端拨号日志,发现添加远端路由失败 3)关闭服务器安全狗,重新连接VPN依旧失败。4)检查系统路由表,发现客户VPN段内网地址与VM内网地址段冲突,造成路由表添加失败;询问客户无使用我方SLB\RDS等内网产品后将内网网卡禁用,重新拨号连接,依旧发现路由表添加失败。5)手动添加路由后,VPN网络正常 ------------------------- 问题:使用一件安装包安装环境php报错 php virtual memory exhausted: Cannot allocate memory解决:该问题一般出现在512M内存的系统上,内存不足导致,可以让用户升级内存,升级内存后解决。 ------------------------- 问题:用户反馈Windows服务器无法远程,连接的时候提示协议错误。解决:用户反馈远程连接端口是3188,注册表中查询远程连接端口确实被改成了3188,但是在主机上远程连接也提示协议错误,使用netstat -nao 分析发现 3188对应的进程pid为4,对应经查system,找测试测试机对比,发现远程连接端口对应进程是svchost,修改注册表远程连接端口为3389后,测试恢复正常。] ------------------------- 问题:用date命令修改Linux系统的时间为什么无效解决:需要手动修改一下系统的时区才能显示正确的时间,这里以上海时区为例1. 找到相应的时区文件 /usr/share/zoneinfo/Asia/Shanghai用这个文件替换当前的文件/etc/localtime#cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime2. 修改/etc/sysconfig/clock文件,修改为: ZONE="Asia/Shanghai" UTC=true ARC=false 3. 一般只需要这两步就可以了,或者再执行下句命令校正一下时间/usr/sbin/ntpdate –u 0.asia.pool.ntp.org4. 如果没有安装ntp程序包则先执行下面这条语句yum install -y ntp* ------------------------- 问题:linux服务器x64位安装32位软件包(如libstc++.i386等)安装不上的解决方法解决方法:如果有用户反馈在linux服务器x64位安装32位软件包(如libstc++.i386等)不安装不上,可以尝试让用户在/etc/yum.conf 文件中将exclude=*.i386 kernel kernel-xen kernel-debug 注释掉,在进行安装尝试,参考http://blog.csdn.net/lixiucheng005/article/details/8787856 ------------------------- 问题:云服务器的物理机宕机怎么办?云服务器是部署在物理机上的,底层物理机性能出现异常或者其他原因都会导致物理机宕机,当检测到云服务器所在的物理机机发生故障,系统会启动保护性迁移,将您的服务器迁移到性能正常的宿主机上 ,一旦发生宕机迁移,您的服务器就会被重启,如果您希望您的服务器重启以后应用服务器自动恢复,需要您把应用程序设置成开机自动启动,如果应用服务连接的数据库,需要在程序中设置成自动重连机制。 ------------------------- 问题:Linux 服务起出现500 OOPS: vsftpd: cannot locate user specified in 'ftp_username':ftp错误? vsftp无法使用,尝试查看/etc/passwd下的目录发现用户使用的账号没有问题,但是尝试telnet 127.0.0.1 21 的时候主机报错500 OOPS: vsftpd: cannot locate user specified in 'ftp_username':ftp 处理办法在/etc/vsftpd.conf 文件内加入ftp_username=nobody 保存,该问题即可解决 ------------------------- 问题:物理机宕机迁移怎么办?云服务器是部署在物理机上的,底层物理机性能出现异常或者其他原因都会导致物理机宕机,当检测到云服务器所在的物理机机发生故障,系统会启动保护性迁移,将您的服务器迁移到性能正常的宿主机上 ,一旦发生宕机迁移,您的服务器就会被重启,如果您希望您的服务器重启以后应用服务器自动恢复,需要您把应用程序设置成开机自动启动,如果应用服务连接的数据库,需要在程序中设置成自动重连机制。 ------------------------- 问题:FTP上传经常中断怎么办?在使用FTP软件进行数据传输时有时会出现断开连接的情况,这和网络环境、硬件环境和软件环境都可能有关系。如果您在FTP管理里出现经常中断的情况,您可以将您要上传的网站程序文件压缩成一个压缩文件,使用FLASHFXP等FTP软件进行断点续传,压缩文件上传之后再在服务器中进行解压缩操作即可。(也有小概率可能受到网络原因传输过程中压缩包损坏,需要再次上传,所以巨大文件建议分割压缩) ------------------------- 问题:无法ping通服务器地址怎么办?通过站长工具—超级ping来分析一下是否是全国范围内都无法ping通云服务器。超级ping地址:http://ping.chinaz.com/如果是全国范围内都突然无法ping通云服务器地址,但是服务器是在正常运行的则可以到www.aliyun.com上提交工单;如果只是本地无法ping通云服务器则在本地使用traceroute或者tracert命令来获取本地到云服务器的路由信息再到www.aliyun.com上提交工单,寻求aliyun的技术支持

qilu 2019-12-02 03:09:51 0 浏览量 回答数 0

回答

微服务 (MicroServices) 架构是当前互联网业界的一个技术热点,圈里有不少同行朋友当前有计划在各自公司开展微服务化体系建设,他们都有相同的疑问:一个微服务架构有哪些技术关注点 (technical concerns)?需要哪些基础框架或组件来支持微服务架构?这些框架或组件该如何选型?笔者之前在两家大型互联网公司参与和主导过大型服务化体系和框架建设,同时在这块也投入了很多时间去学习和研究,有一些经验和学习心得,可以和大家一起分享。 服务注册、发现、负载均衡和健康检查和单块 (Monolithic) 架构不同,微服务架构是由一系列职责单一的细粒度服务构成的分布式网状结构,服务之间通过轻量机制进行通信,这时候必然引入一个服务注册发现问题,也就是说服务提供方要注册通告服务地址,服务的调用方要能发现目标服务,同时服务提供方一般以集群方式提供服务,也就引入了负载均衡和健康检查问题。根据负载均衡 LB 所在位置的不同,目前主要的服务注册、发现和负载均衡方案有三种: 第一种是集中式 LB 方案,如下图 Fig 1,在服务消费者和服务提供者之间有一个独立的 LB,LB 通常是专门的硬件设备如 F5,或者基于软件如 LVS,HAproxy 等实现。LB 上有所有服务的地址映射表,通常由运维配置注册,当服务消费方调用某个目标服务时,它向 LB 发起请求,由 LB 以某种策略(比如 Round-Robin)做负载均衡后将请求转发到目标服务。LB 一般具备健康检查能力,能自动摘除不健康的服务实例。服务消费方如何发现 LB 呢?通常的做法是通过 DNS,运维人员为服务配置一个 DNS 域名,这个域名指向 LB。 Fig 1, 集中式 LB 方案 集中式 LB 方案实现简单,在 LB 上也容易做集中式的访问控制,这一方案目前还是业界主流。集中式 LB 的主要问题是单点问题,所有服务调用流量都经过 LB,当服务数量和调用量大的时候,LB 容易成为瓶颈,且一旦 LB 发生故障对整个系统的影响是灾难性的。另外,LB 在服务消费方和服务提供方之间增加了一跳 (hop),有一定性能开销。 第二种是进程内 LB 方案,针对集中式 LB 的不足,进程内 LB 方案将 LB 的功能以库的形式集成到服务消费方进程里头,该方案也被称为软负载 (Soft Load Balancing) 或者客户端负载方案,下图 Fig 2 展示了这种方案的工作原理。这一方案需要一个服务注册表 (Service Registry) 配合支持服务自注册和自发现,服务提供方启动时,首先将服务地址注册到服务注册表(同时定期报心跳到服务注册表以表明服务的存活状态,相当于健康检查),服务消费方要访问某个服务时,它通过内置的 LB 组件向服务注册表查询(同时缓存并定期刷新)目标服务地址列表,然后以某种负载均衡策略选择一个目标服务地址,最后向目标服务发起请求。这一方案对服务注册表的可用性 (Availability) 要求很高,一般采用能满足高可用分布式一致的组件(例如 Zookeeper, Consul, Etcd 等)来实现。 Fig 2, 进程内 LB 方案 进程内 LB 方案是一种分布式方案,LB 和服务发现能力被分散到每一个服务消费者的进程内部,同时服务消费方和服务提供方之间是直接调用,没有额外开销,性能比较好。但是,该方案以客户库 (Client Library) 的方式集成到服务调用方进程里头,如果企业内有多种不同的语言栈,就要配合开发多种不同的客户端,有一定的研发和维护成本。另外,一旦客户端跟随服务调用方发布到生产环境中,后续如果要对客户库进行升级,势必要求服务调用方修改代码并重新发布,所以该方案的升级推广有不小的阻力。 进程内 LB 的案例是 Netflix 的开源服务框架,对应的组件分别是:Eureka 服务注册表,Karyon 服务端框架支持服务自注册和健康检查,Ribbon 客户端框架支持服务自发现和软路由。另外,阿里开源的服务框架 Dubbo 也是采用类似机制。 第三种是主机独立 LB 进程方案,该方案是针对第二种方案的不足而提出的一种折中方案,原理和第二种方案基本类似,不同之处是,他将 LB 和服务发现功能从进程内移出来,变成主机上的一个独立进程,主机上的一个或者多个服务要访问目标服务时,他们都通过同一主机上的独立 LB 进程做服务发现和负载均衡,见下图 Fig 3。 Fig 3 主机独立 LB 进程方案 该方案也是一种分布式方案,没有单点问题,一个 LB 进程挂了只影响该主机上的服务调用方,服务调用方和 LB 之间是进程内调用,性能好,同时,该方案还简化了服务调用方,不需要为不同语言开发客户库,LB 的升级不需要服务调用方改代码。该方案的不足是部署较复杂,环节多,出错调试排查问题不方便。 该方案的典型案例是 Airbnb 的 SmartStack 服务发现框架,对应组件分别是:Zookeeper 作为服务注册表,Nerve 独立进程负责服务注册和健康检查,Synapse/HAproxy 独立进程负责服务发现和负载均衡。Google 最新推出的基于容器的 PaaS 平台 Kubernetes,其内部服务发现采用类似的机制。 服务前端路由微服务除了内部相互之间调用和通信之外,最终要以某种方式暴露出去,才能让外界系统(例如客户的浏览器、移动设备等等)访问到,这就涉及服务的前端路由,对应的组件是服务网关 (Service Gateway),见图 Fig 4,网关是连接企业内部和外部系统的一道门,有如下关键作用: 服务反向路由,网关要负责将外部请求反向路由到内部具体的微服务,这样虽然企业内部是复杂的分布式微服务结构,但是外部系统从网关上看到的就像是一个统一的完整服务,网关屏蔽了后台服务的复杂性,同时也屏蔽了后台服务的升级和变化。安全认证和防爬虫,所有外部请求必须经过网关,网关可以集中对访问进行安全控制,比如用户认证和授权,同时还可以分析访问模式实现防爬虫功能,网关是连接企业内外系统的安全之门。限流和容错,在流量高峰期,网关可以限制流量,保护后台系统不被大流量冲垮,在内部系统出现故障时,网关可以集中做容错,保持外部良好的用户体验。监控,网关可以集中监控访问量,调用延迟,错误计数和访问模式,为后端的性能优化或者扩容提供数据支持。日志,网关可以收集所有的访问日志,进入后台系统做进一步分析。 Fig 4, 服务网关 除以上基本能力外,网关还可以实现线上引流,线上压测,线上调试 (Surgical debugging),金丝雀测试 (Canary Testing),数据中心双活 (Active-Active HA) 等高级功能。 网关通常工作在 7 层,有一定的计算逻辑,一般以集群方式部署,前置 LB 进行负载均衡。 开源的网关组件有 Netflix 的 Zuul,特点是动态可热部署的过滤器 (filter) 机制,其它如 HAproxy,Nginx 等都可以扩展作为网关使用。 在介绍过服务注册表和网关等组件之后,我们可以通过一个简化的微服务架构图 (Fig 5) 来更加直观地展示整个微服务体系内的服务注册发现和路由机制,该图假定采用进程内 LB 服务发现和负载均衡机制。在下图 Fig 5 的微服务架构中,服务简化为两层,后端通用服务(也称中间层服务 Middle Tier Service)和前端服务(也称边缘服务 Edge Service,前端服务的作用是对后端服务做必要的聚合和裁剪后暴露给外部不同的设备,如 PC,Pad 或者 Phone)。后端服务启动时会将地址信息注册到服务注册表,前端服务通过查询服务注册表就可以发现然后调用后端服务;前端服务启动时也会将地址信息注册到服务注册表,这样网关通过查询服务注册表就可以将请求路由到目标前端服务,这样整个微服务体系的服务自注册自发现和软路由就通过服务注册表和网关串联起来了。如果以面向对象设计模式的视角来看,网关类似 Proxy 代理或者 Façade 门面模式,而服务注册表和服务自注册自发现类似 IoC 依赖注入模式,微服务可以理解为基于网关代理和注册表 IoC 构建的分布式系统。 Fig 5, 简化的微服务架构图 服务容错当企业微服务化以后,服务之间会有错综复杂的依赖关系,例如,一个前端请求一般会依赖于多个后端服务,技术上称为 1 -> N 扇出 (见图 Fig 6)。在实际生产环境中,服务往往不是百分百可靠,服务可能会出错或者产生延迟,如果一个应用不能对其依赖的故障进行容错和隔离,那么该应用本身就处在被拖垮的风险中。在一个高流量的网站中,某个单一后端一旦发生延迟,可能在数秒内导致所有应用资源 (线程,队列等) 被耗尽,造成所谓的雪崩效应 (Cascading Failure,见图 Fig 7),严重时可致整个网站瘫痪。 Fig 6, 服务依赖 Fig 7, 高峰期单个服务延迟致雪崩效应 经过多年的探索和实践,业界在分布式服务容错一块探索出了一套有效的容错模式和最佳实践,主要包括: Fig 8, 弹性电路保护状态图 电路熔断器模式 (Circuit Breaker Patten), 该模式的原理类似于家里的电路熔断器,如果家里的电路发生短路,熔断器能够主动熔断电路,以避免灾难性损失。在分布式系统中应用电路熔断器模式后,当目标服务慢或者大量超时,调用方能够主动熔断,以防止服务被进一步拖垮;如果情况又好转了,电路又能自动恢复,这就是所谓的弹性容错,系统有自恢复能力。下图 Fig 8 是一个典型的具备弹性恢复能力的电路保护器状态图,正常状态下,电路处于关闭状态 (Closed),如果调用持续出错或者超时,电路被打开进入熔断状态 (Open),后续一段时间内的所有调用都会被拒绝 (Fail Fast),一段时间以后,保护器会尝试进入半熔断状态 (Half-Open),允许少量请求进来尝试,如果调用仍然失败,则回到熔断状态,如果调用成功,则回到电路闭合状态。舱壁隔离模式 (Bulkhead Isolation Pattern),顾名思义,该模式像舱壁一样对资源或失败单元进行隔离,如果一个船舱破了进水,只损失一个船舱,其它船舱可以不受影响 。线程隔离 (Thread Isolation) 就是舱壁隔离模式的一个例子,假定一个应用程序 A 调用了 Svc1/Svc2/Svc3 三个服务,且部署 A 的容器一共有 120 个工作线程,采用线程隔离机制,可以给对 Svc1/Svc2/Svc3 的调用各分配 40 个线程,当 Svc2 慢了,给 Svc2 分配的 40 个线程因慢而阻塞并最终耗尽,线程隔离可以保证给 Svc1/Svc3 分配的 80 个线程可以不受影响,如果没有这种隔离机制,当 Svc2 慢的时候,120 个工作线程会很快全部被对 Svc2 的调用吃光,整个应用程序会全部慢下来。限流 (Rate Limiting/Load Shedder),服务总有容量限制,没有限流机制的服务很容易在突发流量 (秒杀,双十一) 时被冲垮。限流通常指对服务限定并发访问量,比如单位时间只允许 100 个并发调用,对超过这个限制的请求要拒绝并回退。回退 (fallback),在熔断或者限流发生的时候,应用程序的后续处理逻辑是什么?回退是系统的弹性恢复能力,常见的处理策略有,直接抛出异常,也称快速失败 (Fail Fast),也可以返回空值或缺省值,还可以返回备份数据,如果主服务熔断了,可以从备份服务获取数据。Netflix 将上述容错模式和最佳实践集成到一个称为 Hystrix 的开源组件中,凡是需要容错的依赖点 (服务,缓存,数据库访问等),开发人员只需要将调用封装在 Hystrix Command 里头,则相关调用就自动置于 Hystrix 的弹性容错保护之下。Hystrix 组件已经在 Netflix 经过多年运维验证,是 Netflix 微服务平台稳定性和弹性的基石,正逐渐被社区接受为标准容错组件。 服务框架微服务化以后,为了让业务开发人员专注于业务逻辑实现,避免冗余和重复劳动,规范研发提升效率,必然要将一些公共关注点推到框架层面。服务框架 (Fig 9) 主要封装公共关注点逻辑,包括: Fig 9, 服务框架 服务注册、发现、负载均衡和健康检查,假定采用进程内 LB 方案,那么服务自注册一般统一做在服务器端框架中,健康检查逻辑由具体业务服务定制,框架层提供调用健康检查逻辑的机制,服务发现和负载均衡则集成在服务客户端框架中。监控日志,框架一方面要记录重要的框架层日志、metrics 和调用链数据,还要将日志、metrics 等接口暴露出来,让业务层能根据需要记录业务日志数据。在运行环境中,所有日志数据一般集中落地到企业后台日志系统,做进一步分析和处理。REST/RPC 和序列化,框架层要支持将业务逻辑以 HTTP/REST 或者 RPC 方式暴露出来,HTTP/REST 是当前主流 API 暴露方式,在性能要求高的场合则可采用 Binary/RPC 方式。针对当前多样化的设备类型 (浏览器、普通 PC、无线设备等),框架层要支持可定制的序列化机制,例如,对浏览器,框架支持输出 Ajax 友好的 JSON 消息格式,而对无线设备上的 Native App,框架支持输出性能高的 Binary 消息格式。配置,除了支持普通配置文件方式的配置,框架层还可集成动态运行时配置,能够在运行时针对不同环境动态调整服务的参数和配置。限流和容错,框架集成限流容错组件,能够在运行时自动限流和容错,保护服务,如果进一步和动态配置相结合,还可以实现动态限流和熔断。管理接口,框架集成管理接口,一方面可以在线查看框架和服务内部状态,同时还可以动态调整内部状态,对调试、监控和管理能提供快速反馈。Spring Boot 微框架的 Actuator 模块就是一个强大的管理接口。统一错误处理,对于框架层和服务的内部异常,如果框架层能够统一处理并记录日志,对服务监控和快速问题定位有很大帮助。安全,安全和访问控制逻辑可以在框架层统一进行封装,可做成插件形式,具体业务服务根据需要加载相关安全插件。文档自动生成,文档的书写和同步一直是一个痛点,框架层如果能支持文档的自动生成和同步,会给使用 API 的开发和测试人员带来极大便利。Swagger 是一种流行 Restful API 的文档方案。当前业界比较成熟的微服务框架有 Netflix 的 Karyon/Ribbon,Spring 的 Spring Boot/Cloud,阿里的 Dubbo 等。 运行期配置管理服务一般有很多依赖配置,例如访问数据库有连接字符串配置,连接池大小和连接超时配置,这些配置在不同环境 (开发 / 测试 / 生产) 一般不同,比如生产环境需要配连接池,而开发测试环境可能不配,另外有些参数配置在运行期可能还要动态调整,例如,运行时根据流量状况动态调整限流和熔断阀值。目前比较常见的做法是搭建一个运行时配置中心支持微服务的动态配置,简化架构如下图 (Fig 10): Fig 10, 服务配置中心 动态配置存放在集中的配置服务器上,用户通过管理界面配置和调整服务配置,具体服务通过定期拉 (Scheduled Pull) 的方式或者服务器推 (Server-side Push) 的方式更新动态配置,拉方式比较可靠,但会有延迟同时有无效网络开销 (假设配置不常更新),服务器推方式能及时更新配置,但是实现较复杂,一般在服务和配置服务器之间要建立长连接。配置中心还要解决配置的版本控制和审计问题,对于大规模服务化环境,配置中心还要考虑分布式和高可用问题。 配置中心比较成熟的开源方案有百度的 Disconf,360 的 QConf,Spring 的 Cloud Config 和阿里的 Diamond 等。 Netflix 的微服务框架Netflix 是一家成功实践微服务架构的互联网公司,几年前,Netflix 就把它的几乎整个微服务框架栈开源贡献给了社区,这些框架和组件包括: Eureka: 服务注册发现框架Zuul: 服务网关Karyon: 服务端框架Ribbon: 客户端框架Hystrix: 服务容错组件Archaius: 服务配置组件Servo: Metrics 组件Blitz4j: 日志组件下图 Fig 11 展示了基于这些组件构建的一个微服务框架体系,来自 recipes-rss。 Fig 11, 基于 Netflix 开源组件的微服务框架 Netflix 的开源框架组件已经在 Netflix 的大规模分布式微服务环境中经过多年的生产实战验证,正逐步被社区接受为构造微服务框架的标准组件。Pivotal 去年推出的 Spring Cloud 开源产品,主要是基于对 Netflix 开源组件的进一步封装,方便 Spring 开发人员构建微服务基础框架。对于一些打算构建微服务框架体系的公司来说,充分利用或参考借鉴 Netflix 的开源微服务组件 (或 Spring Cloud),在此基础上进行必要的企业定制,无疑是通向微服务架构的捷径。 原文地址:https://www.infoq.cn/article/basis-frameworkto-implement-micro-service#anch130564%20%EF%BC%8C

auto_answer 2019-12-02 01:55:22 0 浏览量 回答数 0

问题

【Java问答学堂】4期 如何保证消息的可靠性传输?(如何处理消息丢失的问题?)

剑曼红尘 2020-04-21 10:04:26 105 浏览量 回答数 2

问题

Web测试方法

技术小菜鸟 2019-12-01 21:41:32 7022 浏览量 回答数 1

回答

在开始谈我对架构本质的理解之前,先谈谈对今天技术沙龙主题的个人见解,千万级规模的网站感觉数量级是非常大的,对这个数量级我们战略上 要重 视 它 , 战术上又 要 藐 视 它。先举个例子感受一下千万级到底是什么数量级?现在很流行的优步(Uber),从媒体公布的信息看,它每天接单量平均在百万左右, 假如每天有10个小时的服务时间,平均QPS只有30左右。对于一个后台服务器,单机的平均QPS可以到达800-1000,单独看写的业务量很简单 。为什么我们又不能说轻视它?第一,我们看它的数据存储,每天一百万的话,一年数据量的规模是多少?其次,刚才说的订单量,每一个订单要推送给附近的司机、司机要并发抢单,后面业务场景的访问量往往是前者的上百倍,轻松就超过上亿级别了。 今天我想从架构的本质谈起之后,希望大家理解在做一些建构设计的时候,它的出发点以及它解决的问题是什么。 架构,刚开始的解释是我从知乎上看到的。什么是架构?有人讲, 说架构并不是一 个很 悬 乎的 东西 , 实际 上就是一个架子 , 放一些 业务 和算法,跟我们的生活中的晾衣架很像。更抽象一点,说架构其 实 是 对 我 们 重复性业务 的抽象和我 们 未来 业务 拓展的前瞻,强调过去的经验和你对整个行业的预见。 我们要想做一个架构的话需要哪些能力?我觉得最重要的是架构师一个最重要的能力就是你要有 战 略分解能力。这个怎么来看呢: 第一,你必须要有抽象的能力,抽象的能力最基本就是去重,去重在整个架构中体现在方方面面,从定义一个函数,到定义一个类,到提供的一个服务,以及模板,背后都是要去重提高可复用率。 第二, 分类能力。做软件需要做对象的解耦,要定义对象的属性和方法,做分布式系统的时候要做服务的拆分和模块化,要定义服务的接口和规范。 第三, 算法(性能),它的价值体现在提升系统的性能,所有性能的提升,最终都会落到CPU,内存,IO和网络这4大块上。 这一页PPT举了一些例子来更深入的理解常见技术背后的架构理念。 第一个例子,在分布式系统我们会做 MySQL分 库 分表,我们要从不同的库和表中读取数据,这样的抽象最直观就是使用模板,因为绝大多数SQL语义是相同的,除了路由到哪个库哪个表,如果不使用Proxy中间件,模板就是性价比最高的方法。 第二看一下加速网络的CDN,它是做速度方面的性能提升,刚才我们也提到从CPU、内存、IO、网络四个方面来考虑,CDN本质上一个是做网络智能调度优化,另一个是多级缓存优化。 第三个看一下服务化,刚才已经提到了,各个大网站转型过程中一定会做服务化,其实它就是做抽象和做服务的拆分。第四个看一下消息队列,本质上还是做分类,只不过不是两个边际清晰的类,而是把两个边际不清晰的子系统通过队列解构并且异步化。新浪微博整体架构是什么样的 接下我们看一下微博整体架构,到一定量级的系统整个架构都会变成三层,客户端包括WEB、安卓和IOS,这里就不说了。接着还都会有一个接口层, 有三个主要作用: 第一个作用,要做 安全隔离,因为前端节点都是直接和用户交互,需要防范各种恶意攻击; 第二个还充当着一个 流量控制的作用,大家知道,在2014年春节的时候,微信红包,每分钟8亿多次的请求,其实真正到它后台的请求量,只有十万左右的数量级(这里的数据可能不准),剩余的流量在接口层就被挡住了; 第三,我们看对 PC 端和移 动 端的需求不一样的,所以我们可以进行拆分。接口层之后是后台,可以看到微博后台有三大块: 一个是 平台服 务, 第二, 搜索, 第三, 大数据。到了后台的各种服务其实都是处理的数据。 像平台的业务部门,做的就是 数据存储和读 取,对搜索来说做的是 数据的 检 索,对大数据来说是做的数据的 挖掘。微博其实和淘宝是很类似 微博其实和淘宝是很类似的。一般来说,第一代架构,基本上能支撑到用户到 百万 级别,到第二代架构基本能支撑到 千万 级别都没什么问题,当业务规模到 亿级别时,需要第三代的架构。 从 LAMP 的架构到面向服 务 的架构,有几个地方是非常难的,首先不可能在第一代基础上通过简单的修修补补满足用户量快速增长的,同时线上业务又不能停, 这是我们常说的 在 飞 机上 换 引擎的 问题。前两天我有一个朋友问我,说他在内部推行服务化的时候,把一个模块服务化做完了,其他部门就是不接。我建议在做服务化的时候,首先更多是偏向业务的梳理,同时要找准一个很好的切入点,既有架构和服务化上的提升,业务方也要有收益,比如提升性能或者降低维护成本同时升级过程要平滑,建议开始从原子化服务切入,比如基础的用户服务, 基础的短消息服务,基础的推送服务。 第二,就是可 以做无状 态 服 务,后面会详细讲,还有数据量大了后需要做数据Sharding,后面会将。 第三代 架构 要解决的 问题,就是用户量和业务趋于稳步增加(相对爆发期的指数级增长),更多考虑技术框架的稳定性, 提升系统整体的性能,降低成本,还有对整个系统监控的完善和升级。 大型网站的系统架构是如何演变的 我们通过通过数据看一下它的挑战,PV是在10亿级别,QPS在百万,数据量在千亿级别。我们可用性,就是SLA要求4个9,接口响应最多不能超过150毫秒,线上所有的故障必须得在5分钟内解决完。如果说5分钟没处理呢?那会影响你年终的绩效考核。2015年微博DAU已经过亿。我们系统有上百个微服务,每周会有两次的常规上线和不限次数的紧急上线。我们的挑战都一样,就是数据量,bigger and bigger,用户体验是faster and faster,业务是more and more。互联网业务更多是产品体验驱动, 技 术 在 产 品 体验上最有效的贡献 , 就是你的性能 越来越好 。 每次降低加载一个页面的时间,都可以间接的降低这个页面上用户的流失率。微博的技术挑战和正交分解法解析架构 下面看一下 第三代的 架构 图 以及 我 们 怎么用正交分解法 阐 述。 我们可以看到我们从两个维度,横轴和纵轴可以看到。 一个 维 度 是 水平的 分层 拆分,第二从垂直的维度会做拆分。水平的维度从接口层、到服务层到数据存储层。垂直怎么拆分,会用业务架构、技术架构、监控平台、服务治理等等来处理。我相信到第二代的时候很多架构已经有了业务架构和技术架构的拆分。我们看一下, 接口层有feed、用户关系、通讯接口;服务层,SOA里有基层服务、原子服务和组合服务,在微博我们只有原子服务和组合服务。原子服务不依赖于任何其他服务,组合服务由几个原子服务和自己的业务逻辑构建而成 ,资源层负责海量数据的存储(后面例子会详细讲)。技 术框架解决 独立于 业务 的海量高并发场景下的技术难题,由众多的技术组件共同构建而成 。在接口层,微博使用JERSY框架,帮助你做参数的解析,参数的验证,序列化和反序列化;资源层,主要是缓存、DB相关的各类组件,比如Cache组件和对象库组件。监 控平台和服 务 治理 , 完成系统服务的像素级监控,对分布式系统做提前诊断、预警以及治理。包含了SLA规则的制定、服务监控、服务调用链监控、流量监控、错误异常监控、线上灰度发布上线系统、线上扩容缩容调度系统等。 下面我们讲一下常见的设计原则。 第一个,首先是系统架构三个利器: 一个, 我 们 RPC 服 务组 件 (这里不讲了), 第二个,我们 消息中 间 件 。消息中间件起的作用:可以把两个模块之间的交互异步化,其次可以把不均匀请求流量输出为匀速的输出流量,所以说消息中间件 异步化 解耦 和流量削峰的利器。 第三个是配置管理,它是 代码级灰度发布以及 保障系统降级的利器。 第二个 , 无状态 , 接口 层 最重要的就是无状 态。我们在电商网站购物,在这个过程中很多情况下是有状态的,比如我浏览了哪些商品,为什么大家又常说接口层是无状态的,其实我们把状态从接口层剥离到了数据层。像用户在电商网站购物,选了几件商品,到了哪一步,接口无状态后,状态要么放在缓存中,要么放在数据库中, 其 实 它并不是没有状 态 , 只是在 这 个 过 程中我 们 要把一些有状 态 的 东 西抽离出来 到了数据层。 第三个, 数据 层 比服 务层 更需要 设计,这是一条非常重要的经验。对于服务层来说,可以拿PHP写,明天你可以拿JAVA来写,但是如果你的数据结构开始设计不合理,将来数据结构的改变会花费你数倍的代价,老的数据格式向新的数据格式迁移会让你痛不欲生,既有工作量上的,又有数据迁移跨越的时间周期,有一些甚至需要半年以上。 第四,物理结构与逻辑结构的映射,上一张图看到两个维度切成十二个区间,每个区间代表一个技术领域,这个可以看做我们的逻辑结构。另外,不论后台还是应用层的开发团队,一般都会分几个垂直的业务组加上一个基础技术架构组,这就是从物理组织架构到逻辑的技术架构的完美的映射,精细化团队分工,有利于提高沟通协作的效率 。 第五, www .sanhao.com 的访问过程,我们这个架构图里没有涉及到的,举个例子,比如当你在浏览器输入www.sanhao网址的时候,这个请求在接口层之前发生了什么?首先会查看你本机DNS以及DNS服务,查找域名对应的IP地址,然后发送HTTP请求过去。这个请求首先会到前端的VIP地址(公网服务IP地址),VIP之后还要经过负载均衡器(Nginx服务器),之后才到你的应用接口层。在接口层之前发生了这么多事,可能有用户报一个问题的时候,你通过在接口层查日志根本发现不了问题,原因就是问题可能发生在到达接口层之前了。 第六,我们说分布式系统,它最终的瓶颈会落在哪里呢?前端时间有一个网友跟我讨论的时候,说他们的系统遇到了一个瓶颈, 查遍了CPU,内存,网络,存储,都没有问题。我说你再查一遍,因为最终你不论用上千台服务器还是上万台服务器,最终系统出瓶颈的一定会落在某一台机(可能是叶子节点也可能是核心的节点),一定落在CPU、内存、存储和网络上,最后查出来问题出在一台服务器的网卡带宽上。微博多级双机房缓存架构 接下来我们看一下微博的Feed多级缓存。我们做业务的时候,经常很少做业务分析,技术大会上的分享又都偏向技术架构。其实大家更多的日常工作是需要花费更多时间在业务优化上。这张图是统计微博的信息流前几页的访问比例,像前三页占了97%,在做缓存设计的时候,我们最多只存最近的M条数据。 这里强调的就是做系统设计 要基于用 户 的 场 景 , 越细致越好 。举了一个例子,大家都会用电商,电商在双十一会做全国范围内的活动,他们做设计的时候也会考虑场景的,一个就是购物车,我曾经跟相关开发讨论过,购物车是在双十一之前用户的访问量非常大,就是不停地往里加商品。在真正到双十一那天他不会往购物车加东西了,但是他会频繁的浏览购物车。针对这个场景,活动之前重点设计优化购物车的写场景, 活动开始后优化购物车的读场景。 你看到的微博是由哪些部分聚合而成的呢?最右边的是Feed,就是微博所有关注的人,他们的微博所组成的。微博我们会按照时间顺序把所有关注人的顺序做一个排序。随着业务的发展,除了跟时间序相关的微博还有非时间序的微博,就是会有广告的要求,增加一些广告,还有粉丝头条,就是拿钱买的,热门微博,都会插在其中。分发控制,就是说和一些推荐相关的,我推荐一些相关的好友的微博,我推荐一些你可能没有读过的微博,我推荐一些其他类型的微博。 当然对非时序的微博和分发控制微博,实际会起多个并行的程序来读取,最后同步做统一的聚合。这里稍微分享一下, 从SNS社交领域来看,国内现在做的比较好的三个信息流: 微博 是 基于弱关系的媒体信息流 ; 朋友圈是基于 强 关系的信息流 ; 另外一个做的比 较 好的就是今日 头 条 , 它并不是基于关系来构建信息流 , 而是基于 兴趣和相关性的个性化推荐 信息流 。 信息流的聚合,体现在很多很多的产品之中,除了SNS,电商里也有信息流的聚合的影子。比如搜索一个商品后出来的列表页,它的信息流基本由几部分组成:第一,打广告的;第二个,做一些推荐,热门的商品,其次,才是关键字相关的搜索结果。 信息流 开始的时候 很 简单 , 但是到后期会 发现 , 你的 这 个流 如何做控制分发 , 非常复杂, 微博在最近一两年一直在做 这样 的工作。刚才我们是从业务上分析,那么技术上怎么解决高并发,高性能的问题?微博访问量很大的时候,底层存储是用MySQL数据库,当然也会有其他的。对于查询请求量大的时候,大家知道一定有缓存,可以复用可重用的计算结果。可以看到,发一条微博,我有很多粉丝,他们都会来看我发的内容,所以 微博是最适合使用 缓 存 的系统,微博的读写比例基本在几十比一。微博使用了 双 层缓 存,上面是L1,每个L1上都是一组(包含4-6台机器),左边的框相当于一个机房,右边又是一个机房。在这个系统中L1缓存所起的作用是什么? 首先,L1 缓 存增加整个系 统 的 QPS, 其次 以低成本灵活扩容的方式 增加 系统 的 带宽 。想象一个极端场景,只有一篇博文,但是它的访问量无限增长,其实我们不需要影响L2缓存,因为它的内容存储的量小,但它就是访问量大。这种场景下,你就需要使用L1来扩容提升QPS和带宽瓶颈。另外一个场景,就是L2级缓存发生作用,比如我有一千万个用户,去访问的是一百万个用户的微博 ,这个时候,他不只是说你的吞吐量和访问带宽,就是你要缓存的博文的内容也很多了,这个时候你要考虑缓存的容量, 第二 级缓 存更多的是从容量上来 规划,保证请求以较小的比例 穿透到 后端的 数据 库 中 ,根据你的用户模型你可以估出来,到底有百分之多少的请求不能穿透到DB, 评估这个容量之后,才能更好的评估DB需要多少库,需要承担多大的访问的压力。另外,我们看双机房的话,左边一个,右边一个。 两个机房是互 为 主 备 , 或者互 为热备 。如果两个用户在不同地域,他们访问两个不同机房的时候,假设用户从IDC1过来,因为就近原理,他会访问L1,没有的话才会跑到Master,当在IDC1没找到的时候才会跑到IDC2来找。同时有用户从IDC2访问,也会有请求从L1和Master返回或者到IDC1去查找。 IDC1 和 IDC2 ,两个机房都有全量的用户数据,同时在线提供服务,但是缓存查询又遵循最近访问原理。还有哪些多级缓存的例子呢?CDN是典型的多级缓存。CDN在国内各个地区做了很多节点,比如在杭州市部署一个节点时,在机房里肯定不止一台机器,那么对于一个地区来说,只有几台服务器到源站回源,其他节点都到这几台服务器回源即可,这么看CDN至少也有两级。Local Cache+ 分布式 缓 存,这也是常见的一种策略。有一种场景,分布式缓存并不适用, 比如 单 点 资 源 的爆发性峰值流量,这个时候使用Local Cache + 分布式缓存,Local Cache 在 应用 服 务 器 上用很小的 内存资源 挡住少量的 极端峰值流量,长尾的流量仍然访问分布式缓存,这样的Hybrid缓存架构通过复用众多的应用服务器节点,降低了系统的整体成本。 我们来看一下 Feed 的存 储 架构,微博的博文主要存在MySQL中。首先来看内容表,这个比较简单,每条内容一个索引,每天建一张表,其次看索引表,一共建了两级索引。首先想象一下用户场景,大部分用户刷微博的时候,看的是他关注所有人的微博,然后按时间来排序。仔细分析发现在这个场景下, 跟一个用户的自己的相关性很小了。所以在一级索引的时候会先根据关注的用户,取他们的前条微博ID,然后聚合排序。我们在做哈希(分库分表)的时候,同时考虑了按照UID哈希和按照时间维度。很业务和时间相关性很高的,今天的热点新闻,明天就没热度了,数据的冷热非常明显,这种场景就需要按照时间维度做分表,首先冷热数据做了分离(可以对冷热数据采用不同的存储方案来降低成本),其次, 很容止控制我数据库表的爆炸。像微博如果只按照用户维度区分,那么这个用户所有数据都在一张表里,这张表就是无限增长的,时间长了查询会越来越慢。二级索引,是我们里面一个比较特殊的场景,就是我要快速找到这个人所要发布的某一时段的微博时,通过二级索引快速定位。 分布式服务追踪系统 分布式追踪服务系统,当系统到千万级以后的时候,越来越庞杂,所解决的问题更偏向稳定性,性能和监控。刚才说用户只要有一个请求过来,你可以依赖你的服务RPC1、RPC2,你会发现RPC2又依赖RPC3、RPC4。分布式服务的时候一个痛点,就是说一个请求从用户过来之后,在后台不同的机器之间不停的调用并返回。 当你发现一个问题的时候,这些日志落在不同的机器上,你也不知道问题到底出在哪儿,各个服务之间互相隔离,互相之间没有建立关联。所以导致排查问题基本没有任何手段,就是出了问题没法儿解决。 我们要解决的问题,我们刚才说日志互相隔离,我们就要把它建立联系。建立联系我们就有一个请求ID,然后结合RPC框架, 服务治理功能。假设请求从客户端过来,其中包含一个ID 101,到服务A时仍然带有ID 101,然后调用RPC1的时候也会标识这是101 ,所以需要 一个唯一的 请求 ID 标识 递归迭代的传递到每一个 相关 节点。第二个,你做的时候,你不能说每个地方都加,对业务系统来说需要一个框架来完成这个工作, 这 个框架要 对业务 系 统 是最低侵入原 则 , 用 JAVA 的 话 就可以用 AOP,要做到零侵入的原则,就是对所有相关的中间件打点,从接口层组件(HTTP Client、HTTP Server)至到服务层组件(RPC Client、RPC Server),还有数据访问中间件的,这样业务系统只需要少量的配置信息就可以实现全链路监控 。为什么要用日志?服务化以后,每个服务可以用不同的开发语言, 考虑多种开发语言的兼容性 , 内部定 义标 准化的日志 是唯一且有效的办法。最后,如何构建基于GPS导航的路况监控?我们刚才讲分布式服务追踪。分布式服务追踪能解决的问题, 如果 单一用 户发现问题 后 , 可以通 过请 求 ID 快速找到 发 生 问题 的 节 点在什么,但是并没有解决如何发现问题。我们看现实中比较容易理解的道路监控,每辆车有GPS定位,我想看北京哪儿拥堵的时候,怎么做? 第一个 , 你肯定要知道每个 车 在什么位置,它走到哪儿了。其实可以说每个车上只要有一个标识,加上每一次流动的信息,就可以看到每个车流的位置和方向。 其次如何做 监 控和 报 警,我们怎么能了解道路的流量状况和负载,并及时报警。我们要定义这条街道多宽多高,单位时间可以通行多少辆车,这就是道路的容量。有了道路容量,再有道路的实时流量,我们就可以基于实习路况做预警? 对应于 分布式系 统 的话如何构建? 第一 , 你要 定义 每个服 务节 点它的 SLA A 是多少 ?SLA可以从系统的CPU占用率、内存占用率、磁盘占用率、QPS请求数等来定义,相当于定义系统的容量。 第二个 , 统计 线 上 动态 的流量,你要知道服务的平均QPS、最低QPS和最大QPS,有了流量和容量,就可以对系统做全面的监控和报警。 刚才讲的是理论,实际情况肯定比这个复杂。微博在春节的时候做许多活动,必须保障系统稳定,理论上你只要定义容量和流量就可以。但实际远远不行,为什么?有技术的因素,有人为的因素,因为不同的开发定义的流量和容量指标有主观性,很难全局量化标准,所以真正流量来了以后,你预先评估的系统瓶颈往往不正确。实际中我们在春节前主要采取了三个措施:第一,最简单的就是有降 级 的 预 案,流量超过系统容量后,先把哪些功能砍掉,需要有明确的优先级 。第二个, 线上全链路压测,就是把现在的流量放大到我们平常流量的五倍甚至十倍(比如下线一半的服务器,缩容而不是扩容),看看系统瓶颈最先发生在哪里。我们之前有一些例子,推测系统数据库会先出现瓶颈,但是实测发现是前端的程序先遇到瓶颈。第三,搭建在线 Docker 集群 , 所有业务共享备用的 Docker集群资源,这样可以极大的避免每个业务都预留资源,但是实际上流量没有增长造成的浪费。 总结 接下来说的是如何不停的学习和提升,这里以Java语言为例,首先, 一定要 理解 JAVA;第二步,JAVA完了以后,一定要 理 解 JVM;其次,还要 理解 操作系统;再次还是要了解一下 Design Pattern,这将告诉你怎么把过去的经验抽象沉淀供将来借鉴;还要学习 TCP/IP、 分布式系 统、数据结构和算法。

hiekay 2019-12-02 01:39:25 0 浏览量 回答数 0

回答

Layout Go工程项目的整体组织 首先我们看一下整个 Go 工程是怎么组织起来的。 很多同事都在用 GitLab 的,GitLab 的一个 group 里面可以创建很多 project。如果我们进行微服务化改造,以前很多巨石架构的应用可能就拆成了很多个独立的小应用。那么这么多小应用,你是要建 N 个 project 去维护,还是说按照部门或者组来组织这些项目呢?在 B 站的话,我们之前因为是 Monorepo,现在是按照部门去组织管理代码,就是说在单个 GitLab 的 project 里面是有多个 app 的,每一个 app 就表示一个独立的微服务,它可以独立去交付部署。所以说我们看到下面这张图里面,app 的目录里面是有好多个子目录的,比方说我们的评论服务,会员服务。跟 app 同级的目录有一个叫 pkg,可以存放业务有关的公共库。这是我们的一个组织方式。当然,还有一种方式,你可以按照 GitLab 的 project 去组织,但我觉得这样的话可能相对要创建的 project 会非常多。 如果你按部门组织的话,部门里面有很多 app,app 目录怎么去组织?我们实际上会给每一个 app 取一个全局唯一名称,可以理解为有点像 DNS 那个名称。我们对业务的命名也是一样的,我们基本上是三段式的命名,比如账号业务,它是一个账号业务、服务、子服务的三段命名。三段命名以后,在这个 app 目录里面,你也可以按照这三层来组织。比如我们刚刚说的账号目录,我可能就是 account 目录,然后 VIP,在 VIP 目录下可能会放各种各样的不同角色的微服务,比方说可能有一些是做 job,做定时任务或者流式处理的一些任务,有可能是做对外暴露的 API 的一些服务,这个就是我们关于整个大的 app 的组织的一种形式。 微服务中的 app 服务分类 微服务中单个 app 的服务里又分为几类不同的角色。我们基本上会把 app 分为 interface(BFF)、service、job(补充:还有一个 task,偏向定时执行,job 偏向流式) 和 admin。 Interface 是对外的业务网关服务,因为我们最终是面向终端用户的 API,面向 app,面向 PC 场景的,我们把这个叫成业务网关。因为我们不是统一的网关,我们可能是按照大的业务线去独立分拆的一些子网关,这个的话可以作为一个对外暴露的 HTTP 接口的一个目录去组织它的代码,当然也可能是 gRPC 的(参考 B 站对外的 gRPC Moss 分享)。 Service 这个角色主要是面向对内通信的微服务,它不直接对外。也就是说,业务网关的请求会转发或者是会 call 我们的内部的 service,它们之间的通讯可能是使用自己的 RPC,在 b 站我们主要是使用 gRPC。使用 gRPC 通讯以后,service 它因为不直接对外,service 之间可能也可以相互去 call。 Admin 区别于 service,很多应用除了有面向用户的一些接口,实际上还有面向企业内部的一些运营侧的需求,通常数据权限更高,从安全设计角度需要代码物理层面隔离,避免意外。 第四个是 ecode。我们当时也在内部争论了很久,我们的错误码定义到底是放在哪里?我们目前的做法是,一个应用里面,假设你有多种角色,它们可能会复用一些错误码。所以说我们会把我们的 ecode 给单独抽出来,在这一个应用里面是可以复用的。注意,它只在这一个应用里面复用,它不会去跨服跨目录应用,它是针对业务场景的一个业务错误码的组织。 App 目录组织 我们除了一个应用里面多种角色的这种情况,现在展开讲一下具体到一个 service 里面,它到底是怎么组织的。我们的 app 目录下大概会有 api、cmd、configs、 internal 目录,目录里一般还会放置 README、CHANGELOG、OWNERS。 API 是放置 api 定义以及对应的生成的 client 代码,包含基于 pb 定义(我们使用 PB 作为 DSL 描述 API) 生成的 swagger.json。 而 cmd,就是放 main 函数的。Configs 目录主要是放一些服务所需的配置文件,比方说说我们可能会使用 TOML 或者是使用 YAML 文件。 Internal 的话,它里面有四个子目录,分别是 model、dao、service 和 server。Model 的定位职责就是对我们底层存储的持久化层或者存储层的数据的映射,它是具体的 Go 的一个 struct。我们再看 dao,你实际就是要操作 MySQL 或者 Redis,最终返回的就是这些 model(存储映射)。Service 组织起来比较简单,就是我们通过 dao 里面的各个方法来完成一个完整的业务逻辑。我们还看到有个 server,因为我一个微服务有可能企业内部不一定所有 RPC 都统一,那我们处于过渡阶段,所以 server 里面会有两个小目录,一个是 HTTP 目录,暴露的是 HTTP 接口,还有一个是 gRPC 目录,我们会暴露 gRPC 的协议。所以在 server 里面,两个不同的启动的 server,就是说一个服务和启动两个端口,然后去暴露不同的协议,HTTP 接 RPC,它实际上会先 call 到 service,service 再 call 到 dao,dao 实际上会使用 model 的一些数据定义 struct。但这里面有一个非常重要的就是,因为这个结构体不能够直接返回给我们的 api 做外对外暴露来使用,为什么?因为可能从数据库里面取的敏感字段,当我们实际要返回到 api 的时候,可能要隐藏掉一些字段,在 Java 里面,会抽象的一个叫 DTO 的对象,它只是用来传输用的,同理,在我们 Go 里面,实际也会把这些 model 的一些结构体映射成 api 里面的结构体(基于 PB Message 生成代码后的 struct)。 Rob Pike 当时说过的一句话,a little copying is better than a little dependency,我们就遵循了这个理念。在我们这个目录结构里面,有 internal 目录,我们知道 Go 的目录只允许这个目录里面的人去 import 到它,跨目录的人实际是不能直接引用到它的。所以说,我们看到 service 有一个 model,那我的 job 代码,我做一些定时任务的代码或者是我的网关代码有可能会映射同一个 model,那是不是要把这个 model 放到上一级目录让大家共享?对于这个问题,其实我们当时内部也争论过很久。我们认为,每一个微服务应该只对自己的 model 负责,所以我们宁愿去做一小部分的代码 copy,也不会去为了几个服务之间要共享这一点点代码,去把这个 model 提到和 app 目录级别去共用,因为你一改全错,当然了,你如果是拷贝的话,就是每个地方都要去改,那我们觉得,依赖的问题可能会比拷贝代码相对来说还是要更复杂的。 这个是一个标准的 PB 文件,就是我们内部的一个 demo 的 service。最上面的 package 是 PB 的包名,demo.service.v1,这个包使用的是三段式命名,全局唯一的名称。那这个名称为什么不是用 ID?我见过有些公司对内部做的 CMDB 或者做服务树去管理企业内部微服务的时候,是用了一些名称加上 ID 来搞定唯一性,但是我们知道后面那一串 ID 数字是不容易被传播或者是不容易被记住的,这也是 DNS 出来的一个意义,所以我们用绝对唯一的一个名称来表示这个包的名字,在后面带上这一个 PB 文件的版本号 V1。 我们看第二段定义,它有个 Service Demo 代码,其实就表示了我们这个服务要启动的服务的一个名称,我们看到这个服务名称里面有很多个 RPC 的方法,表示最终这一个应用或者这个 service 要对外暴露这几个 RPC 的方法。这里面有个小细节,我们看一下 SayHello 这个方法,实际它有 option 的一个选项。通过这一个 PB 文件,你既可以描述出你要暴露的是 gRPC 协议,又暴露出 HTTP 的一个接口,这个好处是你只需要一个 PB 文件描述你暴露的所有 api。我们回想一下,我们刚刚目录里面有个 api 目录,实际这里面就是放这一个 PB 文件,描述这一个工程到底返回的接口是什么。不管是 gRPC 还是 HTTP 都是这一个文件。还有一个好处是什么?实际上我们可以在 PB 文件里面加上很多的注释。用 PB 文件的好处是你不需要额外地再去写文档,因为写文档和写服务的定义,它本质上是两个步骤,特别容易不一致,接口改了,文档不同步。我们如果基于这一个 PB 文件,它生成的 service 代码或者调用代码或者是文档都是唯一的。 依赖顺序与 api 维护 就像我刚刚讲到的,model 是一个存储层的结构体的一一映射,dao 处理一些数据读写包,比方说数据库缓存,server 的话就是启动了一些 gRPC 或者 HTTP Server,所以它整个依赖顺序如下:main 函数启动 server,server 会依赖 api 定义好的 PB 文件,定义好这些方法或者是服务名之后,实际上生成代码的时候,比方说 protocbuf 生成代码的时候,它会把抽象 interface 生成好。然后我们看一下 service,它实际上是弱依赖的 api,就是说我的 server 启动以后,要注册一个具体的业务代码的逻辑,映射方法,映射名字,实际上是弱依赖的 api 生成的 interface 的代码,你就可以很方便地启动你的 server,把你具体的 service 的业务逻辑给注入到这个 server,和方法进行一一绑定。最后,dao 和 service 实际上都会依赖这个 model。 因为我们在 PB 里面定义了一些 message,这些 message 生成的 Go 的 struct 和刚刚 model 的 struct 是两个不同的对象,所以说你要去手动 copy 它,把它最终返回。但是为了快捷,你不可能每次手动去写这些代码,因为它要做 mapping,所以我们又把 K8s 里类似 DeepCopy 的两个结构体相互拷贝的工具给抠出来了,方便我们内部 model 和 api 的 message 两个代码相互拷贝的时候,可以少写一些代码,减少一些工作量。 上面讲的就是我们关于工程的一些 layout 实践。简单回溯一下,大概分为几块,第一就是 app 是怎么组织的,app 里面有多种角色的服务是怎么组织的,第三就是一个 app 里面的目录是怎么组织的,最后我重点讲了一下 api 是怎么维护的。 Unittest 测试方法论 现在回顾一下单元测试。我们先看这张图,这张图是我从《Google 软件测试之道》这本书里面抠出来的,它想表达的意思就是最小型的测试不能给我们的最终项目的质量带来最大的信心,它比较容易带来一些优秀的代码质量,良好的异常处理等等。但是对于一个面向用户场景的服务,你只有做大型测试,比方做接口测试,在 App 上验收功能的这种测试,你应用交付的信心可能会更足。这个其实要表达的就是一个“721 原则”。我们就是 70% 写小型测试,可以理解为单元测试,因为它相对来说好写,针对方法级别。20% 是做一些中型测试,可能你要连调几个项目去完成你的 api。剩下 10% 是大型测试,因为它是最终面向用户场景的,你要去使用我们的 App,或者用一些测试 App 去测试它。这个就是测试的一些简单的方法论。 单元测试原则 我们怎么去对待 Go 里面的单元测试?在《Google 软件测试之道》这本书里面,它强调的是对于一个小型测试,一个单元测试,它要有几个特质。它不能依赖外部的一些环境,比如我们公司有测试环境,有持续集成环境,有功能测试环境,你不能依赖这些环境构建自己的单元测试,因为测试环境容易被破坏,它容易有数据的变更,数据容易不一致,你之前构建的案例重跑的话可能就会失败。 我觉得单元测试主要有四点要求。第一,快速,你不能说你跑个单元测试要几分钟。第二,要环境一致,也就是说你跑测试前和跑测试后,它的环境是一致的。第三,你写的所有单元测试的方法可以以任意顺序执行,不应该有先后的依赖,如果有依赖,也是在你测试的这个方法里面,自己去 setup 和 teardown,不应该有 Test Stub 函数存在顺序依赖。第四,基于第三点,你可以做并行的单元测试,假设我写了一百个单元测试,一个个跑肯定特别慢。 doker-compose 最近一段时间,我们演进到基于 docker-compose 实现跨平台跨语言环境的容器依赖管理方案,以解决运行 unittest 场景下的容器依赖问题。 首先,你要跑单元测试,你不应该用 VPN 连到公司的环境,好比我在星巴克点杯咖啡也可以写单元测试,也可以跑成功。基于这一点,Docker 实际上是非常好的解决方式。我们也有同学说,其他语言有一些 in-process 的 mock,是不是可以启动 MySQL 的 mock ,然后在 in-process 上跑?可以,但是有一个问题,你每一个语言都要写一个这样的 mock ,而且要写非常多种,因为我们中间件越来越多,MySQL,HBase,Kafka,什么都有,你很难覆盖所有的组件 Mock。这种 mock 或者 in-process 的实现不能完整地代表线上的情况,比方说,你可能 mock 了一个 MySQL,检测到 query 或者 insert ,没问题,但是你实际要跑一个 transaction,要验证一些功能就未必能做得非常完善了。所以基于这个原因,我们当时选择了 docker-compose,可以很好地解决这个问题。 我们对开发人员的要求就是,你本地需要装 Docker,我们开发人员大部分都是用 Mac,相对来说也比较简单,Windows 也能搞定,如果是 Linux 的话就更简单了。本地安装 Docker,本质上的理解就是无侵入式的环境初始化,因为你在容器里面,你拉起一个 MySQL,你自己来初始化数据。在这个容器被销毁以后,它的环境实际上就满足了我们刚刚提的环境一致的问题,因为它相当于被重置了,也可以很方便地快速重置环境,也可以随时随地运行,你不需要依赖任何外部服务,这个外部服务指的是像 MySQL 这种外部服务。当然,如果你的单元测试依赖另外一个 RPC 的 service 的话,PB 的定义会生成一个 interface,你可以把那个 interface 代码给 mock 掉,所以这个也是能做掉的。对于小型测试来说,你不依赖任何外部环境,你也能够快速完成。 另外,docker-compose 是声明式的 API,你可以声明你要用 MySQL,Redis,这个其实就是一个配置文件,非常简单。这个就是我们在单元测试上的一些实践。 我们现在看一下,service 目录里面多了一个 test 目录,我们会在这个里面放 docker-compose 的 YAML 文件来表示这次单元化测试需要初始化哪些资源,你要构建自己的一些测试的数据集。因为是这样的,你是写 dao 层的单元测试的话,可能就需要 database.sql 做一些数据的初始化,如果你是做 service 的单元测试的话,实际你可以把整个 dao 给 mock 掉,我觉得反而还相对简单,所以我们主要针对场景就是在 dao 里面偏持久层的,利用 docker-compose 来解决。 容器的拉起,容器的销毁,这些工作到底谁来做?是开发同学自己去拉起和销毁,还是说你能够把它做成一个 Library,让我们的同学写单元测试的时候比较方便?我倾向的是后者。所以在我们最终写单元测试的时候,你可以很方便地 setup 一个依赖文件,去 setup 你的容器的一些信息,或者把它销毁掉。所以说,你把环境准备好以后,最终可以跑测试代码也非常方便。当然我们也提供了一些命令函,就是 binary 的一些工具,它可以针对各个语言方便地拉起容器和销毁容器,然后再去执行代码,所以我们也提供了一些快捷的方式。 刚刚我也提到了,就是我们对于 service 也好,API 也好,因为依赖下层的 dao 或者依赖下层的 service,你都很方便 mock 掉,这个写单元测试相对简单,这个我不展开讲,你可以使用 GoMock 或者 GoMonkey 实现这个功能。 Toolchain 我们利用多个 docker-compose 来解决 dao 层的单元测试,那对于我刚刚提到的项目的一些规范,单元测试的一些模板,甚至是我写了一些 dao 的一些占位符,或者写了一些 service 代码的一些占位符,你有没有考虑过这种约束有没有人会去遵循?所以我这里要强调一点,工具一定要大于约束和文档,你写了约束,写了文档,那么你最终要通过工具把它落实。所以在我们内部会有一个类似 go tool 的脚手架,叫 Kratos Tool,把我们刚刚说的约定规范都通过这个工具一键初始化。 对于我们内部的工具集,我们大概会分为几块。第一块就是 API 的,就是你写一个 PB 文件,你可以基于这个 PB 文件生成 gRPC,HTTP 的框架代码,你也可以基于这个 PB 文件生成 swagger 的一些 JSON 文件或者是 Markdown 文件。当然了,我们还会生成一些 API,用于 debug 的 client 方便去调试,因为我们知道,gRPC 调试起来相对麻烦一些,你要去写代码。 还有一些工具是针对 project 的,一键生成整个应用的 layout,非常方便。我们还提了 model,就是方便 model 和 DTO,DTO 就是 API 里面定义的 message 的 struct 做 DeepCopy,这个也是一个工具。 对于 cache 的话,我们操作 memcache,操作 Redis 经常会要做什么逻辑?假如我们有一个 cache aside 场景,你读了一个 cache,cache miss 要回原 DB,你要把这个缓存回塞回去,甚至你可能这个回塞缓存想异步化,甚至是你要去读这个 DB 的时候要做归并回源(singleflight),我们把这些东西做成一些工具,让它整个回源到 DB 的逻辑更加简单,就是把这些场景描述出来,然后你通过工具可以一键生成这些代码,所以也是会比较方便。 我们再看最后一个,就是 test 的一些工具。我们会基于项目里面,比方说 dao 或者是 service 定义的 interface 去帮你写好 mock 的代码,我直接在里面填,只要填代码逻辑就行了,所以也会加速我们的生产。 上图是 Kratos 的一个 demo,基本就是支持了一些 command。这里就是一个 kratos new kratos-demo 的一个工程,-d YourPath 把它导到某一个路径去,--proto 顺便把 API 里面的 proto 代码也生成了,所以非常简单,一行就可以很快速启动一个 HTTP 或者 gRPC 服务。 我们知道,一个微服务的框架实际非常重,有很多初始化的方式等等,非常麻烦。所以说,你通过脚手架的方式就会非常方便,工具大于约定和文档这个这个理念就是这么来的。 Configuration 讲完工具以后,最后讲一下配置文件。我为什么单独提一下配置文件?实际它也是工程化的一部分。我们一个线上的业务服务包含三大块,第一,应用程序,第二,配置文件,第三,数据集。配置文件最容易导致线上出 bug,因为你改一行配置,整个行为可能跟 App 想要的行为完全不一样。而且我们的代码的开发交付需要经过哪些流程?需要 commit 代码,需要 review,需要单元测试,需要 CD,需要交付到线上,需要灰度,它的整个流程是非常长的。在一步步的环境里面,你的 bug 需要前置解决,越前置解决,成本越低。因为你的代码的开发流程是这么一个 pipeline,所以 bug 最终流到线上的概率很低,但是配置文件没有经过这么复杂的流程,可能大家发现线上有个问题,决定要改个线上配置,就去配置中心或者配置文件改,然后 push 上线,接着就问题了,这个其实很常见。 从 SRE 的角度来说,导致线上故障的主因就是来自配置变更,所以 SRE 很大的工作是控制变更管理,如果能把变更管理做好,实际上很多问题都不会出现。配置既然在整个应用里面这么重要,那在我们整个框架或者在 Go 的工程化实践里面,我们应该对配置文件做一些什么事情? 我觉得是几个。第一,我们的目标是什么?配置文件不应该太复杂,我见过很多框架,或者是业务的一些框架,它实际功能非常强大,但是它的配置文件超级多。我就发现有个习惯,只要有一个同事写错了这个配置,当我新起一个项目的时候,一定会有人把这个错误的配置拷贝到另外一个系统里面去。然后当发现这个应用出问题的时候,我们一般都会内部说一下,你看看其他同事有没有也配错的,实际这个配错概率非常高。因为你的配置选项越多,复杂性越高,它越容易出错。所以第一个要素就是说,尽量避免复杂的配置文件。配得越多,越容易出错。 第二,实际我们的配置方式也非常多,有些用 JSON,有些用 YAML,有些用 Properties,有些用 INI。那能不能收敛成通用的一种方式呢?无论它是用 Python 的脚本也好,或者是用 JSON 也好,你只要有一种唯一的约定,不需要太多样的配置方式,对我们的运维,对我们的 SRE 同时来说,他跨项目的变更成本会变低。 第三,一定要往简单化去努力。这句话其实包含了几个方面的含义。首先,我们很多配置它到底是必须的还是可选的,如果是可选,配置文件是不是就可以把它踢掉,甚至不要出现?我曾经有一次看到我们 Java 同事的配置 retry 有一个重试默认是零,内部重试是 80 次,直接把 Redis cluster 打故障了,为什么?其实这种事故很低级,所以简单化努力的另外一层含义是指,我们在框架层面,尤其是提供 SDK 或者是提供 framework 的这些同事尽量要做一些防御编程,让这种错配漏配也处于一个可控的范围,比方重试 80 次,你觉得哪个 SDK 会这么做?所以这个是我们要考虑的。但是还有一点要强调的是,我们对于业务开发的同事,我们的配置应该足够的简单,这个简单还包含,如果你的日志基本上都是写在这个目录,你就不要提供这个配置给他,反而不容易出错。但是对于我们内部的一些 infrastructure,它可能需要非常复杂的配置来优化,根据我的场景去做优化,所以它是两种场景,一种是业务场景,足够简单,一种是我要针对我的通用的 infrastructure 去做场景的优化,需要很复杂的配置,所以它是两种场景,所以我们要想清楚你的业务到底是哪一种形态。 还有一个问题就是我们配置文件一定要做好权限的变更和跟踪,因为我们知道上线出问题的时候,我们的第一想法不是查 bug,是先止损,止损先找最近有没有变更。如果发现有变更,一般是先回滚,回滚的时候,我们通常只回滚了应用程序,而忘记回滚了配置。每个公司可能内部的配置中心,或者是配置场景,或者跟我们的二进制的交付上线都不一样,那么这里的理念就是你的应用程序和配置文件一定是同一个版本,或者是某种意义上让他们产生一个版本的映射,比方说你的应用程序 1.0,你的配置文件 2.0,它们之间存在一个强绑定关系,我们在回滚的时候应该是一起回滚的。我们曾经也因为类似的一些不兼容的配置的变更,二进制程序上线,但配置文件忘记回滚,出现过事故,所以这个是要强调的。 另外,配置的变更也要经过 review,如果没问题,应该也是按照 App 发布一样,先灰度,再放量,再全量等等类似的一种方式去推,演进式的这种发布,我们也叫滚动发布,我觉得配置文件也是一样的思路。 加入阿里云钉钉群享福利:每周技术直播,定期群内有奖活动、大咖问答 原文链接

有只黑白猫 2020-01-09 17:29:54 0 浏览量 回答数 0

问题

程序员报错行为大赏-配置报错

问问小秘 2020-06-11 13:18:25 6 浏览量 回答数 1
阿里云大学 云服务器ECS com域名 网站域名whois查询 开发者平台 小程序定制 小程序开发 国内短信套餐包 开发者技术与产品 云数据库 图像识别 开发者问答 阿里云建站 阿里云备案 云市场 万网 阿里云帮助文档 免费套餐 开发者工具 企业信息查询 小程序开发制作 视频内容分析 企业网站制作 视频集锦 代理记账服务 2020阿里巴巴研发效能峰会 企业建站模板 云效成长地图 高端建站 阿里云双十一主会场 阿里云双十一新人会场 1024程序员加油包 阿里云双十一拼团会场 场景化解决方案 阿里云双十一直播大厅