数据专栏

智能大数据搬运工,你想要的我们都有

科技资讯:

科技学院:

科技百科:

科技书籍:

网站大全:

软件大全:

【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
摘要: 阿里云宣布弹性容器实例 ECI(Elastic Container Instance)正式商业化。
为了应对业务高峰,打算提前多久执行ECS扩展?
买了ECS虚拟机,容器规格不能完美装箱怎么办?
OS又出patch了,什么时候升级?
如何降低系统的运行成本?
近日,阿里云宣布弹性容器实例 ECI(Elastic Container Instance)正式商业化,ECI 是阿里云践行普惠的云计算理念,将 Serverless 和 Container 技术结合,提供的一款敏捷安全的Serverless容器运行服务。通过 ECI 服务,用户无需管理底层服务器,只需要提供打包好的Docker镜像,即可运行容器,并仅为容器实际运行消耗的资源付费。
弹性计算进入秒级时代
弹性是云计算带给用户的最大价值之一,通过将业务部署到云上,用户基础设施的扩缩容等方面能够更加灵活。ECI 服务构建在阿里云整体计算资源平台之上,与阿里云 ECS 服务使用相同的库存管理与调度策略,切实保证充足的库存,满足用户对极致弹性的需求。在性能方面,ECI 针对资源占用和启动时间进行了深度优化,来达到降低容器组资源开销、加快实例启动时间的目的。弹性容器实例的启动可以在数秒内完成,能够在极短时间内完成海量资源的交付和回收。
同时, ECI 支持更细粒度的资源规格,CPU最小支持0.25c 规格,内存最小支持 0.5GiB规格,并根据用户的实际使用量和使用时长按秒进行计费,减少资源浪费同时降低运行成本。
Serverless基础设施
无服务器 (Serverless) 技术的核心是将用户从繁冗的基础设施运维工作中释放出来,让用户专注于自身业务和服务上。用户使用传统的云计算基础设施过程中需要用户自己掌握专业的运维知识,对底层基础设施的规模、配置、运行时环境进行管理。
ECI 通过结合容器技术和无服务器技术,将云厂商的运维边界从基础设施的整机层面提升到了容器运行时层面。随着服务边界的提升,此前需要用户自己管理的组件如操作系统、软件运行时、监控运维工具等均由 ECI 提供和管理。在使用 ECI 服务后,用户不再需要关心操作系统的升级,安全漏洞的修复这些琐碎的工作。
容器组交付,兼容kubernetes
ECI 使用容器组(Container Group) 作为交付的资源实体,容器组之间共享网络和文件系统。容器组是一组容器的集合,这个概念与 Kubernetes 中 Pod 概念十分接近。通过采用容器组的交付方式,让用户在使用ECI的过程中,能够更加的自然和顺畅的处理容器间的资源共享和业务逻辑依赖关系。
对于使用 Kubernetes 服务的用户,通过使用Virtual Kubelet构建虚拟节点,可以将业务无缝部署到 ECI 上,提升业务系统的弹性和突发处理能力。
点击观看发布会: https://yq.aliyun.com/live/779
了解产品详情: https://www.aliyun.com/product/eci
阿里云弹性容器实例(ECI)商业化发布,打造全新用户体验: https://promotion.aliyun.com/ntms/act/ecishangye.html
作者: 孟蓁蓁
原文链接
本文为云栖社区原创内容,未经允许不得转载。
云计算
2019-01-04 15:55:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
Kubernetes 1.13.0已经正式发布,快速升级(含国内镜像快速下载链接)包括升级kubeadm/kubectl/kubelet版本、拉取镜像、升级Kubernetes集群三个主要步骤。
注意: Kubernetes 1.13.0使用ETCDCTL_API=3,需要将目前集群etcd数据先行备份,再恢复回去。 Kubernetes 1.13.0版本暂时不支持最新的Docker 18.09,只能用Docker 18.06及以下版本,参考《 Ubuntu上软件锁定版本不更新 》安装特定DockerCE版本。 主要变化: kube-apiserver/kube-controller-manager/kube-scheduler/kube-proxy升级到了v1.13.0。 coredns升级到1.2.6。 pause:3.1/etcd:3.2.24没有变化。
1、升级kubeadm/kubectl/kubelet版本 sudo apt install kubeadm=1.13.0-00 kubectl=1.13.0-00 kubelet=1.13.0-00
查看该版本的容器镜像版本: kubeadm config images list
输出如下: ~# kubeadm config images list k8s.gcr.io/kube-apiserver:v1.13.0 k8s.gcr.io/kube-controller-manager:v1.13.0 k8s.gcr.io/kube-scheduler:v1.13.0 k8s.gcr.io/kube-proxy:v1.13.0 k8s.gcr.io/pause:3.1 k8s.gcr.io/etcd:3.2.24 k8s.gcr.io/coredns:1.2.6
2、拉取容器镜像
原始的kubernetes镜像文件在gcr上,不能直接下载。我给镜像到了阿里云的杭州机房的容器仓库里,拉取还是比较快的。 echo "" echo "==========================================================" echo "Pull Kubernetes v1.12.2 Images from aliyuncs.com ......" echo "==========================================================" echo "" MY_REGISTRY=registry.cn-hangzhou.aliyuncs.com/openthings ## 拉取镜像 docker pull ${MY_REGISTRY}/k8s-gcr-io-kube-apiserver:v1.13.0 docker pull ${MY_REGISTRY}/k8s-gcr-io-kube-controller-manager:v1.13.0 docker pull ${MY_REGISTRY}/k8s-gcr-io-kube-scheduler:v1.13.0 docker pull ${MY_REGISTRY}/k8s-gcr-io-kube-proxy:v1.13.0 docker pull ${MY_REGISTRY}/k8s-gcr-io-etcd:3.2.24 docker pull ${MY_REGISTRY}/k8s-gcr-io-pause:3.1 docker pull ${MY_REGISTRY}/k8s-gcr-io-coredns:1.2.6 ## 添加Tag docker tag ${MY_REGISTRY}/k8s-gcr-io-kube-apiserver:v1.13.0 k8s.gcr.io/kube-apiserver:v1.13.0 docker tag ${MY_REGISTRY}/k8s-gcr-io-kube-scheduler:v1.13.0 k8s.gcr.io/kube-scheduler:v1.13.0 docker tag ${MY_REGISTRY}/k8s-gcr-io-kube-controller-manager:v1.13.0 k8s.gcr.io/kube-controller-manager:v1.13.0 docker tag ${MY_REGISTRY}/k8s-gcr-io-kube-proxy:v1.13.0 k8s.gcr.io/kube-proxy:v1.13.0 docker tag ${MY_REGISTRY}/k8s-gcr-io-etcd:3.2.24 k8s.gcr.io/etcd:3.2.24 docker tag ${MY_REGISTRY}/k8s-gcr-io-pause:3.1 k8s.gcr.io/pause:3.1 docker tag ${MY_REGISTRY}/k8s-gcr-io-coredns:1.2.6 k8s.gcr.io/coredns:1.2.6 echo "" echo "==========================================================" echo "Pull Kubernetes v1.13.0 Images FINISHED." echo "into registry.cn-hangzhou.aliyuncs.com/openthings, " echo " by openthings@https://my.oschina.net/u/2306127." echo "==========================================================" echo ""
保存为shell脚本,然后执行。 或者,下载脚本: https://github.com/openthings/kubernetes-tools/blob/master/kubeadm/2-images/
3、升级Kubernetes集群
先查看一下需要升级的各个组件的版本。
使用 kubeadm upgrade plan ,输出的版本升级信息如下: COMPONENT CURRENT AVAILABLE API Server v1.11.2 v1.12.3 Controller Manager v1.11.2 v1.12.3 Scheduler v1.11.2 v1.12.3 Kube Proxy v1.11.2 v1.12.3 CoreDNS 1.1.3 1.2.2 Etcd 3.2.18 3.2.24
确保上面的容器镜像已经下载(如果没有提前下载,可能被网络阻隔导致挂起),然后执行升级: kubeadm upgrade -y apply v1.13.0
看到下面信息,就OK了。 [upgrade/successful] SUCCESS! Your cluster was upgraded to "v1.13.0". Enjoy!
4、工作节点的升级
每个工作节点需要拉取上面对应版本的镜像,以及安装kubelet的对应版本。
检查版本: ~$ kubectl version Client Version: version.Info{Major:"1", Minor:"12", GitVersion:"v1.13.0", GitCommit:"4ed3216f3ec431b140b1d899130a69fc671678f4", GitTreeState:"clean", BuildDate:"2018-10-05T16:46:06Z", GoVersion:"go1.10.4", Compiler:"gc", Platform:"linux/amd64"} Server Version: version.Info{Major:"1", Minor:"12", GitVersion:"v1.13.0", GitCommit:"4ed3216f3ec431b140b1d899130a69fc671678f4", GitTreeState:"clean", BuildDate:"2018-10-05T16:36:14Z", GoVersion:"go1.10.4", Compiler:"gc", Platform:"linux/amd64"}
查看Pod信息: kubectl get pod --all-namespaces
完成。
更多参考: Ubuntu上软件锁定版本不更新 Ubuntu 18.04 设置多网卡多端口聚合 快速建立Kubernetes集群,从零开始 Ubuntu 18.04 LTS安装Kubernetes 1.11 Kubernetes集群高可用的策略和实践
云计算
2018-12-10 23:03:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
随着阿里大数据产品业务的增长,服务器数量不断增多,IT运维压力也成比例增大。各种软、硬件故障而造成的业务中断,成为稳定性影响的重要因素之一。本文详细解读阿里如何实现硬件故障预测、服务器自动下线、服务自愈以及集群的自平衡重建,真正在影响业务之前实现硬件故障自动闭环策略,对于常见的硬件故障无需人工干预即可自动闭环解决。
1.背景
1.1.面临挑战
对于承载阿里巴巴集团95%数据存储及计算的离线计算平台MaxCompute,随着业务增长,服务器规模已达到数十万台,而离线作业的特性导致硬件故障不容易在软件层面被发现,同时集团统一的硬件报障阈值常常会遗漏一些对应用有影响的硬件故障,对于每一起漏报,都对集群的稳定性构成极大的挑战。
针对挑战,我们面对两个问题: 硬件故障的及时发现与故障机的业务迁移。 下面我们会围绕这两个问题进行分析,并详细介绍落地的自动化硬件自愈平台——DAM。在介绍之前我们先了解下飞天操作系统的应用管理体系——天基(Tianji)。
1.2.天基应用管理
MaxCompute是构建在阿里数据中心操作系统——飞天(Apsara)之上,飞天的所有应用均由天基管理。天基是一套自动化数据中心管理系统,管理数据中心中的硬件生命周期与各类静态资源(程序、配置、操作系统镜像、数据等)。而我们的硬件自愈体系正是与天基紧密结合,利用天基的Healing机制构建面向复杂业务的硬件故障发现、自愈维修闭环体系。
透过天基,我们可以将各种物理机的指令(重启、重装、维修)下发,天基会将其翻译给这台物理机上每个应用,由应用根据自身业务特性及自愈场景决策如何响应指令。
2.硬件故障发现
2.1.如何发现
我们所关注的硬件问题主要包含:硬盘、内存、CPU、网卡电源等,下面列举对于常见硬件问题发现的一些手段和主要工具:
在所有硬件故障中,硬盘故障占比50%以上,下面分析一下最常见的一类故障:硬盘媒介故障。通常这个问题表象就是文件读写失败/卡住/慢。但读写问题却不一定是媒介故障产生,所以我们有必要说明一下媒介故障的在各层的表象。
a. 系统日志报错是指在/var/log/messages中能够找到类似下面这样的报错

Sep 3 13:43:22 host1.a1 kernel: : [14809594.557970] sd 6:0:11:0: [sdl] Sense Key : Medium Error [current]
Sep 3 20:39:56 host1.a1 kernel: : [61959097.553029] Buffer I/O error on device sdi1, logical block 796203507
b. tsar io指标变化是指rs/ws/await/svctm/util等这些指标的变化或突变,由于报错期间会引起读写的停顿,所以通常会体现在iostat上,继而被采集到tsar中。
● 在tsar io指标中,存在这样一条规则让我们区分硬盘工作是否正常 qps=ws+rs<100 & util>90,假如没有大规模的kernel问题,这种情况一般都是硬盘故障引起的。
c. 系统指标变化通常也由于io 变化引起,比如 D住引起load升高等。
d. smart值跳变具体是指197(Current_Pending_Sector)/5(Reallocated_Sector_Ct)的跳变。这两个值和读写异常的关系是:
● 媒介读写异常后,在smart上能观察到197(pending) +1,表明有一个扇区待确认。
● 随后在硬盘空闲的时候,他会对这个197(pending)中攒的各种待确认扇区做确认,如果读写通过了,则197(pending) -1,如果读写不通过则 197(pending)-1 且 5(reallocate)+1。
总结下来,在整条报错链路中,只观察一个阶段是不够的,需要多个阶段综合分析来证明硬件问题。由于我们可以严格证明媒介故障,我们也可以反向推导,当存在未知问题的时候能迅速地区分出是软件还是硬件问题。
上述的工具是结合运维经验和故障场景沉淀出来,同时我们也深知单纯的一个发现源是远远不够的,因此我们也引入了其他的硬件故障发现源,将多种检查手段结合到一起来最终确诊硬件故障。
2.2.如何收敛
上一章节提到的很多工具和路径用来发现硬件故障,但并不是每次发现都一定报故障,我们进行硬件问题收敛的时候,保持了下面几个原则:
● 指标尽可能与应用/业务无关: 有些应用指标和硬件故障相关性大,但只上监控,不作为硬件问题的发现来源。 举一个例子,当io util大于90%的时候硬盘特别繁忙,但不代表硬盘就存在问题,可能只是存在读写热点。我们只认为io util>90且iops<30 超过10分钟的硬盘可能存在硬件问题。
● 采集敏感,收敛谨慎: 对于可能的硬件故障特征都进行采集,但最终自动收敛分析的时候,大多数采集项只做参考,不作为报修依据。 还是上一个硬盘io util的例子,如果单纯出现io util>90且iops<30的情况,我们不会自动报修硬盘,因为kernel问题也可能会出现这个情况。只有当 smartctl超时/故障扇区 等明确故障项出现后,两者关联才确诊硬盘故障,否则只是隔离观察,不报修。
2.3.覆盖率
以某生产集群,在20xx年x月的IDC工单为例,硬件故障及工单统计如下:
去除带外故障的问题,我们的硬件故障发现占比为97.6%。
3.硬件故障自愈
3.1 自愈流程
针对每台机器的硬件问题,我们会开一个自动轮转工单来跟进,当前存在两套自愈流程:【带应用维修流程】和【无应用维修流程】,前者针对的是可热拔插的硬盘故障,后者是针对余下所有的整机维修硬件故障。
在我们的自动化流程中,有几个比较巧妙的设计:
a. 无盘诊断
● 对于宕机的机器而言,无法进无盘(ramos)才开【无故宕机】维修工单,这样能够大量地减少误报,减少服务台同学负担。
● 无盘中的压测可以完全消除当前版本的kernel或软件的影响,真实地判断出硬件是否存在性能问题。
b. 影响面判断/影响升级
● 对于带应用的维修,我们也会进行进程是否D住的判断。如果存在进程D住时间超过10分钟,我们认为这个硬盘故障的影响面已扩大到了整机,需要进行重启消除影响。
● 在重启的时候如果出现了无法启动的情况,也无需进行人工干预,直接进行影响升级,【带应用维修流程】直接升级成【无应用维修流程】。
c. 未知问题自动化兜底
● 在运行过程中,会出现一些机器宕机后可以进无盘,但压测也无法发现任何硬件问题,这个时候就只能让机器再进行一次装机,有小部分的机器确实在装机过程中,发现了硬件问题继而被修复了。
d. 宕机分析
● 整个流程巧妙的设计,使得我们在处理硬件故障的时候,同时具备了宕机分析的能力。
● 不过整机流程还以解决问题为主导向,宕机分析只是副产品。
● 同时,我们也自动引入了集团的宕机诊断结果进行分析,达到了1+1>2的效果。
3.2.流程统计分析
如果是同样的硬件问题反复触发自愈,那么在流程工单的统计,能够发现问题。例如联想RD640的虚拟串口问题,在还未定位出根因前,我们就通过统计发现了: 同个机型的机器存在反复宕机自愈的情况,即使机器重装之后,问题也还是会出现。 接下来我们就隔离了这批机器,保障集群稳定的同时,为调查争取时间。
3.3.业务关联误区
事实上,有了上面这套完整的自愈体系之后,某些业务上/kernel上/软件上需要处理的问题,也可以进入这个自愈体系,然后走未知问题这个分支。其实硬件自愈解决业务问题,有点饮鸩止渴,容易使越来越多还没想清楚的问题,尝试通过这种方式来解决兜底。
当前我们逐步地移除对于非硬件问题的处理,回归面向硬件自愈的场景(面向软件的通用自愈也有系统在承载,这类场景与业务的耦合性较大,无法面向集团通用化),这样也更利于软硬件问题分类和未知问题发现。
4.架构演进
4.1.云化
最初版本的自愈架构是在每个集群的控制机上实现,因为一开始时候运维同学也是在控制机上处理各种问题。但随着自动化地不断深入,发现这样的架构严重阻碍了数据的开放。于是我们采用中心化架构进行了一次重构,但中心化架构又会遇到海量数据的处理问题,单纯几个服务端根本处理不过来。
因此我们对系统进一步进行分布式服务化的重构,以支撑海量业务场景,将架构中的各个模块进行拆解, 引入了 阿里云日志服务(sls)/阿里云流计算(blink)/阿里云分析数据库(ads) 三大神器, 将各个采集分析任务由云产品分担,服务端只留最核心的硬件故障分析和决策功能。
下面是DAM1与DAM3的架构对比
4.2.数据化
随着自愈体系的不断深入,各阶段的数据也有了稳定的产出,针对这些数据的更高维分析,能让我们发现更多有价值且明确的信息。同时,我们也将高维的分析结果进行降维,采用健康分给每台机器打标。通过健康分,运维的同学可以快速知晓单台机器、某个机柜、某个集群的硬件情况。
4.3.服务化
基于对全链路数据的掌控,我们将整个故障自愈体系,作为一个硬件全生命周期标准化服务,提供给不同的产品线。基于对决策的充分抽象,自愈体系提供各类感知阈值,支持不同产品线的定制,形成适合个性化的全生命周期服务。
5.故障自愈闭环体系
在AIOps的感知、决策、执行闭环体系中,软件/硬件的故障自愈是最常见的应用场景,行业中大家也都选择故障自愈作为首个AIOps落地点。在我们看来,提供一套通用的故障自愈闭环体系是实现AIOps、乃至NoOps(无人值守运维)的基石,应对海量系统运维,智能自愈闭环体系尤为重要。
5.1.必要性
在一个复杂的分布式系统中,各种架构间不可避免地会出现运行上的冲突,而这些冲突的本质就在于信息不对称。而信息不对称的原因是,每种分布式软件架构在设计都是内敛闭环的。现在,通过各种机制各种运维工具,可以抹平这些冲突,然而这种方式就像是在打补丁,伴随着架构的不断升级,补丁似乎一直都打不完,而且越打越多。因此,我们有必要将这个行为抽象成自愈这样一个行为,在架构层面显式地声明这个行为,让各软件参与到自愈的整个流程中,将原本的冲突通过这种方式转化为协同。
当前我们围绕运维场景中最大的冲突点:硬件与软件冲突,进行架构和产品设计,通过自愈的方式提升复杂的分布式系统的整体鲁棒性。
5.2.普适性
透过大量机器的硬件自愈轮转,我们发现:
● 被纳入自愈体系的运维工具的副作用逐渐降低(由于大量地使用运维工具,运维工具中的操作逐渐趋于精细化)。
● 被纳入自愈体系的人工运维行为也逐渐变成了自动化。
● 每种运维动作都有了稳定的SLA承诺时间,不再是随时可能运行报错的运维脚本。
因此,自愈实际上是在复杂的分布式系统上,将运维自动化进行充分抽象后,再构筑一层闭环的架构,使得架构生态形成更大的协调统一。
作者: 隐林
原文链接
本文为云栖社区原创内容,未经允许不得转载。
云计算
2018-11-30 15:45:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
伴随着电商等用户在双11、秒杀之类业务高峰期流量的迅猛增长,对虚拟机网络性能提升的需求日益迫切,25G网络逐渐成为一种标配。为了解决传统纯软件Virtual Switch方案带来的性能瓶颈,我们在调研了业界主流的智能网卡方案之后,最终决定采用基于OpenvSwitch的开源方案,并成功在公有云落地应用。
相较于传统方案,新的智能网卡方案在整个switch的转发上性能为小包24Mpps,单VF的接收性能达15Mpps,网卡整体性能提升10倍以上。应用于云主机后,可将其网络能力提升至少4倍,时延降低3倍,有效解决电商等业务高峰期的稳定性问题。本文将详细讲讲新方案从选型到落地过程中遇到的坑及解决之道,希望能给人以借鉴与启发。
业界主流的智能网卡方案对比
传统的软件Virtual Switch的性能瓶颈,在于其从物理网卡接收报文后,是按照转发逻辑发送给vhost线程,vhost再传递给虚拟机的方式执行,如此一来,vhost的处理能力就成为了影响虚拟机网络性能的关键。
于是,在宿主机上通过25G SmartNIC对网络流量进行卸载成为业界公认的主流方向。现阶段,智能网卡的实现百花齐放,例如:AWS采用基于通用ARM的众核方案、Azure采用基于FPGA的方案、华为云采用基于专用网络处理器(NP)的方案、阿里云采用基于可编程ASIC芯片的方案。就目前来看各个方案各有优劣,并没有特别突出一统天下的方案。
基于通用ARM、MIPS的众核方案,简单将原来跑在宿主机上的vSwitch移植到网卡上,既可以支持Linux Kernel也可以支持DPDK,从而达到释放宿主机计算资源的目的。而其他基于FPGA、NP和可编程ASIC的方案,大多在网卡上维护一个快速转发路径(Fast Path),当收到报文后,首先检查是否在Fast Path已经缓存了该类报文的处理规则,如果找到,则直接按照规则执行动作,否则就转发到Slow Path去处理。而这个Slow Path可以是DPDK,也可以是Linux Kernel。
因此,Fast Path最重要的是看是否支持足够多的Action,以及自定义Action的可扩展性。Slow Path和Fast Path通信除了各厂商的私有接口外,也有标准的TC Offload接口和DPDK提供的RTE Flows接口。
不过,FPGA的功耗和成本较高,研发周期长且不能快速地落地,从硬件到软件都需要投入大量的资源。而其他基于第三方网卡厂家的软件定制化方案,对于网卡软件的稳定性严重依赖于第三方厂商, 遇到问题时不能快速的定位排障。
我们的选择
在业界没有非常完美的实现方案下,我们开始将目光转向开源技术,由于OpenvSwitch本身支持基于Linux Tc Flower Offload卸载接口, 对现有控制管理面影响小,并且能够快速应用落地开发给用户使用。因此,我们选择了基于Tc Flower Offload的OpenvSwitch开源方案。
报文处理可以被看做是通过一系列顺序操作将一个报文从接收发送到最终的目的地,最典型处理的是发送或者丢弃。这一系列操作通常是连续的match然后执行action。Linux kernel TC子系统的Tc Flower可以将报文基于流进行控制转发,而流通常是基于报文常见域来分类,这些域组成了名叫flow key的match项,flow key包括了报文常见域和可选的隧道信息,TC actions对报文执行丢弃、修改、发送等操作。
这个方式类似于OpenvSwitch的分类方式。通过Tc Flower分类器的offload对于flow-based的系统提供强有力的方法来增加吞吐量并减少CPU利用率。
基于OpenvSwitch卸载的智能网卡落地实践
方案选定之后,我们开始在原有架构上进行落地实践,这个过程并非一帆风顺,在具体落地的过程中,我们也遇到了几个方面的问题:
1. 虚拟机的迁移
落地之初,首先要进行虚拟机的迁移。因为各个厂商的SmartNIC都是基于VF passthrough的方案,而VF的不可迁移性为虚拟机迁移带来了困难。在业界,Azure主要通过bonding VF和virtio-net device的方案解决这一问题,但是这种方法需要用户在一定层面上的介入,带来了虚拟机镜像管理的问题。
通过调研upstream( https://patchwork.ozlabs.org
/cover/920005/)“Enable virtio_net toact as a standby for a passthrough device”方案,我们发现此环境下,用户不需要手工设置bonding操作或者制作特定的镜像,可以完美的解决用户介入的问题。最终,我们采用了 VF+standby virtio-net的方式进行虚拟机的迁移。具体迁移过程为:
创建虚拟机自带virtio-net网卡,随后在Host上选择一个VF 作为一个hostdev的网卡,设置和virtio-net网卡一样的MAC地址,attach到虚拟机里面,这样虚拟机就会对virtio-net和VF网卡自动形成类似bonding的功能,此时,在Host上对于虚拟机就有两个网络Data Plane;
virtio-net backend的tap device在虚拟机启动时自动加入到Host的OpenvSwitch bridge上,当虚拟机网卡进行切换的时候datapath也需要进行切换。VF attach到虚拟机后,在OpenvSwitch bridge上将VF_repr置换掉tap device;
2. VXLAN encap/decap不能offload
接下来需要做SmartNIC端的适配。以Mellanox CX5网卡为例,软件环境包括OpenvSwitch-2.10.0、ukernel-4.14和MLNX_OFED-4.4-1.0.0.0。由于mlx5_coredriver最新版本并不支持Ethernet over GRE tunnel offload,所以我们先通过VXLAN进行了测试。
如下图,eth2 是PF, mlx_0是VF0的representor,通过以下命令就进行初始化。首先,开启一个VF设备,将VF设备在driver mlx5_core上解绑,设置PF设备的IP地址,设置PF网卡相关switched模式,开启PF网卡encap功能。
OpenvSwitch 配置如下:虚拟机VF利用representor mlx_0连接到 br0,通过vxlan0 发送给对端。VXLAN隧道本地地址为172.168.152.75,对端地址为172.168.152.208。
Encap/decap报文都能有效收发,但是并没有offload到网卡上:
首先发现dmesg显示错误:
查询原因后发现OpenvSwitch在创建vxlan device时,并没有将vxlan dport信息注册进网卡。OpenvSwitch通常是通过 vxlan device的netdev_ops->ndo_add_vxlan_port接口完成这一功能,但是在较新的内核比如ukernel-4.14中是通过netdev_ops->ndo_udp_tunnel_add接口完成的。
后来我们给OpenvSwitch 提交patch “datapath: support upstream ndo_udp_tunnel_add in net_device_ops” https://patchwork.ozlabs.org/patch/953417/来解决这一问题。
3. Decap报文不能offload
解决上述问题后,egress方向的encap报文虽然可以有效的offload,但是ingress decap报文却依然不可以。
case2的vxlan decap打印是在mlx_0 VF上,因此我们推测decap规则可能也下发到了VF port上。由于tc规则设置于vxlan_sys的虚拟device上,因而很可能是在寻找设置的物理网卡上出现了问题。

通过代码分析,可以看到虚拟device的设置物理网卡是通过action device找到的,即mlx_0 VF,而OpenvSwitch下发给mlx_0 VF的tc_flower带着egress_dev为true的标志,由此推断,TC规则是设置在VF对应的PF上。
沿着此推断,我们查看了mlx5 driver的代码backports/0060-BACKPORT-drivers-net-ethernet-mellanox-mlx5-core-en_.patch
发现ukernel-4.14可以支持cls_flower->egress_devflag,但并不支持HAVE_TC_TO_
NETDEV_EGRESS_DEV。因此,我们断定mlx5_core driver在内核兼容性的判断上出现问题。随后,我们提交了相应的patch给Mellanox解决此问题。
4. Backend tap device encap报文被丢弃
在做live migration时需要用到backend tap sdevice,OpenvSwitch在发送报文时将tc规则设置到了tap device上,依靠tc的in_sw方式进行tunnel_key set然后转发给gre_sys device进行发送,但是gre_sys device直接将报文丢弃,这让我们非常诧异。
分析其原因,我们发现,在tc offload的in_sw情况下,报文会绕过 OpenvSwitch的转发逻辑直接通过gre_sysdevice进行发送。而我们使用的是OpenvSwitch-2.10.0所带的内核模块代码,内核模块兼容性编译时判断ukernel-4.14并不支持USE_UPSTREAM_TUNNEL,所以,gre_sys device并不是内核自带的gre设备,而是OpenvSwitch自己创建的一种不具备nodo_start_xmit函数的设备,OpenvSwitch内核态gre tunnel的转发并不通过gre_sys device真正做发送。
虽然ukernel-4.14不支持USE_UPSTREAM_
TUNNEL,但对于内核自带的gre device是能支持通过ip_tunnel_key进行nodo_start_xmit发送的,因而对于内核自带的gredevice来说,USE_UPSTREAM_TUNNEL的标志是有效的。
由此,OpenvSwitch可以通过acinclude.m4文件去判断
由于OpenvSwitch判断这个功能根据gre以及erspan来决定的,但ukernel-4.14对于erspan来说,USE_UPSTREAM_TUNNEL的标志是无效的。
之后,我们引入上游 https://patchwork.ozlabs.org/
cover/848329/ patch系列“ERSPAN version 2(type III) support”,使OpenvSwitch感知内核支持USE_UPSTREAM_TUNNEL来解决gre_sys device drop报文的问题。
5. Ethernet over gre tunnel不能offload
打入Mellanox提供了基于ethernet over gre的patch后,我们又发现ingress的decap方向不能做offload。
这是由于在gre_sys device上并没有生成tc ingress qdisc,OpenvSwitch 通过vport的get_ifinex获取device的ifindex设置tc 规则,而gre tunnel type的vport 并没有enable get_ifindex功能。
我们查找了upstream的OpenvSwitch,并通过patch“netdev-vport: Make gre netdev type to use TC rules”解决这个问题。
此外,egress encap offload的报文也不能被对方接收,通过抓包发现gre header里面带了csum field,但是OpenvSwitch上的gre tunnel并没有设置csum options。
研究代码cls_tunne_key的set action里默认是带csum field的,必须通过显示的设置TCA_TUNNEL_KEY_NO_CSUM才会关闭csum filed。而OpenvSwicth-2.10.0没有做这方面的适配。
我们查找了upstream的OpenvSwitch,并最终通过patch “netdev-tc-offloads: TC csum option is notmatched with tunnel configuration”解决了这一问题。
综上,我们详细介绍了UCloud 25G SmartNIC的选型方案,以及在实践的过程中遇到的各种技术问题及其解决方案,通过对ukernel、OpenvSwitch、mlx5_core driver的功能补全和bugfix,最后将这一开源方案成功落地应用。
性能对比
落地应用后,我们基于OpenvSwitch卸载的高性能25G智能网卡方案下,从vSwitch性能、虚拟网卡性能等维度进行了系列性能测试。可以看到,
单VF的接收性能可达15Mpps:
整个vSwitch的转发性能为小包24Mpps:
而一般传统纯软件环境下,vSwitch的转发性能为2Mpps,虚拟网卡的接收性能仅1.5Mpps左右。相较于原方案,网卡整体性能提升了10倍以上。
应用在云主机时,同样8核配置的主机,以收向UDP小包(1 Byte)场景为例,新方案的PPS值可达469w,而原值为108w。
后续计划
目前,该方案已经成功应用于公有云上,将作为网络增强2.0云主机推出,使云主机的网络能力提升到目前网络增强1.0版本的4倍以上。后续我们计划将该方案移植到Bare Metal物理云主机产品上,让公有云和物理云主机在功能和拓扑上一致,并研究有状态的Firewall/NAT的Offload。
云计算
2018-11-22 16:13:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
近期,我们推出高性能SSD云盘,满足用户对高性能的场景需求。SSD云盘相比普通云盘,IOPS提升了13倍,稳定性提升了3倍,平均时延降低了10倍。为了做到这些,我们从去年10月份开始对云盘的架构进行了重新设计,充分减少时延和提升IO能力;并通过复用部分架构和软件,提供性能更好、更稳定的普通云盘;同时逐步引入Stack/Kernel Bypass技术,打造下一代超高性能存储。新架构推出后,已服务了现网用户的3400多个云盘实例,总存储容量达800 TB,集群每秒IOPS均值31万。
架构升级要点
通过对现阶段问题和需求的分析,我们整理了这次架构升级的具体要点:
1 、解决原有软件架构不能充分发挥硬件能力的局限
2 、支持SSD云盘,提供QOS保证,充分发挥后端NVME物理盘的IOPS和带宽性能,单个云盘IOPS可达2.4W
3 、支持更大容量云盘,32T甚至更大
4 、充分降低IO流量的热点问题
5 、支持并发创建几千块云盘,支持并发挂载几千块云盘
6 、支持老架构云盘在线向新架构迁移,支持普通云盘在线迁移至SSD云盘
新架构改造实践
改造一:IO路径优化
老架构中,整个IO路径有三大层,第一层宿主Client侧,第二层Proxy侧,第三层存储Chunk层。Proxy负责IO的路由获取以及缓存;IO的读写转发到下一层存储层,负责IO写三份复制。
而新架构中,路由获取交给了Client,IO读写Client可直接访问存储Chunk层,写三份复制也交给了Chunk。整个IO路径变成了2层,一层是宿主Client侧, 另一层存储Chunk层。
架构升级之后,对读IO,一次网络请求直达到后端存储节点,老架构都是2次。对写IO,主副本IO一次网络请求直达后端存储节点,另外2副本经过主副本,经历两次网络转发,而老架构三个副本均为两次。读IO时延平均降低0.2-1ms,写尾部时延减低,也有效的降低总体时延。
改造二:元数据分片
分布式存储中,会将数据进行分片,从而将每个分片按多副本打散存储于集群中。如下图,一个200G的云盘,如果分片大小是1G,则有200个分片。老架构中,分片大小是1G,在实际业务过程中我们发现,部分业务的IO热点集中在较小范围内,如果采用1G分片,普通SATA磁盘性能会很差。并且在SSD云盘中,也不能均匀的将IO流量打散到各个存储节点上。
新架构中,我们支持了1M大小的分片。1M分片,可以充分使用整个集群的能力。高性能存储中,因为固态硬盘性能较好,业务IO热点集中在较小范围内,也能获得较好的性能。
但UCloud元数据采用的是预分配和挂载方案,申请云盘时系统直接分配所有元数据并全部加载到内存。分片过小时,需要同时分配或挂载的元数据量会非常大,容易超时并导致部分请求失败。
例如,同时申请100块300G的云盘,如果按1G分片,需要同时分配3W条元数据;如果按照1M分片,则需要同时分配3000W条元数据。
为了解决分片变小导致的元数据分配/挂载失败问题,我们尝试改变IO时的分配策略,即云盘挂载时,将已分配的元数据加载到内存中。IO时,如果IO范围命中已经分配路由,则按内存中的路由进行IO;如果IO范围命中未分配路由,则实时向元数据模块请求分配路由,并将路由存储在内存中。
按IO时分配,如果同时申请100块300G的云盘, 同时挂载、同时触发IO,大约会产生1000 IOPS,偏随机。最坏情况会触发1000 * 100 = 10W 元数据分配。在IO路径上,还是存在较大消耗。
最终,新架构中我们放弃了中心节点存储分片元数据的方案,采用了以一套统一规则去计算获取路由的方案。
该方案中,Client 端和集群后端采用同样的计算规则R(分片大小、pg个数、映射方法、冲突规则);云盘申请时,元数据节点利用计算规则四元组判断容量是否满足;云盘挂载时,从元数据节点获取计算规则四元组; IO时,按计算规则R(分片大小、pg个数、映射方法、冲突规则)计算出路路由元数据然后直接进行IO。通过这种改造方案,可以确保在1M数据分片的情况下,元数据的分配和挂载畅通无阻,并节省IO路径上的消耗。
改造三:支持SSD高性能云盘
通过上述对比可以看到,NVME固态硬盘性能百倍于机械盘,但需要软件的配套设计,才能利用NVME固态硬盘的能力。
SSD云盘提供QoS保证,单盘IOPS:min{1200+30*容量,24000} 对于SSD云盘,传统的单线程模式会是瓶颈,难以支持后端NVME硬盘几十万的IOPS以及1-2GB的带宽,所以我们采用了多线程模型。
为了较快推出SSD云盘,我们还是采用了传统TCP网络编程模型,未使用Kernel Bypass。同时,通过一些软件细节的优化,来减少CPU消耗。
目前,单个线程写可达6W IOPS,读可达8W IOPS,5个线程可以基本利用NVME固态硬盘的能力。目前我们能提供云盘IO能力如下:
改造四:防过载能力
对于普通云盘,新架构的软件不再是瓶颈,但一般的机械硬盘而言,队列并发大小只能支持到32-128左右。100块云盘,持续同时各有几个IO命中一块物理HDD磁盘时,因为HDD硬盘队列并发布较小,会出现较多的io_submit耗时久或者失败等问题。Client侧判断IO超时后,会重试IO发送,造成Chunk端TCP缓冲区积压越来越多的IO包,越来越多的超时积压在一起,最终导致系统过载。
对于普通云盘,需控制并发提交队列大小,按队列大小,依次遍历所有云盘,下发各云盘的IO,如上图的1、2、3。实际代码逻辑里,还需要考虑云盘大小的权重。
对于SSD云盘来说,传统的单个线程会是瓶颈,难以支持几十万的IOPS以及1-2GB的带宽。
压测中,我们模拟了热点集中在某个线程上的场景,发现该线程CPU基本处于99%-100%满载状态,而其它线程则处于空闲状态。后来,我们采用定期上报线程CPU以及磁盘负载状态的方式,当满足某线程持续繁忙而有线程持续空闲时,选取部分磁盘分片的IO切换至空闲线程,来规避部分线程过载。
改造五:在线迁移
老架构普通云盘性能较差,部分普通云盘用户业务发展较快,希望从普通云盘迁移至SSD云盘,满足更高的业务发展需要。目前线上存在2套老架构,为了快速达到在线迁移的目的,我们第一期决定从系统外围支持在线迁移。
迁移流程如下:
1 后端设置迁移标记;
2 Qemu连接重置到Trans Client;
3 写IO流经过Trans Client 到Trans模块,Trans模块进行双写:一份写老架构,一份写新架构;
4 Trigger 遍历磁盘, 按1M大小触发数据命令给Trans触发数据后台搬迁。未完成搬迁前,IO读经Trans向旧架构Proxy读取;
5 当全部搬迁完成后,Qemu连接重置到新架构Client,完成在线迁移。
加一层Trans及双写,使迁移期间存在一些性能损耗。但对于普通云盘,迁移期间可以接受。我们目前对于新架构也正在建设基于Journal的在线迁移能力,目标在迁移期间,性能影响控制在5%以下。
经过上述系列改造,新的云硬盘架构基本完成了最初的升级目标。目前,新架构已经正式上线并成功运用于日常业务当中。在这里,也谈谈我们正在研发的几项工作。
1、容量具备无限扩展能力
每个可用区,会存在多个存储集群Set. 每个Set可提供1PB左右的存储(我们并没有让集群无限扩容)。当Set1的云盘需要从1T扩容至32T 100T时,可能会碰到Set1的容量不足的问题。
因此,我们计划将用户申请的逻辑盘,进行分Part, 每个Part可以申请再不用的Set中,从而具备容量可以无限扩展的能力。
2、超高性能存储
近10年,硬盘经过 HDD -> SATA SSD -> NVME SSD的发展。同时,网络接口也经历了10G -> 25G -> 100G的跨越式发展。然而CPU主频几乎没有较大发展,平均在2-3GHZ,我们使用的一台物理机可以挂6-8块NVME盘,意味着一台物理机可以提供300-500万的IOPS.
传统应用服务器软件模式下,基于TCP的Epoll Loop, 网卡的收发包,IO的读写要经过用户态、内核态多层拷贝和切换,并且需要靠内核的中断来唤醒,软件很难压榨出硬件的全部能力。例如在IOPS和时延上,只能靠叠加线程去增加IOPS,然而,IOPS很难随着线程的增加而线性增长,此外时延抖动也较高。
我们希望通过引入零拷贝、用户态、轮询的技术方案来优化上图中的三种IO路径,从而减少用户态、内核态、协议栈的多层拷贝和切换,并结合轮询一起压榨出硬件的全部能力。
最终,我们选择了RDMA,VHOST,SPDK三个技术方案。
方案一:超高性能存储-VHOST
传统模式如下,IO经过虚机和Qemu驱动,再经过Unix Domain Socket到Client。 经过多次用户态内核态,以及IO路径上的拷贝。
而利用VHOST User模式,可以利用共享内存进行用户态的VM到Client侧的数据传输。在实际中,我们利用了SPDK VHOST。
研发环境中,我们将Client收到IO请求后立即模拟返回给VM,也就是不向存储后端发送数据,得到的数据如上图。单队列时延可以降低90us,IOPS有几十倍的提升。
方案二:超高性能存储-RDMA+SPDK
RDMA提供了一种消息服务,应用程序利用RDMA可以直接访问远程计算机上的虚拟内存,RDMA减少了CPU占用以及内存带宽瓶颈,提供了很高的带宽,并利用Stack Bypass和零拷贝技术,提供了低延迟的特性。
SPDK可以在用户态高并发零拷贝地以用户态驱动直接访问NVME 固态硬盘。并利用轮询模式避免了内核上下文切换和中断处理带来的开销。
目前团队正在研发利用RDMA和SPDK的存储引擎框架,研发测试环境中,后端用一块NVME固态盘,我们在单队列和IOPS上可以提升如下:
包括SPDK VHOST USER的Client侧,以及RDMA+SPDK的存储侧方案,预计12月会推出公测版。
总结
过去的一年时间里,我们重新设计和优化了云盘的存储架构,解决了过去老架构的诸多问题,并大幅提升了性能。经过4个月公测,SSD云盘和新架构普通云盘都于8月份全量上线,并保持了极高的稳定性,目前单盘可提供2.4W IOPS。
同时,为了追求更佳的IO体验,我们引入Kernel/Stack Bypass技术方案,正在打造更高性能、更低时延的存储引擎,预计12月份会推出超高性能云盘公测版,敬请期待!
云计算
2018-11-12 11:08:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
近日,Nacos 0.3.0 正式发布,该版本旨在增强对服务列表,健康状态管理,服务治理,分布式配置管理等方面的管控能力,以便进一步帮助用户降低管理微服务应用架构的成本,在第一版的 UI 功能规划中,将提供包括下列基本功能:
1、服务管理 服务列表及服务健康状态展示 服务元数据存储及编辑 服务流量权重的调整 服务优雅上下线
2、配置管理 多种配置格式编辑 编辑DIFF 示例代码 推送状态查询 配置版本及一键回滚
3、命名空间
特性详解 - 服务管理
开发者或者运维人员往往需要在服务注册后,通过友好的界面来查看服务的注册情况,包括当前系统注册的所有服务和每个服务的详情。并在有权限控制的情况下,进行服务的一些配置的编辑操作。Nacos在这个版本开放的控制台的服务发现部分,主要就是提供用户一个基本的运维页面,能够查看、编辑当前注册的服务。
服务列表管理
服务列表帮助用户以统一的视图管理其所有的微服务以及服务健康状态。整体界面布局是左上角有服务的搜索框和搜索按钮,页面中央是服务列表的展示。服务列表主要展示服务名、集群数目、实例数目、健康实例数目和详情按钮五个栏目。
在服务列表页面点击详情,可以看到服务的详情。可以查看服务、集群和实例的基本信息。
服务流量权重支持及流量保护
Nacos 为用户提供了流量权重控制的能力,同时开放了服务流量的阈值保护,以帮助用户更好的保护服务服务提供者集群不被意外打垮。如下图所以,可以点击实例的编辑按钮,修改实例的权重。如果想增加实例的流量,可以将权重调大,如果不想实例接收流量,则可以将权重设为0。
服务元数据管理
Nacos提供多个维度的服务元数据的暴露,帮助用户存储自定义的信息。这些信息都是以K-V的数据结构存储,在控制台上,会以k1=v1,k2=v2这样的格式展示。类似的,编辑元数据可以通过相同的格式进行。例如服务的元数据编辑,首先点击服务详情页右上角的“编辑服务”按钮,然后在元数据输入框输入:version=1.0,env=prod。
点击确认,就可以在服务详情页面,看到服务的元数据已经更新了。
服务优雅上下线
Nacos还提供服务实例的上下线操作,在服务详情页面,可以点击实例的“上线”或者“下线”按钮,被下线的实例,将不会包含在健康的实例列表里。
特性详解 - 配置管理
Nacos支持基于Namespace和Group的配置分组管理,以便用户更灵活的根据自己的需要按照环境或者应用、模块等分组管理微服务以及Spring的大量配置,在配置管理中主要提供了配置历史版本、回滚、订阅者查询等核心管理能力。
多配置格式编辑器
Nacos支持 YAML、Properties、TEXT、JSON、XML、HTML 等常见配置格式在线编辑、语法高亮、格式校验,帮助用户高效编辑的同时大幅降低格式错误带来的风险。
Nacos支持配置标签的能力,帮助用户更好、更灵活的做到基于标签的配置分类及管理。同时支持用户对配置及其变更进行描述,方面多人或者跨团队协作管理配置。
编辑DIFF
Nacos支持编辑DIFF能力,帮助用户校验修改内容,降低改错带来的风险
示例代码
Nacos提供示例代码能力,能够让新手快速使用客户端编程消费该配置,大幅降低新手使用门槛。
监听者查询
Nacos提供配置订阅者即监听者查询能力,同时提供客户端当前配置的MD5校验值,以便帮助用户更好的检查配置变更是否推送到 Client 端。
配置的版本及一键回滚
Nacos通过提供配置版本管理及其一键回滚能力,帮助用户改错配置的时候能够快速恢复,降低微服务系统在配置管理上的一定会遇到的可用性风险。
命名空间管理
Nacos 基于Namespace 帮助用户逻辑隔离多个命名空间,这可以帮助用户更好的管理测试、预发、生产等多环境服务和配置,让每个环境的同一个配置(如数据库数据源)可以定义不同的值。
社区参与的前端共建
在Nacos前端风格、布局的讨论中,社区踊跃投票,最终选择了这套经典黑白蓝风格的皮肤,并且通过我们UED程瑶同学的设计、布局,让交互变得十分自然流畅。
在控制台的开发之前我们通过社区招募到了很多前端同学一起参与了前端代码的开发,在此尤其感谢李晨、王庆、王彦民同学在Nacos前端开发过程中的大力支持! 坚持社区化发展,欢迎加入并贡献社区
DISS is cheap, show me your hand 比吐槽更重要的是搭把手,参与社区一起发展Nacos。
双十一广告:阿里云双十一1折拼团活动:已满6人,都是最低折扣了
【满6人】1核2G云服务器99.5元一年298.5元三年 2核4G云服务器545元一年 1227元三年
【满6人】1核1G MySQL数据库 119.5元一年
【满6人】3000条国内短信包 60元每6月
参团地址:http://click.aliyun.com/m/1000020293/
作者: 中间件小哥
原文链接
本文为云栖社区原创内容,未经允许不得转载。
云计算
2018-11-06 11:39:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
这是如何提高阿里云上应用的可用性系列文章的第二篇, 第一篇传送门 。
在单体应用时代,最大的问题是如何解决数据库瓶颈,而微服务之下,一个大应用被拆分成了几十个甚至上百个微服务,数据访问的压力被传导到了服务之间的网络,服务强弱依赖,服务雪崩等各种问题随之而来,那么如何保障服务的可用性以及整个应用的健壮性呢?常见的做法包括:
超时
程序员和女朋友约会在楼下等她的时候一般都会约定 “等你30分钟啊”, 这就是一种超时约定,如果等了半小时女朋友还没有下来,该怎么办?一般有服务治理意识的程序员都会选择超时退出及时止损(不知道这是不是程序员没有女朋友的原因之一)
在应用设计中,为避免集群雪崩或资源耗尽,一切调用都应该设置超时时间,包括RPC/DB/缓存,服务端超时是必选配置。在实际的电商实际场景中,一般服务级别的超时时间通常会设置在100ms~300ms之间。
超时的设定需要注意一个问题就是超时的传递问题, 假设服务A调用服务B,A的超时设定为100ms,B为300ms,那么这个设定就是有问题,因为一旦B的调用时间超过了100ms,A无论如何都会超时,而B的继续调用就会成为一种资源浪费,而在特别复杂的服务依赖关系中,超时的设定一定要考虑传递的问题
重试
当程序员给喜欢的女孩子表白被拒绝了怎么办,一般可以做出万分痛苦状接一句“要不要再考虑一下”,这就是一种重试,在服务调用中,重试就是当对服务端的调用出现异常或者错误时,自动的再次发起调用请求,可见这种方式在服务端出现偶发性抖动或者网络出现抖动的时候可以比较好的提高服务调用的成功率,但同时,如果服务端处在出现故障的边缘时,也有可能成为压垮骆驼的最后一根稻草,所以在生产环境中一定要慎用
熔断
家里面使用的保险丝就是一种典型的熔断,一旦电流过大的时候,就是断开以保护整个电路,在程序设计中,一旦服务端的调用的异常或者错误比例超过一定的阈值时,就停止对此服务的调用,此时处于close状态,经过一段时间的熔断期后会尝试重新发起调用,此时处于close-open状态,如果调用成功则放开调用,切换到open状态,否则继续回到close状态
隔离
远洋大船的内部都会设计多个水密仓,这样一旦事故出现船体破损,也可以把影响控制在水密仓级别而不至于整个船沉默,这就是一种隔离策略,在程序设计中,为了达到资源隔离和故障隔离,通常有两种做法,一种是通过线程池来进行隔离,对于不同类型资源新建不同的线程池,然后通过设置线程池的大小和超时时间来起到隔离资源使用的效果,但是这种方式由于需要新建线程池,对于资源开销比较大,另外一种方式就是通过观察线程的信号量也就是同类型资源的线程数,当超过相应的阈值时快速拒绝新的资源请求。
限流和流控
本质上这两种方式都是对于超出服务提供能力的请求进行限制,区别是限流的话是立刻拒绝,而流控是让请求进行排队,这种方式对于流量的削峰填谷有着比较好的效果
以上的这些能力一般都会在微服务框架中集成提供,如阿里的Dubbo以及Spring Cloud的Hystrix,通过引入jar包在代码中需要增强的地方加入添加相应的高可用代码,需要在应用系统设计之初就充分考虑进去, 后期业务新增或变更时也需及时维护
接下来随之而来的一个问题就是如何测试验证这些高可用措施是有效的?阈值的设置是否合理?
常用的做法有两个:
压测
通过在云端模拟大量的用户请求来测试应用系统面对突发流量的能力和进行容量规划,这里介绍一款阿里云的PTS产品,可以在云端模拟百万并发,以此可以检测各链路是否有限流降级的措施,是否设置合理- 传送门 。
故障演练
故障演练是一种比较新的高可用测试的方式,通过软件层面模拟各种可能出现的故障,观察应用系统对于故障的隔离和降级能力。 这一专门的领域称之为Chaos engineering, 在阿里内部,通过故障演练平台,每天都在进行着各种类型的故障演练,这些故障包括操作系统层面的故障如进程意外退出,CPU内存飚高, 也包括网络层面的故障如网络延迟丢包,DNS解析错误, 还包括了应用服务层面的故障如服务接口延迟,异常返回等。通过这种方式可以比较有效的验证应用的高可用能力,找到潜在风险问题。
当然对于种种原因没有集成高可用框架,也没有自己搭建故障演练平台的各位同学,阿里云推出了应用高可用服务这一业界首款快速提高应用高可用能力的SaaS产品,来自于多年双十一稳定性保障的经验,具有无需修改代码,全界面操作和性能稳定的特点,下面举例示意如何给云上的应用添加限流和降级的能力 (传送门:如何接入应用高可用服务)
对关键接口进行限流



对非关键业务进行降级处理






双十一广告:阿里云双十一1折拼团活动:已满6人,都是最低折扣了
【满6人】1核2G云服务器99.5元一年298.5元三年 2核4G云服务器545元一年 1227元三年
【满6人】1核1G MySQL数据库 119.5元一年
【满6人】3000条国内短信包 60元每6月
参团地址:http://click.aliyun.com/m/1000020293/


作者:中间件小哥
原文链接
本文为云栖社区原创内容,未经允许不得转载。
云计算
2018-11-05 12:11:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
今日,GitHub技术负责人Jason Warner的一篇技术深度解析稿成为IT圈爆款。文中,Jason坦诚地对外讲述了10月21日100G光缆设备故障后,Github服务降级的应急过程以及反思总结。
从Jason Warner的文章中不难看出,造成断网43秒瘫痪24小时的罪魁祸首是数据库。由于部署在两个数据中心的数据库集群没有实时同步。意外发生时,Github的工程师担心数据丢失,不敢快速将主数据库安全切换到东海岸的备份数据中心。
程序员们在GitHub这篇“忏悔录”下面留言,表达对数据库集群的“哀悼”。但更多IT从业者关心的问题是,如何避免这样的灾难事件降临到自己的公司,自己维护的系统。
蚂蚁金服OceanBase分布式数据库专家认为,此次Github事件是典型的城市级故障。如果系统采用的是高可用的三地五中心解决方案,就可以自如应对。
就在一个月前,今年的杭州云栖大会上,蚂蚁金服副CTO胡喜现场模拟剪断支付宝近一半的服务器光缆。只用了26秒,模拟环境中的支付宝就完全恢复了正常,这背后即是OceanBase城市级别故障的自愈能力。
原来,Github类似银行采用的传统数据库两地三中心模式,即“主库(主机房)+同城热备库(同城热备机房)+异地灾备库(异地灾备机房)”。这种方式下通常只有主机房的服务器能提供写服务。如果主城市出现城市级故障,灾备城市的数据库虽然可以工作,但由于没有同步的最新数据,因此灾备库的数据是有损的。
但在三地五中心部署下,任何单个城市故障,OceanBase都不会停止服务,数据也不会有任何损失。
Github表示,为了保证数据完整性,他们不得不牺牲恢复时间。其实,这个问题采用三地五中心方案可以更好的应对。城市故障时,OceanBase只要活着的两个城市的三个机房两两之间能够通信,就可以正常服务,也不会有任何的数据损失。
双十一广告:阿里云双十一1折拼团活动:已满6人,都是最低折扣了
【满6人】1核2G云服务器99.5元一年298.5元三年 2核4G云服务器545元一年 1227元三年
【满6人】1核1G MySQL数据库 119.5元一年
【满6人】3000条国内短信包 60元每6月
参团地址: http://click.aliyun.com/m/1000020293/
作者: 华蒙
原文链接
本文为云栖社区原创内容,未经允许不得转载。
云计算
2018-11-02 11:37:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
摘要: 各位新老用户们,如果您已经开了团,但是还不知道怎么玩?小编告诉来告诉你! 首先,进入活动主页面,点击【我要开团】,选择您想要购买的云产品进行开团!如果您只想开团不想购买,也可以~ 您开团后将享受以下福利: 福利1:拉新赢红包 团长开团后,可通过专属分享链接,邀请好友来参团。
各位新老用户们,如果您已经开了团,但是还不知道怎么玩?小编告诉来告诉你!
首先,进入活动主页面,点击【我要开团】,选择您想要购买的云产品进行开团!如果您只想开团不想购买,也可以~
您开团后将享受以下福利:
福利1:拉新赢红包
团长开团后,可通过专属分享链接,邀请好友来参团。每成功邀请1个新用户参团购买您团里的云产品,您将获得1个拉新红包!红包从几十块到上千块不等!
最大的红包有1111元的现金红包,将即时发放到您的阿里云账户中!拉新人数越多,红包越多!如果您没有开团,参加了您好友开的团,您购买后即成为该团一员,您也可以邀请好友参团,赢取拉新红包~
福利2:享受云产品折扣
参团新用户在活动期间,通过活动页面首次购买指定云产品的,可根据同一团内的拼团人数,享受不同的拼团折扣价格,具体如下:

以2核8G5M配置的云服务器为例:
3年版的配置原价14850元,活动起拼价4140元,相当于28折起购,团首购满6人即低至2070元,相当于14折,最高省12780元。

福利3:云大使返现
参加开团/拼团活动都将加入阿里云云大使。
您参团后即加入阿里云云大使,可获取专属分享链接,邀请其他用户参团。如果您是新用户,不仅能享受以上云产品折扣,和拉新红包,还能获得全订单返25%,30天内拉的用户再消费会再返现15%。
举个例子:
如果您所在的团当前团购的云产品为4140元的ECS云服务器,您每拉一个新人,可获得4140*25%=1035元的返佣。 如果30天内您拉的新人再次购买ECS云服务器,如4140元的云产品,您可再获得4140*15%=621元的返佣。
老用户如何赚钱?
拉新用户即得红包,再享云大使25%的额外返现,如果拉一个新人购买2核8G5M的配置,拼团价4140元,您将会得到(4140元*25%)1035元+1111元(最高)=2146元的最高返现,平均能得>1035元的现金红包及返现。 快来开团吧: http://click.aliyun.com/m/1000020293/
阿里云双十一1折拼团活动:已满6人,都是最低折扣了
【满6人】1核2G云服务器99.5元一年298.5元三年 2核4G云服务器545元一年 1227元三年
【满6人】1核1G MySQL数据库 119.5元一年
【满6人】3000条国内短信包 60元每6月
参团地址: http://click.aliyun.com/m/1000020293/
作者:双11小秘书
原文链接
本文为云栖社区原创内容,未经允许不得转载。
云计算
2018-10-30 17:23:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
摘要: 还在发愁没有数据做深度学习,看看别人如何实现的把!
作为数据科学家,你最重要的技能之一应该是为你的问题选择正确的建模技术和算法。几个月前,我试图解决文本分类问题,即分类哪些新闻文章与我的客户相关。
我只有几千个标记的例子,所以我开始使用简单的经典机器学习建模方法,如TF-IDF上的Logistic回归,但这个模型通常适用于长文档的文本分类。
在发现了我的模型错误之后,我发现仅仅是理解词对于这个任务是不够的,我需要一个模型,它将使用对文档的更深层次的语义理解。
深度学习模型在复杂任务上有非常好的表现,这些任务通常需要深入理解翻译、问答、摘要、自然语言推理等文本。所以这似乎是一种很好的方法,但深度学习通常需要数十万甚至数百万的训练标记的数据点,几千的数据量显然是不够的。
通常,大数据集进行深度学习以避免过度拟合。深度神经网络具有许多参数,因此通常如果它们没有足够的数据,它们往往会记住训练集并且在测试集上表现不佳。为了避免没有大数据出现这种现象,我们需要使用特殊技术。
在这篇文章中,我将展示我在文章、博客、论坛、Kaggle上发现的一些方法,以便在没有大数据的情况下更好地完成目标。其中许多方法都基于计算机视觉中广泛使用的最佳实践。
正 则化
正则化方法是在机器学习模型内部以不同方式使用的方法,以避免过度拟合,这个方法具有强大的理论背景并且可以以通用的方式解决大多数问题。
L1 和L2正则化
这个方法可能是最古老的,它在许多机器学习模型中使用多年。在这个方法中,我们将权重大小添加到我们试图最小化的模型的损失函数中。这样,模型将尝试使权重变小,并且对模型没有帮助的权重将显着减小到零,并且不会影响模型。这样,我们可以使用更少数量的权重来模拟训练集。有关更多说明,你可以阅读 这篇 文章。
Dropout
Dropout是另一种较新的正则化方法,训练期间神经网络中的每个节点(神经元)都将被丢弃(权重将被设置为零),这种方式下,网络不能依赖于特定的神经元或神经元的相互作用,必须学习网络不同部分的每个模式。这使得模型专注于推广到新数据的重要模式。
提早停止
提早停止是一种简单的正则化方法,只需监控验证集性能,如果你发现验证性能不断提高,请停止训练。这种方法在没有大数据的情况下非常重要,因为模型往往在5-10个时期之后甚至更早的时候开始过度拟合。
参数数量少
如果你没有大型数据集,则应该非常小心设置每层中的参数和神经元数量。此外,像卷积层这样的特殊图层比完全连接的图层具有更少的参数,因此在它们适合你的问题时使用它们非常有用。 数据增强
数据增强是一种通过以标签不变的方式更改训练数据来创建更多训练数据的方法。在计算机视觉中,许多图像变换用于增强数据集,如翻转、裁剪、缩放、旋转等。
这些转换对于图像数据很有用,但不适用于文本,例如翻转像“狗爱我”这样的句子不是一个有效的句子,使用它会使模型学习垃圾。以下是一些文本数据增强方法:
同义词替换
在这种方法中,我们用他们的同义词替换我们文本中的随机单词,例如,我们将句子“我非常喜欢这部电影”更改为“我非常爱这部电影”,它仍具有相同的含义,可能相同标签。这种方法对我来说不起作用,因为同义词具有非常相似的单词向量,因此模型将两个句子看作几乎相同的句子而不是扩充。
方向翻译
在这种方法中,我们采用我们的文本,将其翻译成具有机器翻译的中间语言,然后将其翻译成其他语言。该方法在Kaggle毒性评论挑战中成功使用。例如,如果我们将“我非常喜欢这部电影”翻译成俄语,我们会得到“Мнеоченьнравитсяэтотфильм”,当我们翻译成英文时,我们得到“I really like this movie”。反向翻译方法为我们提供了同义词替换,就像第一种方法一样,但它也可以添加或删除单词并解释句子,同时保留相同的含义。
文件裁剪
新闻文章很长,在查看数据时,有时不需要所有文章来分类文档。这让我想到将文章裁剪为几个子文档作为数据扩充,这样我将获得更多的数据。首先,我尝试从文档中抽取几个句子并创建10个新文档。这就创建了没有句子之间逻辑关系的文档,但我得到了一个糟糕的分类器。我的第二次尝试是将每篇文章分成5个连续句子。这种方法运行得非常好,给了我很好的性能提升。
生成对抗性网络
GAN是数据科学中最令人兴奋的最新进展之一,它们通常用作图像创建的生成模型。 这篇博客文章 解释了如何使用GAN进行图像数据的数据增强,但它也可能用于文本。 迁移学习
迁移学习是指使用来自网络的权重,这些网络是针对你的问题通过另一个问题(通常是大数据集)进行训练的。迁移学习有时被用作某些层的权重初始化,有时也被用作我们不再训练的特征提取器。在计算机视觉中,从预先训练的Imagenet模型开始是解决问题的一种非常常见的做法,但是NLP没有像Imagenet那样可以用于迁移学习的非常大的数据集。
预先训练的词向量
NLP深度学习架构通常以嵌入层开始,该嵌入层将一个热编码字转换为数字矢量表示。我们可以从头开始训练嵌入层,但我们也可以使用预训练的单词向量,如Word2Vec,FastText或Glove,这些词向量使用无监督学习方法训练大量数据或训练我们域中的数据。预训练的词向量非常有效,因为它们为基于大量数据的单词提供模型上下文,并减少模型的参数数量,从而显着降低过度拟合的可能性。你可以 在此处 阅读有关词嵌入的更多信息。
预先训练的句子向量
我们可以将模型的输入从单词更改为句子,这样我们可以使用较少的模型,其中参数数量较少,仍然具有足够的表达能力。为了做到这一点,我们可以使用预先训练 好的 句子编码器,如Facebook的 InferSent 或谷歌的 通用句子编码器 。我们还可以使用跳过思维向量或语言模型等方法训练未标记数据的句子编码器。你可以从我 之前的博文中 了解有关无监督句子向量的更多 信息 。
预先训练的语言模型
最近的论文如 ULMFIT 、 Open-AI变换器 和 BERT 通过在非常大的语料库中预训练语言模型,为许多NLP任务获得了惊人的结果。语言模型是使用前面的单词预测句子中的下一个单词的任务。对我来说,这种预训练并没有真正帮助获得更好的结果,但文章已经展示了一些方法来帮助我更好地微调,我还没有尝试过。 这是 一个关于预训练语言模型的好博客。
无人监督或自我监督学习的预训练
如果我们有一个来自未标记数据的大型数据集,我们可以使用无监督的方法,如自动编码器或掩码语言模型,仅使用文本本身预训我们的模型。对我来说更好的另一个选择是使用自我监督。自我监督模型是在没有人类注释的情况下自动提取标签的模型。一个很好的例子是Deepmoji项目,在Deepmoji中,作者训练了一个模型,用于从推文中预测表情符号,在表情符号预测中获得良好结果之后,他们使用他们的网络预先训练了一个获得最新结果的高音扬声器情绪分析模型。表情符号预测和情绪分析显然非常相关,因此它作为预训练任务表现得非常好。新闻数据的自我监督任务可以预测标题、报纸、评论数量、转推的数量等等。自我监督可以是一种非常好的预训方法,但通常很难分辨出哪个代理标签将与你的真实标签相关联。 特征工程
我知道深度学习“杀死”了特征工程,这样做有点过时了。但是,当你没有大数据集时,让网络通过特征工程学习复杂模式可以大大提高性能。例如,在我对新闻文章的分类中,作者、报纸、评论、标签和更多功能的数量可以帮助预测我们的标签。
多模式架构
我们可以使用多模式架构将文档级特征组合到我们的模型中。在multimodal中,我们构建了两个不同的网络,一个用于文本、一个用于特征,合并它们的输出层并添加更多层。这些模型很难训练,因为这些特征通常比文本具有更强的信号,因此网络主要学习特征效果。 这 是关于多模式网络的伟大的Keras教程。这种方法使我的性能表现提高了不到1%。
字级(word level)特征
另一种类型的特征工程是词级特征,如词性标注、语义角色标记、实体提取等。我们可以将一个热编码表示或词级特征的嵌入与词的嵌入相结合,并将其用作模型的输入。我们也可以在这个方法中使用其他单词特征,例如在情感分析任务中我们可以采用情感字典并为嵌入添加另一个维度,其中1表示我们在字典中的单词,0表示其他单词,这样模型可以很容易地学习它需要关注的一些词。在我的任务中,我添加了某些重要实体的维度,这给了我一个很好的性能提升。
预处理作为特征工程
最后一种特征工程方法是以一种模型更容易学习的方式预处理输入文本。一个例子是特殊的“阻止”,如果体育对我们的标签不重要,我们可以改变足球,棒球和网球这个词运动,这将有助于网络了解体育之间的差异并不重要,可以减少数量网络中的参数。另一个例子是使用自动摘要,正如我之前所说的,神经网络在长文本上表现不佳,因此我们可以在文本上运行自动汇总算法,如“文本排名”,并仅向网络提供重要句子。 我的模型
我使用预先训练过的词向量来完成我公司为同一数据为该客户所做的另一项任务。作为特征工程,我在词嵌入中添加了实体字级特征。基本模型的这些变化使我的精确度提高了近10%,这使得我的模型从随机性稍微好一点到具有重要业务影响的模型。
http://click.aliyun.com/m/1000020293/
双十一广告:阿里云双十一1折拼团活动:已满6人,都是最低折扣了
【满6人】1核2G云服务器99.5元一年298.5元三年 2核4G云服务器545元一年 1227元三年
【满6人】1核1G MySQL数据库 119.5元一年
【满6人】3000条国内短信包 60元每6月
参团地址: http://click.aliyun.com/m/1000020293/
本文由 阿里云云栖社区 组织翻译。
文章原标题《lessons-learned-from-applying-deep-learning-for-nlp-without-big-data》
作者: yonatan hadar 译者:虎说八道,审校:。
原文链接
本文为云栖社区原创内容,未经允许不得转载。
云计算
2018-10-31 11:05:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
对于一个从未到过南方的内蒙汉子来说,北京的大学一直是中学时憧憬的殿堂,而离家上千公里浙江大学,则是从来没有考虑过的地方。机缘巧合之下,被一位年近七旬的浙大老师说服,我自此开始了南下“修炼”之旅。没想到转眼间竟已九年,杭州也成为我的第二家乡。

值此1024程序员节来临之际,抚今追昔,回顾一下自己的“修炼”历程。

大学时光,尝试不同的计算

和计算机的缘分也是从大学开始,初入新手村的我拥有了自己的电脑。

升入本科的第一年我们没有细分专业,只有学科大类。大二选专业的活动,就像是第二次高考志愿填报。09年的信电系异常火爆,但比起硬件底层,我对操作系统、软件、app更感兴趣,最后选择了计算机。

然而,计算机系挑战更大,很多进来的同学都早已打下基础,相比之下,从头开始学习如何编写代码的我是彻头彻尾的“萌新”。因此在完成课业之余,我整天泡在图书馆:一个一个实现《算法导论》中的算法,研究解决同样问题;使用不同算法把复杂度从N(n^2)下降到N(nlogn);和同学在ZOJ(Zhejiang University Online Judge)比拼刷题…

逐渐熟悉掌握前人的知识的我,就像获得了打怪的武器。大二开始在不同的领域,逐步尝试用算法和计算来实现自己的想法:

• 作为国内第一批使用Kinect的玩家,基于Kinect的SDK,做了一套手势+肢体动作操作PC的键鼠的小工具,并完成了一局全身充分运动的扫雷。
• 尝试Obj-c, 开发了射击类的iPhone小游戏。依靠这份经验,和小伙伴开发了一套课堂交互系统(支持教室通过app布置作业和回答问题),拿到了网易的app创新比赛奖项。
• 自学《集体智慧编程》和Andrew NG 《机器学习》公开课,逐渐点开了“推荐算法”和“机器学习”的技能树。

正是通过这些积累的经验和知识,大四拿到了阿里巴巴集团的实习offer,正式从新手村毕业进阶。

初到阿里,成为算法达人

从实习到最初两年在阿里集团的工作,我都在和各种算法打交道。而2013年的阿里,“算法工程师”还算是很新的一个岗位,我们要在海量的信息上,通过机器学习和挖掘算法让其可读、可用、有价值。

我最初就职于淘宝,怎样帮助买家在淘宝成百上千品类和数以亿计的商品中,挑选出自己想要购买的商品,或者母婴产品分类该怎么做?我用了一整个月时间,研究了淘宝的母婴类目,从关键词到宝贝类型、细节描述、品牌归属、品牌定位……原本的单身宅男几乎变成了一个母婴专家,甚至在之后半年里,我的女同事们都会找我咨询如何购买母婴产品……

在淘宝的这段时间,也是我成长和学习最快的时候。数据库、机器学习算法、JAVA项目构建、GIT版本管理,每一个技能点都得到了很大的提升。由学生时代的几M数据的算法Demo进阶到TB级的数据处理,传统的单机算法已经远远不能满足需求。


经常优化算法到深夜的我,深刻体会到了算法从N(n^2)下降到N(nlogn)的意义:也许对于算法Demo只是跑的慢一点,但对于业务,可能就决定了这个业务能不能做,能不能控制住成本,能不能真正落地应用,我也觉得身上的责任更重了。

工作不仅仅是完成任务,更是不断地去研究和解决问题。这些披荆斩棘攻坚克难的经历,也让我练就了强大的内功。

拥抱变化,让城市更加智慧

青年们,到祖国最需要的地方去!后来在阿里云的日子,颇有些这样的滋味。

三年前因为团队调整,我们来到了阿里云,也促使我完成了从把自己的算法做好,到帮助用户去实现用户数字化转型的变化。看待问题的视角也从由局部到整体,乃至整个行业。

可以做的事情更多了,挑战也更大了。来阿里云做的第一个产品是针对新媒体行业的推荐引擎,在这个项目中,我第一次完整的参与了一个商业化产品诞生的全过程:立项、研发、测试、发布。个人能力的边界进一步扩展到了项目管理,产品运维,算法来说也有了更加全面的扩展。

2017年,又一次的拥抱变化,是转投向交通行业。在追赶城市大脑的浪潮中,接触到杭州的交通行业,才发现自己对已经待了8年的这座城市,了解还远远不够。杭州“首堵”的称号扬名在外,而每天需要开车一小时通勤上下班的我,逐渐更关心这个城市的每一个交通的脉络,每一个新的规划和改变。道路就像是杭州的“血管”,我们通过算法的应用,为这座城市疏通它的每一寸“经络和血管”,注入能量。


这样的工作实际解决的每一个环节都与我们的生活息息相关。每每想到自己的每一分努力都能够帮助整个城市,都会获得满足感。如果优化算法,能使信号灯的通行效率提升一个点,就可以节约所有人加起来上百个小时的时间。如果切实的减少拥堵和提出建议,更能减少人力资源的浪费。
未来怎么样让这个城市变得更加智慧?也成为了我新的目标。

在淘宝的两年,我关注如何用算法做好一件需求。而在阿里云,我更关心怎样的产品和云平台,能帮用户更好地实现算法的联动,实现无法计算的价值。

寄语

掐指一算,今年正好是来到阿里的第5年,在杭州的第9年。

而这份“修炼”,仍在进行中……

对于有志于做算法工程师的同学,也有一些“修炼”的建议:一是持续学习,多去尝试不同的细分领域,找到自己最喜欢也擅长的方向,当然个人认为喜欢相对来说重要一些。 二是希望大家把关注点放在解决问题上面,无论是用什么框架,什么算法,高效的解决问题才是王道。 三是一定要了解计算逻辑,同时算法开发的能力也很重要,开发的过程中可以帮助梳理思路,评估算法成本。
云计算
2018-10-25 16:22:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
一.ffmpeg安装
第一步:添加源。 sudo add-apt-repository ppa:djcj/hybrid
第二步:更新源。 sudo apt-get update
第三步:下载安装。 sudo apt-get install ffmpeg
第四步:验证。 sudo ffmpeg -version
二.C语言调用ffmpeg库实现rtsp视频流解析并存储为ppm格式图片
1.参考:
https://stackoverflow.com/questions/10715170/receiving-rtsp-stream-using-ffmpeg-library
2.代码:my_streamer.cpp #include #include #include #include #include extern "C" { #include #include #include #include } int main(int argc, char** argv) { // Open the initial context variables that are needed SwsContext *img_convert_ctx; AVFormatContext* format_ctx = avformat_alloc_context(); AVCodecContext* codec_ctx = NULL; int video_stream_index; // Register everything av_register_all(); avformat_network_init(); //open RTSP if (avformat_open_input(&format_ctx, "rtsp://134.169.178.187:8554/h264.3gp", NULL, NULL) != 0) { return EXIT_FAILURE; } if (avformat_find_stream_info(format_ctx, NULL) < 0) { return EXIT_FAILURE; } //search video stream for (int i = 0; i < format_ctx->nb_streams; i++) { if (format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) video_stream_index = i; } AVPacket packet; av_init_packet(&packet); //open output file AVFormatContext* output_ctx = avformat_alloc_context(); AVStream* stream = NULL; int cnt = 0; //start reading packets from stream and write them to file av_read_play(format_ctx); //play RTSP // Get the codec AVCodec *codec = NULL; codec = avcodec_find_decoder(AV_CODEC_ID_H264); if (!codec) { exit(1); } // Add this to allocate the context by codec codec_ctx = avcodec_alloc_context3(codec); avcodec_get_context_defaults3(codec_ctx, codec); avcodec_copy_context(codec_ctx, format_ctx->streams[video_stream_index]->codec); std::ofstream output_file; if (avcodec_open2(codec_ctx, codec, NULL) < 0) exit(1); img_convert_ctx = sws_getContext(codec_ctx->width, codec_ctx->height, codec_ctx->pix_fmt, codec_ctx->width, codec_ctx->height, AV_PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL); int size = avpicture_get_size(AV_PIX_FMT_YUV420P, codec_ctx->width, codec_ctx->height); uint8_t* picture_buffer = (uint8_t*) (av_malloc(size)); AVFrame* picture = av_frame_alloc(); AVFrame* picture_rgb = av_frame_alloc(); int size2 = avpicture_get_size(AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height); uint8_t* picture_buffer_2 = (uint8_t*) (av_malloc(size2)); avpicture_fill((AVPicture *) picture, picture_buffer, AV_PIX_FMT_YUV420P, codec_ctx->width, codec_ctx->height); avpicture_fill((AVPicture *) picture_rgb, picture_buffer_2, AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height); while (av_read_frame(format_ctx, &packet) >= 0 && cnt < 1000) { //read ~ 1000 frames std::cout << "1 Frame: " << cnt << std::endl; if (packet.stream_index == video_stream_index) { //packet is video std::cout << "2 Is Video" << std::endl; if (stream == NULL) { //create stream in file std::cout << "3 create stream" << std::endl; stream = avformat_new_stream(output_ctx, format_ctx->streams[video_stream_index]->codec->codec); avcodec_copy_context(stream->codec, format_ctx->streams[video_stream_index]->codec); stream->sample_aspect_ratio = format_ctx->streams[video_stream_index]->codec->sample_aspect_ratio; } int check = 0; packet.stream_index = stream->id; std::cout << "4 decoding" << std::endl; int result = avcodec_decode_video2(codec_ctx, picture, &check, &packet); std::cout << "Bytes decoded " << result << " check " << check << std::endl; if (cnt > 100) //cnt < 0) { sws_scale(img_convert_ctx, picture->data, picture->linesize, 0, codec_ctx->height, picture_rgb->data, picture_rgb->linesize); std::stringstream file_name; file_name << "test" << cnt << ".ppm"; output_file.open(file_name.str().c_str()); output_file << "P3 " << codec_ctx->width << " " << codec_ctx->height << " 255\n"; for (int y = 0; y < codec_ctx->height; y++) { for (int x = 0; x < codec_ctx->width * 3; x++) output_file << (int) (picture_rgb->data[0] + y * picture_rgb->linesize[0])[x] << " "; } output_file.close(); } cnt++; } av_free_packet(&packet); av_init_packet(&packet); } av_free(picture); av_free(picture_rgb); av_free(picture_buffer); av_free(picture_buffer_2); av_read_pause(format_ctx); avio_close(output_ctx->pb); avformat_free_context(output_ctx); return (EXIT_SUCCESS); }
3.依赖库安装 apt install libavformat-dev apt install libavcodec-dev apt install libswresample-dev apt install libswscale-dev apt install libavutil-dev sudo apt-get install libsdl1.2-dev sudo apt-get install libsdl-image1.2-dev sudo apt-get install libsdl-mixer1.2-dev sudo apt-get install libsdl-ttf2.0-dev sudo apt-get install libsdl-gfx1.2-dev
4.编译 g++ -w my_streamer.cpp -o my_streamer $(pkg-config --cflags --libs libavformat libswscale libavcodec libavutil)
5.运行 ./my_streamer
三.C语言调用ffmpeg库实现rtsp视频流解析并存储为ppm或jpg格式图片,并通过opencv显示
1.代码:my_streamer.cpp #include #include #include #include #include #include #include #include #include extern "C" { #include #include #include #include } static void CopyDate(AVFrame *pictureFrame,int width,int height,int time); //static void SaveFrame_mmp(AVFrame *pictureFrame, int width, int height, int iFrame); static void SaveFrame_jpg_uselibjpeg(AVFrame *pictureFrame, int width, int height, int iFrame); int main(int argc, char** argv) { // Open the initial context variables that are needed SwsContext *img_convert_ctx; AVFormatContext* format_ctx = avformat_alloc_context(); AVCodecContext* codec_ctx = NULL; int video_stream_index; // Register everything av_register_all(); avformat_network_init(); //open RTSP if (avformat_open_input(&format_ctx, "rtsp://192.168.31.100:8656/main", NULL, NULL) != 0) { return EXIT_FAILURE; } if (avformat_find_stream_info(format_ctx, NULL) < 0) { return EXIT_FAILURE; } //search video stream for (int i = 0; i < format_ctx->nb_streams; i++) { if (format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) video_stream_index = i; } AVPacket packet; av_init_packet(&packet); //open output file AVFormatContext* output_ctx = avformat_alloc_context(); AVStream* stream = NULL; int cnt = 0; //start reading packets from stream and write them to file av_read_play(format_ctx); //play RTSP // Get the codec AVCodec *codec = NULL; codec = avcodec_find_decoder(AV_CODEC_ID_H264); if (!codec) { exit(1); } // Add this to allocate the context by codec codec_ctx = avcodec_alloc_context3(codec); avcodec_get_context_defaults3(codec_ctx, codec); avcodec_copy_context(codec_ctx, format_ctx->streams[video_stream_index]->codec); std::ofstream output_file; if (avcodec_open2(codec_ctx, codec, NULL) < 0) exit(1); img_convert_ctx = sws_getContext(codec_ctx->width, codec_ctx->height, codec_ctx->pix_fmt, codec_ctx->width, codec_ctx->height, AV_PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL); int size = avpicture_get_size(AV_PIX_FMT_YUV420P, codec_ctx->width, codec_ctx->height); uint8_t* picture_buffer = (uint8_t*) (av_malloc(size)); AVFrame* picture = av_frame_alloc(); AVFrame* picture_rgb = av_frame_alloc(); int size2 = avpicture_get_size(AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height); uint8_t* picture_buffer_2 = (uint8_t*) (av_malloc(size2)); avpicture_fill((AVPicture *) picture, picture_buffer, AV_PIX_FMT_YUV420P, codec_ctx->width, codec_ctx->height); avpicture_fill((AVPicture *) picture_rgb, picture_buffer_2, AV_PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height); //geyg AVFrame *pictureRGB; int numBytes; uint8_t *buffer; int i=0; long prepts = 0; pictureRGB=avcodec_alloc_frame(); if(pictureRGB==NULL) return -1; // Determine required buffer size and allocate buffer numBytes=avpicture_get_size(PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height); buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t)); // Assign appropriate parts of buffer to image planes in pFrameRGB avpicture_fill((AVPicture *)pictureRGB, buffer, PIX_FMT_RGB24, codec_ctx->width, codec_ctx->height); while (av_read_frame(format_ctx, &packet) >= 0 && cnt < 1000) { //read ~ 1000 frames std::cout << "1 Frame: " << cnt << std::endl; if (packet.stream_index == video_stream_index) { //packet is video std::cout << "2 Is Video" << std::endl; if (stream == NULL) { //create stream in file std::cout << "3 create stream" << std::endl; stream = avformat_new_stream(output_ctx, format_ctx->streams[video_stream_index]->codec->codec); avcodec_copy_context(stream->codec, format_ctx->streams[video_stream_index]->codec); stream->sample_aspect_ratio = format_ctx->streams[video_stream_index]->codec->sample_aspect_ratio; } int check = 0; packet.stream_index = stream->id; std::cout << "4 decoding" << std::endl; int result = avcodec_decode_video2(codec_ctx, picture, &check, &packet); std::cout << "Bytes decoded " << result << " check " << check << std::endl; if(check!=0 && cnt > 100) { static struct SwsContext *img_convert_ctx; // Convert the image into YUV format that SDL uses if(img_convert_ctx == NULL) { int w = codec_ctx->width; int h = codec_ctx->height; img_convert_ctx = sws_getContext(w, h, codec_ctx->pix_fmt, w, h, PIX_FMT_RGB24, SWS_BICUBIC, NULL, NULL, NULL); if(img_convert_ctx == NULL) { fprintf(stderr, "Cannot initialize the conversion context!\n"); exit(1); } } int ret = sws_scale(img_convert_ctx, picture->data, picture->linesize, 0, codec_ctx->height, pictureRGB->data, pictureRGB->linesize); // Save the frame to disk SaveFrame_jpg_uselibjpeg(pictureRGB, codec_ctx->width, codec_ctx->height, cnt); CopyDate(pictureRGB, codec_ctx->width, codec_ctx->height,packet.pts-prepts); prepts = packet.pts; } /* if (cnt > 100) //cnt < 0) { sws_scale(img_convert_ctx, picture->data, picture->linesize, 0, codec_ctx->height, picture_rgb->data, picture_rgb->linesize); std::stringstream file_name; file_name << "test" << cnt << ".ppm"; output_file.open(file_name.str().c_str()); output_file << "P3 " << codec_ctx->width << " " << codec_ctx->height << " 255\n"; for (int y = 0; y < codec_ctx->height; y++) { for (int x = 0; x < codec_ctx->width * 3; x++) output_file << (int) (picture_rgb->data[0] + y * picture_rgb->linesize[0])[x] << " "; } output_file.close(); } */ cnt++; } av_free_packet(&packet); av_init_packet(&packet); } av_free(picture); av_free(picture_rgb); av_free(picture_buffer); av_free(picture_buffer_2); av_read_pause(format_ctx); avio_close(output_ctx->pb); avformat_free_context(output_ctx); return (EXIT_SUCCESS); } static void CopyDate(AVFrame *picture,int width,int height,int time) { if(time <=0 ) time = 1; int nChannels; int stepWidth; uchar* pData; cv::Mat frameImage(cv::Size(width, height), CV_8UC3, cv::Scalar(0)); stepWidth = frameImage.step; nChannels = frameImage.channels(); pData = frameImage.data; for(int i = 0; i < height; i++) { for(int j = 0; j < width; j++) { pData[i*stepWidth+j*nChannels+0] = picture->data[0][i*picture->linesize[0]+j*nChannels+2]; pData[i*stepWidth+j*nChannels+1] = picture->data[0][i*picture->linesize[0]+j*nChannels+1]; pData[i*stepWidth+j*nChannels+2] = picture->data[0][i*picture->linesize[0]+j*nChannels+0]; } } cv::namedWindow("Video", cv::WINDOW_NORMAL); cv::imshow("Video", frameImage); cv::waitKey(1); } static void SaveFrame_mmp(AVFrame *picture, int width, int height, int iFrame) { FILE *pFile; char szFilename[32]; int y; // Open file sprintf(szFilename, "frame%d.ppm", iFrame); pFile=fopen(szFilename, "wb"); if(pFile==NULL) { printf("%s\n","create file fail!"); return; } // Write header fprintf(pFile, "P6\n%d %d\n255\n", width, height); // Write pixel data for(y=0; ydata[0]+y*picture->linesize[0], 1, width*3, pFile); // Close file fclose(pFile); } static void SaveFrame_jpg_uselibjpeg(AVFrame* pFrame, int width, int height, int iFrame) { char fname[128] = { 0 }; struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; JSAMPROW row_pointer[1]; int row_stride; uint8_t *buffer; FILE *fp; buffer = pFrame->data[0]; sprintf(fname, "%s%d.jpg", "frame", iFrame); fp = fopen(fname, "wb"); cinfo.err = jpeg_std_error(&jerr); jpeg_create_compress(&cinfo); jpeg_stdio_dest(&cinfo, fp); cinfo.image_width = width; cinfo.image_height = height; cinfo.input_components = 3; cinfo.in_color_space = JCS_RGB; jpeg_set_defaults(&cinfo); jpeg_set_quality(&cinfo, 80, true); jpeg_start_compress(&cinfo, TRUE); row_stride = width * 3; while (cinfo.next_scanline < height) { row_pointer[0] = &buffer[cinfo.next_scanline * row_stride]; (void)jpeg_write_scanlines(&cinfo, row_pointer, 1); } jpeg_finish_compress(&cinfo); fclose(fp); jpeg_destroy_compress(&cinfo); return; }
2.依赖库安装 1. 安装opencv:用户显示 2. apt install libavformat-dev apt install libavcodec-dev apt install libswresample-dev apt install libswscale-dev apt install libavutil-dev apt install libjpeg-dev 3. sudo apt-get install libsdl1.2-dev sudo apt-get install libsdl-image1.2-dev sudo apt-get install libsdl-mixer1.2-dev sudo apt-get install libsdl-ttf2.0-dev sudo apt-get install libsdl-gfx1.2-dev 4. ubuntu下zmq安装 (1)下载zmq:wget http://download.zeromq.org/zeromq-4.1.4.tar.gz (可以将“4.1.4”改成当前最新版本编号) (2)解压:tar -zxvf zeromq-4.1.4.tar.gz (3)编译安装 A.执行configure文件:./configure 出现错误: configure: error: Package requirements (libsodium) were not met: No package 'libsodium' found 解决方案:忽略这个库 ./configure --prefix=/home/ygy/zmq --without-libsodium(prefix中的路径是zmq存放的目录) B.编译:make C.安装:make install D.配置环境变量 vi /etc/profile export C_INCLUDE_PATH="$C_INCLUDE_PATH:/usr/local/include" export CPLUS_INCLUDE_PATH="$CPLUS_INCLUDE_PATH:/usr/local/include" export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/local/lib" export LIBRARY_PATH="$LIBRARY_PATH:/usr/local/lib" C语言zmq使用 引用:#include
3.编译 g++ -w my_streamer.cpp -o my_streamer $(pkg-config --cflags --libs libavformat libswscale libavcodec libavutil opencv libjpeg libzmq)
4.运行 ./my_streamer
四.C语言调用ffmpeg库实现本地视频播放
1.参考:https://github.com/mpenkov/ffmpeg-tutorial
2.依赖库安装:见上节二.3
3.编译: git clone https://github.com/mpenkov/ffmpeg-tutorial.git cd ffmpeg-tutorial make
4.运行: ./tutorial01.out ×.avi
云计算
2018-10-09 12:35:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
如何安装docker for win请参考我之前的文章 《Docker在Win10下的安装和配置》

打开Kitematic图形管理工具,搜索portainer镜像
创建镜像,制定端口到宿主机9000端口(这个自定义)
宿主机直接访问http://localhost:9000即可
配置节点,我们选择远程连接方式
这里有个很隐晦的地方,就是主机的ip地址我们怎么填,在docker for win中我们需要先打开2375端口
从这里看是localhost,这个是宿主机,那么我们的portainer是在虚拟机里的,那么对于虚拟机来说如何访问宿主机的docker服务呢?
其实很简单,我们只需要填写 docker.for.win.localhost:2375 即可。
连接成功

我们可以方便的使用portainer进行容器的管理了。
在docker文档中可以找到:

云计算
2018-09-29 10:00:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
在微服务架构下,服务之间的关系是非常复杂的,是一个典型的有向有环图,在一个中等规模的项目中,一般会有100多个服务,而大型项目中,则会有数百个服务。
假设我们有如下6个服务:
每个服务都指定了自己依赖的服务:
AaaSvc:
BbbSvc:
CccSvc:
DddSvc:
EeeSvc:
FffSvc:
我们如何把如上6个服务中跟服务AaaSvc相关的服务可视化呢?如下图所示:
要完成这样的服务关联图,需要如下几个步骤:
1、遍历指定项目下的所有服务,构造两个map,serviceToServiceMap 和 reverseServiceToServiceMap,存储所有服务的直接依赖和反向直接依赖。 public static void runService(String projectId, Map> serviceToServiceMap, Map> reverseServiceToServiceMap){ if(! (serviceToServiceMap instanceof ConcurrentHashMap) ){ throw new RuntimeException("参数serviceToServiceMap必须是ConcurrentHashMap的实例"); } if(! (reverseServiceToServiceMap instanceof ConcurrentHashMap) ){ throw new RuntimeException("参数reverseServiceToServiceMap必须是ConcurrentHashMap的实例"); } MetaServiceRepository metaServiceRepository = SpringContextUtils.getBean("metaServiceRepository"); List services = metaServiceRepository.findByProjectId(projectId); services.parallelStream().filter(item->!item.getName().contains("Deprecate")).forEach(item->{ List dependencyServices = item.constructDependencyServices(); String key = item.getName()+"("+item.getDescription()+")"; if(dependencyServices != null){ dependencyServices.parallelStream().filter(dep->!dep.getName().contains("Deprecate")).forEach(dependencyService->{ String value = dependencyService.getName()+"("+dependencyService.getDescription()+")"; serviceToServiceMap.putIfAbsent(key, Collections.newSetFromMap(new ConcurrentHashMap<>())); serviceToServiceMap.get(key).add(value); reverseServiceToServiceMap.putIfAbsent(value, Collections.newSetFromMap(new ConcurrentHashMap<>())); reverseServiceToServiceMap.get(value).add(key); }); } }); }
2、以服务AaaSvc为入口,利用直接依赖和反向直接依赖,构造服务依赖图和反向服务依赖图。 String name = metaService.getName()+"("+metaService.getDescription()+")"; Set set = serviceToServiceMap.get(name); ServiceDependencyGraph serviceDependencyGraph = new ServiceDependencyGraph(new HashMap<>(), name, set, serviceToServiceMap); set = reverseServiceToServiceMap.get(name); ServiceDependencyGraph reverseServiceDependencyGraph = new ServiceDependencyGraph(new HashMap<>(), name, set, reverseServiceToServiceMap); import org.apache.commons.collections4.CollectionUtils; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; /** * 服务依赖图 * @date 2017-09-2 * @author 杨尚川 */ public class ServiceDependencyGraph { private String name; private List children = new ArrayList<>(); public ServiceDependencyGraph(Map stopServiceNames, String name, Set set, Map> serviceToServiceMap){ this.name = name; if(CollectionUtils.isNotEmpty(set)) { for (String item : set) { String key = name+"_"+item; stopServiceNames.putIfAbsent(key, new AtomicInteger()); stopServiceNames.get(key).incrementAndGet(); if(stopServiceNames.get(key).get()<10) { Set sub = serviceToServiceMap.get(item); ServiceDependencyGraph serviceDependencyGraph = new ServiceDependencyGraph(stopServiceNames, item, sub, serviceToServiceMap); children.add(serviceDependencyGraph); } } } } public String getName() { return name; } public void setName(String name) { this.name = name; } public List getChildren() { return children; } }
3、利用服务依赖图和反向服务依赖图,构造带有点和边描述信息的JSON结构: List> nodes = new ArrayList<>(); addNode(serviceDependencyGraph, nodes); addNode(reverseServiceDependencyGraph, nodes); List> edges = new ArrayList<>(); addEdge(reverseServiceToServiceMap, serviceDependencyGraph, edges, false); addEdge(reverseServiceToServiceMap, reverseServiceDependencyGraph, edges, true); Map graph = new HashMap<>(); graph.put("edges", edges); graph.put("nodes", nodes); private void addNode(String node, List> nodes){ for(Map item : nodes){ if(node.equals(item.get("id"))){ return; } } Map nodeMap = new HashMap<>(); nodeMap.put("id", node); nodeMap.put("name", node); nodes.add(nodeMap); } private void addNode(ServiceDependencyGraph serviceDependencyGraph, List> nodes){ if(serviceDependencyGraph == null){ return; } String node = serviceDependencyGraph.getName(); addNode(node, nodes); if(serviceDependencyGraph.getChildren() != null){ serviceDependencyGraph.getChildren().forEach(item->addNode(item, nodes)); } } private void addEdge(Map> reverseServiceToServiceMap, ServiceDependencyGraph serviceDependencyGraph, List> edges, boolean reverse){ if(serviceDependencyGraph == null){ return; } String source = serviceDependencyGraph.getName(); serviceDependencyGraph.getChildren().forEach(target -> { boolean duplicate = false; Map map = new HashMap<>(); if(reverse){ String id = target.getName()+"-->"+source; for(Map item : edges){ if(id.equals(item.get("id"))){ duplicate = true; } } map.put("id", id); map.put("target", source); map.put("source", target.getName()); map.put("directed", true); map.put("source_score", reverseServiceToServiceMap.get(target.getName()) == null ? 0 : reverseServiceToServiceMap.get(target.getName()).size()); map.put("target_score", reverseServiceToServiceMap.get(source) == null ? 0 : reverseServiceToServiceMap.get(source).size()); }else { String id = source+"-->"+target.getName(); for(Map item : edges){ if(id.equals(item.get("id"))){ duplicate = true; } } map.put("id", id); map.put("source", source); map.put("target", target.getName()); map.put("directed", true); map.put("source_score", reverseServiceToServiceMap.get(source) == null ? 0 : reverseServiceToServiceMap.get(source).size()); map.put("target_score", reverseServiceToServiceMap.get(target.getName()) == null ? 0 : reverseServiceToServiceMap.get(target.getName()).size()); } if(!duplicate) { edges.add(map); } addEdge(reverseServiceToServiceMap, target, edges, reverse); }); }
生成的JSON结构如下所示: { "nodes":[ { "globalWeight":4, "name":"AaaSvc(服务Aaa)" }, { "globalWeight":4, "name":"CccSvc(服务Ccc)" }, { "globalWeight":5, "name":"DddSvc(服务Ddd)" }, { "globalWeight":4, "name":"EeeSvc(服务Eee)" }, { "globalWeight":4, "name":"FffSvc(服务Fff)" }, { "globalWeight":3, "name":"BbbSvc(服务Bbb)" } ], "edges":[ { "distance":8, "source":0, "target":1 }, { "distance":8, "source":1, "target":0 }, { "distance":9, "source":0, "target":2 }, { "distance":9, "source":2, "target":3 }, { "distance":9, "source":3, "target":2 }, { "distance":9, "source":2, "target":4 }, { "distance":8, "source":4, "target":3 }, { "distance":8, "source":3, "target":4 }, { "distance":9, "source":4, "target":2 }, { "distance":7, "source":0, "target":5 }, { "distance":7, "source":5, "target":1 }, { "distance":7, "source":1, "target":5 } ] }
4、使用d3-force对如上的JSON进行展示: 测试项目_testDemo -- 服务Aaa_AaaSvc -- 服务关联图

测试项目_testDemo -- 服务Aaa_AaaSvc -- 服务关联图

重力调节 最短边长 边长放大倍数 最短半径 半径放大倍数 箭头大小

最终运行的效果如下:

云计算
2018-09-28 20:20:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
近日,阿里巴巴在Github上线了静态开源站点搭建工具 Docsite ,这是一款集官网、文档、博客和社区为一体的静态开源站点的解决方案,具有简单易上手、上手不撒手的特质,同时支持react和静态渲染、PC端和移动端、支持中英文国际化、SEO、markdown文档、全局站点搜索、站点风格自定义、页面自定义等功能,借助Docsite,可以极大的提高前端工程师搭建静态开源站点的效率。
近年来,随着Github Pages 的静态托管服务的兴起,静态站点生成器因为其静态生成对托管环境要求低、维护简单、可配合版本控制、灵活又多变的优点,获得了极大的发展,涌现出一批优秀的静态站点解决方案。
阿里巴巴前端开发工程师尹挚介绍道:“虽然目前有不少的静态站点生成器,但在我们的前期调研过程中发现,这类解决方案,例如Gatsby、docsify,或直接在wiki上写,并不能完全满足我们的需求,于是我们就自己着手打造一款静态站点搭建工具。因为主要用于静态站点的搭建,且支持 markdown 文档,所以就把他起名为 Docsite。”
目前,阿里巴巴已经开源400多个项目,如果每个项目都上线一个项目官网,会耗费大量的前端开发资源。此时,借助Docsite,将极大的提高网站的上线效率,同时方便对网站的用户体验进行统一和规范。
据悉,阿里巴巴Dubbo、Nacos等多个开源项目已在使用Docsite。
云计算
2018-09-28 17:10:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
负载均衡(Server Load Balancer)是将访问流量根据转发策略分发到后端多台云服务器(ECS实例)的流量分发控制服务。负载均衡扩展了应用的服务能力,增强了应用的可用性。
负载均衡通过设置虚拟服务地址,将添加的ECS实例虚拟成一个高性能、高可用的应用服务池,并根据转发规则,将来自客户端的请求分发给云服务器池中的ECS实例。
负载均衡默认检查云服务器池中的ECS实例的健康状态,自动隔离异常状态的ECS实例,消除了单台ECS实例的单点故障,提高了应用的整体服务能力。此外,负载均衡还具备抗DDoS攻击的能力,增强了应用服务的防护能力。
组成部分
负载均衡由以下三个部分组成: 负载均衡实例 (Server Load Balancer instances)
一个负载均衡实例是一个运行的负载均衡服务,用来接收流量并将其分配给后端服务器。要使用服负载均衡服务,您必须创建一个负载均衡实例,并至少添加一个监听和两台ECS实例。 监听 (Listeners)
监听用来检查客户端请求并将请求转发给后端服务器。监听也会对后端服务器进行健康检查。 后端服务器(Backend Servers)
一组接收前端请求的ECS实例。您可以单独添加ECS实例到服务器池,也可以通过虚拟服务器组或主备服务器组来批量添加和管理。
如下图所示,来自客户端的请求经过负载均衡实例后,监听会将请求根据配置的监听规则分发给后端添加的ECS实例处理。
产品优势 高可用
采用全冗余设计,无单点,支持同城容灾。搭配DNS可实现跨地域容灾,可用性高达99.95%。
根据应用负载进行弹性扩容,在流量波动情况下不中断对外服务。 低成本
与传统硬件负载均衡系统高投入相比,成本可下降60%。 安全
阿里云对开源四层负载均衡LVS的管理软件Keepalived进行了全面优化,使得基于LVS的四层负载均衡具备接近于实时防御的能力。结合云盾,可提供5G以下的防DDOS攻击能力。
采用Tengine作为负载均衡基础模块的七层负载均衡具备多维度的CC攻击防御能力。
关于负载均衡的详细内容: 负载均衡入门与产品使用指南
(负载均衡(Server Load Balancer)是对多台云服务器进行流量分发的负载均衡服务,可以通过流量分发扩展应用系统对外的服务能力,通过消除单点故障提升应用系统的可用性。
本课程主要介绍负载均衡的相关技术以及阿里云负载均衡产品的使用方法)
更多精品课程:
阿里云大学官网( 阿里云大学 - 官方网站,云生态下的创新人才工场 )
云计算
2018-09-27 15:18:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
摘要: MaxCompute大数据计算服务,能提供快速、完全托管的PB级数据仓库解决方案,能够使用户经济且高效地分析处理海量数据。而用户往往之前使用了Hadoop实现大数据计算任务,在选择了阿里云大数据计算服务之后,如何从Hadoop向MaxCompute进行迁移就成为了一个需要面对的问题了。在本文中,阿里云数据技术专家结网就为大家分享了从Hadoop迁移到MaxCompute的理论与实践。
直播视频回看, 传送门!
分享资料下载, 传送门!
更多精彩内容传送门: 大数据计算技术共享计划 — MaxCompute技术公开课第二季

以下内容根据演讲视频以及PPT整理而成。
通常而言,将Hadoop迁移到MaxCompute会分为两个主要部分:数据迁移和任务迁移。首先,对于数据迁移而言,可以通过Datax、数据集成以及DataxOnHadoop这几种工具实现。Datax是阿里云开源的一款数据传输工具;而数据集成的底层就是由Datax实现的。如果在数据迁移的过程中要使用Datax,那么需要用户来自定义调度,这对于gateway资源具有一定的要求。Datax在做数据传输的时候需要有一个管道机,通常就称之为gateway,数据的传输都是通过这个gateway来实现的,因此在使用Datax的时候对于gateway的资源是具有一定的要求的。此外,数据集成是在DataWorks里面集成化的数据传输工具。如果想要应用数据集成,那么其调度就是在DataWorks里面完成的,设置完数据周期等一些属性,DataWorks就可以自动实现任务的调度。如果使用数据集成,在网络允许的情况下,可以使用DataWorks的gateway公共网络资源,如果网络不允许则可以使用自定义的调度资源。
除了上述两种方式之外,还有DataxOnHadoop。DataxOnHadoop运行在客户端,用户自己进行调度,与前面的两种方式最大的不同,就是DataxOnHadoop使用的是Hadoop集群的资源,这就相当于提交MapReduce任务,通过MapReduce任务进行数据传输,因此对于网络的要求比较高。因为需要提交MapReduce任务,这就要求Hadoop集群的每个Worker或者DataNode Manager节点和MaxCompute的Tunnel网络打通,这也是这种方案的应用难点。
除此之外,还有一些因素会影响我们在进行数据迁移时做出方案的选择,分别是网络、数据量和迁移周期。对于网络而言,通常分为这样的几种类型,混合云VPC,也就是客户本地机房与阿里云打通在一个VPC里面,还有客户本地机房,一般而言客户的本地机房会有一部分主机具有公网IP,这时候在进行数据迁移的时候就倾向于使用Datax,这是因为客户的集群没有办法直接与MaxCompute打通,还可能使用数据集成,通过使用自定义调度资源来完成这个事情。此外,还有一种情况就是客户集群位于阿里云上,对于经典网络集群,可以通过数据集成直接将数据迁移过来;而对于VPC网络而言,数据集成可能无法直接深入VPC内部,这时候也需要自定义调度资源。当然对于VPC集群而言,也可以DataxOnHadoop,每个节点正常情况下会与MaxCompute的Tunnel可以打通。对于混合云VPC而言,其选项会比多,数据集成以及DataxOnHadoop都可以使用。而对于数据量而言,可以和迁移周期综合起来考虑,线下机房需要迁移的数据有多大以及要求的工期有多长也会影响我们选择的数据迁移方式,并且对于需要准备的网络带宽等资源也是有影响的。
Datax
从总体上而言,Datax改变了一种模式,就是数据的导入和导出,比如MySQL到Oracle或者MySQL到ODPS都是单点的,每一种导入和导出都会有单独的工具作为支持。而Datax就实现了各种插件,无论是各个数据库之间如何导入导出,都是通过Datax的gateway实现中转的,首先到Datax,然后再到ODPS,这样就从原来的网状模式变成了星型模式。
下图较好地解释了Datax的应用,可以看到前面有一个ReadPlugin,无论是从哪个源端到哪个目标端,都是有一个Reader。对于MySQL而言就有一个MySQLReader,对于HDFS,就有一个HDFSWriter,这样结合MySQLReader和HDFSWriter就能形成MySQL到HDFS的传输。再设想一下,下面还有一个ODPSWriter,那么也就能够通过MySQLReader到ODPSWriter,形成这样的链路,从而能够形成各种组合,打通各条链路。而之前提到的Reader和Writer都是在gateway上运行的,需要从源端读取数据,向目标端写入数据,所以gateway需要占用带宽资源以及CPU内存资源,这也就是为何需要考虑gateway以及其资源的原因。
任务迁移
除了数据迁移之外,还需要关注任务迁移。这部分也分为两部分,一部分是任务本身的迁移,另外一部分是调度平台的迁移。对于任务本身的迁移而言,比如原来使用的Hive SQL,想要迁移到MaxCompute的SQL,这样在迁移的匹配上可能会有一些迁移的工作量。原来在Hive上定义的UDF,写的MaxCompute程序或者Spark任务这些也都需要进行迁移。除此之外,还有一类就是调度平台的迁移,原来的Hive SQL以及MaxCompute程序是通过某些调度工作进行周期性的任务运行,当迁移到MaxCompute之后,这些任务也需要进行相应的迁移。这里列举了两类,一类是迁移之后裸用MaxCompute,就相当于还作为原来的Hive来使用或者还是使用命令行或者API的方式做调用,此时原来的调度系统基本上不用变化,只需要将原来对Hive的接口改为对MaxCompute的接口就可以了。还有一类就是在迁移之后需要通过DataWorks进行调用,这个时候任务迁移的工作量就会大一些,首先需要将原来的任务迁移到DataWorks里面去,其次还要将原来的调度属性也配置到DataWorks里面去。
接下来具体说明任务迁移需要做哪些具体工作,首先Hive SQL到MaxCompute SQL的兼容度非常高,目前而言,Hive的数据类型基本上直接可以对接到MaxCompute中,MaxCompute对于Hive语法而言也是基本上兼容的,仅需要简单调试即可。如果UDF不涉及到磁盘读写或者网络IO,也可以直接拿到ODPS来使用的,原来的Jar包不需要修改。MapReduce的改造量相对大一些,这是因为MaxCompute沙箱限制比较严重,那么一些文件读写以及网络IO操作是被禁止掉的。而对于MaxCompute而言,输出输出都是表,而MapReduce主要针对的是HDFS的文件系统,因此需要做映射,对此MaxCompute也提供了相应的工具,只不过相对于UDF而言会略微麻烦一点。除此之外,还有Spark任务,这在原来的HDFS上相对会多一些,之后会有一个SparkOnMaxCompute,可以支持用户将Spark程序无缝地迁移到MaxCompute上。
“HDFS到MaxCompute的数据迁移流程”的具体实操内容演示请见视频内容。
作者: 午夜漫步者
原文链接
本文为云栖社区原创内容,未经允许不得转载。
云计算
2018-09-25 15:09:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
 七牛云发展至今,累积已服务于 70 多万家客户,产品矩阵愈发清晰丰富,围绕富媒体场景推出了对象存储、融合 CDN 加速、容器云、大数据平台、深度学习平台、智能日志分析平台等产品,并提供一站式智能视频云解决方案。而如何保障这些产品的质量,是七牛云工程效率部测试服务一直从事和探索的问题。接下来,我将简要的介绍下我们的具体实践以及一些方向上思考,希望对大家有所帮助。 

整体的测试策略,我们主要落实到四个方向:  
 • 保障基础代码质量 • 构建业务测试覆盖 • 增加质量监测环节 • 普及与改进流程规范 

保障基础代码质量

 首先明确,产品质量并不是简单的测出来的,它依赖于软件生命周期中的各个环节,且越是早期进行质量保证活动,效果会越好。所以在提测之前的基础代码质量上,我们非常看重。在把控上,我们会重点参与到三个交付物环节的 review,具体包括需求评审、架构评审,以及我们的测试设计评审,确保产品从规划、实现和验收标准上就符合整个团队的预期。 
 同时我们也在推广和探索测试技术应如何更好的自动化保障基础代码。比如我们会通过静态扫描周期性的检查所有代码库,为开发人员提供反馈,让其知道哪里做的有问题。同时通过收集语言层面的编程规范,推广 code review 最佳实践。当然,单元测试层面也会重点强化基础服务建设。 
 在七牛云,核心业务库的单测覆盖达到了 80%+,比如核心纠删码存储系统,自研 HTTP 缓存服务等。同时我们会把单测覆盖率统计自动化做到每个 github PR 的统计上,让大家清晰的看到,本次提交的覆盖率详情如何,为研发和 code review 人员提供清晰指引: 
  

构建业务测试覆盖

 有了基础代码的质量保障,我们还要从业务角度关注产品质量到底怎么样,做好质检和验收。 
 先说迭代模式,我们在接到研发的提测需求时,首先会检查这一阶段的准入标准,比如单测是否符合标准,代码是否有人 review 过,不符合标准会被打回,符合标准的,就会进入待测试阶段。之后会在充分把握需求的同时,对具体技术实现细节,进行深入理解和分析,在此基础上进行具体测试场景的设计或者补充,再到最终的测试执行。之后研发在拿到我们输出的验收结论时,也要 review 这个结果,是否有明显遗漏。通过这种互相检查机制,再加上深入到代码细节的白盒测试,确保整个交付的质量严格把控。 
 其次在测试执行的具体策略,也是遵循分层理念,不光验收单个服务的接口行为,还要确保多个服务之间的集成测试,以及最终系统层面的场景验收通过。 
 当然除了常规测试手段,在云服务测试上,还有几个点是我们比较看重的。 
  
常态化并发场景下的测试验收

 云服务一般都是分布式,高可用架构,我们在测试一个接口时,一次请求没问题,不代表这个接口就没问题。很多时候,问题都需要在并发场景,一定压力下才会暴漏。所以在平时的测试验收上,这一点需要特别注意。当然在过往的经验中,我们也积累较多的 go 语言并发模型及相关测试框架的使用经验,能让我们在平时的迭代中,轻松自如的做到这一点。
 
  
高可用测试

 常规的测试验收是保证系统在正常的情形下做正确的事,而高可用测试,考量的则是如果服务所依赖的环境不符合预期了,系统还能正常工作吗?实践发现,在面对多机房,海量机器的场景下,云计算基础设施出问题的概率是非常大的。比较常见的如磁盘损坏、网络故障、机器宕机等等,可能时时刻刻都在发生,每一种故障都有可能引发数据丢失、系统雪崩等重大灾难,对业务造成难以估量的损失。所以云服务的高可用测试尤其重要。 
 有一个很典型的例子,就是我们在验证七牛云存储核心存储引擎的删除回收功能时,需要在测试环境不间断的模拟各种文件的上传与下载,以及随机删除请求,同时还要对整个存储系统注入各种随机的异常场景,如服务挂掉,磁盘损坏等,然后在这样的场景下,连续不间断的测试一个月以上,确保所有预期数据不丢失,不损坏,方才算验收通过。其标准之苛刻,可见一斑。 
  
尽可能提高测试覆盖率

 云服务都是服务海量用户,任何的严重错误都是不可容忍的。但是我们知道测试矩阵又是无穷尽的,在有限的测试人力下,不能盲目地投入到无限测试中去。所以在如何提高测试覆盖率方向上,我们也是一直在探索。目前主要从两大方向着手。一是精准测试,我们内部研发了 go 语言的系统测试覆盖率统计系统,能够精确从源码层面反应测试覆盖程度,来辅助我们日常的迭代。另一方面,通过复制线上真实流量来验收每一个版本迭代,确保无回归问题。这一方案,已运用在七牛云 CDN 缓存系统的常规质量保障上,效果显著。 

质量监测体系

 前面我们从代码质量和业务验证角度,描述我们如何保障质量。但实践中发现,还有些场景和问题,上述场景并不能很好的覆盖到。比如句柄泄露,内存泄露等问题,这种问题需要一定的时间的发酵,且单纯的从业务角度,感知也不会太明显。而质量监测体系就帮我们解决这个问题,所以我们将业务质量的监测结果提升到常规的迭代验收层面。 
 在平时,我们不仅验收服务的对外行为,还需要关注业务调用链是否健康,服务的自身运行时是否有问题,业务性能指标是否有退化等等。通过这些手段,尽可能的在测试阶段就检出更多的问题,减少问题遗漏到线上的几率。如果说业务验收从用户角度来考虑,那么业务质量监测就是从整个系统端来度量。各有各的优势,在质量保证体系里,二者缺一不可。 

流程规范普及与改进

 技术在不同阶段总有其局限性,任何环节出问题,影响产品最终服务客户的质量都是不可容忍的。所以在常规的技术保障之外,我们也会推动和普及一定的流程规范, 确保全流程,各个环节的质量有效把控,比如典型的迭代规范,发布和线上操作规范,以及事故处理流程等等。 
 

 
牛人说

 「牛人说」专栏致力于技术人思想的发现,其中包括技术实践、技术干货、技术见解、成长心得,还有一切值得被发现的内容。我们希望集合最优秀的技术人,挖掘独到、犀利、具有时代感的声音。 
 
云计算
2018-08-14 15:31:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
Thrift 多语言接入
​ Thrift 提供多语言访问HBase的能力,支持的语言包从Thrift官网看括: C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, OCaml , Delphi 以及别的语言.主要流程是用户thrift Client 通过Thrift协议访问HBase的thriftserver,thriftserver做请求转发给HBase的存储服务来做数据的读以及写操作.大概架构图如下:

​ 要通过thrift 多语言访问HBase需要以下几步:
一、开通HBase thriftserver服务:
​ 在用户自己管控页面点击这里参考开通thriftserver服务化(高可用版本thriftserver),会得到一个host:port的访问入口;或者自己可以选择ECS自建thriftserver方法,参考 这里 ,最终自建ECS的ip (host)以及默认的话9090端口作为访问入口。
二、用户Thrift client访问:
​ 一般客户常见的访问方式是python的访问方式以及php的访问方式 ,这里我们先一步步给出php的访问方式;
2.1 . 以php走thrift访问HBase:
​ 2.1.1 . 安装thrift 编译环境;
​ 我们云HBase的thrift环境是0.9.0,所以建议客户自己建立自己的thrift环境也是0.9.0,这里可以从 这里 下载thrift的0.9.0 版本,下载的源码包我们后面会用到,这里需要先安装thrift编译环境,对于源码安装可以参考 thrift官网 ;
通过如下命令可以看出安装thrift的版本信息; thrift --version
​ 2.1.2. 生成thrift访问client的访问文件;
​ 我们从 这里 下载出我们云HBase的Hbase.thrift文件,这里我们云HBase使用的是thrift1协议,具体可以参考文件看出使用格式,下载完成以后执行thrift命令进行编译;
​ 编译命令如下: thrift --gen Hbase.thrift
​ 上述是语言的缩写,那么常见的有如下: thrift --gen php Hbase.thrift thrift --gen cpp Hbase.thrift thrift --gen py Hbase.thrift
​ 执行thrift --gen php Hbase.thrift 以后会在目录下得到gen-php 这个就是我们需要的函数包文件; thrift git:(last_dev) ll total 56 -rw-r--r-- 1 xuanling.gc staff 24K 3 5 15:06 Hbase.thrift drwxr-xr-x 3 xuanling.gc staff 96B 8 1 16:03 gen-php
​ 此外我们在2.1.1得到thrift的源码包文件将下载到的Thrift源码文件夹下的/lib/php/lib下面的Thrift文件夹以及gen-php一起丢在我们的业务逻辑代码一个src目录下面,加上我们自己的client.php的代码,目录结果如下所示: [root@xxxxxxxxxxx thrift_client]# ll total 12 -rw-r--r-- 1 zookeeper games 2743 Aug 2 11:16 client.php drwxr-xr-x 3 zookeeper games 4096 Aug 2 01:22 gen-php drwxr-xr-x 12 zookeeper games 4096 Aug 2 01:22 Thrift
​ 2.1.3. php访问代码编写;
​ 这个时候,我们来编写我们的client.php代码逻辑,上述的Thrift文件夹以及gen-php文件夹,可以随自己项目以及个人风格命名,这里方便大家搞清目录结构,就保留原来风格;下面贴出php的代码,我们下面的所有程序都是在HBase 建了一张表"new": setSendTimeout(10000); // 发送超时,单位毫秒 $socket->setRecvTimeout(20000); // 接收超时,单位毫秒 $transport = new TBufferedTransport($socket); $protocol = new TBinaryProtocol($transport); $client = new HbaseClient($protocol); $transport->open(); ####列出表#### echo "----list tables----\n"; $tables = $client->getTableNames(); foreach ($tables as $name) { var_dump($tables); } $tablename='new'; ####写数据#### echo "----write data----\n"; $row = 'key'; $value = 'value'; $atrribute = array(); $mutations = array( new Mutation(array( 'column' => 'info:cn1', 'value' => $value )), ); try { $client->mutateRow($tablename, $row, $mutations, $atrribute); } catch (Exception $e) { var_dump($e);//这里自己打log } ###读数据#### echo "---read data---\n"; $result = $client->getRow($tablename, $row, $atrribute); var_dump($result); ###删数据#### echo "---delete data---\n"; $client->deleteAllRow($tablename, $row, $atrribute); echo "---get data---\n"; $result = $client->getRow($tablename, $row, $atrribute); var_dump($result); ?>
​ 代码执行结果如下: [root@xxxxxxxxxxx thrift_client]# php client.php ----list tables---- array(1) { [0]=> string(3) "new" } ----write data---- ---read data--- array(1) { [0]=> object(Hbase\TRowResult)#8 (3) { ["row"]=> string(3) "key" ["columns"]=> array(1) { ["info:cn1"]=> object(Hbase\TCell)#10 (2) { ["value"]=> string(5) "value" ["timestamp"]=> int(1533179795969) } } ["sortedColumns"]=> NULL } } ---delete data--- ---get data--- array(0) { }
2.2.python访问流程;
​ 此外还有常见的python的客户,对于python的话,有happybase这种python的第三方包含thrift的库去做,我们见过一些客户使用Happybase进行访问HBase thrift,参见 文章 ;此外,python 有丰富的库,我们通过pip可以安装thrift,以及访问HBase的thrift库;执行流程如下,假设用户已经安装python以及pip: pip install thrift //安装thrift默认最新版本 pip install hbase-thrift //安装hbase thrift接口库
​ 上面2步执行完成以后,既可以编写访问HBase的代码: import sys import time import os from thrift import Thrift from thrift.transport import TSocket, TTransport from thrift.protocol import TBinaryProtocol from hbase import ttypes from hbase.Hbase import Client, ColumnDescriptor, Mutation def printRow(entry): print "row: " + entry.row + ", cols:", for k in sorted(entry.columns): print k + " => " + entry.columns[k].value, print transport = TSocket.TSocket('hb-bp12pt6alr1788y35-001.hbase.rds.aliyuncs.com', 9099) transport = TTransport.TBufferedTransport(transport) protocol = TBinaryProtocol.TBinaryProtocol(transport) client = Client(protocol) transport.open() print "---list table--" print client.getTableNames() table="new" row="key" print "---write data---" mutations = [Mutation(column="info:cn1", value="value")] client.mutateRow(table, row, mutations) print "---get data----" printRow(client.getRow(table, row)[0]) print "---delete data---" client.deleteAllRow(table, row) print "---end----" transport.close()
​ 对应上述的程序执行的结果如下: [root@Test ~]# python Hbase_client.py ---list table-- ['new'] ---write data--- ---get data---- row: key, cols: info:cn1 => value ---delete data--- ---end----
三、访问HBase thriftserver
​ 3.1、访问机器开通白名单
​ 将访问的机器的ip加入HBase集群的白名单,然后就可以正常执行代码;
作者: 玄陵
原文链接
本文为云栖社区原创内容,未经允许不得转载。
云计算
2018-08-13 10:33:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
本文作者:HelloDeveloper
10 月 27 日,82 期百度技术沙龙,邀请了数位百度前端技术部 Web 前端资深研发工程师,从 Web 前端技术出发,通过五个主题,立足现在面向未来,由内到外地分享百度在搜索组件化的探索、搜索体验增强、开放 Web 速度优化及开放 Web 未来发展发面的技术沉淀和积累。
1
搜索组件化探索与实践
首先进行分享的是百度前端技术部资深研发工程师陈骁带来的《搜索组件化的探索与实践》。
为什么搜索要做组件化?
据陈骁介绍,最开始的百度搜索移动端的前端架构是从 PC 时代迁移过来,服务器端使用 Smarty 来渲染模版,实现前后端分离。前端使用 Zepto 来完成交互逻辑,但是它的扩展性比较有限,难以实现对 HTML、CSS 代码的组件化管理,随着移动端的交互形式越来越复杂,原本的方案出现了局限性。
于是,组件化应运而生。组件化是把一些可复用的单元提取出来,通过对几个组件的管理,实现对整个搜索结果页样式的控制,提高开发的效率和横向团队整体升级的效率。
目前百度已经有了非常多的组件化解决方案,包括 Lavas 和 Reac t。可以具体到组件语法、基础框架以及同构区块。
如下图所示,组件语法包括四部分:
Template:组件代理结构
浏览器端:组件前端逻辑
Style:前端样式
Config:同构逻辑

前三部分基本能够覆盖组件的常用语法,而同构在服务器端和浏览器端都能执行,主要有 props、data、components、computed 等。
那么这个组件代码怎么在线上跑起来呢?
首先会在线下通过编译器,把它编译成 PHP、JavaScript 两份原码。PHP 的编译产物完全使用 PHP 的语法,可以在后端形成一个 Server Runtime,在这个过程中,也能够把 PHP 的编译产物渲染成字符串,通过网络传输到浏览器端。而在浏览器端运行时可以用编码产物 Javascript 的组件,渲染成可操作的 HTML 代理结构,包括它的事件和交互。
其中的难点在于怎么把一个组件代码编译成在 PHP、在 JS 都能跑的组件代码。百度会做对于模板和一些表达设计的处理。例如,模板代码有一个文本节点,有一个自定义组件,在编译的过程中,会利用编译器把它转化成抽象语法树,形成树的结构,每个节点都有一些属性和信息,利用语法树的结构和属性信息,就可以通过代码生成器分别生成 PHP 和 JS 的代码。

这里还有一个问题,为什么需要一个同构区块呢?这是因为同构区块可以很好控制服务器端能执行的代码,方便语法解析。另外,百度对同构代码块进行语法限制,以保证服务器端的稳定性,也可以更加方便解析成想要的 PHP 代码。
通过改造,组件化渲染框架不仅可以使得效率提升,保证了体验一致性,而且进行了横向升级降低成本。
性能优化
针对服务器端的渲染性能,百度做了非常细致的优化:
在框架层,对渲染流程进行了简化,添加了缓存;
在基础组件层,对控制的简单组件进行编译优化;
在业务层,提供先验工具、准入规范,线上监控和报警,并提供 a-nossr 指令。
那么组件是如何在服务器端渲染成想要的 HTML 字符串呢?
如下图所示,会经过以下步骤:首先,加载组件的配置,创建组件的实例。在实例的创建过程中,对这个组件所有的数据进行初始化,包括一些特征和计算属性,得到初始化状态以后,再渲染出虚拟 DOM 树,把整个组件节点数渲染成一个实例的形式,用虚拟 DOM 树渲染成 HTML 字符串。

与此同时,百度搜索对整个渲染的过程进行了简化。在框架层,通过创建虚拟 DOM,减少了一次递归,也减少了在线上运行时的逻辑。在基础组件层,百度对横向团队能够完全控制的一些简单组件进行了优化。利用 HTML 编译器编译成语法树,语法树对它每一个 AST 节点进行优化,通过将 Tag 直接定义为普通的 DOM 节点的方法,生成最后想要的函数代码。

框架层:渲染流程简化

简单组件编译优化
目前进展
目前,百度提供搜索组件化的工具。比如搜索 Web 无障碍规划、搜索性能准入规范、搜索设计规范;服务方面包括性能监控、前后端异常监控等;运行方面提供 VSL 语音交互框架帮助开发者开发一些语音交互逻辑;工程方面提供搜索敏捷平台,帮助开发者直接完成联调、提测、上线;在应用方面,有卡片、图片搜索、咨询搜索、移动端的首页,还有一些独立的站,包括百度体育和百度招聘。

搜索组件化技术全景图
2
移动体验标准化建设
第二个 Session 是由百度前端技术部资深前端工程师刘浪宇带来的《移动体验标准化建设》。
极致的用户体验是 Web 产品所追求的,那么什么是好的用户体验,如何去量化用户体验做到好的体验呢?首先需要有一套清晰的体验指导标准,然后再去落地。
移动体验指南
移动体验指南是基于移动 Web 生态提出一套通用的体验指导规范,目的是更好地服务于用户及产品的系统,为广大用户提供优质的体验。从用户的体验层次、交互和移动 Web 现状,百度归纳出六个纬度:
第一,快速的信息呈现。速度快慢直接影响用户对站点的体验评级,所以让主体内容快速呈现给用户才是优质的体验必需的。
第二,设计交互层面强调一致性。一致的设计交互可以利用用户的学习经验,降低学习和使用的成本。
第三,好产品需要做到让用户低成本、高效地完成所有交互操作,整体操作要清晰无阻,带给用户最流畅的体验。
第四,内容强调优质阅读观感。站点的内容可读性、内容本身质量是否能够达到,都是优质的体验所必需的。
第五,情感层面有两点,首先是愉悦的情感认知,其次是让用户对站点信任,页面是否安全、是否及时告知流量信息等等。
第六,关于强健的场景适配,优秀的站点应当适合于不同的人群和宿主环境。
移动体验检测平台
有了体验指南,如何快速知道站点存在哪些问题?这就需要体验检测平台 Radar。
Radar 的最底层是 Headless Chrome,百度通过协议接口可以非常快捷地操作这个浏览器。中间的运行是基于谷歌开源的一个网页工具 Lighthouse 。它主要有两个内容,第一是网页数据收集,通过数据分析获得数据,按照规则的需要,对于这些数据进行分析后输出想要的结果。第二,Radar 的核心是非常多的规则,主要分两类,一类是普通的,一类是交互的。
刘浪宇以交互的规则为例,详细阐述了一个规则是如何实现的。如下图,交互的规则主要分为两部分,第一是场景识别,第二是交互分析。举一个比较简单的例子,当用户在页面看到一个输入框时,觉得点击可以直接输入是一个良好的体验。那么如何量化这个规则呢?首先是场景识别,找到在这个页面中看起来像评论输入框的元素。然后找一些特征,从海量数据里面标注、提取一些通用特征之后为这个场景建立特征库。之后再基于场景所需要的特征,进行网页结构化数据提取。

Radar 规则架构(交互类规则为例)
接下来这些场景元素就要进行交互分析,首先进行深度筛选然后进行交互操作。以模拟屏幕的点击举例,点击之前用户会看页面的变动,比如说 DOM 的变动、跳转的变动,然后对变动进行分析,看是否符合预期。
3
基于 Custom Elements 标准组件化构建 Web 应用
第三个主讲人是百度前端技术部资深前端工程师邹淼江,他现场分享了如何高效快速的构建一个体验良好的 Web 应用、基于 Custom Elements 标准的组件化设计、如何提升用户端体验和开发效率。
首先看自定义标签,自定义标签在功能上逻辑上与 JavaBean 类似,都封装 Java 代码,是可重用的组件代码,并且允许开发人员为复杂的操作提供逻辑名称。另外,自定义标签具有⽀持⽆障碍、提高开发效率、评估性能、对 SEO 良好的特点。
其中,如何使用自定义标签进行性能评估呢?百度提供了一套搜索引擎的验证工具。比如,符合某一种规则的 Custom Elements,给它标高分,为符合高性能标签。但如果使用 DIV 的方式,搜索引擎没办法知道布局是不是高性能,也没办法知道所对应的 JS 如何实现,如果有了 Custom Elements 的标准,就能清晰地知道这个页面想干什么。
基于此,我们可以设想:如果完全使用这些 Custom Elements 语义化标签构建 Web 站点可行吗?
这就需要引入组件化设计。其实目前存在的组件化设计都千篇一律,把一个页面的功能模块以组件树状的形式自由组合,堆积成一个功能的页面或者是模块,这就是组件的结构。具体要求:
每⼀个 Custom Element 是⼀个组件
组件内部实现相应的交互、功能和数据处理逻辑
组件之间逻辑和样式是独⽴隔离的
组件是可以通信的
组件是可复⽤的
Web Components 标准
Web Components 是指通过一种标准化的非侵入的方式封装的一个组件。主要标准包括 Custom Elements,Shadow DOM,HTML Templates,HTML Imports 等多个维度的规范与实现。
Custom Elements 是提供一种方式让开发者可以自定义 HTML 元素,包括特定的组成,样式和行为。支持 Web Components 标准的浏览器会提供一系列 API 给开发者用于创建自定义的元素,或者扩展现有元素。
Shadow DOM 旨在提供一种更好地组织页面元素的方式,来为日趋复杂的页面应用提供强大支持,避免代码间的相互影响。开发者可利用 Shadow DOM 封装自己的 HTML 标签、CSS 样式和 JavaScript 代码。
HTML Imports 是一种在 HTML 中引用以及复用其他的 HTML 文档的方式,可以简单理解为常见的模板中的 include 之类的作用。我们可以通过 HTML Import 的形式,直接将做的 Custom Elements 的标签放进 HTML 中进行渲染渲染。

Web Components 兼容性
4
搜索落地页体验技术及应用
第四个主题由百度前端技术部前端工程师李兆明讲述。如何更快、更好的将各类搜索结果页面传递到用户端一直以来是百度搜索前端的核心关注点。基于此,李兆明分别从如何让落地页加载更快,如何让搜索结果页和落地页之间切换更加顺滑以及未来的新标准,介绍百度搜索落地页体验技术的探索。
如何让落地页加载更快
思路一:提前加载。通过 Resource Hint 提示浏览器预解析域名、建立预连接,甚至进行预渲染。若是不支持的浏览器,则可以通过 JavaScript 模拟一部分。
思路二:抓取数据。通过开放平台提交数据,由百度来渲染。
思路三:MIP / AMP。MIP 提供多重措施,让使用 MIP 技术的页面加载速度更上一层楼。例如,CDN 加速服务;使用 MIP 设计的网站没有任何可以阻塞渲染的脚本,所有脚本都在页面主体加载完成后才执行。此外,MIP 要求所有页面都是静态的,如果有需要实时更新的数据需要异步获取,这样设计节省了后端的渲染时间。
如何把两个页面融合在一起?
其实,无论有多少优化加载速度的手段,归根结底离不开页面跳转。但是,浏览器跳转相对来说不够平滑,用户体验不够好,能不能把前后两个页面融合到一起呢?
答案当然是肯定的。李兆明在保证体验、保障安全及保持开放的基础上,讲解了百度前端搜索的解决方案:
保证体验:通过 Iframe 加载页面;通过 PostMessage 等方法实现交互动效。
保障安全:不允许使用外部脚本,需要封装组件审核;通过校验确保 HTML 符合规范。
保持开放:通过 GitHub 追踪开发。
展望新技术
在未来,百度搜素将基于域名、Iframe 渲染问题,为开发者带来 Navigation Transition、Promotable Iframe、Portals 及 Web Packaging 新标准,带来最流畅的体验。
Navigation Transition:页面切换的交互方式。解决了跨域问题,没有 Iframe 渲染的历史包袱。不过前一个页面依然不能控制后一个页面的加载、渲染。iframe 可以提前加载,但是 Navigation Transitions 一定要在用户切换的时候加载。
Promotable Iframe:与 Iframe 相关,核心代码是 Promotable 的 API,只要调用 Promotable,就会调动页面的一小块,而后调动整个页面及内容。但是这种方法涉及一些生命周期的管理和 JS 的回收问题,是不够安全的实现,而且这样没有解决 CDN 的问题,依然需要改域名。
Portals:传送门,将一个页面传送另一个页面。这个标准是 Promotable Iframe 的增强,引入了一个新的 HTML 标签 portal,这个标签用来替代 Iframe 显示一块网页,写法和 Iframe 类似。但是它比 Iframe 多一个功能,就是可以通过 “active” 方法激活它。与此同时, portal 的子文档会收到一个 portal zactive 事件,事件中可以拿到它的上级元素,这样又可以把上级元素当成一个 portal 插入回自己的文档流,使得页面切换回去成为可能。
Web Packaging:解决了 CDN 跨越问题。这个标准包括三方面:签名、打包、加载。如下图,左边内容提供者是站长,缓存的 CDN 类比 MIP 的 CDN ,右边是访问用户,用户浏览我们百度搜索结果页的时候,通过 MIP 的 Cache CDN 提前把数据取过来,用户真正点击的时候,直接从刚才取回来的页面去加载它。由于内容本身是内容提供者提供的,所以他可以对于自己 URL 进行签名。有了这个签名且签名有效的时候,浏览器可以自己显示原始的网址,同时原始的网址可以和原来的服务器进行交互,像通过原网址打开的一样,解决了 CDN 跨域问题。

5
如何通过 Lavas 快速构建 PWA 站点
最后一个主题的讲师是百度前端技术部资深研发工程师王轶盛为大家介绍如何通过 Lavas 快速构建 PWA 站点。
PWA
PWA(Progress Web App)是 WEB 未来的发展方向。从体验上来说,PWA 接近原生 APP,通过 Manifest 技术允许用户快速打开站点并获得沉浸式的体验,通过 Service Worker 能够做到资源预加载和离线可用等从而提升性能和可用性;同时 PWA 又拥有 Web 站点的共同优势:免安装和自动更新。
但与 Web 站点不同的是,PWA 又具有可靠、快速、黏性等特点:
第一是可靠。在断网的情况下,PWA 可做到比较友好的离线提示,这个是 PWA 断网的最高级,叫断网可用。
第二是快速。53% 的用户会放弃加载时间超过 3 秒的网站,越快的加载速度就有越少的用户流失。PWA 提供 Service Worker,确定哪些访问缓存、哪些访问网页,缩短加载时间。
第三是黏性。黏性是指用户访问过一次,下一次访问是否麻烦。PWA 会用一个半秒的启动动画来保证浏览器首页启动的顺滑。另外,启动之后没有的地址栏、菜单栏,保证用户的沉浸式体验。
从技术层面讲,PWA 有分为四部分:
第一是 Service Worker 。定义预缓存、网络拦截和缓存策略。它本身是一个 Worker,有专门的语法,需要 CACHES API,需要注册及更新。
第二是 Manifest 。这是一个 Json 文件,定义快速入口,启动动画。
第三是 Web Push and Notification 。是服务器推送给客户端的主动通知。
第四是 APP Shell 。这并不是新技术,但它是常用的 PWA 架构。简单来说,就是把一个 APP 分成了外壳和内容,用 Service Worker 把外壳缓存起来,将里面的页面进行跳转。
通过 Lavas 搭建 PWA 站点
Lavas 包括工具、文档以及对应的解决方案和建站模板,是一个开源的解决方案。Lavas 本身有两部分,Lavas cli 和 Lavas core,内部用 Vue + Vue Router + Vuex 搭建站点,内置两套模板 (basic & app-shell),支持传统模式 SPA 和 SSR 快速渲染,可以快速拥有 PWA 特性,灵活性强,配置简单,而且文档及时更新,内容完整。通过 Lavas 搭建 PWA 站点主要有八个步骤:
准备环境 & 初始化项目。安装 Lavas cli,初始化项目,选择模板,安装依赖。

创建新页面。

添加链接。使用 ,注意和 Vue 保持一致,to 属性指明目标页面,支持字符串格式的地址,支持对象。然后启动调试服务器。

和服务端通讯。安装 axios,引入 axios,向后端发送请求。

使用 Vues 管理数据。
创建 STORE,需要定义一些内容。把请求数据移动到 action 里面,获取成功后调用 commit 触发 mutation 去更改 state。
在组件中,通过 store.dispatch 触发 action 获取数据,然后通过 mapState 把 state 和计算属性关联,最后通过计算属性在页面上使用。

配置 Manifest 。Manifestt.json 定义了启动 URL,定义各种尺寸的 icon,定义动画配色和启动模式。

配置 Service Worker。配置,指定模板位置、构建位置

构建和上线。执行构建命令 > lavas build;启动生产环境 > cd dist,> lavas start。
Lavas 技术原理
Lavas 的技术原理主要有自动生成路由规则、Skeleton、App Shell。
Vue Router 需要四个步骤做整件事情:第一步定义和引用组件,第二步把组件和路由联系起来,第三步是把刚刚联系起来的数据放到 Router 函数创建实例,第四是把 Router 放到 VUE 创建实例,结束 Vue 实例挂载就。
经过改进, Router 不用自己定义页面级组件,可以认定只要在 Pages 目录中,那组件都是页面级的,从而可以实现自动化 Import,不需要每次写一大堆的代码。另外,绝大多数情况路由规则和组件名称是有对应关系的。自动生成路由规则映射,省去了列出映射关系的麻烦,也避免后期组件改名带来的维护成本。
Skeleton 叫骨架屏,就是实际内容展现之前,有个大概内容给用户看,这样用户提前看到一些东西。这是 Loading 升级版,因为每个组件可以自定义样式、切换时机、列表等。
Lavas 的 Skeleton 都可以用,实现思路是 Vue 的挂载点一般是个空的 DIV,在构建时将 Skeleton 的内容添加到挂载点中,Vue 挂载前清空 DIV 内的占位内容,挂载后渲染为实际内容,使用 SW 预缓存 HTML,访问时直接从缓存中获取 HTML,这样可以让用户看到占位的东西。
App Shell,就是把一个 APP 分两部分,有外壳和内容,把外壳缓存起来,每打开页面先把外壳拿出来,然后再是内容渲染。App Shell 实现有两个步骤,第一是划分,告诉程序哪部分是外壳、哪部分是内容;第二是程序把外壳缓存起来。这需要实现两方面,第一是 SPA,首次请求服务器返回 Index.HTML,所有页面的渲染均由 JS 完成,只在挂载点内重新渲染,单页 Index.html 就是 Shell,使用 SW 预缓存 Index.html 即可。第二是 SSR,首次请求服务器返回给全部内容,后续页面的渲染由 JS 完成。
Web 生态的发展就是互联网的发展,新技术的不断涌现和新场景的不断实现也让这个开放的生态得以持续繁荣。王轶盛表示,百度希望国内的开发者与站长能够多多参与到 PWA 项目中,共同建设和改善国内的 Web App 生态。
原文链接地址: https://developer.baidu.com/topic/show/290231
云计算
2019-07-23 16:57:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
本文作者:HelloDeveloper
在 6 月 16 日由 @百度 主办、 @InfoQ 负责策划组织和实施的第 27 期百度技术沙龙活动上,来自百度高级工程师,用户体验研究平台技术负责人王集鹄( @王集鹄 ),街旁前端工程师齐伟(@hustkiwi)分别分享了各自在 HTML5 技术实践上取得的成果及经验,话题涉及“HTML5 中的图形图像处理”,以及“应用 HTML5 搭建街旁新版混合式 iOS 客户端”等。本文将对他们各自的分享做下简单的回顾,同时提供相关资料的下载。


主题一:HTML5 中的图形图像处理(微盘下载讲稿,Demo 下载)
来自百度高级工程师王集鹄第一个为大家分享,本次演讲主要对 HTML5 中 Canvas 和 SVG 矢量图的使用经验以及对曲线变化进行了研究,并通过丰富的 Demo 与参会者分享了一些综合应用。王集鹄首先分享了来自ie6countdown.com上的一份数据,数据表明:
目前,全球范围内,IE6 使用比重最多的国家就是中国,占到了 22.4% 的比重。然而其他国家的占比则非常小,占比在 1% 以下。
接下来王集鹄分别通过老虎的实例说明了 SVG 缩放时不失真的特点,还演示了 SVG 动画、Path 和路径编辑器、Canvas 热力图、贝塞尔曲线等精彩的示例。此外,还对 2012 年春节时,百度首页的舞龙效果进行了技术分享,最后,王集鹄对本次的分享进行了总结:
HTML5 发展现状
SVG 两种加载方式
Canvas 的像素处理,包括二进制存储
Canvas 动画原理、性能、时间轴
SVG Path 辅助工具——路径编辑器
贝赛尔曲线两个公式:计算轨迹、切分曲线
SVG+ 前端模版组合
Canvas 中绘制 SVG
更多精彩内容和演示代码请参考讲稿和 Demo。
主题二:应用 HTML5 搭建街旁新版混合式 iOS 客户端(微盘下载讲稿)
街旁前端工程师齐伟第二个为大家分享,混合式应用(Hybird App)继承了方便调用原生接口操控底层 API 与应用 HTML5 前端技术快速开发的优点。随着移动设备硬件的提升,成为一种可行的应用开发架构趋势。在街旁新版 iOS 客户端“街旁 5”中,对应用 HTML5 搭建混合式应用进行了大胆实践,并积累了一些有关混合式应用开发、架构和优化相关的宝贵经验。齐伟首先引用了 Steve Jobs 的话开场:
New open standars created in the mobile era,such as HTML5,will win on mobile devices.
在提到为什么采用 Hybrid 方式时,齐伟提到:
IOS 开发资源不足

很难招到有经验的 iOS 开发者,维护成本较大
需要更快的开发迭代

引入界面及交互上的 AB Test;绕过 Apple Store 发布流程的 Bugfix
接下来讲解了 Native 和 WebView 的相互调用方法,并针对使用 Backbone.js 给出了使用建议:
1.API 应严格遵循 RESTful JSON 接口规范
2.避免在不被销毁的标签上绑事件
3.统一捕获跳转事件
最后,齐伟还谈到了在使用 LocalStorage 中所遇到的挑战:
1.是同步的,会阻塞网络
2.对 I/O 有操作,时间不可控
3.有大小限制,甚至在内存吃紧时会丢数据
Open Space(开放式讨论环节)
和以往的环节一样,​为了让参会者能够有更多的时间进行相互的交流,本次活动依然设置了 Open ​Space(开放式讨论)环节。除了讲师王集鹄、齐伟外,Storm 团队 @含冰、@Mr.Null,蒸汽猛犸团队张振熙也参与了小组讨论。在 Open Space 的总结环节,几位话题小组长​分别对讨论的内容进行了总结。
王集鹄:主要讨论了 HTML5 目前的应用情况,以及性能优化的技术细节。
齐伟:主要讨论了通过 Hybrid 的方式,可以借助 HTML5 对于原生 API 的开发支持,但同时在应用和性能方面还有提升的空间,但一致认为这是未来应用开发的趋势。
MR.NULL:主要讨论了如何基于 Canvas 原生事件对层进行捕获,模拟原生 DOM 响应的问题以及动画相关的话题讨论。
张振曦:向大家揭示了“别碰我的妞儿”游戏,是如何在 30 小时内设计和开发出来的。技术层面,一起讨论了粗粒度刷新、细粒度刷新等相关问题。
会后,一些参会者也通过新浪微博分享了他们的参会感受:​​
@破车推荐:@hustKiwi 老师 PPT 的 Transition 效果是世界级的。
@李二栋 Star:主题是 html5 之美,的确是好活动。百度有很大影响力,活动吸引了很多技术大牛和爱好者,从中能了解很多有意义的信息。还好我今天去基本能听懂大思路,因为前段时间看完前端的一本书,有了基础。
@蒋宇捷:第二个演讲里提到的,关于 Linkedin iPad Web 版本的优化方式,我也正好有过相关的文章《 用 HTML5 实现 iPad 应用无限平滑滚动 》: http://t.cn/zOHNB4o 。
@做自己的心理丶医生 v:在# 百度技术沙龙 #听到了第一个干货, 用 HTML5 加 Object-C 开发 app 实在是太不友好了。

原文链接地址: https://developer.baidu.com/topic/show/290203
云计算
2019-07-23 13:16:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
作者:许佳珺


前言
随着越来越多的企业将云计算产品应用到基础设施及其核心业务中,如何提高和保证软件交付质量、减少软件开发迭代周期、加速软件发布频率成为所有云厂商面临的关键问题。
根据IDC 2018年的预测,中国云计算市场在未来5年将持续高速发展的态势,主要表现为:中国传统的非云计算IT基础架构占整体IT基础架构的投入比例将从2018年的50.3%下降到2022年的40.7%;中国私有云平台建设的市场规模将以年均24.8%的复合增长率快速增长;中国云计算IT基础架构支出占全球市场比将从2018年的12%上升到2022年的25%,届时中国私有云IT基础架构支出将超过美国,成为全球第一大市场。在这一轮新的迭代更新中,更多的企业和行业开始部署或者建立更大规模的私有云;而新应用(数据分析,AI,IoT,移动)和新场景(边缘计算,智慧/平安城市,行业云)也对云平台提出了更高的需求。
ZStack凭借创新的产品化理念,在业内率先提出云计算的4S标准 – 简单Simple,健壮Strong,弹性Scalable,智能Smart。同时,ZStack企业版从第一版发布到最新的3.5.0版本,一直以每六周一次的周期迭代更新软件版本,快速提升和扩展产品功能,积极应对云计算市场对私有云产品不断增长的需求。而保证其私有云产品化的关键要素有以下三点:
1. 流程 – 快速敏捷
2. 运维 – 智能高效
3. 测试 – 严谨全面

注:ZStack坚持快速、简洁、高效的开发、运维、测试流程,确保新需求六周便可实现
1. 流程 – 快速敏捷
ZStack开发流程依然定义了传统开发模式中的几个关键阶段 - FF、CF、RC和GA。同时针对不同阶段的任务和目标,进行有的放矢地优化。在Feature Freeze阶段,主要以需求分析为主,要求产品经理将客户的需求分片化、分级化,需求描述本地化,更有效地将需求安排到不同发布版本周期中。开发和测试工程师则需要将Code Freeze和Release Candidate的任务提前到Feature Freeze阶段中,减少互相之间任务的依赖,提高各个阶段的并发度。而测试不仅需要渗透到开发的每个环节中,同时也要通过模型测试、路径测试、稳定性测试等方法,提高代码的覆盖度和测试效率。每个发布周期通过反复地从需求->开发->测试的快速迭代,保证了产品的新需求和问题始终能够被快速满足和解决。
注:ZStack产品开发流程高度并发,保证版本之间快速迭代
2. 运维 – 智能高效
作为私有云产品开发的基础保证,一套快速、稳定、高并发、可伸缩的运维系统是必要的。而传统运维提供的简单CI和CD功能是显然无法满足这样快速迭代的需求。ZStack产品化过程中,搭建了一套以ZStack + Kubernetes为基础、面向公司各个部门的整体性服务框架。这套框架中所包括的服务内容涵盖从开发&测试人员使用的测试环境、到整个项目的管理工具。框架的底层以ZStack作为IaaS提供给上层可靠的、可扩展的物理资源,同时结合Kubernetes,将容器运行于云主机中,既保证了隔离性、又充分利用了ZStack和Kubernetes对云主机和Docker调度的优势,起到了对上层服务高可用、高并发及可伸缩的双重保障。
注:ZStack作为IaaS层向上层服务提供可靠的物理资源,而更重要的是,内部的ZStack环境也会随着发布版本更新,真正做到了自己的产品自己先用起来

注:实际生产环境中,一次自动化测试至少在Jenkins上并发创建500+个请求,每个请求包含10~50个测试用例,ZStack + Kubernetes保证了这些请求几秒内可以被处理
3. 测试 – 严谨全面
打造一个产品化的私有云软件需要全面且严谨的测试,这不仅仅是单元测试和集成测试能保证的。ZStack从以下四个方面入手强化测试:
3.1 测试高效化 :整个产品流程中开发和测试要同步进行,这包括了对不同的开发分支需要有不同深度的测试代码保证其质量——例如,对于Release分支,必须有持续性的Nightly测试把控每天进入的代码质量;对于Feature分支,需要能快速检测出patch对代码核心功能影响的BAT测试。同时测试系统和CI系统要高度集成并且做到同步触发。
高效化的另一个重点就是要做到所有测试都能运行在云端,提高测试的并发度和资源利用率。ZStack内部的测试都是跑在云端的,而云端环境也是基于ZStack自身搭建的,利用其对底层硬件资源的抽象和管理,模拟出测试中需要的不同的硬件配置场景,包括网络、存储、虚拟化平台、甚至不同的ZStack高级功能配置,如企业管理、灾备服务等。同时,为了满足大规模资源需求的测试场景,例如1万台或10万台云主机的测试场景,ZStack测试中还实现了simulator机制,即不真实分配硬件资源,而使用mock后端API的方式提供了对后端资源的调配,真正做到了有针对性的测试。
注:ZStack云端测试的环境构建是通过XML配置文件实现的,测试工程师可以非常简单地用几分钟配置出一台自动化环境
3.2 测试标准化 :ZStack所涵盖的测试内容不仅包括功能性测试,还包括一套完整测试体系所需要的各种测试,如开发工程师需要做的集成/单元测试,测试工程师需要做的系统测试中的压力、性能、可靠性测试、以及针对不同版本定制的发布测试。例如ZStack的可靠性测试就包括了两类测试 – MTBF和DPMO测试,MTBF会对ZStack平台进行15,000小时长时间的真实用户操作模拟;DPMO测试则会对ZStack平台进行高达10,000次的断/上电、重启等测试。
标准化的另一方面体现在对关键节点的标准把控上,对FF、CF、RC和GA各个阶段都会有相应的代码准入和验收标准,例如CF阶段后功能开发代码禁止进入发布分支而只能进入下一个发布版本的周期;又例如各个阶段验收时要求的bug数量限制,CF阶段要求小于5个P0,GA阶段要求没有P0的bug。


3.3 测试覆盖智能化 :软件测试没法达到100%的覆盖率,所以我们要做的是在资源有限的情况下,以尽量少的代价做到尽可能高的覆盖率。要提高覆盖率,需从两方面入手,一方面是对代码进行覆盖率检查,我们在日常CI的包中插入了代码不同模块的覆盖率,不管是手动还是自动测试,或是日常bug的验证,都会为覆盖率提供数据。
另一方面我们增加了模型测试,它可以产生由随机API组合构成的场景,会持续运行直到遇到预定义的退出条件或者找到一个缺陷。这种模型测试很好地弥补了人为定义用例的不足,提高了测试场景和路径的覆盖率。由这种测试模型,也衍生出了三种不同场景的覆盖率提高测试:


3.3.1 覆盖率测试 :除常规有序的测试步骤外,运用模型测试,收集无序测试步骤下的测试覆盖率。
3.3.2 MTBF测试 : 从有序和无序两种测试维度,对系统稳定性及可靠性进行测试。
3.3.3 路径测试 : 通常一个系统测试用例最多5-6个操作步骤,而最终客户的问题场景是极其复杂的,通常需要10~20个以上的步骤才能重现,运用模型测试的方法,可以有效减少构建测试用例的代码量。

注:一个典型路径测试,只需要将测试对象和操作步骤写到测试用例中即可完成
3.4 报告立体化 : 主要从两方面实现,一是测试报告的结果自动化、可读化,是通过对测试用例中插入DITA描述实现的。另一方面是结果的可追溯和可回放,这是通过记录测试过程中API的调用顺序和参数实现的。

注:一个测试结果的操作记录及回放方法,能够有效帮助开发测试工程师重现bug
总结
作为产品化的云计算公司,ZStack一直致力于打造自研的ZStack私有云、ZStack混合云、ZStack Mini超融合一体机、ZStack CMP多云管理平台、ZStack企业级分布式存储等产品和方案。本文从开发流程、基础运维以及测试能效等角度,介绍了 ZStack 团队如何高效打造一个产品化的私有云。


欢迎关注ZStack中国社区QQ群、ZStack官方微信!
云计算
2019-07-19 22:34:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
2019年6月20日,由Rancher Labs(以下简称Rancher)主办的第三届企业容器创新大会(Enterprise Container Innovation Conference, 以下简称ECIC)在北京喜来登大酒店盛大举行。本届ECIC规模宏大,全天共设置了17场主题演讲,吸引了近千名容器技术爱好者参加,超过10000名观众在线上直播平台观看了本次盛会。
来自Rancher、阿里云、百度云、平安科技、中国联通、飞贷金融科技、中国人寿、SmartX、华泰保险、厦门航空、JFrog、新东方、Cisco等十多家企业的技术负责人出席了本届ECIC,现场带来关于企业容器项目实践经验的精彩分享,为参会的容器技术爱好者带来企业容器化的经验分享。
贴近容器用户需求,推动中国容器持续创新
Rancher联合创始人及CEO梁胜表示,容器技术的发展存在周期性,Kubernetes正从初创期走向成熟期,变成一个被云计算服务提供商及数据中心广泛应用的商品。然而容器技术的发展而言是永无止境的,用户需求是容器发展的源动力,同时也是保持容器技术持续创新的关键要素。
Rancher联合创始人及CEO梁胜
梁胜以Rancher 2019年3月发布的史上最轻量级Kubernetes发行版k3s为例验证了他的这一观点:“过去的一年间,数十个和Rancher达成合作的企业客户均向我们表达,他们认为Kubernetes是管理边缘基础设施的理想平台,但他们不愿意在他们的边缘设备中投入大量资源来运行一个成熟的Kubernetes平台。K3s为这些团队提供了一个小于512MB RAM的Kubernetes发行版,非常适用于边缘计算的案例。”
大会上,Rancher还为现场的容器爱好者带来了三个惊喜产品,一是新一代容器化分布式存储项目Longhorn,这是一个开源的、基于云和容器部署的分布式快存储新方式;二是发布了Rancher中国企业版Pandaria,Pandaria是Rancher Kubernetes管理平台面向中国区的企业版本,旨在不断满足中国市场的快速灵活多变的需求,主要功能包括Harbor镜像仓库集成、支持Audit log 审计日志、为国内公有云提供更多的优化支持等;三是进行了Rancher 2.3 Preview发布及功能演示,在即将发布的 Rancher 2.3版本中,Rancher将正式支持Windows Kubernetes、镜像仓库、镜像扫描、服务网格、Google登陆、集群模版、集群安全扫描和集群自动扩缩容。
深耕合作伙伴生态,共同赋能云原生产业
阿里云容器服务研发总监易立
阿里云作为国内最大的云计算服务提供商,拥有业内规模最大的云原生应用实战经验,服务了互联网、金融、政务等领域企业和机构。阿里云容器服务研发总监易立强调:“在公共云、混合云,抑或是云、边、端广泛互联的IoT场景中,更加标准化、高效地交付应用,是云原生技术带给企业的重要价值所在。”
值得一提的是,阿里云和Rancher早已在去年便已达成了公有云容器项目的合作,Rancher可以实现阿里云Kubernetes的托管服务。而在本次大会上,易立透露,未来阿里云将和Rancher展开更深层级的合作,共同布道云原生服务,为全球企业提供更简单易用的容器技术。
Rancher&SmartX战略合作与联合解决方案发布
本次大会的另一个亮点是业内领先的超融合厂商 SmartX 和 Rancher 发布了战略合作伙伴关系与联合解决方案。解决方案围绕着用户容器环境“生产就绪”面临的诸多挑战,基于 SmartX 为大规模虚拟化和容器打造的数据中心操作系统SMTX OS,涵盖其功能丰富且经过生产环境检验的虚拟化、分布式存储等模块,既可通过超融合方式在单套系统内提供从容器、编排到虚拟化,存储和管理的全栈解决方案,亦可仅作为持久化存储单独部署与K8s集群配合。
SmartX市场与战略合作总监库依楠表示:“SmartX非常高兴能在容器领域和Rancher形成战略合作,Rancher对于专业的技术和用户需求的深刻理解,和SmartX Make IT Simple的理念是完全一致的,相信这次联合发布的解决方案,将会为用户带来更大的价值。”
除此之外,Rancher在本次大会上还显示了强大的生态合作伙伴能力,百度云、JFrog、Cisco等技术类合作伙伴均与Rancher达成了长期的生态系统合作,Rancher将携手合作伙伴积极推进容器生态系统的建设,共同促进容器技术和云计算领域的创新。
以用户需求为核心,推进企业容器化落地
在大会的企业容器化实践分享上,不同行业的企业技术负责人则分别给出了他们的答案。
平安科技CTO及总架构师方国伟
平安科技CTO及总架构师方国伟提出,近年来在云计算赛道上,容器因为它轻量、灵活、易管理、易迁移等特性被企业广泛采用,如一辆高速前进的方程式赛车脱颖而出,成为了企业云化历程中的大势所趋。所以在未来3年,平安云将会重点投入容器建设,解决容器快速交付的难题,并且进行微服务的支撑。
中国联通集团信息化副总经理王志军
中国联通作为国内三大运营商之一,拥有国内领先的大数据平台,中国联通集团信息化副总经理王志军分享道:“通过研究、探索和实践,我们发现Kubernetes+Docker的技术路线更契合联通的实际需求,它几乎支持了所有的容器业务类型,也正是基于联通的技术选型,我们引入了Rancher的产品部署和Kubernetes集群管理功能,为联通的容器化大数据云平台提供更强而有力的容器技术及容器服务支撑。”
飞贷金融科技副总裁陈定玮
对于飞贷金融科技副总裁陈定玮而言,首先面对的是金融行业数据具有相较于其他行业更为严格的安全高标准要求,同时支撑飞贷金融科技的核心业务也是根本需求,而传统模式系统的DB在运维、研发、产品交付一直无法跟上微服务容器化的步伐,飞贷通过持续创新,结合当前的产品研发体系,飞贷自研中间件,在满足金融领域标准和业务要求状况下,进行生产DB容器化,带来10x的DB交付效率,极致的弹性扩容能力,解决了金融领域DB与应用的服务标准效率差距太大这一难题。
中国人寿开发五部云计算架构师张青南
中国人寿研发中心高级架构师张青南表示,从2017年起,中国人寿正式开始利用容器技术搭建PaaS平台“稻客云”,结合持续集成/交付技术,实现了研发全流程自动化及对应用容器的全面管理,至2019年,“稻客云”已支持中国人寿15个关键系统的生产运行,管理应用容器4800多个。“容器技术的应用促进了中国人寿整个研发流程的优化和可管控,软件的迭代周期大大缩短,并且以容器部署的方式承载了应用,实现弹性伸缩,应用快速构建部署。”
厦门航空信息部系统工程师、云平台负责人周钊
厦门航空和Rancher的合作可以追溯到2年前。2017年,厦门航空完成了厦航云计算平台项目建设,基于Rancher、IaaS和CMP搭建了三位一体的厦门航空云计算平台。“航空行业电商的发展催生了大量的业务请求访问,平台需要做到具备极强的稳定性和自动弹性收缩能力,而原有的传统开发模式和软件开发模式早已无法满足现有的需求。” 厦门航空信息部系统工程师、云平台负责人周钊分享道:“在这样的情形下,我们找到了Rancher,通过自主研发及微服务架构与Rancher容器平台完美结合,共同打造出厦航电商战略的支持平台。”
新东方信息管理部平台架构负责人姜江
同样是2017年,新东方开始了利用容器化手段将中间件业务服务化的探索,基于Rancher 1.6使用ES;2019年,新东方再次开始了扩大了中间件的业务服务化,基于Kubernetes使用Kafka、ES和Redis。新东方信息管理部平台架构负责人姜江总结道:“利用容器化手段将中间件服务化有效提升了运维团队的工作效率,缩短了软件开发流程。”
总的来说,这些企业关于容器化落地的精彩分享充分显示了Rancher在容器领域的巨大影响力,以及对于多个行业的共同推动作用。
展望未来
Rancher成立至今已经有将近5年的时间,在短短数载,Rancher迅速成为了业界领先的容器管理软件提供商,为超过20000家企业用户提供了企业化容器落地解决方案,本次大会中演讲的生态合作伙伴及各行业客户便是最好的证明。而这仅仅只是Rancher的起点。
一如梁胜在演讲中强调的那样: “Rancher在中国的用户以及合作伙伴生态系统都非常活跃,我们时常可以收到中国用户和伙伴对所需功能及支持项目的反馈和需求。在未来,Rancher希望能为中国用户带来更多、更实用的容器技术,推动中国企业容器化的持续创新。” 大会视频直播回放链接: http://www.itdks.com/index.php/Act/apply_upgrade/id/2965/mUid/20022/tpl/tpltwo.html#dingbu
云计算
2019-06-24 15:36:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
## WARNING: kube-prometheus moved to [coreos/kube-prometheus](https://github.com/coreos/kube-prometheus)!
# https://sysdig.com/blog/kubernetes-monitoring-prometheus-operator-part3/
# https://github.com/coreos/kube-prometheus
# 1. package download
wget http://10.245.254.93/linux/soft/docker/kubernetes/prometheus/kube-prometheus-0.1.0.tar.gz
tar zxpf kube-prometheus-0.1.0.tar.gz
cd kube-prometheus-0.1.0
# 2. 离线安装的情况下, manifests目录内的所有image需下载到本地registry ,并修改yaml文件指向到本地
sed -i "s|quay.io/prometheus|ispcdocker.com/coreos|g" manifests/*yaml
sed -i "s|quay.io/coreos|ispcdocker.com/coreos|g" manifests/*yaml
sed -i "s|k8s.gcr.io|ispcdocker.com/coreos|g" manifests/*yaml
sed -i "s|grafana/grafana:6.0.1|ispcdocker.com/coreos/grafana:6.1.6|g" manifests/*yaml
# 3. manifests目录下yaml文件太多, 使用默认方式,没法完全按照优先顺序执行。 虽然部分文件名被官方改成了数字0开头,但效果不佳。 在先后顺序错乱的情况下,只会没玩没了的报错:ServiceMonitor找不到。所以,新增一个子目录,将数字0开头的yaml文件单独存放,并先执行。
mkdir manifests/first
mv manifests/0*yaml manifests/first
kubectl create -f manifests/first/
kubectl create -f manifests/
# 4. 查询状态
# kubectl -n monitoring top pods
# kubectl -n monitoring get all
# kubectl -n monitoring get pod
# kubectl get customresourcedefinitions
# kubectl -n monitoring get svc
# kubectl -n monitoring get endpoints
# kubectl -n monitoring get servicemonitors
云计算
2019-06-21 09:41:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
本文作者:HelloDeveloper
在 4 月 7 日由 @百度 主办、 @InfoQ 策划组织和实施的第 25 期百度技术沙龙活动上,来自百度数据流计算系统 DStream 项目负责人杨栋( @Sherlock__Yang)、58 同城 (58.com) 云平台技术负责人,58 同城技术中心架构部架构师徐振华( @浊者)分别分享了各自在海量数据存储和处理上取得的成果及经验,话题涉及“Hypertable Goes Realtime at Baidu”,以及“58 同城在分布式存储方面的架构实践”等。本文将对他们各自的分享做下简单的回顾,同时提供相关资料的下载。

主题一:Hypertable Goes Realtime at Baidu(微盘下载讲稿)

来自百度数据流计算系统 DStream 项目负责人杨栋第一个为大家分享,本次演讲的主要内容包括:Hypertable 能够满足应用的哪些需求、实际应用中遇到的挑战有哪些、可靠性 or 性能、如何应对这些挑战以及 Hypertable 和 HBase 有哪些异同。杨栋提到,在 Noah 系统最初建设时,主要遇到了以下的问题:

MySQL


Not inherently distributed(数据的无序增长、频繁地手工分配数据);表大小的限制;不够灵活的结构
Hadoop


不支持随机写入;随机读取的支持也不理想
由此,Hypertable+Hadoop 的组合成为了最终的理想方案,在此基础上 S,不仅从系统的角度有了足够多的灵活性,数据写入的高吞吐量、高可用的灾难恢复特性、错误隔离机制以及随机扫描等特性都得以大大增强。在详细介绍了模型设计和评估方法之后,杨栋对主要的设计关键点进行了总结:

应用层面
表设计
加载策略
去重处理
高可用层面
数据集中化
日志与数据隔离
负载均衡
内存使用
内存池
简洁策略
读 / 写性能
内存 /SSD/SAS/SATA
块 / 队列缓存
压缩策略
资源隔离
最后,杨栋从多个角度对 Hypertable 和 HBase 进行了对比:

社区(Hypertable:Hypertable;HBase:Apache)
实现语言(Hypertable:Boost C++;HBase:Java)
内存管理(Hypertable:详尽的内存管理;HBase:垃圾回收)
缓存管理(Hypertable:动态的缓存管理;HBase:Java 堆栈缓存)
性能(Hypertable:高;HBase:一般)
编译配置(Hypertable:容易;HBase:复杂)
压缩机制(Hypertable:直接的 Native 压缩;HBase:基于 JNI 方式)
主题二:58 同城在分布式存储方面的架构实践(微盘下载讲稿)

58 同城 (58.com) 云平台技术负责人,58 同城技术中心架构部架构师徐振华第二个为大家分享,徐振华主要从理论、分析和实践三个层次分享了 58 同城在分布式存储领域的思考和实践。首先,通过 Draw Something 成功和 C10K 问题,引出分布式系统的目标是提高资源利用率, 做到线性扩展;同时分享了分布式存储的主要存储模型,分布式 hash 表和分布式 B+ 树,以及常用的用空间换时间,用错误率换空间,用查询性能换插入性能等思想:

Consistent hash(去中心化)
B+ tree(实时、随机)
LSM tree(批量、顺序)
接着,和大家分享了 58 同城做为一个创业公司,如何根据自身业务的特点,选择适合自己的技术和架构,用最小的成本获得最大的回报:

分析需求,做好平衡
使用 Kiss 原则,做到 RAS(可靠、可用、可扩展)
设计和充分利用硬件,分级存储
然后,和大家分享了 58 同城在分布式存储方面的实践:

信息系统 :Search engine(index) +MySQL(shard + M/S)+ memcached
统计数系统 :MongoDB + Auto sharding
图片系统 :CDN+Nginx+simple GFS(master-slave)
统计分析:Hadoop + HBase
最后,徐振华提到 58 同城在使用开源软件的同时,也在积极参与和回报开源社区,推动开源社区的发展。

Open Space(开放式讨论环节)

和以往的环节一样,​为了让参会者能够有更多的时间进行相互的交流,本次活动依然设置了 Open ​Space(开放式讨论)环节。除了讲师杨栋、徐振华外,新浪微博唐福林、阿里云王乐珩也参与了小组讨论。在 Open Space 的总结环节,几位话题小组长​分别对讨论的内容进行了总结。

杨栋:主要分享了“如何构建一套完整的数据分析平台”的话题,包括如何构建分布式的存储系统、如何构建分布式的计算系统以及如何构建分布式的数据仓库,此外还讨论了关于实时计算和数据量方面的问题,并与个别参会者就如何处理压缩的问题进行了细节的讨论。

徐振华:主要分享了“如何构建一个弹性计算平台”的话题,并就 Hadoop 的使用经验与大家进行了讨论。

唐福林:主要分享了“最简单的大数据实现(微博计数器)”的话题,从微博计数器出发,引出每种大数据解决方案在特定限制条件下都有不足,并就如何选择和开发适合自己的大数据解决方案工具进行了讨论。

王乐珩:主要分享了“Offline 大数据处理”的话题,并就云平台上数据分析的工具和方法进行了讨论。

会后,一些参会者也通过新浪微博分享了他们的参会感受:​​

@genstoneV:即时心得:云集算服务需要满足很多业务特点,所以什么边界条件都要研究。

@gqgl_work:58 实现计算资源的统筹,任务与计算不绑定,灵活部署。

@Andy 平安:Draw Something 为什么可以这么火?出色的产品创意不可否认,另外一方面是 Zynga 早在用户膨胀之前就提前做了 Couchbase 方面的技术储备。兵马未动,粮草先行,用户数据量的增长是难以准确 hold 的,我们不能总是被动升级现有系统。

@genstoneV:刚听完# 百度技术沙龙 # 的 Hypertable 的分享,对分布式系统的搭建过程,需要面临的细节问题提了些,很有心得。不过分享时能否尽量不要用 e 文呢,毕竟大家都是说中文,理解有些慢。

@Baidu 朱涛:百度需要的是持续创新,永葆活力,这样才能赢得更多百度用户的好评和网民的认可。

@solochar:# 百度技术沙龙 #hypertable 高可用,内存,读写优化。Hypertable 很多思想与 HBase 很一致,优化的想法也很一致。C++ 的优势在于操控性,用于较苛刻的场景。

@赵国栋 TMT:百度技术沙龙,讨论大数据技术。主题是海量数据处理技术。人非常多,许多人席地而座。我们准时到达,也只能站边上。

@ujnjing:# 百度技术沙龙 # 诺亚最开始使用 MySQL 存储数据量确实太大了,而且数据格式无规律。

此外,在本次的沙龙活动中,还特别邀请到中科院计算所副研究员、大规模数据计算专家查礼(@solochar)来与大家分享在大数据领域的研究成果。
原文链接地址: https://developer.baidu.com/topic/show/290185
云计算
2019-06-18 15:00:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
本文作者:HelloDeveloper
在 9 月 17 日百度主办、InfoQ 策划组织实施的第 18 期百度技术沙龙活动上,来自百度质量部高级架构师王磊以及 HP 测试工程师,7 点测试论坛坛主 Zee,分别分享了与大型网站性能测试的相关话题,话题涉及互联网产品性能测试案例及经验分享和企业级系统性能分析实践。本文将对他们各自的分享做下简单的回顾,同时提供相关资料的下载。

主题一:互联网性能测试案例及经验分享(视频,MP3 和 Slides 等资料下载)

来自百度的高级架构师王磊第一个为大家分享,王磊讲解了四个具体的实例,其中包括测试结果与实际情况不符、OS 对性能测试的影响、网络环境对性能的影响以及不良代码对性能的影响。在每部分的案例讲解中,都将问题进行了重现,首先说明问题表现,其次说明该问题所导致的后果,由如何找到原因再到案例的结论分析等。其中,重点讲解了不良代码对性能的影响部分:​​​​​​

测试对象为一个检索模块,问题为性能表现与预期的相差很大,在分析具体原因时王磊首先讲解了内存分配的原理:

检查要访问的虚拟地址是否合法
查找 / 分配一个物理页
填充物理页内容(读取磁盘)
建立映射关系(虚拟地址到物理地址)
重新执行发生断页中断的那条指令
从代码的角度上来看:

一个请求过来,用 malloc 分配 2MB 内存,请求结束后 free 这块内存
日志显示分配内存语句耗时 10us,平均一条请求处理耗时 1000us
从分析中最后得出结论,性能差的原因是:

内存申请造成缺页中断
因为这种缺页不需要磁盘,所以是 minfit
缺页中断在内核态执行,进程的内核态 CPU 消耗很大
主题二:找出系统性能瓶颈:企业级系统性能分析实践(视频,MP3 和 Slides 等资料下载)

Zee 的演讲主要包含以下几个部分,理解性能测试、性能测试需求的获取和分析、性能测试执行、控制及分析、可用性统计分析、排队论在分析过程中的应用,最后对各种场景的性能问题通过实例进行了分享。在 Zee 的演讲过程中,重点讲述了性能测试执行、控制及分析。Zee 首先带领读者一同梳理了性能问题分析的流程,接着介绍了如何从系统架构来分析瓶颈点,列举了常见的系统故障征兆:

持续运行缓慢
系统性能随时间的增加逐渐下降
系统性能随负载的增加逐渐下降
间发性的系统挂起或异常错误
可预见的死锁
系统突然出现混乱
稍后,Zee 详细列举了系统常见的问题及解决方法,常见问题涉及内存泄漏呈线性增长、内存泄漏呈指数级增长、导致无限循环的编码缺陷、资源泄漏、外部瓶颈、外部系统的过度使用、频繁调用 CPU 密集型组件的编码缺陷、桥接层本身存在的问题、内部资源的过度使用或分配不足、不断重试、线程阻塞点、线程的死锁或活锁、网络饱和等。针对以上“疾病”,分别列举了出现的征兆,分析其原因并提供了相应的解决办法。紧接着,Zee 还对分析性能问题时需要注意的信息进行了讲解,介绍了如何执行针对 SQL 的性能分析,通过图形的形式展现了性能指标和用户数两者之间的关系和影响并通过思维导图的方式将与性能调整有关的议题进行了呈现。

​最后,Zee 针对性能测试中需要注意的一些问题进行了总结:

在正式测试之前进行实验性的测试
不要对生产环境造成不良影响
数据聚集问题
没有及时通知其他相关人员
全面分析测试数据
注意硬件设备对性能的影响
没有确定测试需要采集的数据
没有确定测试的范围和目的
测试时关注系统的出错信息
测试的网络环境不清楚
相关人员没有及时在现场
没有测试一个完整的回路
并发数与发送流量的问题
​​​​会后一些网友在新浪微博分享了他们参会的感受:

@醉梦如烟 _ 燕飞:# 百度技术沙龙 # 王磊、高楼大家本次关于性能测试这块非常不错,让我受益匪浅,希望今后能更多的参与这样的讲座。

@savager:# 百度技术沙龙 # 好地方,前沿技术,多学习。

@陈奎 _ 走行寻:今天的百度技术沙龙性能测试专场,人数出奇的爆满。

@haitao_yao:# 百度技术沙龙 # 第二场有料,惠普的性能测试跟我遇到的场景类似,没白来,哈哈。

​此外,Zee 在会后的随笔中,记录了参加本期沙龙演讲后的感触,请参阅《Zee 随笔—第十八期 InfoQ:百度技术沙龙演讲之后》。
原文链接地址: https://developer.baidu.com/topic/show/290178
云计算
2019-06-18 14:50:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
本文作者:HelloDeveloper
2014 年 5 月 17 日,在由@百度主办、@InfoQ负责策划组织和实施的第 50 期百度技术沙龙活动上,来自百度架构师许立强,和青云联合创始人研发副总甘泉,各自分享了其在私有云、公有云架构方面的实战经验。他们的话题分别为“百度社区私有云”和“青云的设计理念以及架构实践”,本文将对两位专家各自的分享做简单的回顾,同时提供相关资料的下载。

主题一:百度社区私有云(下载讲稿)

许立强从架构、资源管理、分级发布、弹性服务介绍了百度私有云的背景及解决了哪些业务问题。

“对于大规模海量的互联网应用来说,分级发布也是必备的点。这里主要讲的是整体的流程,百度怎么做分级发布。我们提供了统一的上线平台,可以进行分级上线,第一个是上线预览机,之后我们会提供一系列的联动,如果没有问题的话他们还可以看到我可以继续放量,如果没有问题的是逐步的放量,这是我们这个平台上支持的分级发布的标准流程。”
Runtime,说简单一点就是两件事情. 以前是机器,现在我们不能是机器了,是资源。因为我们在制定规范,所以我们做的第二件事情就是标准化,这张图描述的是我们这个机器上最终它是怎么去划分的,怎么支持的。
Service 部分,有一部分是在 Runtime 里面的,一部分在 Service 里面,所有的 APP 里面都有。过程就是封闭细节,方便开发者使用。
许立强总结说,“结合我们自己对弹性服务的理解,第一个是弹性伸缩,你让你的业务随着你的性能,随着你的流量,随着业务的变化自动的伸缩流量,这是第一个点。第二个点是我能够自动的屏蔽异常处理,我的机器出问题的时候,对业务是透明的,也是没有影响的。”
主题二:青云的设计理念以及架构实践
青云副总甘泉主要涉及到两点,第一点就是为什么要做 QINGCLOUD,第二点是怎么做 QINGCLOUD。甘泉的 PPT 全部为英文,建议大家结合视频一起观看。
“我们以前给用户管输的云计算的概念都是错的!”
甘泉解释说,“以前给用户管输的理念是,云就是虚拟机,就是云主机,一台一台的云主机,难道它就是云吗?你怎么可能想象说,我拥有一千台云主机,然后都插到同一个交换机上,怎么可能没有一个网络的层级的结构,没有网络的隔离,然后去做这个事情呢?”
甘泉认为,要想普及云计算,一方面要考虑它的成本,另一方面是它的弹性,没有弹性和成本的优势,那就是糊弄用户。
甘泉谈及了企业现有的计算环境,如何经济、弹性地与云端资源协调成一个整体计算环境, 将多地分散的数据中心形成一个统一的、兼顾公私的混合云 ( Hybrid Cloud ), 以最大程度地满足企业在不同阶段不同类型的计算需求,且保持 IT 资产投资的规模适度。QingCloud 如何为企业应用设计云基础设施方案,以及如何实现,如何在为企业提供实时、按需的高性能 IT 资源的同时,保障企业 IT 系统及数据的安全性。
OpenSpace(开放式讨论环节)
为了促进参会者与我们每期的嘉宾以及讲师近距离交流,深入探讨在演讲过程中的疑问,本次活动依然设置了 Open Space(开放式讨论)环节。在 Open Space 的总结环节,几位话题小组长分别对讨论的内容进行了总结。
会上,一些参会者也通过新浪微博分享了他们的参会感受:
刘同斌 Iverson:听起来很牛,落地测试下

曹坤波 - 乐视:哥,你能实在点

@Rogee_Y: 没有两件格子衬衫,不好意思自称 IT 男
原文链接地址: https://developer.baidu.com/topic/show/290160
云计算
2019-06-18 00:26:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
本文作者:天工智能物联网
数以亿计的设备,无处不在的链接
成就了物联网
一切神秘而复杂
通过拖拖拽拽
展现炫酷图表
物可视化的世界
以真实可感的数据形态
揭开神秘面纱
给我们呈现出最直观的感受
这就是物可视化的强大功效
在这背后
数据处理功能到底是怎么实现的呢
本期带你解读

上一期 《图解物联网场景,百度云天工带你玩转物可视》 ,物可视图大拿给大家介绍了如何在物可视中拖拽生成物联网可视化,以及如何将可视化页面嵌入到应用中。很多小伙伴尝试并给予反馈,我们从反馈中发现:大家对于物可视的数据处理功能既困惑又好奇。

今天我们就在这里给大家揭秘一下物可视的强大数据变换功能。

以下案例1、2针对的是数据变换中的预设变换。


有包括行列排序、重命名、行列转换、数据透视表等预设变换能力。

案例3、4针对的是数据变换中的自定义变换。

也就是大家最最好奇的通过JS语法窗实现的各种强大功能,只有想不到没有做不到。

案例1 行列转换完成饼图制作

1、准备数据源
进入“数据表”页面 选择设备影子类型的数据表、命名任意(这里叫“饼图制作”),进入下一步 勾选所有物影子状态,确定

2、数据表变形
进入“数据表”页面 选中上一步创建的数据表(“饼图制作”),点击顶部的图标按钮切换至“暂停”状态 点击新创建的节点右边的“+”号按钮,添加“列排序”,将timestamp列隐藏 点击新创建的节点右边的“+”号按钮,添加“行转列”

3、添加可视化
返回“仪表盘”页面 从左边栏找到“图表”>“饼图”>“饼图”,拖放至画布上

4、绑定数据
选中拖上来的“饼图”组件,在右边栏切换至“数据设置”标签,在“数据表”下拉框中选取之前创建的数据表(当前位置) 类目选“device”、度量选“vizuetest”

► 展现效果


案例2 数据透视表与玫瑰图

1、准备数据源
进入“数据表”页面 选择静态数据类型的CSV、命名任意(这里叫“玫瑰图”),进入下一步 贴入示例数据,点击确定

2、数据表变形
进入“数据表”页面 选中上一步创建的数据表(“玫瑰图”),点击顶部的图标按钮切换至“暂停”状态 点击新创建的节点右边的“+”号按钮,添加“透视表” 选择“door”作为“Dimension/表头”,选择“Stop”作为“Dimension/首列”, 选择“get_off_cnt”作为“Measure/数据列” 聚合方式选择求和,点击确定 点击新创建的节点右边的“+”号按钮,添加“重命名”,对Door的数据“1”“2”进行重命名,点击确定

3、添加可视化
返回“仪表盘”页面 在搜索框搜索“南丁格尔”,找到玫瑰图,拖放至画布上

4、绑定数据
选中拖上来的“南丁格尔”组件,在右边栏切换至“数据设置”标签,在“数据表”下拉框中选取之前创建的数据表(当前位置) 类目选“Stop”、度量选“前门”“后门”

► 展现效果


► 操作示范

案例3 行列横向相加相减

1、准备数据源
进入“数据表”页面 选择静态数据类型的CSV、命名任意(这里叫“数据处理”),进入下一步 贴入示例数据,点击确定

2、数据表变形
进入“数据表”页面 选中上一步创建的数据表(“数据处理”),点击顶部的图标按钮切换至“暂停”状态 点击新创建的节点右边的“+”号按钮,添加“新建列” 新建列名可自取(“相加”、“相减”、“行聚合”),基础列选择要处理的列,这里选取第一列C1 在“语法窗”内贴入“多列相减”“多列相加”“行聚合求和”中给出的示例代码,点击确定

► 示例数据
c1,c2 1,3 3,0 0,-1 5,6 -2,8 5,7 0,4 3,0 12,2

► 多列相减
return cell - rows[rowIndex][1]

► 显示效果


► 多列相加
return cell + rows[rowIndex][1]

► 显示效果


► 行聚合求和
function transform(cell, rowIndex, col, rows, header) { var rows_sofar = col.slice(0, rowIndex+1) var sum = 0 for (var i = 0; i< rows_sofar.length; i++) { sum = sum + rows_sofar[i] } return sum }

► 显示效果


► 操作示范

案例4 时间聚合统计

1、数据准备

(1)配置TSDB类型的数据表,添加『Sum 1月』聚合函数。
(2)表操作中基于timestamp列增加一个string类型的列(月份),变形脚本如下:
var date = new Date(cell) var month = date.getMonth() var month_names = "一 二 三 四 五 六 七 八 九 十 十一 十二".split(" ") return month_names[month] + '月'

2、绑定图表

在仪表盘中添加一个『统计柱状图』,数据绑定时X轴选『月份』,Y轴选对应的数据列即可。效果如下:


通过物可视化数据处理功能,够有效的将大数据进行整理、归纳、分析、预测,且具有互联网的自动反馈功能,从而能够帮助企业对市场和消费者的情况进行推测,使之在商业决策上可以做出更好、更聪明的判断,决胜于千里之外,助力企业真正实现智能化转型。
原文链接地址: https://developer.baidu.com/topic/show/290149
云计算
2019-06-14 15:39:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
一 简介
用户对超高并发、超大规模计算等需求推动了存储硬件技术的不断发展,存储集群的性能越来越好,延时也越来越低,对整体IO路径的性能要求也越来越高。在云硬盘场景中,IO请求从生成到后端的存储集群再到返回之间的IO路径比较复杂,虚拟化IO路径尤其可能成为性能瓶颈,因为虚机内所有的IO都需要通过它下发给后端的存储系统。我们使用了SPDK来优化虚拟化IO路径,提出了开源未解决的SDPK热升级和在线迁移方案,并且在高性能云盘场景中成功应用,取得了不错的效果,RSSD云硬盘最高可达120万IOPS。本文主要分享我们在这方面的一些经验。
二 SPDK vhost的基本原理
SPDK(Storage Performance Development Kit )提供了一组用于编写高性能、可伸缩、用户态存储应用程序的工具和库,基本组成分为用户态、轮询、异步、无锁 NVMe 驱动,提供了从用户空间应用程序直接访问SSD的零拷贝、高度并行的访问。
在虚拟化IO路径中,virtio是比较常用的一种半虚拟化解决方案,而virtio底层是通过vring来通信,下面先介绍下virtio vring的基本原理,每个virtio vring 主要包含了以下几个部分:
desc table数组,该数组的大小等于设备的队列深度,一般为128。数组中每一个元素表示一个IO请求,元素中会包含指针指向保存IO数据的内存地址、IO的长度等基本信息。一般一个IO请求对应一个desc数组元素,当然也有IO涉及到多个内存页的,那么就需要多个desc连成链表来使用,未使用的desc元素会通过自身的next指针连接到free_head中,形成一个链表,以供后续使用。
available数组,该数组是一个循环数组,每一项表示一个desc数组的索引,当处理IO请求时,从该数组里拿到一个索引就可以到desc数组里面找到对应的IO请求了。
used 数组,该数组与avail类似,只不过用来表示完成的IO请求。当一个IO请求处理完成时,该请求的desc数组索引就会保存在该数组中,而前端virtio驱动得到通知后就会扫描该数据判断是否有请求完成,如果完成就会回收该请求对应的desc数组项以便下个IO请求使用。
SPDK vhost的原理比较简单,初始化时先由qemu的vhost驱动将以上virtio vring数组的信息发送给SPDK,然后SPDK通过不停的轮寻available数组来判断是否有IO请求,有请求就处理,处理完后将索引添加到used数组中,并通过相应的eventfd通知virtio前端。
当SPDK收到一个IO请求时,只是指向该请求的指针,在处理时需要能直接访问这部分内存,而指针指向的地址是qemu地址空间的,显然不能直接使用,因此这里需要做一些转化。
在使用SPDK时虚机要使用大页内存,虚机在初始化时会将大页内存的信息发送给SPDK,SPDK会解析该信息并通过mmap映射同样的大页内存到自己的地址空间,这样就实现了内存的共享,所以当SPDK拿到qemu地址空间的指针时,通过计算偏移就可以很方便的将该指针转换到SPDK的地址空间。
由上述原理我们可以知道SPDK vhost通过共享大页内存的方式使得IO请求可以在两者之间快速传递这个过程中不需要做内存拷贝,完全是指针的传递,因此极大提升了IO路径的性能。
我们对比了原先使用的qemu云盘驱动的延时和使用了SPDK vhost之后的延时,为了单纯对比虚拟化IO路径的性能,我们采用了收到IO后直接返回的方式:
1.单队列(1 iodepth, 1 numjob)
qemu 网盘驱动延时:
SPDK vhost延时:
可见在单队列情况下延时下降的非常明显,平均延时由原来的130us下降到了7.3us。
2.多队列(128 iodepth,1 numjob)
qemu 网盘驱动延时:
SPDK vhost延时:
多队列时IO延时一般会比单队列更大些,可见在多队列场景下平均延时也由3341us下降为1090us,下降为原来的三分之一。
三 SPDK热升级
在我们刚开始使用SPDK时,发现SPDK缺少一重要功能——热升级。我们使用SPDK 并基于SPDK开发自定义的bdev设备肯定会涉及到版本升级,并且也不能100%保证SPDK进程不会crash掉,因此一旦后端SPDK重启或者crash,前端qemu里IO就会卡住,即使SPDK重启后也无法恢复。
我们仔细研究了SPDK的初始化过程发现,在SPDK vhost启动初期,qemu会下发一些配置信息,而SPDK重启后这些配置信息都丢失了,那么这是否意味着只要SPDK重启后重新下发这些配置信息就能使SPDK正常工作呢?我们尝试在qemu中添加了自动重连的机制,并且一旦自动重连完成,就会按照初始化的顺序再次下发这些配置信息。开发完成后,初步测试发现确实能够自动恢复,但随着更严格的压测发现只有在SPDK正常退出时才能恢复,而SPDK crash退出后IO还是会卡住无法恢复。从现象上看应该是部分IO没有被处理,所以qemu端虚机一直在等待这些IO返回导致的。
通过深入研究virtio vring的机制我们发现在SPDK正常退出时,会保证所有的IO都已经处理完成并返回了才退出,也就是所在的virtio vring中是干净的。而在意外crash时是不能做这个保证的,意外crash时virtio vring中还有部分IO是没有被处理的,所以在SPDK恢复后需要扫描virtio vring将未处理的请求下发下去。这个问题的复杂之处在于,virtio vring中的请求是按顺序下发处理的,但实际完成的时候并不是按照下发的顺序的。
假设在virtio vring的available ring中有6个IO,索引号为1,2,3,4,5,6,SPDK按顺序的依次得到这个几个IO,并同时下发给设备处理,但实际可能请求1和4已经完成,并返回了成功了,如下图所示,而2,3,5,6都还没有完成。这个时候如果crash,重启后需要将2,3,5,6这个四个IO重新下发处理,而1和4是不能再次处理的,因为已经处理完成返回了,对应的内存也可能已经被释放。也就是说我们无法通过简单的扫描available ring来判断哪些IO需要重新下发,我们需要有一块内存来记录virtio vring中各个请求的状态,当重启后能够按照该内存中记录的状态来决定哪些IO是需要重新下发处理的,而且这块内存不能因SPDK重启而丢失,那么显然使用qemu进程的内存是最合适的。所以我们在qemu中针对每个virtio vring申请一块共享内存,在初始化时发送给SPDK,SPDK在处理IO时会在该内存中记录每个virtio vring请求的状态,并在意外crash恢复后能利用该信息找出需要重新下发的请求。
四 SPDK在线迁移
SPDK vhost所提供的虚拟化IO路径性能非常好,那么我们有没有可能使用该IO路径来代替原有的虚拟化IO路径呢?我们做了一些调研,SPDK在部分功能上并没有现有的qemu IO路径完善,其中尤为重要的是在线迁移功能,该功能的缺失是我们使用SPDK vhost代替原有IO路径的最大障碍。
SPDK在设计时更多是为网络存储准备的,所以支持设备状态的迁移,但并不支持设备上数据的在线迁移。而qemu本身是支持在线迁移的,包括设备状态和设备上的数据的在线迁移,但在使用vhost模式时是不支持在线迁移的。主要原因是使用了vhost之后qemu只控制了设备的控制链路,而设备的数据链路已经托管给了后端的SPDK,也就是说qemu没有设备的数据流IO路径所以并不知道一个设备那些部分被写入了。
在考察了现有的qemu在线迁移功能后,我们觉着这个技术难点并不是不能解决的,因此我们决定在qemu里开发一套针对vhost存储设备的在线迁移功能。
块设备的在线迁移的原理比较简单,可以分为两个步骤,第一个步骤将全盘数据从头到尾拷贝到目标虚机,因为拷贝过程时间较长,肯定会发生已经拷贝的数据又被再次写入的情况,这个步骤中那些再次被写脏的数据块会在bitmap中被置位,留给第二个步骤来处理,步骤二中通过bitmap来找到那些剩余的脏数据块,将这些脏数据块发送到目标端,最后会block住所有的IO,然后将剩余的一点脏数据块同步到目标端迁移就完成了。
SPDK的在线迁移原理上于上面是相同的,复杂之处在于qemu没有数据的流IO路径,所以我们在qemu中开发了一套驱动可以用来实现迁移专用的数据流IO路径,并且通过共享内存加进程间互斥的方式在qemu和SPDK之间创建了一块bitmap用来保存块设备的脏页数量。考虑到SPDK是独立的进程可能会出现意外crash的情况,因此我们给使用的pthread mutex加上了PTHREAD_MUTEX_ROBUST特性来防止意外crash后死锁的情况发生,整体架构如下图所示:
五 SPDK IO uring体验
IO uring是内核中比较新的技术,在上游内核5.1以上才合入,该技术主要是通过用户态和内核态共享内存的方式来优化现有的aio系列系统调用,使得提交IO不需要每次都进行系统调用,这样减少了系统调用的开销,从而提供了更高的性能。
SPDK在最新发布的19.04版本已经包含了支持uring的bdev,但该功能只是添加了代码,并没有开放出来,当然我们可以通过修改SPDK代码来体验该功能。
首先新版本SPDK中只是包含了io uring的代码甚至默认都没有开放编译,我们需要做些修改:
1.安装最新的liburing库,同时修改spdk的config文件打开io uring的编译;
2.参考其他bdev的实现,添加针对io uring设备的rpc调用,使得我们可以像创建其他bdev设备那样创建出io uring的设备;
3.最新的liburing已经将io_uring_get_completion调用改成了io_uring_peek_cqe,并需要配合io_uring_cqe_seen使用,所以我们也要调整下SPDK中io uring的代码实现,避免编译时出现找不到io_uring_get_completion函数的错误:
4.使用修改open调用,使用O_SYNC模式打开文件,确保我们在数据写入返回时就落地了,并且比调用fdatasync效率更高,我们对aio bdev也做了同样的修改,同时添加读写模式:
经过上述修改spdk io uring设备就可以成功创建出来了,我们做下性能的对比:
使用aio bdev的时候:
使用io uring bdev的时候:
可见在最高性能和延时上 io uring都有不错的优势,IOPS提升了约20%,延迟降低约10%。这个结果其实受到了底层硬件设备最大性能的限制,还未达到io uring的上限。
六 总结
SPDK技术的应用使得虚拟化IO路径的性能提升不再存在瓶颈,也促使UCloud高性能云盘产品可以更好的发挥出后端存储的性能。当然一项技术的应用并没有那么顺利,我们在使用SPDK的过程中也遇到了许多问题,除了上述分享的还有一些bug修复等我们也都已经提交给了SPDK社区,SPDK作为一个快速发展迭代的项目,每个版本都会给我们带来惊喜,里面也有很多有意思的功能等待我们发掘并进一步运用到云盘及其它产品性能的提升上。
云计算
2019-05-31 14:39:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
以上是整个部署更新的流程图:
1.开发人员对上线的代码打一个tag,然后把带tag的代码推到AWS codecommit上面。
git   add  -A   *
git   commit   -a -m "${tag}"
git   tag   "${tag}"
git  push   origin   分支   ${tag}
5.jenkins进行代码构建作业:
(首先需要安装插件: Amazon ECR plugin 、 Docker plugin )
以下是jenkins项目配置的示例:

以下是构建image和把image推送到ECR上
以下是更新ECS服务的设置(适用于更新接口、对外接口、定时任务、前端、app的H5前端):
例子:(api的配置)
#!/bin/bash
REGION="ap-northeast-1"    #区域
REPOSITORY_NAME="exchange-api"   #ECR的存储库
CLUSTER="online-exchange"    #集群名称
SERVICE_NAME="online-exchange-api"    #服务名称
FAMILY="online_exchange-api"     #任务定义名称
NAME="online-exchange-api"       #容器名称
TASKDEFNAME="online_exchange-api"    ##任务定义名称
#列出存储库的URL
REPOSITORY_URI=`aws ecr describe-repositories --repository-names ${REPOSITORY_NAME} --region ${REGION} | jq .repositories[].repositoryUri | tr -d '"'`
#根据构建的tag标签去创建一个生成任务定义的json文件
sudo sed  -e "s;%TAG%;${tag};g"  -e "s;%REPOSITORY_URI%;${REPOSITORY_URI};g" /opt/update-exchange/update-api/online-ecs-exchange-api.json > /opt/update-exchange/update-api/${NAME}-${tag}.json
#根据ECR里面的URL,创建一个新的任务定义
aws ecs register-task-definition --family ${FAMILY} --cli-input-json file:///opt/update-exchange/update-api/${NAME}-${tag}.json  --region ${REGION}
SERVICES=`aws ecs describe-services --services ${SERVICE_NAME} --cluster ${CLUSTER} --region ${REGION} | jq .failures[]`
#获取最新的版本
REVISION=`aws ecs describe-task-definition --task-definition ${TASKDEFNAME} --region ${REGION} | jq .taskDefinition.revision`
#创建或者更新服务
if [ "$SERVICES" == "" ]; then
  echo "entered existing service"
  DESIRED_COUNT=`aws ecs describe-services --services ${SERVICE_NAME} --cluster ${CLUSTER} --region ${REGION} | jq .services[].desiredCount`
  if [ ${DESIRED_COUNT} = "0" ]; then
    DESIRED_COUNT="1"
  fi
  aws ecs update-service --cluster ${CLUSTER} --region ${REGION} --service ${SERVICE_NAME} --task-definition ${FAMILY}:${REVISION} 
else
  echo "entered new service"
  aws ecs create-service --service-name ${SERVICE_NAME} --desired-count 2 --task-definition ${FAMILY} --cluster ${CLUSTER} --region ${REGION}
fi
#更新服务成功之后,执行清理镜像,清理文件。
docker  rmi   786381498352.dkr.ecr.ap-northeast-1.amazonaws.com/exchange-api:latest
docker  rmi   786381498352.dkr.ecr.ap-northeast-1.amazonaws.com/exchange-api:${tag}
\rm  /opt/update-exchange/update-api/${NAME}-${tag}.json
以下是ECS更新的配置(适用于更新撮合、结算):
例子(结算):
#!/bin/bash
REGION="ap-northeast-1"
REPOSITORY_NAME="exchange-deal"
CLUSTER="online-exchange"
SERVICE_NAME="online-exchange-deal"
FAMILY="online_exchange-deal"
NAME="online-exchange-deal"
TASKDEFNAME="online_exchange-deal"
REPOSITORY_URI=`aws ecr describe-repositories --repository-names ${REPOSITORY_NAME} --region ${REGION} | jq .repositories[].repositoryUri | tr -d '"'`
#Replace the build number and respository URI placeholders with the constants above
sudo sed  -e "s;%TAG%;${tag};g" -e "s;%REPOSITORY_URI%;${REPOSITORY_URI};g" /opt/update-exchange/update-deal/online-ecs-exchange-deal.json > /opt/update-exchange/update-deal/${NAME}-${tag}.json
#Register the task definition in the repository
aws ecs register-task-definition --family ${FAMILY} --cli-input-json file:///opt/update-exchange/update-deal/${NAME}-${tag}.json  --region ${REGION}
SERVICES=`aws ecs describe-services --services ${SERVICE_NAME} --cluster ${CLUSTER} --region ${REGION} | jq .failures[]`
#Get latest revision
REVISION=`aws ecs describe-task-definition --task-definition ${TASKDEFNAME} --region ${REGION} | jq .taskDefinition.revision`
#首先把预期数改为0,再删除服务,再创建新的服务。
if [ "$SERVICES" == "" ]; then
    echo "entered existing service"
    aws ecs update-service --cluster  ${CLUSTER}   --service  ${SERVICE_NAME}  --desired-count 0
    sleep 10
    aws ecs delete-service --cluster  ${CLUSTER}   --service ${SERVICE_NAME}
    sleep 100
    aws ecs create-service --cluster ${CLUSTER} --service-name ${SERVICE_NAME} --task-definition ${FAMILY}:${REVISION} --desired-count 1 --launch-type "FARGATE" --network-configuration "awsvpcConfiguration={subnets=[subnet-04a486cb94c9c9032,subnet-0d93a8c5452781c8f],securityGroups=[sg-0c66800c0bdd235fc],assignPublicIp=ENABLED}"
else
    echo "service does not exist"
    echo "create a new service"
    aws ecs create-service --cluster ${CLUSTER} --service-name ${SERVICE_NAME} --task-definition ${FAMILY}:${REVISION} --desired-count 1 --launch-type "FARGATE" --network-configuration "awsvpcConfiguration={subnets=[subnet-04a486cb94c9c9032,subnet-0d93a8c5452781c8f],securityGroups=[sg-0c66800c0bdd235fc],assignPublicIp=ENABLED}"
fi
#更新服务成功之后,执行清理镜像,清理文件。
docker  rmi   786381498352.dkr.ecr.ap-northeast-1.amazonaws.com/exchange-deal:latest
docker  rmi   786381498352.dkr.ecr.ap-northeast-1.amazonaws.com/exchange-deal:${tag}
\rm  /opt/update-exchange/update-deal/${NAME}-${tag}.json
 
先删除服务的目的是为了绝对的保证服务只会存在一个,最后有一个清理镜像,清理文件,是为了减少磁盘的压力。
以下是ECS更新的配置(适用于更新推送):
例子(推送):
#!/bin/bash
REGION="ap-northeast-1"
REPOSITORY_NAME="exchange-ws"
CLUSTER="online-exchange"
SERVICE_NAME="online-exchange-ws"
FAMILY="online_exchange-ws"
NAME="online-exchange-ws"
TASKDEFNAME="online_exchange-ws"
REPOSITORY_URI=`aws ecr describe-repositories --repository-names ${REPOSITORY_NAME} --region ${REGION} | jq .repositories[].repositoryUri | tr -d '"'`
#Replace the build number and respository URI placeholders with the constants above
sudo sed -e "s;%TAG%;${tag};g" -e "s;%REPOSITORY_URI%;${REPOSITORY_URI};g" /opt/update-exchange/update-ws/online-ecs-exchange-ws.json > /opt/update-exchange/update-ws/${NAME}-${tag}.json
#Register the task definition in the repository
aws ecs register-task-definition --family ${FAMILY} --cli-input-json file:///opt/update-exchange/update-ws/${NAME}-${tag}.json  --region ${REGION}
SERVICES=`aws ecs describe-services --services ${SERVICE_NAME} --cluster ${CLUSTER} --region ${REGION} | jq .failures[]`
#Get latest revision
REVISION=`aws ecs describe-task-definition --task-definition ${TASKDEFNAME} --region ${REGION} | jq .taskDefinition.revision`
#首先把预期数改为0,等待服务中没有运行得任务,再去更新任务。
aws ecs update-service --cluster online-exchange   --service  online-exchange-ws  --desired-count 0
while :
do
    count=`aws ecs describe-services --cluster ${CLUSTER} --service ${SERVICE_NAME} | grep runningCount | tail -n1 | egrep -oE '[0-9]'`
    sleep 30
    if [ $count -eq 0 ];then
       aws ecs update-service --cluster ${CLUSTER} --region ${REGION} --service ${SERVICE_NAME} --task-definition ${FAMILY}:${REVISION} --desired-count 1
       exit
    fi
done
#更新服务成功之后,执行清理镜像,清理文件。
docker  rmi   786381498352.dkr.ecr.ap-northeast-1.amazonaws.com/exchange-ws:latest
docker  rmi   786381498352.dkr.ecr.ap-northeast-1.amazonaws.com/exchange-ws:${tag}
\rm  /opt/update-exchange/update-ws/${NAME}-${tag}.json
云计算
2019-05-27 14:57:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
“UAI-Train平台可以让我们方便地在短时内使用大量的GPU资源,用较低的成本训练海量的数据集,提高算法模型迭代优化的效率。” — 拍拍贷算法研究员 朱运
UAI-Train是什么
UAI-Train是面向AI训练任务的大规模分布式计算平台,基于P40、V100等GPU云主机集群,通过分布式扩展,最高可实现192TFlops的单精度计算能力。提供一站式训练任务托管服务,可自动化解决计算节点调度、训练环境准备、数据上传下载以及任务容灾等问题,并支持按需收费、成本可控,无需担心资源浪费。在视频图像识别、自然语言处理、语音处理等领域均已有诸多实践。
拍拍贷接入UAI-Train的效果
通过使用分布式GPU训练平台,700W人脸数据的模型训练所需时长可从原先的一周缩短至一天, 整体算法优化效率提升85.7%, 相应的迭代频率也提高数倍,为更深层次的模型结构试验提供了可能。同时UAI-Train平台备有大量GPU资源,拍拍贷的算法工程师可以同时探索多种算法模型结构,极大缩短初期算法结构探索的时间。最重要的是UAI-Train平台具备按需收费的特性,拍拍贷人脸识别算法的 GPU资源成本可由原先的上万元/月,下降至数千元/月, GPU资源的有效利用率也达到了100%。
表:UAI-Train与购买GPU资源的特性对比
关于拍拍贷
拍拍贷是一家行业领先的金融科技公司,同时也是一家非常注重技术驱动、强调自主研发的高科技公司。一直以来非常重视AI技术的探索和应用,涉及到计算机视觉、语音分析和建模、自然语言处理、复杂网络分析等针对特定非结构化数据的领域,并将迁移学习、主动学习、强化学习、多任务学习、在线学习、非监督半监督等各种机器学习算法应用至多种业务场景。尤其是人脸识别、OCR、不良中介识别和欺诈团伙挖掘、智能对话机器人、社交文本挖掘等项目,在实际的业务实践中取得了不俗的效果,极大地提升了风险反欺诈水平和运营效率。
人脸识别
人脸识别是拍拍贷AI技术的一个重要研究方向,它通过算法识别人的脸部特征,从而可以做到实时地从图片或者视频流中检测和追踪特定的人。
目前拍拍贷自研人脸识别算法,在700W规模多年龄段、多姿态、多表情、多环境的人脸图片上进行训练。通过尝试不同的网络结构,包含Inception-v3、优化后的resnet等,以及多种损失函数,例如triplet_loss、sphere、cosine、arc_loss等来优化人脸识别算法,从而提升1:1人脸认证、1:N人脸搜索、N:N人脸交叉比对、人脸聚类等场景的识别精度,并将此类技术应用于拍拍贷的风险监控、反欺诈等业务,并发挥了重要作用。
图:人脸识别业务场景
面临的问题
算法人员在优化人脸识别算法的过程中发现**使用单台GPU机器迭代一次算法需要一周左右的时间,**效率过低影响研发进度,但是采购更多的GPU机器来探索不同算法会导致资源成本线性增长;此外由于算法调优工作涉及诸多研究内容,例如算法效果分析、新算法调研、开发等,实际的资源使用率不高。
接触UAI-Train
在一次线下技术交流活动中,拍拍贷技术人员了解到UCloud提供一种面向人工智能算法训练的UAI-Train平台,并支持GPU资源的按需租售服务,同时该平台上还可执行多机多卡的分布式训练任务。
为了提升模型训练的效率,充分高效地利用更多的新数据来进一步提高其准确率,拍拍贷抉择后选择尝试UAI-Train平台。UCloud AI团队在GitHub上发布了适配UAI-Train平台的Insightface开发案例,用于协助拍拍贷的算法工程师很方便地将单机的人脸识别算法转化成支持分布式训练的人脸识别算法,并成功在UAI-Train平台上进行算法的快速优化。
Insightface是GitHub上一个基于MXNet框架的开源人脸识别项目( https://github.com/deepinsight/insightface)。UCloud基于insightface开发了一整套能支持分布式训练的人脸识别训练和在线推理的案例代码,并发布在GitHub上(https://github.com/ucloud/uai-sdk/tree/master/examples/mxnet/insightface),其中包括基于MXNet框架的代码及开发案例。拍拍贷的工程师基于该案例,结合自身人脸识别算法的实现和数据, 一周时间内就完成了开发和调试, 并顺利在UAI-Train平台上逐步展开人脸识别算法的训练迭代工作。
图:人脸识别算法接入过程
在多次算法优化迭代尝试后,拍拍贷通过利用高维向量表征人脸,余弦距离表达相似度,最终在开源测试集准确率表现为: lfw 99.8%, cfp_fp 97%, agedb_30 98.2% ,实际业务应用中的准确率高达 99% 以上,进一步提升了风险监管、反欺诈等业务的效率。
后续拍拍贷和UCloud计划在更多算法场景和应用场景展开深入合作,更好地服务于金融领域客户。
对人工智能更多应用场景和解决方案感兴趣的,欢迎扫描下方二维码进群交流。
TIC 2019报名火热进行中,欢迎扫描下方二维码或点击阅读原文加入我们,共同探讨企业上云的更多落地案例!
云计算
2019-05-10 15:20:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
先觉条件: 安装配置AWS CLI ECS的基本设置 aws用户有运行的ECS的IAM权限 已经有VPC和安全组
创建集群
aws ecs create-cluster --cluster-name 集群名字
输出:
{ "cluster": { "status": "ACTIVE", "statistics": [], "clusterName": "fargate-cluster", "registeredContainerInstancesCount": 0, "pendingTasksCount": 0, "runningTasksCount": 0, "activeServicesCount": 0, "clusterArn": "arn:aws:ecs: region : aws_account_id :cluster/fargate-cluster" } }
注册任务定义
必须先注册任务定义才能在ECS集群上运行任务,以下是注册任务定义的一个fargate启动类型的示例文件:
{
"family": "sample-fargate",
"taskRoleArn": "ecs TaskExecutionRole",
"executionRoleArn": "ecs TaskExecutionRole",
"networkMode": "awsvpc",
"containerDefinitions": [
{
"name": "test_nginxweb",
"cpu": 256,
"memory": 512,
"image": "023663056036.dkr.ecr.ap-northeast-1.amazonaws.com/test-qulp:nginx_web0.0",
"portMappings": [
{
"containerPort": 80,
"hostPort": 80,
"protocol": "tcp"
}
],
"essential": true
}
],
"requiresCompatibilities": [
"FARGATE"
],
"cpu": "256",
"memory": "512"
}
以下是fargate类型受支持的范围:
以下是EC2类型受支持的范围:
则受支持的值介于 128 个 CPU 单元( 0.125 个 vCPU)和 10240 个 CPU 单元( 10 个 vCPU)之间。
有两种方式传递JSON文件到 AWS CLI 。
第一种:将任务定义JSON保存成文件,使用选项传递
aws ecs register-task-definition --cli-input-json file://JSON文件的位置
第二种:直接在AWS CLI命令行中使用引号传递JSON字符串。
注册任务定义后的返回:

列出任务定义
aws ecs list-task-definitions
创建服务
aws ecs create-service --cluster 集群名字 --service-name 服务名字 --task-definition 任务定义:1 --desired-count (服务的数量) --launch-type (启动类型)"FARGATE" --network-configuration "awsvpcConfiguration={subnets=[subnet-abcd1234],securityGroups=[sg-abcd1234],assignPublicIp=ENABLED}"
起中的子网和安全组都是需要自己之前创建的。
列出集群中的服务
aws ecs list-services --cluster 集群名字
描述正在运行的服务
aws ecs describe-services --cluster 集群名称 --services 服务名称
云计算
2019-05-05 17:52:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
迁移线下git存储库到codecommit
步骤 1:创建 CodeCommit 存储库
步骤 2:将本地内容迁移到 CodeCommit 存储库
现在,您有了一个 CodeCommit 存储库,您可以在本地计算机上选择一个目录,将其转化为本地 Git 存储库。可以使用 git init 命令将现有的非版本控制内容转化为 Git 存储库,或在尚无任何文件或内容的情况下初始化一个新的空存储库。 在本地计算机上的终端或命令行中,进入要用作存储库源的目录。 运行 git init 命令在该目录中初始化 Git 版本控制。这会在启用版本控制跟踪的目录的根目录中创建一个 .git 子目录。.git 文件夹还包含存储库的所有必需元数据。 git init 添加要置于版本控制之下的文件。在本教程中,将运行带 . 说明符的 git add 命令来添加该目录中的所有文件。有关其他选项的信息,请参阅 Git 文档。 git add . 为添加的文件创建一个带有提交消息的提交。 git commit –m "Initial commit" 运行 git push 命令,指定目标 CodeCommit 存储库的 URL 和名称以及 --all 选项。(这是您在 步骤 1:创建 CodeCommit 存储库 中复制的 URL。)
例如,如果将存储库命名为 MyFirstRepo 并设置为使用 HTTPS,则可以键入下面的命令: git push https://git-codecommit.us-east-2.amazonaws.com/v1/repos/ MyFirstRepo --all
云计算
2019-04-22 16:14:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
本文作者:AIOps智能运维
干货概览

今天我们不聊上层建筑,不聊单机房自愈,也不聊智能运维的暗夜与黎明,今天我们聊一个很基础的话题:如何执行一条命令。许多人看到这,可能觉得这是一个简单至极的问题,事实果真如此吗,别急,下面我们来抽丝剥茧,一探究竟。

什么是命令

首先回顾一下“命令”的具体含义,发令以使之,谓发令而使其做某事,这是“命令”一词的基础释义。从这里我们可以看命令的三个最基本的要素:命令内容(令)、命令传递(发)、命令执行(使)。如果将这三要素限定在服务器上,它们又是如何运作的呢?

图1 windows与linux下的命令

命令内容(令)

无论是windows还是linux操作系统,都会提供相应的CLI(不要吐槽windows的CLI难用),供使用者交互执行命令或运行批处理脚本。仔细观察,所有命令行都有一个相同的特点:固定词+选项+参数,无出其右。因CLI伴随着操作系统的诞生,且命令行处理又是一个复杂但相似的过程,因此各种语言也都提供了相应的库支持,如C语言提供了getopt/getopt_long等函数,C++的boost提供了Options库,shell中处理此事的是getopts和getopt。

命令传递(发)

命令传递有两种方式,一种是文件形式,将bat/shell脚本上传到服务器然后执行。另外一种就是交互式,通过telnet/ssh等方式远程连接服务器后,直接在命令行界面执行。虽然从形式上我们将命令传递分为了两种方式,但从本质上来说,服务器上的命令传递,都没有逃脱网络传输这个过程。

命令执行(使)

对于操作系统来说,命令的执行,其实就是启动一个进程并传递相应的参数,运行完成后得到相应的结果。这里我们并不关心进程如何创建,PBC的结构如何等细节,我们只关心命令进程的启动方式以及结果的获取方式。

为什么要执行命令

在分布式产品的开发维护过程中,有三个主题是无法绕过的,分别是配置管理、部署升级和监控采集。

配置管理

配置管理的目标是为了标识变更、控制变更、确保变更正确实现并向其他有关人员报告变更。从某种角度讲,配置管理是一种标识、组织和控制修改的技术。通常情况下,配置管理都会统一部署配置服务器来同步所有节点的配置。但是在开发测试过程中,总会出现临时修改某个或某一批节点的配置的情况,这时通过人工逐个登录来完成修改显然是不太可能的。

部署升级

DevOps的概念如今日趋流行,部署升级越发成为开发运维过程中重要的一环,频繁的交互意味着频繁的部署。部署过程可以拆解为两个小的步骤,一是新软件包的上传,二是服务进程的重新启动。服务进程的重新启动不必多说,软件包的上传可能有多种方式,如sftp的集中式,p2p的点对点式等。

监控采集

软件运维过程需要时刻监控系统及业务软件的运行状态,各种运维决策都是以这些数据为依据进行的。随着自动化运维的发展,很多运维动作都从人工执行变为了自动执行,自动执行的决策过程更是需要采集大量的实时信息(前期文章《百度大规模时序数据存储》中介绍的TSDB就是为了解决这些数据的存储问题而研发的)。监控数据的来源主要分两种,一种是通过业务软件提供的接口直接读取状态数据,另一种是通过日志/进程状态/系统状态等(如使用grep提取日志,通过ps查询进程状态,通过df查询磁盘使用等)方式间接查询。

无论是配置管理、部署变更还是监控采集,都有一个共同的目的:控制服务器。在现阶段,要想对服务器进行控制,离不开“在大量服务器上执行命令并收集结果”这一基础能力,这也是今天我们的主题“如何执行一条命令”的意义所在。

面临的困难

命令行的三要素,也是如何执行一条命令行面对的三个问题,如前文所述,对于单机环境来说,这三个问题在前人的努力下已经被很好的解决。可是如果要在几十万台机器上每天执行几十亿条命令,同时保证时效性,保证执行成功率,保证结果正确收集,保证7*24小时稳定运行,就不是一件简单的事情了。所谓远行无轻担,量大易也难,在构建这样的执行系统的过程中要面临诸多困难,此处举几个突出的例子如下:

信息存储问题:为了支持水平扩展,需要高效的内存数据库作为缓存。为了做到执行命令的可追溯、可统计,需要对执行过的命令信息持久化。日均几十亿的热数据,年均上万亿的冷数据,需要仔细选择存储方案。

任务调度问题:为了达到在任意多台服务器上执行命令的要求,需要确定何时分发命令、何时回收结果以及怎么样的并发度批量下发。

消息传输问题:为了保证命令高效正确送达目标服务器,需要构建一个可靠的命令传输网络,使命令信息在准确送达的前提下保障传输的可靠与高效,毕竟百度的几十万台服务器分布在世界各地。

代理执行问题:为了更好的处理权限、单机并发等单机执行问题,需要在目标机构建执行代理,以应对单机的复杂执行环境。

图2简单问题放大后也变得困难

百度目前拥有分布在世界各地的几十万台服务器,并且随着业务的不断扩张,这个数字还在持续增长,构建一个高效稳定通用可扩展的命令描述、传递、执行系统在这样的环境中有着重要的现实意义。对百度各产品线的用户来说,这样的一个系统,最基础的要求是:执行高效,控制灵活,扩展方便。

1.执行高效:

单机执行,要求能够达到秒级命令下发/执行/结果收集。

集群执行,要求支持同时在10万台服务器上并行执行,同时保证集群中每个机器达到单机执行的性能。

2.控制灵活:

单机控制,要求支持暂停、取消、重做功能。

集群控制,要求支持暂停点功能,也即可以在执行到某台服务器时暂停,等待人工检查确认无问题后可继续执行。

3.扩展方便:

支持插件,要求支持自定义执行插件,用户可编写自己的插件执行相应操作。

支持回调,要求支持自定义用户回调,如任务执行失败调用相应回调接口。

除了以上的业务需求外,一个分布式系统的搭建,还要考虑可用性、可扩展性、性能、一致性等方面的硬性要求。

如何解决

为了解决这个简单的难题,我们设计了如图3所示的百度集群控制系统(Cluster Control System,简称CCS系统),通过分离控制信息与执行信息建立了两级数据模型,结合命令执行及机房部署特点建立了四级传输模型,通过三级守护方式建立了稳定的执行代理,在大规模服务器集群上解决了“命令三要素”问题。

图3百度集群控制系统架构

截至目前,CCS系统已经部署在全百度的所有机房中,用户可以方便的在任意一台机器上进行秒级命令下发和结果收集,日均承载数亿次来自各产品的接口调用。关于数据模型、传输模型、执行代理这“分布式命令三要素”的设计及应用,我们将在下一篇文章中详细介绍。

原文链接地址: https://developer.baidu.com/topic/show/290057
云计算
2019-03-30 11:04:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
2018年10月份,UCloud数据中心基础网络完成了V4新架构的落地,自此,新建的数据中心(下简称DC)全面升级到25G/100G网络,极大提升了DC容量和DC间互联的性能。V4架构下的单可用区可提供320,000个服务器接入端口,是此前V3架构的4倍。并且支持无损网络特性,提供可用区资源的水平扩展和滚动升级能力。上线以来,新架构有力保障了UCloud福建GPU可用区开放、北京二可用区B/C/D扩容等需求。
对比云产品通过软件的灵活性来创造丰富的用户价值,公有云物理网络更注重规划的前瞻性与设计的合理性。其目标是简单、稳定、高效。通过对上层虚拟网络提供极度可靠的、一维寻址的逻辑连通面,来帮助实现上层产品“软件定义一切”的使命。下文就将详述我们秉承这种理念设计DCN V4架构的细节。
UCloud DCN V3架构设计
UCloud公有云以可用区(下简称AZ)为最小资源池单位对外提供服务,一个可用区由一个或多个数据中心组成。UCloud数据中心基础网络架构(下简称DCN)在2016年升级到V3架构,如下图所示:
图:UCloud DCN V3架构
V3架构的设计目的:
全面升级到10G接入、40G互连; 彻底拆掉了堆叠,避免了堆叠的种种弊端; 采用了两级CLOS、Spine-Leaf架构,实现了一定的水平扩展能力; 数据中心核心交换机为Spine,提供标准的BGP路由接入,TOR/Border为Leaf;业务服务器的网关落在TOR Leaf上;DC的 Border Leaf连接城域网POP机房,实现DC到DC外的互通,一个DC即一个可用区。 V3解决了V2时代堆叠和MC-LAG的弊端,CLOS架构有水平扩展能力,全网统一接入方式提升了网络部署效率。
V3上线后,适逢UCloud发力建设海外节点,为首尔、东京、华盛顿、法兰克福等节点在短时间内的快速落地,提供了有效支撑。
V3架构的新挑战
近两年,随着UCloud业务高速发展,以及25G/100G网络设备的成熟,业务对网络的性能提出了全新需求,V3架构逐渐显示出一些不足之处,主要如下:
性能不足 分布式计算、实时大数据、NVMeoF等的发展,要求网络提供更大的带宽和更低的时延,以及服务质量保证。
以NVMeoF为例,网络存储比起传统存储,在网络设备转发、传输、TCP/IP协议栈上有额外开销。近来RDMA技术的成熟,极大降低了TCP/IP协议栈开销,提升了IO性能。但我们在实践中发现,V3架构下的轻微拥塞,可能造成大量RMDA报文重传,占用相当带宽并造成业务性能下降,这种网络性能上的瓶颈需要突破。
容量不足 用户常希望在一个可用区有无限的资源可以扩容。V3的两级CLOS架构水平扩容能力,最终受限于Spine设备端口数,一个DC网络大概能容纳的规模为一两万台服务器或一两千个机架。而一座机房可以有上万甚至上十万的机架,在V3架构下,需要做多个DC网络,DCN之间通过POP互连互通,不但性能难以提升,而且成本巨大。
灵活性不足 全网统一接入方式,便于大规模上架布线部署工作,确确实实提高了效率,但同时带了灵活性下降。比如有的业务要求集群服务器二层可达,有的业务要求经典网络做Overlay……总之,整齐划一的网络规划不能满足所有主流的业务需求。
DCN V4架构的设计与优化
为了解决上面的问题,2017年底开始,团队对DCN架构进行重新设计、硬件选型和标准化,并于2018年10月份完成DCN V4整套方案并在新建数据中心落地,整体架构如下:
图:UCloud DCN V4架构
新架构中,我们主要做了如下优化:
1. 硬件整体升级到25G/100G平台 2017年底到2018年上半年,各商用交换机大厂的25G/100G网络设备逐渐成熟,25G/100G光模块价格也趋于合理,同时GPU、实时大数据、NVMeoF等业务需求爆发,IO瓶颈从服务器内部转移到了网络上。因此,我们开始着手将硬件从10G升级到25G平台。
我们从2017年底开始,对各主流交换机、光模块、光纤、服务器网卡厂商的主流25G/100G产品进行了选型、交叉测试、线上小批量,投入了8个月的时间,累计交叉测试超过300个产品组合,最终确定整套25G/100G硬件产品。
本月已上线的福建GPU可用区,利用此架构,同时支持10G/25G物理网络。25G网络带来更高的集群运算效率,和普通可用区提供的GPU云主机相比,整体性能翻倍,这对AI训练这样看重绝对性能的场景非常重要。
图:GPU物理云10G/25G网关集群
2. 3级CLOS的设计
图:2级CLOS
CLOS架构要求下一级设备需要跟上一级设备full-mesh,因此在V3的2级CLOS架构下,Leaf层的接入交换机(下简称AS)必须连接到所有Spine层的核心交换机(下简称DS),也就是2台DS;如果设计为4台DS,那么AS就必须四上连到每一台DS,复杂度直线上升。因此DCN整体容量取决于DS设备的总端口数,DS设备的槽位数越多、单槽位端口密度越大,那么一个DCN可接入服务器容量就越大。
图:3级CLOS
V4改用新的3级CLOS设计。Leaf层的每一台汇聚交换机(下简称CS)需要上连到所有Spine层的DS。比如一台典型的CS是32端口100G设备,16口上连DS,16口下联AS:
设计的2台DS,1台CS出8个口连到DS1、8个口连到DS2,总共16个上连,每台DS消耗8个端口; 如果设计的是4台DS,1台CS的16个上连口分成4组,每组4个口分别上连到DS1/2/3/4,每台DS消耗4个端口; 如果是8台DS,那么1台CS只需要消耗DS的2个端口…… 可以看到,设计的Spine层的设备越多,每台CS需要DS的端口数越少,可以接入的CS数量就越多,在其他条件不变的情况下,整个DCN接入容量就越大。
我们通过2级CLOS→3级CLOS的架构变化,使得整个DCN的接入容量得以提升,理论上,随着硬件技术的发展,设计容量可以提升到无穷大。这就解决了DCN容量上的问题。 按我们目前的设计,单DC容量最大可以提供80,000个服务器接入端口,单可用区可达到320,000个,是DCN V3时代的4倍,能满足UCloud所有地域未来几年平滑扩容的需要。
3. POD的引入 2级CLOS变为3级CLOS之后,多出了一个汇聚层,我们把一组汇聚交换机及其下连的接入交换机、以及接入交换机带的机架,总体称为一个POD。单个POD提供一致的网络能力,包括:
一致的连接方式。一个POD里,所有AS到CS的连接方式是一样的,比如都是1 100G单线互连或者都是2 100G;所有服务器到AS的连接也是一致的,比如每台服务器1 25G连到AS或者2 25G连到AS。 一致的网络特性。一个POD支持的网络特性是一样的,比如支持ECMP、支持开启QoS、支持直接接入到公网等。 这让我们可以根据业务对网络性能和特性的要求,针对性的开设POD。
例如,当前的业务分区有公有云区、物理云区、托管云区、网关区、管理区、IPv6区等,其中公有云区、网关区、管理区、IPv6区对基础网络的要求基本一致,在新的POD设计思路下,均合并为“内网POD”。而大数据区、云存储区等网络IO极高的业务,则设置了“高性能内网POD”,具有每台服务器2*25G全线速接入的网络能力, 提供QoS和无损网络特性。此外,还有“综合POD”应对要求公网/其他特殊网络需求的服务器接入,“混合云POD”提供裸金属或用户私有云接入等,满足不同的业务需求,来解决灵活性问题。
总的来说,POD是按照网络能力设计的,满足不同业务的需求,且能避免成本浪费,控制CAPEX,并避免按业务分区导致过多的网络分区,控制维护的复杂度。
4. DC Group UCloud公有云资源池分为“地域”(一般是一个地理上的城市)和“可用区”(简称AZ,两个可用区一般距离10km以上,基础设施隔离)两级。
一个AZ可以包含多个DC,但实际上,由于V3架构下DC都是连接到POP、与其他DC互通,这就需要拉光缆、架设波分,带来带宽瓶颈和时延上升。所以即使两个DC距离非常近,作为一个AZ资源池也不合适,作为两个AZ则与AZ的距离要求相悖、也不合适。
图:DC Group产生前后对比
V4架构提出了「DC Group」概念,将地理位置相近的DC间full-mesh连接起来,作为同一个AZ对外提供服务。带来的好处有:
网络时延低。DC Group内的DC之间距离非常近,通常不超过10km,由此带来的时延在0.1ms以内; 增加冗余度和带宽。由于DC之间距离近,光缆成本也低,我们可以增加更多的光缆连接,一方面保证足够的冗余度,另一方面增加足够的带宽; 可滚动升级。可以通过新建新一代DC的方式,满足新业务在原AZ里上线的要求,且对运行中的DC基本无影响。 例如,前段时间我们发布了高性能SSD云盘产品。在业务部署阶段,恰逢北京二可用区D的空闲机柜不多,如果等申请到新机柜再部署,就浪费了宝贵的时间。而如果只把产品部署在新开的可用区,就无法照顾原可用区用户的需要。
这个矛盾在DC Group架构下,就可以通过添加新DC得到良好解决。
总结
UCloud总体网络设计中,基础网络的目标是「稳定」和「高效」。基础网络通过组织物理线路、经典网络设备和网络技术,形成了一张稳定而且高性能的网络底层,为上层业务提供IP连通性。基础网络下承机房基础设施、上接业务,需要解决「业务需求变化快」和「基础网络升级难」这一对永恒的矛盾。DCN数据中心网络是基础网络最重要的一个组成部分。
图:UCloud总体网络设计
我们过去一年所重新设计的DCN V4架构,令新建的DC全面升级到25G/100G、支持无损网络特性、提升了DC容量和DC间的性能、提供了AZ资源的水平扩展和滚动升级能力。总而言之,平衡了「新需求」和「老架构」之间的矛盾,可以满足数年的发展需求。未来,基础网络会继续紧跟技术发展潮流,为各公有云产品提供更稳定、更高效的底层网络。
云计算
2019-03-15 18:34:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
基本介绍
如果用户对视频播放中的某一帧画面特别感兴趣,可以使用截图功能将这一帧视频保存起来。另外有一种场景想知道是否有声音,或者想感知声音的大小震动频率等,可以通过显示一个声音的波形来形象的表示。如下图所示:
那么播放器提供了类似的方法可以让用户有办法去实现音频波形这个功能。那么这种通常在音乐播放器中比较常见,或者在直播场景中来标识对方讲话是否有声音等,有一定的应用场景。
视频截图
实现接口
iOS接口如下:
/** * 功能:截取当前正在播放图像 * */ -(UIImage*) snapshot;
Android接口如下:
public Bitmap snapShot();
需要注意
视频内容截取
需要知道的是视频截图截取的是视频的真实内容,而不是渲染窗口大小的图像。比如播放的是1920x1080的图像,窗口渲染大小是800*600,那么截取出来的图像是原始的1080p的图像,而不是窗口渲染大小的图像。这样截取出来的内容不会有失真的情况。
保持镜像和旋转
如果此时用户设置了镜像或者旋转模式,那么截取出来的视频内容也是有旋转和镜像的图像。SDK内部已经对这种情况进行了处理。
音频波形
实现接口
用户要实现音柱功能,播放器SDK必须要将实时的播放音频数据回调出来,具体见一下方法:
iOS接口:通过一个block回调出PCM音频数据
/** * 功能: * 参数:block:音频数据回调 * */ -(void) getAudioData:(void (^)(NSData *data))block;
Android接口:通过一个监听来获取音频数据
public interface OnPcmDataListener { public void onPcmData(byte[] data, int size); } public void setOnPcmDataListener(OnPcmDataListener onPcmDataListener);
实现音频波形
拿到了PCM数据之后,如何去绘制音频波形,就是应用层的事情了,iOS和Java层都有很多绘制音频波形的方法。
要绘制成什么样的形状都可以安装自己的需求来做。这些在网上都有很多相关的资料,在这里就不进行描述。
类似如下比较炫的效果都可以实现。
作者: 隽阜
原文链接
本文为云栖社区原创内容,未经允许不得转载。
云计算
2019-03-05 17:00:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>> containerd是被阿里云、AWS、Rancher Labs、Docker、Google、IBM以及容器生态系统内的其他更多成员最广泛采用的容器运行时。
美国时间2019年2月28日,CNCF正式宣布containerd毕业了!
containerd是继Kubernetes、Prometheus、Envoy和CoreDNS之后,第五个从CNCF毕业的项目。从孵化成熟阶段开始,要想最终毕业,项目必须表现出高度的多样性,被大量用户广泛使用,拥有正式的治理过程,并且面向整个开源社区坚持其可持续性及包容性。
“大概两年前,containerd正式成为CNCF的项目,这之后我们能明显看到containerd显著的发展势头,而这也充分展示了市场对基础容器技术的巨大需求。”CNCF首席技术官Chris Aniszczyk表示,“社区共同协作并投入了大量精力,对稳定的核心容器运行时进行开发和测试。而且社区也付出了很多努力为其扩大维护者和采用基础、通过外部安全审计,现在,我们无比激动看到containerd正式毕业!”
2014年,containerd诞生于Docker,最初它是Docker引擎的底层运行时管理器。继2017年3月被CNCF接受之后,containerd已经成为一个行业标准的容器运行时,它简单、稳定、有良好的可移植性,最广泛的使用方式是作为Docker引擎和OCI runc执行器之间的层。
containerd亦可用作Linux和Windows的守护进程。它还可以管理其主机系统的完整容器生命周期,从镜像传输和存储,到容器执行和监督,再到底层存储,再到网络附件等等。
“当Docker向社区提供containerd时,我们的目标是共享一个强大且可扩展的运行时,数百万用户和成千上万的组织已经将其标准化为Docker Engine的一部分,”containerd维护者、Docker工程师Michael Crosby说。“我们一直在不断努力希望能进一步满足现代容器平台(如Docker平台和Kubernetes生态系统)的需求。过去一年中containerd被更多组织采用,并且拥有了进一步的创新,我们的工作也就有所回报了。containerd的用户数量不断增长,使用范围更为广泛了,我们期待在整个生态系统中继续合作,继续推动我们的行业发展。“
containerd自成立以来就拥有各种维护者和贡献者,目前有来自阿里巴巴、Cruise Automation、Docker、Facebook、Google、华为、IBM、微软、NTT、特斯拉等公司的14位committer,拥有4406份commit以及166位贡献者。
containerd是被阿里云、AWS、Rancher Labs、Docker、Google、IBM、Cloud Foundry以及更多生态系统支持者最广泛采用的容器运行时。containerd和Rancher Labs的很多产品都颇有渊源,比如容器操作系统RancherOS和新近发布的轻量级Kubernetes发行版K3s。
对于RancherOS,它是专为容器而生的container Linux,与其他Linux发行版不同的是,它使用system-docker来代替systemd来作为Pid 1,而containerd就是system-docker的重要组成部分。
Rancher Labs两天前新近发布的K3s——史上最轻量的、开源Kubernetes发行版,正是使用containerd代替Docker作为运行时的容器引擎。K3s只有40M大小,通过用containderd替换Docker,K3s显著减少了运行时占用空间,删除libnetwork、swarm、Docker存储驱动程序和其他插件等功能。
为了正式从孵化状态毕业,containerd还采用了CNCF 行为准则,执行了独立的安全审计,并确定了自己的治理结构以发展社区。此外,containerd还必须获得(并维护)核心基础设施倡议(CII)的最佳实践徽章。2018年9月1 日,containerd获得的CII徽章,正是证实了其代码质量和安全最佳实践的一贯承诺。
containerd,毕业快乐!
云计算
2019-03-04 10:22:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>

基本介绍
如何保障视频内容的安全,不被盗链、非法下载和传播,阿里云视频点播已经有一套完善的机制保障视频的安全播放:
那么在播放器中支持哪一些安全播放的机制呢?
这里有料: 视频安全解决方案 。
Referer访问控制
基于 HTTP 协议支持的 Referer机制,通过 Referer跟踪来源,对来源进行识别和判断,用户可配置访问的 Referer 黑、白名单(二者互斥)来限制视频资源被访问的情况。
1. 阿里云控制台支持黑名单和白名单两种模式,访客对资源发起请求后,请求到达CDN 节点,节点会根据用户预设的防盗链黑名单或白名单进行过滤,符合规则可顺利请求到视频数据;若不符合,请求会被拒绝,并返回403响应码。
2. 配置后会自动添加泛域名支持,例如填写a.com,最终配置生效的是*.a.com,所有子级域名都会生效。
3. 由于移动端一般拿不到Referer,当前默认支持空Referer访问,可选择关闭。
控制台配置页面如下:
播放器referer接口
阿里云播放器提供了Referer的设置。提供了 setReferer 接口。
比如:控制台设置的白名单为:aliyun.com 。 那么使用如下:
AliyunVodPlayer aliyunVodPlayer = new AliyunVodPlayer(this); //注意:加上http(s)://的协议头 aliyunVodPlayer.setReferer("http://aliyun.com");
那么这样才能播放视频。如果黑名单是aliyun.com,则如上设置不能播放视频。
视频加密播放
防盗链安全机制能有效保障用户的合法访问,但对于付费观看视频的场景,用户只需通过一次付费行为拿到视频合法的防盗链播放URL,将视频下载到本地,进而实现二次分发。因此,防盗链方案对于视频版权保护是远远不够的。视频文件一旦泄露,会给付费观看模式造成十分严重的经济损失。
阿里云视频加密是对视频数据加密,即使下载到本地,视频本身也是被加密的,无法恶意二次分发,可有效防止视频泄露和盗链问题。
阿里云私有加密
阿里云视频加密采用私有的加密算法和安全传输机制,提供云端一体的视频安全方案,核心部分包括 “加密转码” 和 “解密播放”。
核心优势 每个媒体文件拥有独立的加密钥匙,能有效避免采用单一密钥时,一个密钥的泄露引起大范围的安全问题。 提供信封加密机制“密文Key+明文Key”,仅密文Key入库,明文Key不落存储,所有过程只在内存中,用完即销毁。 提供安全的播放器内核SDK,涵盖iOS/Android/多平台,自动对加密内容进行解密播放。 播放器和云端使用私有加密协议进行密文传输,不传输明文Key,有效防止密钥被窃取。 提供安全下载,缓存到本地的视频会再次加密,在确保无网离线播放前提下,防止视频被拷贝窃取。 注意:阿里云视频加密仅支持输出HLS格式,且只能使用阿里云播放器。
更多信息参考 阿里云-视频加密
如何进行加密播放
阿里云播放器将内部解密逻辑、服务端交互逻辑都封装到了SDK内部,对用户无感知。播放加密视频和普通方式没有区别,不用做多余属性的设置,只需要通过videoId的播放方式集成播放器播放视频即可。
所以用户只需要配置加密转码即可,用户可以零成本使用加密播放。
HLS标准加密
HLS标准加密支持 HTTP Live Streaming 中规定的通用加密方案,使用AES-128对视频内容本身进行加密,同时能支持所有的HLS播放器,用户可选择使用自研或开源的播放器。相比私有加密方案,灵活性更好,但使用门槛更高、安全性更低:
用户需搭建密钥管理服务,提供密钥生成(用于转码时对视频内容进行加密)和解密服务(用于播放时获取解密密钥),也可基于 阿里云KMS 进行封装。 用户需提供令牌颁发服务,用于验证播放端的身份,避免解密密钥被非法获取,此处为关键点,处理不好会千里之堤溃于蚁穴。 播放器和云端传输明文Key,容易被窃取。 具体可以参考 HLS标准加密流程 #### mtsHlsUriToken 阿里云播放器支持用户令牌传递,阿里CDN会动态修改m3u8文件中的解密URI,解密URI中会带上用户的令牌,业务方可以对令牌进行验证, - (void)prepareWithVid:(NSString*)vid accId:(NSString *)accId accSecret:(NSString*)accSecret stsToken:(NSString*)stsToken authInfo:(NSString*)authInfo region:(NSString*)region playDomain:(NSString*)playDomain mtsHlsUriToken:(NSString*)mtsHlsUriToken;
chinaDRM
高端的视频节目,需要满足内容提供商的安全要求,如好莱坞。阿里视频云与获得广电和好莱坞双认证的ChinaDRM服务商合作,推出国内首款云端DRM解决方案。
目前阿里云移动端播放器支持ChinaDRM的加密播放,来看一下系统框图:
如何使用
同样,阿里云播放器做到了对用户零成本的接入,用户不需要在客户端进行任何特殊的处理,只需要使用加密的vid进行播放即可。
作者: 隽阜
原文链接
本文为云栖社区原创内容,未经允许不得转载。
云计算
2019-02-22 16:48:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>> Apache ServiceComb 项目成立已经 2 周年,一路以来,社区遵循 Apache Way,坚持中立、开放、多样化的原则,携手用户和开发者长足健康发展。
2019 年,在认真听取社区声音后,社区推出 5 大创新新品项目,期望与用户和开发者一起思考如何共同去解决微服务中的难题,为更好地回馈社区用户和开发者,在 Apache 软件基金会成立 20 周年之际,Apache ServiceComb 在 HC2019 华为全联接大会会场举办了“Apache 开源开发详解”和“微服务创新实践解放开发者”社区活动。本文回顾了此次活动中嘉宾的精彩分享内容,以及用户和开发者聚焦的典型问题。
Apache 软件基金会董事会主席 Craig Russell、Apache 孵化器管理委员会主席 Justin Mclean 两位重磅嘉宾出席了此次活动,并为中国的开源爱好者独家剖析 Apache 的开源开发之道,对国内开源开发者、在校同学在实践中遇到的困惑给出了独到的见解和建议。
同时,来自华为的 Apache ServiceComb VP 姜宁、Apache ServiceComb 架构师马彬、华为云 ServiceStage 架构师王启军为大家分享了 ServiceComb 进入 Apache 的成长之路和趟过的那些坑、ServiceComb 面向用户痛点创新的 5 个项目解读、华为云 ServiceStage 在微服务自动化拆分工具的创新实践,并对开发者关心的遗留应用向微服务转型如何拆分数据库 / 表、如何降低对底层开发框架的学习门槛快速实现微服务改造和开发、多厂商集成过程中可能出现的异构服务如何互通,以及多语言如何实现微服务转型等问题做了开放式的探讨。
Apache 软件基金会董事会主席 Craig Russell 话开源之道
Apache 之所以能够受到世界上众多开源开发者的青睐,并且长盛不衰的原因是什么呢?Apache 软件基金会董事会主席 Craig Russell 结合 Apache 的使命和 Apache 之道诠释: Apache 是公益性组织,坚持“为公众利益提供免费的软件”的使命,使用商业友好的 Apache 协议,让整个世界的公众从中获益,并乐于接受所有人的捐赠。 Apache 保持中立,不受任何企业或个人控制,注重构建社区并且为这些社区提供项目管理服务,是“一个基于协作,一个基于交流和共同打造伟大的软件的地方”。 Apache 提供了对社区项目的治理之道 Apache Way,它让社区和人们可以携手走在一起,来追求一个共同的目标,其核心理念是“社区胜于代码”,社区的位置放在首位,没有独裁者,由社区来决定什么才是正确的事情,并且每个人都可以通过参与社区贡献并获得功绩。
Craig Russell 表示:Apache 为众多开源爱好者提供了广阔的舞台,中国作为亚洲使用 Apache 软件最活跃的国家,越来越多的公司或个人项目加入到 Apache 回馈社区,社区也在积极地回馈每一位贡献者:免费的培训和学习平台,打造高质量的代码,合作与竞争的共赢平衡,并且使所有贡献者受到法律保护。
Apache 软件基金会孵化器主席 Justin Mclean 谈成长为 Apache 顶级项目之道
在认识 Apache 之后,项目如何进入 Apache 孵化器发展,并最终毕业成长为世界顶级项目呢?Apache 软件基金会孵化器主席 Justin Mclean 结合丰富的管理和实践经验,给出了非常中肯的建议: 围绕项目建立社区,活跃的社区“可以自我纠正,应对各种挑战和问题”,社区沟通的原则倡导友善、尊重、信任和谦虚,Justin 表示:“我们要信任,要假设其他人都是有善意的”。 许可协议非常关键,它保障用户使用软件时不出现任何纠纷,同时也保护社区的商标、项目名字不被别人仿照,是合规性重要的一环,也是成为顶级项目的必要条件。 发布版本,为了提供法律保护和发展社区,发布的流程需要确保符合 Apache 的流程和规定,并且必须由 PMC 投票。 项目毕业,当一个项目具备自管理、独立发布的运作能力,并遵从 Apache 软件基金会的规则,建立好法律框架,不再需要孵化器组织或者导师的帮助,即满足从 Apache 孵化器毕业成为顶级项目的条件。
Apache ServiceComb VP 聊项目成长之路和趟过的那些坑
作为 Apache Member、Apache ServiceComb 首席技术专家,姜宁老师也曾担任过 Apache RocketMQ 项目孵化阶段的导师,有丰富的实战经验,姜宁老师为大家分享了 ServiceComb 如何从零开始,并在 1 年内成长为首个 Apache 微服务顶级项目的经验: 与 Apache 导师保持充分交流非常重要,在导师丰富经验的帮助下,可以更快速地了解和适应 Apache 规则和流程。 充分利用好 Apache 邮件列表、JIRA 等公共的沟通渠道,让更多的参与者了解项目、社区构建以及未来的规划,邮件列表归档的功能也能使刚进入社区的贡献者能快速找到每个事情的上下文,融入社区。 项目捐赠给 Apache 之后,名字和商标不能在商业产品里面随便乱用。 定期举行线上线下活动,为社区的参与者和开源爱好者提供互相交流的平台,有利于促进与其他社区、项目之间的合作和推广。 鼓励大家参与,为社区贡献者留下适当的发挥空间,建立“帮扶”机制,让更多的人能够参与进来,壮大社区。 抱着善意的心态去对待投票 -1,因为每个 -1 意见都包含着参与者对社区的付出,并且从每次 -1 票中找出问题并改进。
- 务必确保项目的每行代码的来源是清楚的,没有 copy right 和 license 的使用问题,这也是每次版本发布前需要重点检查的地方。
Apache ServiceComb 架构师解读面向用户微服务痛点的创新项目
众所周知,微服务是一种架构理念,软件架构极大依赖于专家经验,而专家经验更多地是依赖口口相传或者文档传播,在企业向微服务转型过程中,有没有相应的软件或工具能够解放专家手脚、帮助开发者快速上手成为用户的关键痛点。
ServiceComb 进入 Apache 以来,认真听取社区声音,确定了系列解决用户微服务化过程中痛点的方向,并且在社区里面继续创新孵化,于 2019 年推出 5 大新品项目解决微服务痛点问题,Apache ServiceComb 架构师马彬解读了 5 个新品项目面向的场景、现状和下一步开发计划: servicecomb-mesher,高性能服务网格框架,开箱即用、多语言、零侵入业务代码实现微服务化改造。
越来越多的企业开始向微服务架构转型,不同的企业使用的语言不同,甚至同一个企业由于业务差异、联合创新等因素,都有可能涉及使用不同的语言,而传统的微服务开发框架具有业务侵入性特征,无法满足多语言场景、异构框架的服务治理互通诉求。
servicecomb-mesher 支持以 sidecar 的形态无业务侵入解决用户在多语言场景下的痛点问题,并且其始终遵循开放式的设计,支持接入云原生、运维、监控等流行生态,未来将在网关 / 生态 / 异构支撑等方面继续探索,帮助用户以最小化改造完成微服务转型。 servicecomb-toolkit,一键式微服务开发工具,自动化生成微服务工程、API、代码、文档,并支持 API 与代码一致性校验能力。
在集团型企业中,集成多个开发商应用的场景很常见,然而,不同的开发商存在开发语言、框架、习惯方面的差异,导致数据、服务标准不统一。
servicecomb-toolkit 帮助用户快速构建基于 ServiceComb 和 SpringMVC/Jax-RS/RPC 等编程模型的微服务脚手架,提升遗留系统重构、全新微服务开发的效率,协同用户实现基于标准 API 数据、服务标准化管控。未来 servicecomb-toolkit 将在支持一键制作基于 Spring Cloud 的微服务脚手架、OAI V3 规范、以插件集成到流行 IDE 方面做进一步的探索。 servicecomb-service-center/syncer,对用户透明的数据同步工具,使能异构、多服务中心数据互通。
多数据中心部署的企业,不同数据中心之间的服务数据如何互通?集成不同开发商的集团型企业,异构微服务开发框架实现的微服务如何互通?这些问题在传统企业做微服务化选型或改造过程中经常被提及。
ServiceComb syncer 为此场景而设计,它提供数据同步能力,对用户透明,对多服务中心提供对等网络,并支持异构服务中心的数据转换和同步,使基于不同微服务技术栈实现的业务可以进行数据通信。未来,syncer 将对跨云、跨数据中心等场景提供更完善的支持。 servicecomb-kie,语义型分布式系统配置中心,使运维人员通过易于理解的数据和入口,管理复杂的分布式系统配置。
传统的配置中心,多使用 key:value 数据模型(如:ServiceB.user.getUser.timeout=10s),key 的规则只在该服务内生效,对于运维人员来说难以理解。而且随着规则定义的不断增长,key 也会越来越复杂,对用户呈现也只有 key/value 单一视图,影响了可读性且不易于管理。
servicecomb-kie 通过支持 key(label):value 的数据模型设计改进了用户配置方式(如:Timeout(service=serviceB, schema=user, operation=getUser):10s),通过 key 和 label 的组合提升了用户可读性,方便扩展变更,并且支持生成多角度的配置视图。未来,servicecomb-kie 配置中心将在数据加密、对接 k8s 生态等方面通过更多支持,使用户更灵活选择方案。 servicecomb-fence,微服务认证鉴权框架,帮助用户快速构建微服务的认证鉴权能力。
典型的互联网应用不仅需要访问本应用的资源,还需要访问第三方的资源,同时还提供接口给第三方使用。应用的接入形式是多样化的,有手机,WEB 客户端,API 访问等。认证的方式包括用户名密码、手机验证码、人脸识别等。面对复杂场景,在微服务架构中,如何构建分布式、安全和高效的认证鉴权机制是用户关心的问题。
servicecomb-fence 提供开箱即用的标准化认证流程框架代码,它结合 Oauth2.0 和 OpenID Connect 协议,实现 Oauth 4 种认证模型、Token 和 Session 组合的认证机制,支持微服务内部认证鉴权、对接第三方认证鉴权服务、为第三方提供认证鉴权服务等应用场景,帮助用户快速搭建高性能、安全的微服务认证鉴权能力。
华为云微服务架构师谈“黑科技”微服务拆分创新实践
华为云在 17 年将商用了 3 年的微服务框架 ServiceComb 完全开源并捐赠给 Apache 之后,继续基于 ServiceComb 在微服务应用平台 ServiceStage 上提供商业云服务,并持续投入与创新,作为社区开发主力积极回馈社区。本次活动,华为云微服务架构师王启军为大家带来了解决用户最关心的微服务拆分痛点问题的创新实践。 微服务自动拆分工具
对于用户和开发者来说,微服务改造第一大难题就是服务如何拆分。服务拆分需要考虑的方面很多,团队大小、交付周期、业务方向、故障范围、数据规模、吞吐量、一致性等都是影响拆分结果的因素,并且可能涉及业务、平台、DBA、测试、运维等多职能部门的协同。
微服务拆分并不是一个容易的工作,如果服务拆分不合理,会给用户带来服务数量爆炸而运维复杂、服务数量太少而不够灵活、接口频繁变更、系统架构复杂度提升等问题;如果是由经验丰富的架构师们来拆分服务,问题可能会减少很多,但是时间、人力成本也会剧增,而且并非所有的团队都拥有有经验的架构师。
综上所言,服务拆分成为遗留应用向微服务转型首要解决的难题。那么,是否有可能通过自动化的工具来替代人去实现一些业务分析、拆分工作,从而解放开发者手脚,降低微服务入门门槛呢?从最关键的拆分数据库 / 表的典型场景入手,华为云微服务团队开启了微服务自动拆分工具化的探索,通过从遗留应用中解析 DAO 对象、提取 SQL 语句和业务访问日志等客观指标的方法,提供自动拆表、微服务建模和生成代码的功能,工具具备的特征: 当业务很复杂的时候,工具可以帮助用户自动梳理出业务逻辑和关联度。 从数据库中的表关联关系和代码中 model 的关联关系我们能够分析出表之间的关联度。 从表中的数据量和访问日志我们能够分析出业务的核心程度。
目前,微服务自动拆分工具已迈出第一步,具备作为辅助性工具支持微服务拆分的输入参考,后续将在支持搜集和分析更多相关指标(比如研发人员的数量、产品未来的发展方向、交付周期等等这些比较主观的因素)、提高自动化度、提高拆分精确度等方面做更深一步的探索和验证。未来,希望将微服务拆分工具开源出来,联合社区用户和开发者力量共同发展。
“到底工具能不能代替人去拆分呢?是能的,之所以说不能,是因为指标不够全面,不够准确。当我们掌握了足够的指标之后,工具比人做的决策更准确。但是,现在我们的指标还没有那么全面,那么准确,所以,现在工具更多的是辅助性的,但是,未来一定可以做到”王启军表示。
主题演讲精彩互动问答收录
在主题演讲结束后,现场与会的开源爱好者和微服务开发者与演讲嘉宾进行了积极的互动交流,小编摘录了社区用户和开发者最关心的典型问题:
Q1: 在中国,人们习惯使用微信交流,而 Apache 基金会项目是需要使用邮件列表交流的。我想请问在发展新用户的过程中,需要怎样处理这些习惯上的障碍?
Justin Mclean: 其实很容易的,我觉得项目决策是很重要的事情,它应该被记录在邮件列表中。在邮件列表中探讨和记录问题,可以做到有迹可循,有助于新加入的用户了解项目。只要做到这一点,其他都不是问题。
Q2: 作为一个学生,如何参与一个开源小项目,有没有什么建议?
Justin Mclean: 首先要找到一个你感兴趣的项目,项目里一般会有相关的问题列表,你可以从一些容易达成的目标,特别是一些文本修复任务入手。
Q3: 我想问的是作为一个 PMC 成员,我想要参加更多的社区,我需要以怎样的方式开始?
Craig Russell:其实在 Apache 里,很多人是对多个项目进行贡献的。做贡献的方式有很多形式,如果你对一个项目有兴趣,你可以去读读他们的文档,然后脑子里就会产生问题,那么问问题也就是你贡献社区的的一种形式。因为你问这个问题,意味着肯定有一些内容不太清楚、不太清晰。
你问出这个问题,就会促进社区去改善。或者你找到一个 BUG,哪怕他只是一个拼写的错误,你只需要在写邮件或者在相关的邮件后面跟帖,你就做了贡献。如果后面你看见其他人也在提这个问题,把你所知道的告诉他,也是贡献的方法。贡献不仅仅是写代码。
Q4:怎么样去评估微服务自动化拆分工具的拆分质量?
A:拆分质量的衡量指标很多,更多的时候是主观的感受,难以量化。比如:对于注重交付速度的团队,会尽可能的将服务拆分得小;对于注重组织架构的团队,会以降低业务复杂度,使团队配合、交流以及技术演进更加方便,这时候可能就要拆的更小;而对于注重性能的团队,如果服务拆太小,可能会带去资源占用变高、调用链路增长、响应时间增加的情况。
Q5:刚提到 ServiceComb 提供了一个叫 Mesher 的项目,请问它是和 Istio 一样的解决方案么?之前大家对 Istio 的性能有诟病,不知道 ServiceComb-Mesher 有做这方面的优化么?想在是否可以用于商用阶段?
A:ServiceComb-Mesher 与 Istio 不是一个对等的东西,你可以理解为 Mesher 是服务网格 Sidecar 的一种实现,只是在里面做了一些治理能力的扩充。对于 Mesher 最主要是它是一个微服务多语言支持的解决方案,它不绑定运行环境,K8S、裸机都可以使用。ServiceComb-Mesher 是先商用后开源,具备商用要求。
Q6:刚提到的微服务改造工具可以帮助用户将普通应用装换为基于 ServiceComb 的微服务,并形成一些 API 文档。我想问的是转换后的工程是直接可运行的么?转换后需要人工介入修改代码吗?工作量有多少?语言的亲和性怎么样?能不能稍微讲解一下?
A:可以理解 ServiceComb-Toolkit 生成的是一个微服务脚手架工程,目前还不支持将业务代码一并迁移,但生成的微服务工程是可以直接运行的。它已经做好的项目的基本配置,pom、java 包依赖、框架代码等,用户需要做的就是基于通讯接口迁移具体的业务实现。对于业务代码的迁移,其实是有一些想法的,比如说可以引入 AST 抽象语法树对业务代码进行分析。当然也欢迎大家一起来提意见,一起参与进来,一起来完成这些想法。
在此感谢姜宁、王启军提供部分内容素材。
本文转载至infoq
原文链接: https://www.infoq.cn/article/dbMDURNo0BCyh8Ivxxcb
云计算
2019-10-26 11:19:00
【围观】麒麟芯片遭打压成绝版,华为亿元投入又砸向了哪里?>>>
作者 | 伍冲斌  VPGAME 运维开发工程师 导读 :VPGAME 是集赛事运营、媒体资讯、大数据分析、玩家社群、游戏周边等为一体的综合电竞服务平台。总部位于中国杭州,在上海和美国西雅图分别设立了电竞大数据研发中心和 AI 研发中心。本文将讲述 VPGAME 将服务器迁移至 Kubernetes 的过程。
背景
随着容器技术的日趋成熟,公司近期计划将服务迁移至容器环境,通过 Kubernetes 对容器进行调度、编排和管理。并借此机会,对服务进行标准化,优化整个 CI/CD 的流程,提高服务部署的效率。
CI/CD 工具的选择
CI/CD 工具上,我们选择了 GitLab-CI。GitLab-CI 就是一套配合 GitLab 使用的持续集成系统,以完成代码提交之后的安装依赖、编译、单元测试、lint、镜像构建以及发布等工作。
GitLab-CI 完美地和 GitLab 进行集成,在使用的时候只需要安装配置 gitlab-runner 即可。GitLab-Runner 在向 GitLab 完成注册后可以提供进行 CI/CD 操作的环境,负责从 GitLab 中拉取代码,根据代码仓库中配置的 gitlab-ci.yml ,执行相应的命令进行 CI/CD 工作。
相比于 Jenkins,GitLab-CI 配置简单,只需在工程中配置 gitlab-ci.yml 文件完成 CI/CD 流程的编写,不需要像在 Jenkins 里一样配置 webhook 回调地址,也不需要 Jenkins 新建这个项目的编译配置。并且个人认为 GitLab 的 CI/CD 过程显示比 Jenkins 更加美观。当然 Jenkins 依靠它丰富的插件,可以配置很多 GitLab-CI 不存在的功能。按照现在我们的需求, GitLab-CI 简单易用,在功能也满足我们的需求。
服务运行环境
容器环境优点
传统的服务部署方式是在操作系统中安装好相应的应用依赖,然后进行应用服务的安装,这种部署方式的缺点是将服务的程序、配置、依赖库以及生命周期与宿主机操作系统紧密地耦合在一起,对服务的升级、扩缩容、迁移等操作不是十分便利。
容器的部署方式则是以镜像为核心,在代码进行编译构建时,将应用程序与应用程序运行所需要的依赖打包成一个镜像,在部署阶段,通过镜像创建容器实例完成服务的部署和运行。从而实现以应用为中心的管理,容器的隔离性实现了资源的隔离,由于容器不需要依赖宿主机的操作系统环境,所以可以很好地保证开发、测试和生产环境的一致性。此外,由于构建好的镜像是不可变的,并且可以通过 tag 进行版本控制,所以可以提供可靠、频繁的容器镜像构建和部署,亦可方便及快速进行回滚操作。
Kubernetes 平台功能
Kubernetes(简称 k8s),作为一个容器调度、编排和管理平台,可以在物理或虚拟机集群上调度和运行应用程序容器,提供了一个以容器为核心的基础架构。通过 Kubernetes,对容器进行编排和管理,可以: 快速、可预测地部署服务 拥有即时扩展服务的能力 滚动升级,完成新功能发布 优化硬件资源,降低成本
阿里云容器服务优势
我们在服务迁移中选用了阿里云的容器服务,它基于原生 Kubernetes 进行适配和增强,简化集群的搭建和扩容等工作,整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳的 Kubernetes 容器化应用运行环境。在便捷性上,可以通过 Web 界面一键完成 Kubernetes 集群的创建、升级以及节点的扩缩容。功能上,在网络、存储、负载均衡和监控方面与阿里云资源集成,在迁移过程中可以最小化减少迁移带来的影响。
此外,在选择集群创建时,我们选择了托管版 Kubernetes,只需创建 Worker 节点,Master 节点由容器服务创建并托管。如此一来,我们在 Worker 节点的规划与资源隔离上还是具备自主性和灵活性的同时不需要运维管理 Kubernetes 集群 Master 节点,可以将更多的精力关注在应用服务上。
GitLab Runner 部署
GitLab CI 工作流程
GitLab CI 基本概念
在介绍 GitLab CI 之前,首先简单介绍一下 GitLab CI 里的一些基本概念,具体如下: Pipeline:Gitlab CI 里的流水线,每一次代码的提交触发 GitLab CI 都会产生一个 Pipeline; Stage:每个 Pipeline 由多个 Stage 组成,并且每个 Stage 是有先后顺序的; Job:GitLab CI 里的最小任务单元,负责完成具有一件事情,例如编译、测试、构建镜像等。每个 Job 都需要指定 Stage ,所以 Job 的执行顺序可以通过制定不同的 Stage 来实现; GitLab Runner:是具体执行 Job 的环境,每个 Runner 在同一时间只能执行一个 Job; Executor:每个 Runner 在向 GitLab 注册的时候需要指定 Executor,来决定通过何种类型的执行器来完成 Job。
GitLab CI 的工作流程
当有代码 push 到 GitLab 时,就会触发一个 Pipeline。然后进行编译,测试和镜像构建等操作等操作,其中每一步操作都为一个 Job。在 CD 阶段,会将 CI 阶段构建出来的结果根据情况部署到测试环境或生产环境。
GitLab Runner 介绍
Gitlab Runner 分类
GitLab 中有三种类型的 Runner ,分别为: shared:所有项目使用 group:group下项目使用 specific:指定项目使用
我们可以根据需要向 GitLab 注册不同类型的 Runner,注册的方式是相同的。
Gitlab Runner 工作过程
Runner 首先会向 GitLab 发起注册请求,请求内容中包含 token、tag 等信息,注册成功后 GitLab 会向 Runner 返回一个 token,后续的请求,Runner 都会携带这个请求。
注册成功后,Runner 就会不停的向 GitLab 请求 Job,时间间隔是 3s。若没有请求到 Job,GitLab 返回 204 No Content。如果请求到 Job,GitLab 会把 Job 信息返回回来,Runner 在接收到 Job 之后,会向 GitLab 发送一个确认请求,同时更新任务的状态。之后,Runner 开始 Job 的执行, 并且会定时地将中间数据,以 Patch 请求的方式发送给 GitLab。
GitLab Runner 的 Executor
Runner 在实际执行 Job 时,是通过调用 Executor 来完成的。Runner 在注册时提供了 SSH、Shell、Docker、docker-ssh、VirtualBox、Kubernetes 等不同类型的 Executor 来满足不同的场景和需求。
其中我们常用的有 Shell 和 Docker 等 Executor,Shell 类型主要是利用 Runner 所在主机的环境进行 Job的执行。而 Docker 类型的 Executor 在每个 Job 开始时,拉取镜像生产一个容器,在容器里完成 Job,在 Job 完成后,对应的容器就会被销毁。由于 Docker 隔离性强、轻量且回收,我们在使用时选用 Docker 类型的 Executor 去执行 Job,我们只要提前做好 Job 所需环境的 Docker 镜像,在每个 Job 定义好 image 即可使用对应的环境,操作便捷。
GitLab Runner 安装与配置
Docker 安装
由于我们需要使用 Docker 类型的 Executor,所以需要在运行 Runnner 的服务器上先安装 Docker,具体步骤如下(CentOS 环境):
安装需要的软件包,yum-util 提供 yum-config-manager 功能,另外两个是 DeviceMapper 驱动依赖: yum install -y yum-utils device-mapper-persistent-data lvm2
设置 yum 源: yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
安装 Docker: yum install docker-ce -y
启动并加入开机启动: systemctl start docker systemctl enable docker
Gitlab runner 安装与启动
执行下面的命令进行 GitLab Runner 的安装和启动: curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.rpm.sh | sudo bash sudo yum install gitlab-runner -y gitlab-runner start
GitLab Runner 注册与配置更新
启动 GitLab Runner 后还需要向 GitLab 进行注册,在注册前需要从 GitLab 里查询 token。不同类型的 Runner 对应的 token 获取的路径不同。shared Runner 需要 admin 权限的账号,按如下方式可以获取对应的 token。
其他两种类型在对应的页面下( group 或 project 主页)的 setting—>CI/CD—>Runner 可以获取到 token。
Runner 的注册方式分为交互式和非交互式两种。其中交互式注册方式,在输入 gitlab-runner register 命令后,按照提示输入注册所需要的信息,包括 gitlab url、token 和 Runner 名字等。这边个人比较推荐非交互式命令,可以事先准备好命令,完成一键注册,并且非交互式注册方式提供了更多的注册选项,可以满足更多样化的需求。
按如下示例即可完成一个 Runner 的注册: gitlab-runner register --non-interactive \ --url "http://git.xxxx.cn" \ --registration-token "xxxxxxxxxxx" \ --executor "docker" \ --docker-image alpine:latest \ --description "base-runner-docker" \ --tag-list "base-runner" \ --run-untagged="true" \ --docker-privileged="true" \ --docker-pull-policy "if-not-present" \ --docker-volumes /etc/docker/daemon.json:/etc/docker/daemon.json \ --docker-volumes /etc/gitlab-runner/key/docker-config.json:/root/.docker/config.json \ --docker-volumes /etc/gitlab-runner/find_diff_files:/usr/bin/find_diff_files \ --docker-volumes /etc/gitlab-runner/key/id_rsa:/root/.ssh/id_rsa \ --docker-volumes /etc/gitlab-runner/key/test-kube-config:/root/.kube/config
我们可以通过 --docker-pull-policy 指定 Executor 执行 Job 时 Dokcer 镜像下载策略。--docker-volumes 指定容器与宿主机(即 Runner 运行的服务器)的文件挂载映射关系。上面挂载的文件主要是用于 Runner 在执行 Job 时,运用的一些 key,包括访问 GitLab、Docker Harbor 和 Kubernetes 集群的 key。当然,如果还有其他文件需要共享给容器,可以通过 --docker-volumes 去指定。
/etc/docker/daemon.json 文件主要为了可以以 http 方式访问 docker horbor 所做的设置: { "insecure-registries" : ["http://docker.vpgame.cn"] }
完成注册后,重启 Runner 即可: gitlab-runner restart
部署完成后,可以在 GitLab 的 Web 管理界面查看到不同 Runner 的信息。
此外,如果一台服务需要注册多个 Runner ,可以修改 /etc/gitlab-runner/config.toml 中的 concurrent 值增加 Runner 的并发数,修改完之后同样需要重启 Runner。
Docker 基础镜像制作
为了满足不同服务对运行环境的多样化需求,我们需要为不同语言的服务提前准备不同的基础镜像用于构建镜像阶段使用。此外,CI/CD 所需要的工具镜像也需要制作,作为 Runner 执行 Job 时生成容器所需要的 Docker 镜像。
所有的镜像都以编写 Dockerfile 的形式通过 GitLab 进行管理,并且我们编写了 .gitlab-ci.yml 文件,使得每次有 Dockerfile 新增或者修改就会触发 Pipeline 进行镜像的构建并上传到 Harbor 上。这种管理方式有以下优点: 按照一定规则自动构建镜像,可以快速便捷地新建和更新镜像 根据规则可以找到镜像对应的 Dockerfile,明确镜像的具体组成 团队成员可以通过提交 Merge Request 自由地构建自己需要的镜像
镜像分类
运行时基础镜像:提供各个语言运行时必须的工具和相应的 package。 CI 镜像:基于运行时基础镜像,添加单元测试、lint、静态分析等功能,用在 CI/CD 流程中的 test 环节。 打包上线镜像:用在 CI/CD 流程中的 build 和 deploy 环节。
Dockerfile 目录结构
每个文件夹都有 Dockerfile 来描述镜像的基本情况,其中包含了 Java、PHP、Node 和 Go 等不同语言的运行时基础镜像和 CI 镜像,还有 docker-kubectl 这类工具镜像的 Dockerfile。
以 PHP 镜像为例: php/ ├── 1.0 │ ├── Dockerfile │ ├── ci-1.0 │ │ └── Dockerfile │ ├── php.ini │ ├── read-zk-config │ ├── start_service.sh │ └── www.conf └── nginx ├── Dockerfile ├── api.vpgame.com.conf └── nginx.conf
该目录下有一个名为 1.0 的文件夹,里面有一个 Dockerfile 用来构建 php fpm 运行时基础进行镜像。主要是在 php:7.1.16-fpm-alpine3.4 加了我们自己定制化的文件,并指定工作目录和容器初始命令。 FROM php:7.1.16-fpm-alpine3.4 RUN sed -i 's/dl-cdn.alpinelinux.org/mirrors.aliyun.com/g' /etc/apk/repositories\ && apk upgrade --update && apk add --no-cache --virtual build-dependencies $PHPIZE_DEPS \ tzdata postgresql-dev libxml2-dev libmcrypt libmcrypt-dev libmemcached-dev cyrus-sasl-dev autoconf \ && apk add --no-cache freetype libpng libjpeg-turbo freetype-dev libpng-dev libjpeg-turbo-dev libmemcached-dev \ && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ && echo "Asia/Shanghai" > /etc/timezone \ && docker-php-ext-configure gd \ --with-gd \ --with-freetype-dir=/usr/include/ \ --with-png-dir=/usr/include/ \ --with-jpeg-dir=/usr/include/ \ && docker-php-ext-install gd pdo pdo_mysql bcmath opcache \ && pecl install memcached apcu redis \ && docker-php-ext-enable memcached apcu redis \ && apk del build-dependencies \ && apk del tzdata \ && rm -rf /var/cache/apk/* \ && rm -rf /tmp/* \ && rm -rf /working/* \ && rm -rf /usr/local/etc/php-fpm.d/* COPY start_service.sh /usr/local/bin/start_service.sh COPY read-zk-config /usr/local/bin/read-zk-config COPY php.ini /usr/local/etc/php/php.ini COPY www.conf /usr/local/etc/php-fpm.d/www.conf WORKDIR /work CMD ["start_service.sh"]
在 1.0/ci-1.0 还有一个 Dockerfile,是用来构建 PHP 在进行单元测试和 lint 操作时所使用的 CI 镜像。可以看到它基于上面的基础运行时镜像增加其他工具来进行构建的。 FROM docker.vpgame.cn/infra/php-1.0 ENV PATH="/root/.composer/vendor/bin:${PATH}" ENV COMPOSER_ALLOW_SUPERUSER=1 RUN mkdir -p /etc/ssh && echo "StrictHostKeyChecking no" >> /etc/ssh/ssh_config RUN apk --update add --no-cache make libc-dev autoconf gcc openssh-client git bash &&\ echo "apc.enable_cli=1" >> /usr/local/etc/php/conf.d/docker-php-ext-apcu.ini RUN pecl install xdebug && docker-php-ext-enable xdebug &&\ echo -e "\nzend_extension=xdebug.so" >> /usr/local/etc/php/php.ini RUN wget https://vp-infra.oss-cn-beijing.aliyuncs.com/gitlab-ci/software/download/1.6.5/composer.phar -O /bin/composer && \ chmod +x /bin/composer && \ composer config -g -q repo.packagist composer https://packagist.laravel-china.org RUN composer global require -q phpunit/phpunit:~5.0 squizlabs/php_codesniffer:~3.0 WORKDIR / CMD ["/bin/bash"]
另外 Nginx 目录下同样有 Dockerfile,来定制化我们 PHP 项目所需要的 Nginx 镜像。
在 GitLab 里第一次增加新的 Dockerfile 或者更改 Dockerfile 时,会触动 Pipeline 自动进行镜像的构建并上传的我们私有的 Docker Harbor 上。
镜像自动构建基本原理
由于各个镜像通过 Dockerfile 进行管理, Master 分支有新的合并,可以通过 git diff 命令找出合并前后新增或更新的 Dockerfile,然后根据这些 Dockerfile 依据一定的命名规则构建镜像,并上传到 Docker Harbor 上。 for FILE in `bash ./find_diff_files|grep Dockerfile|sort`; do DIR=`dirname "$FILE"`; IMAGE_NAME=`echo $DIR | sed -e 's/\//-/g'`; echo $CI_REGISTRY/$HARBOR_DIR/$IMAGE_NAME; docker build -t $CI_REGISTRY/$HARBOR_DIR/$IMAGE_NAME -f $FILE $DIR; docker push $CI_REGISTRY/$HARBOR_DIR/$IMAGE_NAME; done
上面命令中 finddifffiles 基于 git diff 命令找出合并前后有差异的文件。
加速 tips Alpine Linux Package Management(APK)镜像地址: http://mirrors.aliyun.com; 一些海外软件下载会比较慢,可以先下载下来上传至阿里云 OSS 后下载。Dockerfile 使用阿里云 OSS 作为下载源,减少构建镜像时间。
基于 .gitlab-ci.yml 的 CI/CD 流程
在完成 GitLab Runner 以及 Docker 基础镜像的制作之后,我们便可以进行 CI/CD 流程来完成代码更新之后的单元测试、lint、编译、镜像打包以及部署等工作。通过 GitLab CI 进行 CI/CD 的操作只需要在代码仓库里编辑和维护一个 .gitlab-ci.yml 文件,每当代码有更新,GitLab CI 会读取 .gitlab-ci.yml 里的内容,生成一条 Pipeline 进行 CI/CD 的操作。
.gitlab-ci.yml 的语法比较简单,基于 yaml 语法进行 Job 的描述。我们把 CI/CD 流程中所需要完成的任务拆分成文件里的 Job,只要对每个 Job 完成清晰的定义,便可形成一套合适高效并具有普适性的 CI/CD 流程。
定义 stages
stages 是一个非常重要的概念, 在 .gitlab-ci.yml 中进行全局定义, 在定义 Job 时指定其中的值来表明 Job 所处的 stage。而在 stages 里元素的顺序定义了 Job 的执行顺序:所有在相同 stage 的 Job 会并行执行,只有当前 stage 的所有成功完成后,后面 stage 的 Job 才会去执行。 例如,定义如下 stages: stages: - build - test - deploy 首先,所有 build 里的 Job 会并行执行; 当 build 里所有 Job 执行成功, test 里所有 Job 会并行执行; 如果 test 里所有 Job 执行成功, deploy 里所有 Job 会并行执行; 如果 deploy 里所有 Job 执行成功, 当前 Pipeline 会被标记为 passed; 当某个 stage 的 Job 执行失败, Pipeline 会标记为为 failed,其后续stage 的 Job 都不会被执行。
Job 的描述
Job 是 .gitlab-ci.yml 文件中最重要的组成部分,所有的 CI/CD 流程中所执行的任务均可以需要通过定义 Job 来实现。具体来说,我们可以通过关键字来对每一个 Job 进行描述。由于 Job 中的关键字众多,并且用法比较丰富,这边针对我们自己实战中的一个 Job 来进行说明。 unittest: stage: test image: docker.vpgame.cn/infra/php-1.0-ci-1.1 services: - name: docker.vpgame.cn/infra/mysql-5.6-multi alias: mysql - name: redis:4.0 alias: redis_default script: - mv .env.tp .env - composer install --no-dev - phpunit -v --coverage-text --colors=never --coverage-html=coverage --stderr artifacts: when: on_success paths: - vendor/ - coverage/ expire_in: 1 hour coverage: '/^\s*Lines:\s*\d+.\d+\%/' only: - branches - tags tags: - base-runner
上面的 Job 主要完成了单元测试的功能,在起始行定义了 Job 的名称。下面我们来解释 Job 每个关键字的具体含义。 stage,定义了 Job 所处的 stage,值为定义在全局中 stages 里的值;
image,指定了 Runner 运行所需要的镜像,这个镜像是我们之前制作的基本镜像。通过该镜像运行的 Docker 即是 Job 运行的环境; services,Runner 所运行的 Docker 所需要的连接依赖,在这边分别定义了 MySQL 和 Redis,在 Job 运行时会去连接这两个镜像生成的 Docker; script,Job 运行的具体的命令 ,通过 Shell 来描述。此 Job 中的 script 主要完成了代码的编译和单元测试; artifacts,主要是将此 Job 中完成的结果打包保存下来,可以通过 when 指定何时保存,path 定义了保存的文件路径, expire_in 指定了结果保存的有效期。与之对应的是 dependencies 参数,如果其他 Job 需要此 Job 的 artifacts ,只需要在 Job 按照如下定义即可; dependencies: - unittest only 关键字指定了 Job 触发的时机,该例子中说明只有分支合并或者打 tag 的情况下,该 Job 才会被触发; 与 only 相对还有 except 关键字来排除触发 Job 某些情况。此外 only 还支持正则表达式,比如; job: only: - /^issue-.*$/ except: - branches
这个例子中,只有以 issue- 开头 tag 标记才会触发 Job。如果不加 except 参数,以 issue- 开头的分支或者 tag 标记会触发 Job。 tags,tags关键字主要是用来指定运行的 Runner 类型。在我们实际运用中,部署测试环境和生产环境所采用的 Runner 是不一样的,它们是通过不同的 tag 去标识区分。
所以,我们在 Job 定义中,通过 tags 指定 Runner 的值,来指定所需要的 Runner。
我们可以看到 Job 的定义非常的清晰和灵活,关于 Job 的使用远不止这些功能,更详细的用法可以参考 GitLab CI/CD 官方文档。
CI/CD 流程编排
在清楚了如何描述一个 Job 之后,我们通过定义一个个 Job,并进行编排形成 Pipelines。因为我们可以描述设定 Job 的触发条件,所以通过不同的条件可以触发形成不一样的 Pipelines。
在 PHP 项目 Kubernetes 上线过程中,我们规定了合并 Master 分支会进行 lint、unitest、build-test 以及 deploy-test 四个 Job。
在测试环境验证通过之后,我们再通过打 tag 进行正式环境的上线。此处的 Pipelines 包含了 unittest、build-pro 和 deploy-pro 三个 Job。
在 .gitlab-ci.yml 文件中,test 阶段主要完成 lint 和 unitest 两个 Job,不同的语言在进行 Job 定义时会各有不同。我们重点来看一下 build 和 deploy 两个 stage 的 Job 描述。build stage: # Build stage .build-op: stage: build dependencies: - unittest image: docker.vpgame.cn/infra/docker-kubectl-1.0 services: - name: docker:dind entrypoint: ["dockerd-entrypoint.sh"] script: - echo "Image name:" ${DOCKER_IMAGE_NAME} - docker build -t ${DOCKER_IMAGE_NAME} . - docker push ${DOCKER_IMAGE_NAME} tags: - base-runner build-test: extends: .build-op variables: DOCKER_IMAGE_NAME: ${DOCKER_REGISTRY_PREFIX}/${CI_PROJECT_PATH}:${CI_COMMIT_REF_SLUG}-${CI_COMMIT_SHORT_SHA} only: - /^testing/ - master build-prod: extends: .build-op variables: DOCKER_IMAGE_NAME: ${DOCKER_REGISTRY_PREFIX}/${CI_PROJECT_PATH}:${CI_COMMIT_TAG} only: - tags
在这边,由于 build 阶段中测试环境和生产环境进行镜像打包时基本操作时是相同的,都是根据 Dockerfile 进行镜像的 build 和镜像仓库的上传。这里用到了一个 extend 参数,可以减少重复的 Job 描述,使得描述更加地简洁清晰。
我们先定义一个 .build-op 的 Job,然后 build-test 和 build-prod 都通过 extend 进行继承,可以通过定义关键字来新增或覆盖 .build-op 中的配置。比如 build-prod 重新定义了变量( variables)DOCKER_IMAGE_NAME以及触发条件(only)更改为了打 tag 。
这边我们还需要注意到的是在定义 DOCKER_IMAGE_NAME 时,我们引用了 GitLab CI 自身的一些变量,比如 CI_COMMIT_TAG 表示项目的 commit 的 tag 名称。我们在定义 Job 变量时,可能会引用到一些 GitLab CI 自身变量,关于这些变量的说明可以参考 GitLab CI/CD Variables 中文文档。
deploy stage: # Deploy stage .deploy-op: stage: deploy image: docker.vpgame.cn/infra/docker-kubectl-1.0 script: - echo "Image name:" ${DOCKER_IMAGE_NAME} - echo ${APP_NAME} - sed -i "s~__NAMESPACE__~${NAMESPACE}~g" deployment.yml service.yml - sed -i "s~__APP_NAME__~${APP_NAME}~g" deployment.yml service.yml - sed -i "s~__PROJECT_NAME__~${CI_PROJECT_NAME}~g" deployment.yml - sed -i "s~__PROJECT_NAMESPACE__~${CI_PROJECT_NAMESPACE}~g" deployment.yml - sed -i "s~__GROUP_NAME__~${GROUP_NAME}~g" deployment.yml - sed -i "s~__VERSION__~${VERSION}~g" deployment.yml - sed -i "s~__REPLICAS__~${REPLICAS}~g" deployment.yml - kubectl apply -f deployment.yml - kubectl apply -f service.yml - kubectl rollout status -f deployment.yml - kubectl get all,ing -l app=${APP_NAME} -n $NAMESPACE # Deploy test environment deploy-test: variables: REPLICAS: 2 VERSION: ${CI_COMMIT_REF_SLUG}-${CI_COMMIT_SHORT_SHA} extends: .deploy-op environment: name: test url: http://example.com only: - /^testing/ - master tags: - base-runner # Deploy prod environment deploy-prod: variables: REPLICAS: 3 VERSION: ${CI_COMMIT_TAG} extends: .deploy-op environment: name: prod url: http://example.com only: - tags tags: - pro-deploy
与 build 阶段类似,先先定义一个 .deploy-op 的 Job,然后 deploy-test 和 deploy-prod 都通过 extend 进行继承。
.deploy-op 主要完成了对 Kubernetes Deployment 和 Service 模板文件的一些变量的替换,以及根据生成的 Deployment 和 Service 文件进行 Kubernetes 服务的部署。
deploy-test 和 deploy-prod 两个 Job 定义了不同变量(variables)以及触发条件(only)。除此之外, deploy-prod 通过 tags 关键字来使用不同的 Runner,将部署的目标集群指向给生产环境的 Kubernetes。
这里还有一个关键字 environment 需要特别说明,在定义了 environment 之后,我们可以在 GitLab 中查看每次部署的一些信息。除了查看每次部署的一些信息之外,我们还可以很方便地进行重新部署和回滚。
可以看到,通过对 Job 的关键字进行配置,我们可以灵活地编排出我们所需要的 CI/CD 流程,非常好地满足多样化的场景。
Deployment 与 Service 配置
在 CI/CD 流程中完成 Docker 镜像的打包任务之后需要将服务所对应的镜像部署到 Kubernetes 集群中。Kubernetes 提供了多种可以编排调度的资源对象。首先,我们简单了解一下 Kubernetes 中的一些基本资源。
Kubernetes 基本资源对象概览
Pod
Pod 作为无状态应用的运行实体是其中最常用的一种资源对象,Kubernetes 中资源调度最小的基本单元,它包含一个或多个紧密联系的容器。这些容器共享存储、网络和命名空间,以及如何运行的规范。
在 Kubernetes 中,Pod 是非持久的,会因为节点故障或者网络不通等情况而被销毁和重建。所以我们在 Kubernetes 中一般不会直接创建一个独立的 Pod,而是通过多个 Pod 对外提供服务。
ReplicaSet
ReplicaSet 是 Kubernetes 中的一种副本控制器,控制由其管理的 Pod,使 Pod 副本的数量维持在预设的个数。ReplicaSets 可以独立使用,但是在大多数场景下被 Deployments 作为协调 Pod 创建,删除和更新的机制。
Deployment
Deployment 为 Pod 和 ReplicaSet 提供了一个声明式定义方法。通过在 Deployment 中进行目标状态的描述,Deployment controller 会将 Pod 和 ReplicaSet 的实际状态改变为所设定的目标状态。Deployment 典型的应用场景包括: 定义 Deployment 来创建 Pod 和 ReplicaSet 滚动升级和回滚应用 扩容和缩容 暂停和继续 Deployment
Service
在 Kubernetes 中,Pod 会被随时创建或销毁,每个 Pod 都有自己的 IP,这些 IP 也无法持久存在,所以需要 Service 来提供服务发现和负载均衡能力。
Service 是一个定义了一组 Pod 的策略的抽象,通过 Label Selector 来确定后端访问的 Pod,从而为客户端访问服务提供了一个入口。每个 Service 会对应一个集群内部的 ClusterIP,集群内部可以通过 ClusterIP 访问一个服务。如果需要对集群外部提供服务,可以通过 NodePort 或 LoadBalancer 方式。

deployment.yml 配置
deployment.yml 文件用来定义 Deployment。首先通过一个简单的 deployment.yml 配置文件熟悉 Deployment 的配置格式。
上图中 deployment.yml 分为 8 个部分,分别如下: apiVersion 为当前配置格式的版本; kind 指定了资源类型,这边当然是 Deployment; metadata 是该资源的元数据,其中 name 是必需的数据项,还可以指定 label 给资源加上标签; spec 部分是该 Deployment 的规格说明; spec.replicas 指定了 Pod 的副本数量; spec.template 定义 Pod 的基本信息,通过 spec.template.metadata 和 spec.template.spec 指定; spec.template.metadata 定义 Pod 的元数据。至少需要定义一个 label 用于 Service 识别转发的 Pod, label 是通过 key-value 形式指定的; spec.template.spec 描述 Pod 的规格,此部分定义 Pod 中每一个容器的属性,name 和 image 是必需项。
在实际应用中,还有更多灵活个性化的配置。我们在 Kubernetes 的部署实践中制定了相关的规范,在以上基础结构上进行配置,得到满足我们实际需求的 deployment.yml 配置文件。
在 Kubernetes 的迁移实践中,我们主要在以下方面对 Deployment 的配置进行了规范的约定:
文件模板化
首先我们的 deployment.yml 配置文件是带有变量的模版文件,如下所示: apiVersion: apps/v1beta2 kind: Deployment metadata: labels: app: __APP_NAME__ group: __GROUP_NAME__ name: __APP_NAME__ namespace: __NAMESPACE__
APPNAME 、 GROUPNAME 和 NAMESPACE  这种形式的变量都是在 CI/CD 流程中会被替换成 GitLab 每个 project 所对应的变量,目的是为了多了 project 用相同的 deployment.yml 文件,以便在进行 Kubernetes 迁移时可以快速复制,提高效率。
服务名称 Kubernetes 中运行的 Service 以及 Deployment 名称由 GitLab 中的 groupname 和 projectname 组成,即 {{groupname}}-{{projectname}},例:microservice-common;
此名称记为 app_name,作为每个服务在 Kubernetes 中的唯一标识。这些变量可以通过 GitLab-CI 的内置变量中进行获取,无需对每个 project 进行特殊的配置。 Lables 中用于识别服务的标签与 Deployment 名称保持一致,统一设置为 app:{{app_name}}。
资源分配
节点配置策略,以项目组作为各项目 Pod 运行在哪些 Node 节点的依据,属于同一项目组的项目的 Pod 运行在同一批 Node 节点。具体操作方式为给每个 Node 节点打上形如 group: GROUP_NAME 的标签,在 deployment.yml 文件中做如下设置进行 Pod 的 Node 节点选择: ... spec: ... template: ... spec: ... affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: group operator: In values: - __GROUP_NAME__ ...
资源请求大小,对于一些重要的线上应用,limit 和 request 设置一致,资源不足时 Kubernetes 会优先保证这些 Pod 正常运行。为了提高资源利用率。对一些非核心,并且资源不长期占用的应用,可以适当减少 Pod 的 request,这样 Pod 在调度时可以被分配到资源不是十分充裕的节点,提高使用率。但是当节点的资源不足时,也会优先被驱逐或被 oom kill。
健康检查(Liveness/Readiness)配置
Liveness 主要用于探测容器是否存活,若监控检查失败会对容器进行重启操作。Readiness 则是通过监控检测容器是否正常提供服务来决定是否加入到 Service 的转发列表接收请求流量。Readiness 在升级过程可以发挥重要的作用,防止升级时异常的新版本 Pod 替换旧版本 Pod 导致整个应用将无法对外提供服务的情况。
每个服务必须提供可以正常访问的接口,在 deployment.yml 文件配置好相应的监控检测策略。 ... spec: ... template: ... spec: ... containers: - name: fpm livenessProbe: httpGet: path: /__PROJECT_NAME__ port: 80 initialDelaySeconds: 3 periodSeconds: 5 readinessProbe: httpGet: path: /__PROJECT_NAME__ port: 80 initialDelaySeconds: 3 periodSeconds: 5 ... ...
升级策略配置
升级策略我们选择 RollingUpdate 的方式,即在升级过程中滚动式地逐步新建新版本的 Pod,待新建 Pod 正常启动后逐步 kill 掉老版本的 Pod,最终全部新版本的 Pod 替换为旧版本的 Pod。
我们还可以设置 maxSurge 和 maxUnavailable 的值分别控制升级过程中最多可以比原先设置多出的 Pod 比例以及升级过程中最多有多少比例 Pod 处于无法提供服务的状态。 ... spec: ... strategy: rollingUpdate: maxSurge: 25% maxUnavailable: 25% type: RollingUpdate ...
日志配置
采用 log-tail 对容器日志进行采集,所有服务的日志都上报到阿里云日志服务的一个 log-store中。在 deployment.yml 文件里配置如下: ... spec: ... template: ... spec: ... containers: - name: fpm env: - name: aliyun_logs_vpgame value: stdout - name: aliyun_logs_vpgame_tags value: topic=__APP_NAME__ ... ...
通过设置环境变量的方式来指定上传的 Logstore 和对应的 tag,其中 name 表示 Logstore 的名称。通过 topic 字段区分不同服务的日志。
监控配置
通过在 Deployment 中增加 annotations 的方式,令 Prometheus 可以获取每个 Pod 的业务监控数据。配置示例如下: ... spec: ... template: metadata: annotations: prometheus.io/scrape: "true" prometheus.io/port: "80" prometheus.io/path: /{{ project_name }}/metrics ...
其中 prometheus.io/scrape: "true" 表示可以被 Prometheus 获取,prometheus.io/port 表示监控数据的端口,prometheus.io/path 表示获取监控数据的路径。
service.yml 配置
service.yml 文件主要对 Service 进行了描述。 apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/alicloud-loadbalancer-address-type: intranet labels: app: __APP_NAME__ name: __APP_NAME__ namespace: __NAMESPACE__ spec: ports: - port: 80 protocol: TCP targetPort: 80 selector: app: __APP_NAME__ type: LoadBalancer
对 Service 的定义相比于 Deoloyment 要简单的多,通过定义 spec.ports 的相关参数可以指定 Service 的对外暴露的端口已经转发到后端 Pod 的端口。spec.selector 则是指定了需要转发的 Pod 的 label。
另外,我们这边是通过负载均衡器类型对外提供服务,这是通过定义 spec.type 为 LoadBalancer 实现的。通过增加 metadata.annotations 为 service.beta.kubernetes.io/alicloud-loadbalancer-address-type: intranet 可以在对该 Service 进行创建的同时创建一个阿里云内网 SLB 作为对该 Service 请求流量的入口。
如上图所示,EXTERNAL-IP 即为 SLB 的 IP。
总结
在以上工作的基础上,我们对各个服务划分为几类(目前基本上按照语言进行划分),然后为每一类中的服务通过 .gitlab-ci.yml 制定一套统一的 CI/CD 流程,与此相同的,同一类中的服务共用一个 Deployment 和 Service 模板。这样我们在进行服务迁移到 Kubernetes 环境时可以实现快速高效地迁移。
当然,这只是迁移实践路上迈出的第一步,在 Kubernetes 中的服务的稳定性、性能、自动伸缩等方面还需要更深入地探索和研究。 “ 阿里巴巴云原生微信公众号(ID:Alicloudnative)关注微服务、Serverless、容器、Service Mesh等技术领域、聚焦云原生流行技术趋势、云原生大规模的落地实践,做最懂云原生开发者的技术公众号。”
云计算
2019-10-21 17:54:00