阿里云栖开发者沙龙PHP技术专场聊聊服务稳定性保障这些事

摘要:本文主要带大家了解服务稳定性的重要性和相关策略。策略大概分两部分,第一方面从架构层面介绍保障服务稳定性的常见策略(限流,降级,隔离,超时,重试和集群)。第二个方面是从流程方面(code review, 压测,灰度和监控)讲解怎么去保证稳定性。演讲嘉宾简介: 信海龙(花名沧龙),十余年的互联网开发经验,2013年加入阿里巴巴,深耕于电商、社区相关应用开发与架构。同时也是多个开源项目的开发者和维护者。代表开源作品,tclip,基于人脸识别的图片裁剪扩展。 本次直播视频精彩回顾,戳这里!直播回顾:https://yq.aliyun.com/live/965PPT分享:https://yq.aliyun.com/download/3530以下内容根据演讲嘉宾视频和PPT分享整理而成。 本次的分享主要围绕以下三个方面: 稳定性的重要性保障策略架构篇保障策略流程篇稳定性的重要性对很多企业来说服务稳定性非常重要,首先稳定性问题会对企业带来直接的经济损失。举例来说,亚马逊的“Prime Day”当天出现的一个故障,给亚马逊带来了高达9900万美元的损失。这一个故障损失就可能是其它小公司市值的几倍。所以服务稳定性对公司影响是特别大的。而对于个人来说,服务不稳定性会影响员工的绩效,甚至影响个人前程。 保障策略架构篇从架构层面保障稳定性,常见的策略包括限流,降级,隔离,超时,重试和集群等。 1.限流限流目的 限流的目的主要有两点,第一点是防止系统高负荷运行,第二点是有效利用服务器资源。为什么要做限流?假如不封锁请求,可能会导致服务器报警,如果平时服务器只能处理100个请求,突然多出两个请求服务器或许勉强能够处理,但突然多了500个请求的话,后面的400个请求只处在积压状态,等服务器处理到第500个请求的时候,用户等待时间就会过长,而且最后积压部分的请求可能根本就是无效的处理,因为用户早已流失。 限流算法 常见限流的算法包括漏桶算法和令牌桶算法。漏桶算法如下图,图中的例子有个小桶,桶下面有个孔,每流一滴水就可以认为是一个请求进去。滴水的速率是一样的,孔的高度也是固定的。漏桶算法能保证每个请求的负载时长,即确定每秒能处理的请求数量。 漏痛算法实现如下图,可以设定桶的高度是5个,每秒漏两个。执行效果中前面5次结果都是true,之后中间一次结果是false,这说明桶已经装满,之后又漏了两滴水,因为false的时候sleep了一秒,所以下面又有两个true出来。 令牌桶算法 如下图,令牌桶算法也是有一个桶,但是桶不漏,桶里面放了一些令牌,每来一个请求就在桶里拿一个令牌,如果没有令牌它就可以等待,令牌满了就不再往里面加令牌。这样方法基本上也可以达到一个限流的目的。令牌桶算法和漏桶算法的一个显著区别是漏桶算法在后端取请求量时,基本上漏的速率是一样的,但是令牌桶算法中后端部分可以有突发请求,如果桶满了,可以将桶里所有令牌都拿走。 下图是令牌桶算法lua代码实现部分,当然读者还可以使用Nginx,Java脚本或者php脚本来实现。 2.降级社区降级案例 一般情况下,系统上线之后总会遇到一些不稳定情况,比如redis挂掉,甚至后端数据库My SQL挂掉。当出现不稳定情况之后,系统如何保证继续提供这些服务。以社区案例为例,即便是My SQL挂掉,也要能够保证社区为用户提供基本的可读服务。其中一个策略是将一些热点数据,即用户经常浏览的信息或者最新的信息缓存起来,当后端服务不可用的时候,把这些数据展现给用户。大概流程如下图,数据存储部分后端会有一个脚本去分析Nginx里面的日志,然后去请求Vanish,Vanish再去请求后端,这样的话Vanish会有一个有效期,能够保证Vanish存进去的数据都是用户经常访问的一些数据。第二步,如何保证后端数据库挂掉的数据时候能迁过去?下图可以看到,Nginx中使用lua脚本进行实现,它会检测后端服务返回的一些状态,使用计数器计算失败次数,如果频繁的达到一定程度的失败次数,就切换到从Vanish获取数据,最后推送给用户。这样能保证即便是后端的数据库挂掉,甚至即便所有的php进程都挂掉的时候,社区也能给用户提供一些基本的服务。 降级目的 降级的目的比较简单,第一个是保障服务器基本可用,第二个是保障服务的核心服务可用。降级是怎么一个思路呢?一般降级的每个策略都是针对一个场景,预想特定场景下需要要解决什么问题;然后再梳理在这个场景下需要保留哪些核心基本服务;最后才选定技术方案,系统化的进行实现。简单讲就是先确定需要达到什么目的,再去了解是什么样的情况,最后制定策略或者计划。比如,系统会调用第三方服务,而第三方服务有可能挂掉,这是一种典型的场景。再比如,系统本身调用推荐服务,但是推荐服务也会挂掉,这种场景下不能够因为没有推荐数据就不显示数据,还是需要展示一些数据,这是一种基本的核心服务。每年的双11或者一些大型活动中基本都会存在降级。降级不仅仅是存在于资源故障场景下,资源不够用时也可能会需要降级,因为资源不够用需要关注重点。如大促活动中,需要先保证交易服务正常运行,其它消耗资源的服务(如对账)可以后续再去处理。 3.超时超时案例 社区对外提供接口服务,对方的反馈是接口服务较慢。接口部分流程是查一段数据,然后将数据反映过去,其问题点在于系统中超时时间设置过长。比如调用Memcache,但是Memcache已经挂掉,由于超时设置过长,数据需要等到超时时间结束以后再返回,导致接口一直在等待。那如何设置超时时间才合理?要注意超时时间并不是固定的值,而是需要针对整个业务,根据特定场景设置超时时间值。 如何设置超时时间 大体的思路如下图。第一步,识别业务需要的服务响应时间。比如,需要100毫秒去响应数据,之后统计业务里面可能需要调多少服务。第二步,统计服务日常的响应时间。第三步,分清主次,即分出哪些是核心服务。因为核心服务一旦失败,整个链路便不可用,所以可以对核心服务的时间设置的宽松一些。如果一些服务调不通,但又不影响整个链路,可以对它的时间设置的相对严格。 设置完超时之后需要验证,借助模拟手段封端口(如下图),模拟故障,然后检查数据返回时间是否在指定的时间内。 4.隔离隔离案例 下2013年左右,手机客户端开始逐渐升级起来,很多项目既有PC端也有客户端,所以同一个服务即要为PC端又要为客户端提供API接口。一旦遇到大型活动或者需要手机推送,服务会遇到不稳定情况,服务的不稳定会导致PC端也受影响,所以需要将服务进行物理隔离,从原先耦合到一块的服务器分到不同的机器组。隔离目的非常简单,要限制住不稳定因素导致的风险,停止传播。 隔离形式 隔离的常见形式包括几种。第一是秒杀场景,秒杀场景一个高并发的场景,可能带来的问题也比较多,在高并发场景下秒杀的时候,需要和一些正常的业务区分开来,不建议一台机器既提供秒杀也提供进程服务。另外,秒杀的时候会产生热点数据,如售卖数据。数据库更新比较频繁,从数据库层面也可以进行隔离,将热点部分和正常服务部分从资源上隔离。第二个场景是慢SQL隔离,一个资源隔离。一条慢SQL会导致整个服务不稳定。每请求一次线程,慢SQL会一直耗着当前线程,所以资源占用非常大。第三个场景是机房隔离。一般大公司都会做多机房部署,其目的就是确保稳定性。确保稳定性时不要做跨机房调用,否则耦合度会比较高,假如A调B,B挂掉,A服务也会受影响。一般确保稳定性都是做本机房的调用。而且本机房的调用性能也比较快。最后一个场景是进程隔离,因为进程比线程更加稳定。 5.集群对小公司而言,一台机器就提供一个服务,如果机器挂掉服务恢复就会成为一个问题。一般解决方法是做一个集群,从原来的一台机器提供服务变为可以用多台机器提供服务。集群的目的是为了解决单点的问题。集群的形式主要有主备,即同时只有一台机器提供整个服务,可以有一台或者多台提供备份,备份不仅要包含代码层面,整个服务运行所依赖的资源都要有备份。另外一个形式是主从。主是提供一个完整的服务,从是提供部分的服务。还有一种是多主,多主指的是每一台机器的决策是对等的,都会对外提供一些服务。随着集群形式的不同,对代码编写的并发性上有一定要求。主备只需要考虑单机的并发控制,主从是考虑同时提供服务的部分。比如加锁,主备上只要加一个本地的技能锁就可以,主从或者多主则需要加分布式锁。 保证策略流程篇保证稳定性策略的流程方面上分为下图中四个点,code review, 压测,灰度和监控。 1.Code reviewcode review目的是在项目上线前及时发现一些问题。经验比较丰富的人可以将经验进行分享。code review基本经过三个阶段。第一个阶段是头脑风暴式,一群开发人员围着代码做code review,虽然时间成本较高,效果也不太理想,但是这种方式也有好处,在前期可以将大家的意见进行整理,制定code review的规范。第二种code review形式是演讲式,专家事先把代码做一下review,整理一些点,然后进行分享。演讲式可以按照轮岗制,相对头脑风暴式大大节约了时间。目前常见的code review 形式是结对式,由一个或者两个专家结对,相互review,时间上比较灵活,也不需要占据会议室资源。 2.压测压测目的 压测的目的,第一是保证系统稳定性。在高并发的时候,检测系统是否稳定,因为一些问题在流量比较低的时候发现不了,只有在高并发的时候才能发现这个问题。第二是检测性能的抗压能力,检查系统能承受多大的QPS。 压测关注点 首先,压测机器和被压测服务在同一网段,尽量避免因为网络原因导致压测的结果不准确。第二点是关注服务器的负载,注意不要把服务器压到100%,服务器快要崩的时候,得到的值意义不大。应该是服务器负载达到60%~70%的时候,看QPS是多少。另外,压测并发数据是逐步递增的过程,到一个点的时候,并发数据越多代表QPS越低。最后,根据测试环境的压测结果估算线上的承载能力。估算的公式是线上QPS = 单机QPS 机器数 0.7。后面会乘以一个系数(0.7)是因为线上put上去的时候总会存在一些损耗。 ...

April 29, 2019 · 1 min · jiezi

如何防范服务器入侵

Vitaliy Kolesov 原作,授权 LeanCloud 翻译。 加固服务器并不难,但有很多例行操作需要进行时,有可能会遗忘。以我为例,刚买的服务器就在两周内被人入侵了。有天早上我收到几封来自第三方的邮件,说我服务器上有东西在尝试入侵他们的服务器。所以,我需要快速解决这个问题。 如何查找漏洞我碰到的情况比较简单,我执行了以下命令: cat /var/log/auth.log | grep Accepted该命令返回了我的服务器上的成功认证记录,其中有一个 IP 不是我的。所以,是 SSH 服务被入侵了。 别忘了还有一个命令 last,这个命令返回最近成功登录的用户。 如何加固服务器购买服务器后需要立刻进行的操作: 安装 ufw,简单易用的防火墙软件;关闭除 SSH、HTTP(s) 外的所有端口;安装配置 fail2ban 工具。这个工具基于 /var/log/auth.log 识别恶意行为并封禁 IP;修改 sshd 配置,只使用密钥认证。具体怎么做?如果发生了入侵,你需要知道如何调查和清扫。最好的方式是重新创建 VPS。我就是这么做的。我在 hetzner 买了服务器,它的控制台提供了重新创建(移除旧 VPS,新建一个)VPS 并保留原 IP 的功能。 所以我重新创建了一个 VPS。之后我在本地计算机上使用 ssh-keygen 工具(标准 OpenSSH 包的一部分)生成了 SSH 密钥:(下面的命令同时适用于 Linux 和 macOS) ssh-keygen该命令在 ~/.ssh 目录中创建了一对密钥。之后运行以下命令: ssh-copy-id you_user@your_server_id该命令会将新创建的公钥上传到服务器。接下来,登录服务器并修改 sshd 配置: nano /etc/ssh/sshd_config修改配置文件中的 PasswordAuthentication 配置: PasswordAuthentication no这一配置禁用了使用密码登录(只能使用密钥登录)。 安装配置 ufw 和 fail2ban服务器上我用的系统是 Ubuntu,所以通过以下命令可以安装这两个工具: ...

April 29, 2019 · 1 min · jiezi

一份还热乎的蚂蚁金服面经已拿Offer附答案

本文来自我的知识星球的球友投稿,他在最近的校招中拿到了蚂蚁金服的实习生Offer,整体思路和面试题目由作者——泽林提供,部分答案由Hollis整理自知识星球《Hollis和他的朋友们》中「直面Java」板块。 经历了漫长一个月的等待,终于在前几天通过面试官获悉已被蚂蚁金服录取,这期间的焦虑、痛苦自不必说,知道被录取的那一刻,一整年的阴霾都一扫而空了。 笔者面的是阿里的Java研发工程师岗,面试流程是3轮技术面+1轮hr面。 意外的一面一面的时候大概是3月12号,面完等了差不多半个月才突然接到二面面试官的电话。一面可能是简历面,所以问题比较简单。 ArrayList和LinkedList区别 ArrayList 是一个可改变大小的数组.当更多的元素加入到ArrayList中时,其大小将会动态地增长.内部的元素可以直接通过get与set方法进行访问,因为ArrayList本质上就是一个数组. LinkedList 是一个双链表,在添加和删除元素时具有比ArrayList更好的性能.但在get与set方面弱于ArrayList. 当然,这些对比都是指数据量很大或者操作很频繁的情况下的对比,如果数据和运算量很小,那么对比将失去意义. 什么情况会造成内存泄漏 在Java中,内存泄漏就是存在一些被分配的对象,这些对象有下面两个特点: 首先,这些对象是可达的,即在有向图中,存在通路可以与其相连; 其次,这些对象是无用的,即程序以后不会再使用这些对象。 如果对象满足这两个条件,这些对象就可以判定为Java中的内存泄漏,这些对象不会被GC所回收,然而它却占用内存。 什么是线程死锁,如何解决 产生死锁的条件有四个: 1.互斥条件:所谓互斥就是进程在某一时间内独占资源。 2.请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。 3.不剥夺条件:进程已获得资源,在末使用完之前,不能强行剥夺。 4.循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。 线程死锁是因为多线程访问共享资源,由于访问的顺序不当所造成的,通常是一个线程锁定了一个资源A,而又想去锁定资源B;在另一个线程中,锁定了资源B,而又想去锁定资源A以完成自身的操作,两个线程都想得到对方的资源,而不愿释放自己的资源,造成两个线程都在等待,而无法执行的情况。 要解决死锁,可以从死锁的四个条件出发,只要破坏了一个必要条件,那么我们的死锁就解决了。在java中使用多线程的时候一定要考虑是否有死锁的问题哦。 红黑树是什么?怎么实现?时间复杂度 红黑树(Red-Black Tree,简称R-B Tree),它一种特殊的二叉查找树。 红黑树是特殊的二叉查找树,意味着它满足二叉查找树的特征:任意一个节点所包含的键值,大于等于左孩子的键值,小于等于右孩子的键值。 除了具备该特性之外,红黑树还包括许多额外的信息。 红黑树的每个节点上都有存储位表示节点的颜色,颜色是红(Red)或黑(Black)。 红黑树的特性: (1) 每个节点或者是黑色,或者是红色。 (2) 根节点是黑色。 (3) 每个叶子节点是黑色。 (4) 如果一个节点是红色的,则它的子节点必须是黑色的。 (5) 从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。 关于它的特性,需要注意的是: 第一,特性(3)中的叶子节点,是只为空(NIL或null)的节点。 第二,特性(5),确保没有一条路径会比其他路径长出俩倍。因而,红黑树是相对是接近平衡的二叉树。 具体实现代码这里不贴了,要实现起来,需要包含的基本操作是添加、删除和旋转。在对红黑树进行添加或删除后,会用到旋转方法。旋转的目的是让树保持红黑树的特性。旋转包括两种:左旋 和 右旋。 红黑树的应用比较广泛,主要是用它来存储有序的数据,它的查找、插入和删除操作的时间复杂度是O(lgn)。 TCP三次握手 三次握手(three times handshake;three-way handshake)所谓的“三次握手”即对每次发送的数据量是怎样跟踪进行协商使数据段的发送和接收同步,根据所接收到的数据量而确定的数据确认数及数据发送、接收完毕后何时撤消联系,并建立虚连接。 为了提供可靠的传送,TCP在发送新的数据之前,以特定的顺序将数据包的序号,并需要这些包传送给目标机之后的确认消息。TCP总是用来发送大批量的数据。当应用程序在收到数据后要做出确认时也要用到TCP。 第一次握手:建立连接时,客户端发送syn包(syn=j)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。 第二次握手:服务器收到syn包,必须确认客户的SYN(ack=j+1),同时自己也发送一个SYN包(syn=k),即SYN+ACK包,此时服务器进入SYN_RECV状态; 第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=k+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。 突如其来的二面一面的时候大概是3月12号,面完等了差不多半个月才突然接到二面面试官的电话。 介绍项目 Storm怎么保证一致性 Storm是一个分布式的流处理系统,利用anchor和ack机制保证所有tuple都被成功处理。如果tuple出错,则可以被重传,但是如何保证出错的tuple只被处理一次呢?Storm提供了一套事务性组件Transaction Topology,用来解决这个问题。 Transactional Topology目前已经不再维护,由Trident来实现事务性topology,但是原理相同。 参考:https://cloud.tencent.com/info/5721fb4532f6a72ed2e563f9449fd025.html 说一下hashmap以及它是否线程安全 ...

April 26, 2019 · 2 min · jiezi

电子设备散热技术详解

随着5G、人工智能、物联网、智慧城市的蓬勃发展以及大数据、云计算技术的深入发展和应用,作为数据计算、存储或连接交换的基础支撑与驱动技术进步的基石,数据中心是中国推进新一代信息技术产业发展的关键资源,数据中心的发展将持续强劲增长。CPU频率更高!计算速度更快!图像处理更强! 服务器能力的递增,随之而来的就是整体功耗的上涨;而机房布局面积限定与机架尺寸限定使得服务器的体积不能有太大的变化,要在有限的空间里装进无限可能,服务器只能在“功耗胖子”的路上越走越远······ 功耗的增加必然会导致服务器的散热需求的增加,那么这个越来越胖的家伙怎么才能进行有效地散热呢? 相信大家都会有这样的生活经验,在炎炎夏日中我们如何才能舒适惬意?最初的办法就是找个树荫,晒不到就凉快了!如果还是热?那就扇扇子!再不行?那就开空调!依然不行?那就直接去冲个凉吧! 电子设备的散热设计也是相似的历程,最初的自然散热设备只要找个温度不高的使用环境就能很好的工作了,散热设计?ME随便摆一下就OK了! 自然扇热设备 当慢慢自然散热搞不定的时候,风冷散热模式上线,系统里放几颗风扇、整体风道划分,散热问题就能解决,轻松加愉快! 风冷散热设备 再后来电子设备尤其是服务器的需求量增大,集群部署能更好的运营管理,数据中心机房要维持良好的设备运行环境,机房空调就必不可少,无论集中送风还是冷水列间,机房环境温度低了,服务器也就安生了! 传统数据中心制冷流程图 当前电子设备的功耗密度已经是最初的几倍甚至十几倍,设备不断更新迭代,但机房没法跟上更新的节奏,部署密度受限、机房供风不足、整体PUE过高等这些问题亟待解决;对服务器端,功耗明显上升的都是个别部件,整个系统热岛现象明显,受限于结构空间,只能不断的加大系统风量,就要求风扇的转速越来越高,伴随的就是震动强、噪声高、功耗大;面对这些问题,风冷散热模式捉襟见肘,用冷水冲个凉吧! 数据中心液冷机房 工质在散热设计中扮演搬运工的角色,搬运工人数可理解为密度,单人每次负重量理解为比热容C,单位时间内搬运的次数就是换热系数h;空气的比热容约为1.0KJ/(KgK)、换热系数20~100 W/(m2K)、密度约为1.3g/L,而水的比热容约为4.0KJ/(Kgk)、换热系数200~1000 W/(m2K)、密度约为1Kg/L;简单换算工作效率可以得到,风冷相当于一个人搬、一次搬运一个箱子、单位时间搬运20次,而水冷就相当于770人搬、每人一次搬运4个箱子,每人单位时间搬运200次,理论上是风冷的3万倍!实际运行中因各类限制,不会达到这么大的差距,但液冷的散热效率也是风冷的几千倍。 液冷的方式有多种,主要可以归纳为浸没式、喷淋式、冷板式三个大类; 浸没式:将整个服务器直接浸泡在工作介质中,根据工质工作状态可细分为非相变和相变两类; 喷淋式:工质通过服务器上盖板,直接滴漏或喷射在服务器的热源上,再通过服务器底壳收集运出,通常工质不发生相变;喷淋式液冷服务器 冷板式:工质通常选用纯水,利用管路输送进服务器,再通过冷板与系统热源发生换热后导出服务器。 冷板式液冷服务器 综合考虑机房运维、系统性能、上线风险等方面,目前容易接受且应用最多的是冷板式液冷模式;根据循环架构的不同,又可分为开式循环系统和闭式循环系统。 闭式系统是自循环的小系统,最常见的应用是PC主机箱液冷,透明机箱加带色的工质,系统一运转,非常炫酷: 闭式循环系统系统&原理 与闭式循环系统相比,开式系统对机房节可能更有帮助。它能够将热量转移至室外进行散热,减少机房的空调用量,降低整体PUE。 系统通常划分成一次侧和二次侧两部分,一次侧为机房供水,包括室外的干冷器和冷水机组;二次侧为机房内布局部分,包括供液环路和服务器内部流道;两个部分通过CDU(Coolant Distribution Unit冷量分配单元)中的板式换热器发生间壁式换热,工质不做混合。 开式循环系统 冷板式液冷服务器主要由快速接头、管路和冷板组成: 快速接头可以实现带压插拔维护服务器,水路的自动断开和导通;管路负责水路的运输工作,在服务器内进行流道设计;液冷板的作用是提供冷水与热源之间换热的场所,内部有各类流道设计应对不同使用场景。结语根据DCFF发布的《中国数据中心能源使用报告2018》,截止2018年底,中国大小数据中心总量在40万个以上,在线使用服务器数量超过1200万台,年增长率在13.4%~17.7%之间,所有服务器及网络设备耗电量约324.4亿度电,占全社会总用电量1%,随着数据中心的数量及服务器保有量增加,该比例会持续增大,达到或接近美国数据中心社会总用电量占比的1.5%~2%水平。 初步评估,液冷机房的PUE可以做到1.1左右,即324.4亿度电需要的散热配套设备功耗为32.44亿度电,而当前较好的风冷机房PUE平均可以做到1.4左右,即散热配套设备功耗为129.76亿度电;液冷一年可以节省97亿度电!相当于千万级人口大城市的年均居民用电总量。 由于其回液温度明显高于传统空调系统回液,废热品味显著提高,可以大幅度提升热回收应用价值,在未来规划利用新型数据中心余热回收技术,为需求场所提供绿色清洁的热源,从而达到能源的高效与绿色化应用。 京东云AIDC(AI/Alliances+IDC),即京东云在IDC业务领域联合最广大的IDC渠道商,依托京东云自建骨干网,形成一个遍及全国的资源大网,充分满足客户对地理、时延等方面的需求。京东云AIDC除包括传统IDC如机柜租赁、带宽等产品外,还包括丰富的增值服务产品、智能化产品、云产品以及定制化产品。再结合京东公有云丰富的产品线,AIDC可以为客户提供私有云托管、专有云、混合云、云灾备等整体解决方案。 点击了解

April 25, 2019 · 1 min · jiezi

Windows平台安装Oracle Database 18.3

Windows平台安装Oracle Database 18.3对于Win10同样适用,大同小异。软件环境Windows Server 2019评估版虚拟机(不破解的话180天试用)Oracle Database 18.3 64bitJava 81. 检查Jdk是否完成配置JDK安装和配置在搜索引擎上很多很详细,这里就不赘述了。2. 下载Oracle Database 18.3安装包18c下载地址,选到18.3 Windows x64版本,下载到的会是一个ZIP的压缩包。3. 解压并运行setup.exe4. 安装Oracle Database 18.3来了来了,要跳坑了!a. Configuration Option:Create and configure a single instance databaseb. System Class:Destop Classc. Oracle Home User: Use Virtual Accountd. Typical Installation:默认的配置是这里设置Oracle base、Database file location指向相对的位置和设置Oracle Database的password。注意:这里不修改base文件所在位置,会出现以下的错误[INS-30011]–The specified Oracle base location is invalid。错误[INS-32014]是说我设置的密码不符合Oracle的标准。这里,我又新建了一个文件夹叫做“Oracle Base”,然后再Oracle Base那一栏选择刚建好的文件夹,下方Database file location也会自动变成E:Oracle Baseoradata,然后改了下密码下一步。e. Prerequisite Checks:这里需要一点时间。然后会弹出来这个界面,勾上Ignore All选项就可以继续往下了f.Summary:点install开始安装g. Install Project:这里等待安装时间比较久h. Finsih:看到这个界面,那么数据库安装已经完成。i. 测试是否已安装,使用安装时候附带sqlplus或者进入cmd后键入sqlplus命令都可以,登陆用户名为system,密码为你刚才上面设置的密码。出现 SQL> 说明登陆成功。工具连接Oracle Database命令行窗口操作并不方便,所以我们需要让工具连接到我们的数据库来操作。数据库管理工具有很多,比如DataGrip、Navicat、PL/SQL Developer、DBEaver、SQLyog等,我这里用Navicat。该软件收费,文末附上补丁,有条件还是支持正版好。下载后安装打开,新建connection,选择Oracle。这里要选择连接类型要选择TNS,否则会出错。Navicat补丁 提取码:9wss 链接失效可以留言或关注微信公众号“大大大西西瓜皮”后台回复。

April 20, 2019 · 1 min · jiezi

在 IntelliJ IDEA 中部署应用到服务器(Eclipse)

在之前的文章《在 Intellij IDEA 中部署 Java 应用到 阿里云 ECS》中讲解了如何将一个本地应用部署到阿里云 ECS 上去,有些读者反馈目前还有一些测试机器是在经典网络,甚至是在本地机房中,咨询是否可以通过 Cloud Toolkit 插件将应用部署到这些服务器上去?最新版本的 Cloud Toolkit 已经发布,完全支持啦。本地开发无论是编写云端运行的,还是编写本地运行的 Java 应用程序,代码编写本身并没有特别大的变化,因此本文采用一个及其基础的样例《在 Web 页面打印 HelloWorld 的 Java Servlet 》为例,做参考。public class IndexServlet extends HttpServlet { private static final long serialVersionUID = -112210702214857712L; @Override public void doGet( HttpServletRequest req, HttpServletResponse resp ) throws ServletException, IOException { PrintWriter writer = resp.getWriter(); //Demo:通过 Cloud Toolkit ,高效的将本地应用程序代码修改,部署到云上。 writer.write(“Deploy from alibaba cloud toolkit. 2018-10-24”); return; } @Override protected void doPost( HttpServletRequest req, HttpServletResponse resp ) throws ServletException, IOException { return; }}源代码下载上述代码就是一个标准的 Java 工程,用于在 Web 页面上打印一串“Hello World”的文案。安装插件阿里云提供了基于 Intellij IDEA 的插件,以方便开发人员能够高效的将本地 IDE 中编写的应用程序,极速部署到服务器中去。插件主页:https://www.aliyun.com/product/cloudtoolkit阿里云的这个 IntelliJ IDEA 插件的安装过程,和普通的插件大同小异,这里不再赘述,读者请自行安装。添加服务器如上图所示,在菜单 Tools - Alibaba Cloud - Alibaba Cloud View - Host中打开机器视图界面,如下图:点击右上角Add Host按钮,出现添加机器界面部署在 IntelliJ IDEA 中,鼠标右键项目工程名,在出现的菜单中点击 Alibaba Cloud - Deploy to Host…,会出现如下部署窗口:在 Deploy to Host 对话框设置部署参数,然后单击 Deploy,即可执行初次部署。部署参数说明:Deploy File:部署文件包含两种方式。Maven Build:如果当前工程采用 Maven 构建,可以使用 Cloud Toolkit 直接构建并部署。Upload File:如果当前工程并非采用 Maven 构建,或者本地已经存在打包好的部署文件,可以选择并直接上传本地的部署文件。Target Deploy host:在下拉列表中选择Tag,然后选择要部署的服务器。Deploy Location :输入在 ECS 上部署路径,如 /root/tomcat/webapps。Commond:输入应用启动命令,如 sh /root/restart.sh。表示在完成应用包的部署后,需要执行的命令 —— 对于 Java 程序而言,通常是一句 Tomcat 的启动命令。本文作者:银时阅读原文本文为云栖社区原创内容,未经允许不得转载。 ...

April 18, 2019 · 1 min · jiezi

趣谈预留实例券,一文搞懂云上省钱最新玩法

摘要: 一文搞懂时髦的预留实例券(RI)ECS近期推出了预留实例券(Reserved Instances),简称RI,这东西很cool,今天我们聊聊这个。首先这篇Blog不是文档,读完后想详细了解文档的朋友请点击一个小故事我来给大家讲一个故事理解云上的几种付费方式:包年包月(预付费),按量付费(后付费),和预留实例券。小明爱好游泳。一开始小明工作忙,去游泳的次数不固定,每次去都是锻炼完付款给老板(后付费),好处是非常自由,想来就来,想偷懒就偷懒(按量付费在云上随时创建随时释放,按秒计费),但是每次的价格贵(请大家参见ECS价格表,按量付费价格是最贵的)。后来,小明渐渐发现自己游泳非常规律,每天都去,想降低开销。于是他和老板谈了一个合同,合同如下:小明先交钱(预付费),然后每次来都可以使用窗边那条泳道,可以使用一年(包年),这样可以得到比较大的折扣。有朋友会想,这合同好奇怪啊……大家淡定我只是想类比一下云上的情况,大家想一想,云上的预付费(包年月)是不是直接绑定优惠到一台具体的机器(实例)的?好,有一天小明因为种种原因不想用窗边的泳道了,想换个大门边的泳道锻炼,咋办?因为违反合同了,小明应该把当前合同解除,再签订一个大门边泳道的合同。大家想想,在云上,如果包年月的使用者因为一些原因想释放掉当前实例,再创建(这个过程常常发生,比如公司不同阶段机器用途不一样,或者业务配比不一样),是不是要走退款流程,再下单购买,再创建……财务流程反复,还需要一些人工运维参与。最近,小明发现泳池推出了一种会员卡(云上类比预留实例券),一次性购买会员卡后,可以随便来免费游泳,哪个泳道都可以游,甚至还能去两条街以外的连锁泳池使用,而且每次来游泳,都能保证小明有泳道可以用(资源预留)。会员卡花费和签合同差不多,但是灵活性大大加强。预留实例券(Reserved Instances)是什么?预留实例券就类似一张云上的会员卡,或者说抵扣券。会员卡上都有各自属性吧,只有属性匹配上了才能用,我们来看看这个预留实例券这个会员卡长啥样?这是一张小编从购买页面抽象出来的图,可以看到有5个重要信息,分别是:实例规格,例如图上为ecs.g5.2xlarge地理位置,例如图上为华北2 可用区G操作系统,例如图上为Linux有效期,例如图上为3年预留台数,例如图上为预留2台顺便附上购买页面里的参数选择窗口地理位置选择,有朋友可能会问这个有预留和无预留啥意思,别急后面会说到实例规格和操作系统选择,目前预留实例券暂时只支持Linux有效期和预留台数选择买了这个会员卡后怎么用?答案是:搭配按量付费(后付费)实例用。只要这个预留实例券在有效期(图例中为3年),只要你的按量付费实例满足券面属性,你会发现,你的按量付费的计算部分(vCPU+内存)账单直接被抵扣掉了,不需要对这部分费用再花钱!例如,你有上图例子中的预留实例券,你在华北2可用区G拥有一台ecs.g5.2xlarge,操作系统为Linux的实例,这个实例计算部分的账单是直接被完全抵扣掉的。不过,这个例子中,如果你的实例规格是ecs.c5.2xlarge,或者操作系统用的Windows,那抵扣会失败,因为没有和券的属性完全符合。当你的实例用完不想要了,释放后再开一台,只要还符合这些属性,账单仍然能被抵扣。不过请注意同时抵扣的按量付费实例不能超过券面的预留台数(图例中为2台)。明白了吧,预留实例券就是通过按量付费(后付费)的方式把灵活性保留的,同时客户通过承诺使用时间(例如3年期,1年期),云厂商可以为客户大幅降低使用按量付费的成本(最高可以降低79%)。预留实例券(Reserved Instances)的灵活变配再来看看一些更有意思的玩法,首先看预留实例券的拆分。假设您的实例券可抵扣台数均为1台,规格是ecs.g5.2xlarge(8核),那可以抵扣您一台ecs.g5.2xlarge(8核)的按量付费实例。有一天,你觉得不需要单节点那么大算力,于是想能不能让券去抵扣两台ecs.g5.xlarge(4核),答案是:可以,只需要把券给拆分了就行。那么能不能变成抵扣4台ecs.g5.large(2核)?答案仍然是:可以,只需要再拆一次。然后是预留实例券的合并。刚刚这个过程逆向看,仍然成立。你有一堆小规格的券,通过合并,也可以合出大规格的券。具体的拆分合并规则请参见所以,预留实例券购买的是整个算力的折扣,在实例家族确定情况下,vCPU总数不变情况下,可以灵活调整你要的具体规格大小。预留实例券(Reserved Instances)的种类从有效期来看,目前线上的预留实例券有两种:1年期,3年期。从付费类型看,目前线上的预留实例券有三种:全预付(即一次性把会员卡费用付清),部分预付(先付一半费用,剩下的每小时出账单),0预付(购买时不付任何费用,后面每小时出账单)。详情请点击从资源预留来看,目前线上的预留实例券有两种:地域级,可用区级。下面我们说说这俩啥区别。地域级RI和可用区级RI首先,写给不熟悉ECS的读者一个概念:地域是一个区域的概念,可能包括多个可用区,比如下图,华北2这个地域下面有7个可用区。您购买的实例地理位置上最后都会落到一个具体的可用区。可用区级RI如果你购买页面选择地理位置时,选了有预留,那么你需要指定地域和具体的可用区,这时你购买的是可用区级RI。对于可用区级RI,是不支持同地域下跨可用区抵扣的,比如你的RI券是华北2可用区G,那么只能抵扣华北2可用区G的按量实例,不能抵扣华北2可用区F的实例。如果你需要抵扣的实例迁移去了另一个可用区,那么你需要通过修改券属性,把你券的地理位置属性也改到另一个可用区。另外,可用区级RI的抵扣必须和实例规格完全匹配才能抵扣,比如RI券是ecs.g5.2xlarge,那么实例也必须是ecs.g5.2xlarge才能抵扣。如果你要支持ecs.g5家族下其他规格,可用在总vCPU不变情况下选择拆分和合并。你可能会问,不是刚刚说了本来就要完全匹配么,别急,一会儿你看看地域级RI是怎么玩的。可用区级RI有一个最大优势,就是资源预留,当你购买了可用区级别RI时,ECS库存系统会为你预留对应的按量付费实例。比如券面是ecs.g5.2xlarge,预留10台,那么在RI券有效期内,永远有10台ecs.g5.2xlarge实例是为你留着的,保证你随时要服务,都能顺利开出。很多朋友问,过年啊,春运啊,线上资源那么紧张,大家怎么100%保证自己的计算资源随开随有?小编偷偷告诉你,预留实例券是个好方法……这也是这个产品名字里“预留”这个功能的直接体现。地域级RI如果你购买页面选择地理位置时,选了无预留,那么你无需指定具体的可用区,只要选择地域就好,这时你购买的是地域级RI。地域级RI可以抵扣你在该地域任何一个可用区符合抵扣标准的按量付费实例,灵活性更好。另外,地域级RI的抵扣条件更宽松,只要你的按量实例和券面的实例家族符合就能抵扣(当然操作系统这些还是要符合属性哦)。比如,你的券面是1年期(即8760小时)ecs.c5.large(2核),你的按量实例只要满足ecs.c5这个条件就能抵扣,假设你的按量实例是ecs.c5.xlarge(4核),没关系,可以抵扣它跑半年。更多例子见下表。刚刚说的是小券抵大实例,反过来,大券抵小实例也是OK的。假设你的券是1年期的ecs.c5.4xlarge(16核),可以抵扣1台16核c5跑一年,或者抵扣2台8核c5跑一年,或者抵扣4台4核c5跑一年,或者抵扣8台2核c5跑一年。刚刚说的地域级RI跨核数抵扣,都是自动匹配的,无需手动拆分合并。显然,地域级RI灵活性更好,不过地域级RI是不保证资源预留的,库存极度紧张时,开按量实例有可能需要等待。说了这么多,给大家看看预留实例券控制台里可用区级RI和地域级RI长啥样。上面的框是可用区级RI,可以看到可用区和实例规格是很明确的。下面的框是地域级RI,只有地域信息,后面写的是跨可用区,实例规格也只写了实例家族信息(例子是ecs.c5)和总vCPU核数。顺便说一下,地域级RI和可用区级RI是可以互相转换的,不怕买错,同时可用区级RI的具体可用区属性也可以修改。关于这两种RI,详情文档在这里,请点击谈谈钱现在谈谈钱吧,看看RI的购买成本。我们对比一下华北2(北京)地域,ecs.c5.large实例的计算部分在三种计费规则下跑一个月的价格:预付费包月、预留实例券(1年期全预付)、按量付费预付费包月预留实例券(1年期全预付)按量付费179元152.15元446元注:价格截取自2019年4月17日的阿里云官网另外请注意,RI是用来抵扣按量实例账单的计算部分,存储网络部分并不覆盖。另外,RI的1年期、3年期对比,3年期折扣更低;全预付、部分预付、0预付对比,全预付折扣最低。如何购买?当前预留实例券正在大规模邀测,你可以通过ECS控制台看到预留实例券的入口,如图,进去就能看到邀测页面了。当然也可以直接点击提交邀测申请。本文作者:雁鹰阅读原文本文为云栖社区原创内容,未经允许不得转载。

April 18, 2019 · 1 min · jiezi

现代IM系统中的消息系统架构 - 架构篇

前言IM全称是『Instant Messaging』,中文名是即时通讯。在这个高度信息化的移动互联网时代,生活中IM类产品已经成为必备品,比较有名的如钉钉、微信、QQ等以IM为核心功能的产品。当然目前微信已经成长为一个生态型产品,但其核心功能还是IM。还有一些非以IM系统为核心的应用,最典型的如一些在线游戏、社交应用,IM也是其重要的功能模块。可以说,IM系统已经是任何一个带有社交属性的应用需要具备的基础功能,网络上对于这类系统的设计与实现的讨论也越来越多。IM系统在互联网初期即存在,其基础技术架构在这十几年的发展中更新迭代多次,从早期的CS、P2P架构,到现在后台已经演变为一个复杂的分布式系统,涉及移动端、网络通信、协议、安全、存储和搜索等技术的方方面面。IM系统中最核心的部分是消息系统,消息系统中最核心的功能是消息的同步、存储和检索:消息的同步:将消息完整的、快速的从发送方传递到接收方,就是消息的同步。消息同步系统最重要的衡量指标就是消息传递的实时性、完整性以及能支撑的消息规模。从功能上来说,一般至少要支持在线和离线推送,高级的IM系统还支持『多端同步』。消息的存储:消息存储即消息的持久化保存,传统消息系统通常只能支持消息在接收端的本地存储,数据基本不具备可靠性。现代消息系统能支持消息在服务端的在线存储,功能上对应的就是『消息漫游』,消息漫游的好处是可以实现账号在任意端登陆查看所有历史消息。消息的检索:消息一般是文本,所以支持全文检索也是必备的能力之一。传统消息系统通常来说也是只能支持消息的本地检索,基于本地存储的消息数据来构建。而现在消息系统在能支持消息的在线存储后,也具备了消息的『在线检索』能力。本篇文章内容主要涉及IM系统中的消息系统架构,会介绍一种基于阿里云表格存储Tablestore的Timeline模型构建的消息系统。基于Tablestore Timeline构建的现代消息系统,能够同时支持消息系统的众多高级特性,包括『多端同步』、『消息漫游』和『在线检索』。在性能和规模上,能够做到全量消息云端存储和索引,百万TPS写入以及毫秒级延迟的消息同步和检索能力。之后我们会继续发表两篇文章,来更详细介绍Tablestore Timeline模型概念及使用:模型篇:详细介绍Tablestore Timeline模型的基本概念和基础数据结构,并结合IM系统进行基本的建模。实现篇:会基于Tablestore Timeline实现一个具备『多端同步』、『消息漫游』和『在线检索』这些高级功能的简易IM系统,并共享我们的源代码。传统架构 vs 现代架构传统架构下,消息是先同步后存储。对于在线的用户,消息会直接实时同步到在线的接收方,消息同步成功后,并不会在服务端持久化。而对于离线的用户或者消息无法实时同步成功时,消息会持久化到离线库,当接收方重新连接后,会从离线库拉取所有未读消息。当离线库中的消息成功同步到接收方后,消息会从离线库中删除。传统的消息系统,服务端的主要工作是维护发送方和接收方的连接状态,并提供在线消息同步和离线消息缓存的能力,保证消息一定能够从发送方传递到接收方。服务端不会对消息进行持久化,所以也无法支持消息漫游。消息的持久化存储及索引同样只能在接收端本地实现,数据可靠性极低。现代架构下,消息是先存储后同步。先存储后同步的好处是,如果接收方确认接收到了消息,那这条消息一定是已经在云端保存了。并且消息会有两个库来保存,一个是消息存储库,用于全量保存所有会话的消息,主要用于支持消息漫游。另一个是消息同步库,主要用于接收方的多端同步。消息从发送方发出后,经过服务端转发,服务端会先将消息保存到消息存储库,后保存到消息同步库。完成消息的持久化保存后,对于在线的接收方,会直接选择在线推送。但在线推送并不是一个必须路径,只是一个更优的消息传递路径。对于在线推送失败或者离线的接收方,会有另外一个统一的消息同步方式。接收方会主动的向服务端拉取所有未同步消息,但接收方何时来同步以及会在哪些端来同步消息对服务端来说是未知的,所以要求服务端必须保存所有需要同步到接收方的消息,这是消息同步库的主要作用。对于新的同步设备,会有消息漫游的需求,这是消息存储库的主要作用,在消息存储库中,可以拉取任意会话的全量历史消息。消息检索的实现依赖于对消息存储库内消息的索引,通常是一个近实时(NRT,near real time)的索引构建过程,这个索引同样是在线的。以上就是传统架构和现代架构的一个简单的对比,现代架构上整个消息的同步、存储和索引流程,并没有变复杂太多。现代架构的实现本质上是把传统架构内本地存储和索引都搬到云上,最大挑战是需要集中管理全量消息的存储和索引,带来的好处是能实现多端同步、消息漫游以及在线检索。可以看到现代架构中最核心的就是两个消息库『消息同步库』和『消息存储库』,以及对『消息存储库』的『消息索引』的实现,接下来我们逐步拆解这几个核心的设计和实现。基础模型在深入讲解消息系统的设计和实现之前,需要对消息系统内的几个基本概念和基础模型有一个理解。网上分析的很多的不同类型的消息系统实现,实现差异上主要在消息同步和存储的方案上,在消息的数据模型上其实有很大的共性。围绕数据同步模型的讨论主要在『读扩散』、『写扩散』和『混合模式』这三种方案,目前还没有更多的选择。而对于数据模型的抽象,还没有一个标准的定义。本章节会介绍下表格存储Tablestore提出的Timeline模型,这是一个对消息系统内消息模型的一个抽象,能简化和更好的让开发者理解消息系统内的消息同步和存储模型,基于此模型我们会再深入探讨消息的同步和存储的选择和实现。Timeline模型Timeline是一个对消息抽象的逻辑模型,该模型会帮助我们简化对消息同步和存储模型的理解,而消息同步库和存储库的设计和实现也是围绕Timeline的特性和需求来展开。如图是Timeline模型的一个抽象表述,Timeline可以简单理解为是一个消息队列,但这个消息队列有如下特性:每条消息对应一个顺序ID:每个消息拥有一个唯一的顺序ID(SequenceId),队列消息按SequenceId排序。新消息写入能自动分配递增的顺序ID,保证永远插入队尾:Timeline中是根据同步位点也就是顺序ID来同步消息,所以需要保证新写入的消息数据的顺序ID绝对不能比已同步的消息的顺序ID还小,否则会导致数据漏同步,所以需要支持对新写入的数据自动分配比当前已存储的所有消息的顺序ID更大的顺序ID。新消息写入也能自定义顺序ID,满足自定义排序需求:上面提到的自动分配顺序ID,主要是为了满足消息同步的需求,消息同步要求消息是根据『已同步』或是『已写入』的顺序来排序。而消息的存储,通常要求消息能根据会话顺序来排序,会话顺序通常由端的会话来决定,而不是服务端的同步顺序来定,这是两种顺序要求。支持根据顺序ID的随机定位:可根据SequenceId随机定位到Timeline中的某个位置,从这个位置开始正序或逆序的读取消息,也可支持读取指定顺序ID的某条消息。支持对消息的自定义索引:消息体内数据根据业务不同会包含不同的字段,Timeline需要支持对不同字段的自定义索引,来支持对消息内容的全文索引,或者是任意字段的灵活条件组合查询。消息同步可以基于Timeline很简单的实现,图中的例子中,消息发送方是A,消息接收方是B,同时B存在多个接收端,分别是B1、B2和B3。A向B发送消息,消息需要同步到B的多个端,待同步的消息通过一个Timeline来进行交换。A向B发送的所有消息,都会保存在这个Timeline中,B的每个接收端都是独立的从这个Timeline中拉取消息。每个接收端同步完毕后,都会在本地记录下最新同步到的消息的SequenceId,即最新的一个位点,作为下次消息同步的起始位点。服务端不会保存各个端的同步状态,各个端均可以在任意时间从任意点开始拉取消息。消息存储也是基于Timeline实现,和消息同步唯一的区别是,消息存储要求服务端能够对Timeline内的所有数据进行持久化,并且消息采用会话顺序来保存,需要自定义顺序ID。消息检索基于Timeline提供的消息索引来实现,能支持比较灵活的多字段索引,根据业务的不同可有自由度较高的定制。消息存储模型如图是基于Timeline的消息存储模型,消息存储要求每个会话都对应一个独立的Timeline。如图例子所示,A与B/C/D/E/F均发生了会话,每个会话对应一个独立的Timeline,每个Timeline内存有这个会话中的所有消息,消息根据会话顺序排序,服务端会对每个Timeline进行持久化存储,也就拥有了消息漫游的能力。消息同步模型消息同步模型会比消息存储模型稍复杂一些,消息的同步一般有读扩散(也叫拉模式)和写扩散(也叫推模式)两种不同的方式,分别对应不同的Timeline物理模型。如图是读扩散和写扩散两种不同同步模式下对应的不同的Timeline模型,按图中的示例,A作为消息接收者,其与B/C/D/E/F发生了会话,每个会话中的新的消息都需要同步到A的某个端,看下读扩散和写扩散两种模式下消息如何做同步。读扩散:消息存储模型中,每个会话的Timeline中保存了这个会话的全量消息。读扩散的消息同步模式下,每个会话中产生的新的消息,只需要写一次到其用于存储的Timeline中,接收端从这个Timeline中拉取新的消息。优点是消息只需要写一次,相比写扩散的模式,能够大大降低消息写入次数,特别是在群消息这种场景下。但其缺点也比较明显,接收端去同步消息的逻辑会相对复杂和低效。接收端需要对每个会话都拉取一次才能获取全部消息,读被大大的放大,并且会产生很多无效的读,因为并不是每个会话都会有新消息产生。写扩散:写扩散的消息同步模式,需要有一个额外的Timeline来专门用于消息同步,通常是每个接收端都会拥有一个独立的同步Timeline(或者叫收件箱),用于存放需要向这个接收端同步的所有消息。每个会话中的消息,会产生多次写,除了写入用于消息存储的会话Timeline,还需要写入需要同步到的接收端的同步Timeline。在个人与个人的会话中,消息会被额外写两次,除了写入这个会话的存储Timeline,还需要写入参与这个会话的两个接收者的同步Timeline。而在群这个场景下,写入会被更加的放大,如果这个群拥有N个参与者,那每条消息都需要额外的写N次。写扩散同步模式的优点是,在接收端消息同步逻辑会非常简单,只需要从其同步Timeline中读取一次即可,大大降低了消息同步所需的读的压力。其缺点就是消息写入会被放大,特别是针对群这种场景。Timeline模型不会对选择读扩散还是写扩散做约束,而是能同时支持两种模式,因为本质上两种模式的逻辑数据模型并无差别,只是消息数据是用一个Timeline来支持多端读还是复制到多个Timeline来支持多端读的问题。针对IM这种应用场景,消息系统通常会选择写扩散这种消息同步模式。IM场景下,一条消息只会产生一次,但是会被读取多次,是典型的读多写少的场景,消息的读写比例大概是10:1。若使用读扩散同步模式,整个系统的读写比例会被放大到100:1。一个优化的好的系统,必须从设计上去平衡这种读写压力,避免读或写任意一维触碰到天花板。所以IM系统这类场景下,通常会应用写扩散这种同步模式,来平衡读和写,将100:1的读写比例平衡到30:30。当然写扩散这种同步模式,还需要处理一些极端场景,例如万人大群。针对这种极端写扩散的场景,会退化到使用读扩散。一个简单的IM系统,通常会在产品层面限制这种大群的存在,而对于一个高级的IM系统,会采用读写扩散混合的同步模式,来满足这类产品的需求。采用混合模式,会根据数据的不同类型和不同的读写负载,来决定用写扩散还是读扩散。典型架构设计如图是一个典型的消息系统架构,架构中包含几个重要组件:端:作为消息的发送和接收端,通过连接消息服务器来发送和接收消息。消息服务器:一组无状态的服务器,可水平扩展,处理消息的发送和接收请求,连接后端消息系统。消息队列:新写入消息的缓冲队列,消息系统的前置消息存储,用于削峰填谷以及异步消费。消息处理:一组无状态的消费处理服务器,用于异步消费消息队列中的消息数据,处理消息的持久化和写扩散同步。消息存储和索引库:持久化存储消息,每个会话对应一个Timeline进行消息存储,存储的消息建立索引来实现消息检索。消息同步库:写扩散形式同步消息,每个用户的收件箱对应一个Timeline,同步库内消息不需要永久保存,通常对消息设定一个生命周期。新消息会由端发出,通常消息体中会携带消息ID(用于去重)、逻辑时间戳(用于排序)、消息类型(控制消息、图片消息或者文本消息等)、消息体等内容。消息会先写入消息队列,作为底层存储的一个临时缓冲区。消息队列中的消息会由消息处理服务器消费,可以允许乱序消费。消息处理服务器对消息先存储后同步,先写入发件箱Timeline(存储库),后写扩散至各个接收端的收件箱(同步库)。消息数据写入存储库后,会被近实时的构建索引,索引包括文本消息的全文索引以及多字段索引(发送方、消息类型等)。对于在线的设备,可以由消息服务器主动推送至在线设备端。对于离线设备,登录后会主动向服务端同步消息。每个设备会在本地保留有最新一条消息的顺序ID,向服务端同步该顺序ID后的所有消息。总结本篇文章主要介绍了现代IM系统中消息系统所需要具备的能力,对比了传统架构和现代架构。为方便接下来的深入探讨,介绍了表格存储Tablestore推出的Timeline模型,以及在IM系统中消息存储和消息同步模型的基本概念和策略,最后介绍了一个典型的架构设计。本文作者:木洛阅读原文本文为云栖社区原创内容,未经允许不得转载。

April 16, 2019 · 1 min · jiezi

Node.js 应用故障排查手册 —— 大纲与常规问题指标简介

楔子你是否想要尝试进行 Node.js 应用开发但是又总听人说它不安全、稳定性差,想在公司推广扩张大前端的能力范畴和影响又说服不了技术领导。JavaScript 发展到今天,早已脱离原本浏览器的战场,借助于 Node.js 的诞生将其触角伸到了服务端、PC 跨平台客户端方案等各个领域,但是与此同时,JS Runtime 对于绝大部分的开发者来说又一如既往的处于黑盒状态——开发者无法感知其运行状态,出现一些性能、内存问题时也没有很好的工具链进行更深入的支持。本书将在基于 Node.js 性能平台 的基础上,从多个大家开发上线过程中可能遇到的疑难杂症的视角,观察如何去发现、定位和解决这些问题,帮助读者构建对 Node.js 这门语言的更多信心。因为本书将属于 Node.js 开发进阶的内容,因此我们希望本书的读者具备以下的基本技能:常规的 Node.js 应用开发的能力常规的服务器性能指标参数的理解,比如 CPU、Memory、Load、文件打开数等常见的数据库、缓存等操作负载均衡、多进程模型如果使用容器,容器的基本知识,资源管理等本书首发在 Github,仓库地址:https://github.com/aliyun-node/Node.js-Troubleshooting-Guide,云栖社区会同步更新。常规排查的指标当我们第一次遇到线上异常时,很多人会感觉无从下手。本节作为预备篇,将从服务器异常时常见的排查指标开始,帮助大家建立一个更加直观的问题处理体系。毕竟如果我们面对线上异常时,如果连系统哪里有问题都不知道,那么后续的借助 Node.js 性能平台 更深入定位问题代码就更加无从谈起了。错误日志当我们的应用出现问题时,首先需要去查看我们应用的错误日志,观察在这段时间内是不是有错误在一直抛出,导致了我们的服务不稳定。这一块的信息显然是因各个应用而异的,当我们的项目比较大(Ecs/Docker 节点比较多)的时候,就需要对错误日志的进行统一的采集收集来保证出问题时的快速定位。一个比较简单的统一日志平台可以设计如下:其中的采集服务器和 Agent 上报之间一般会采用消息队列(Kafka)来作为缓冲区减轻双方的负载,ELK 就是一个比较成熟的日志服务。有了统一的日志平台后,当我们的应用出现问题时,首先应该去日志平台上查看当前的错误日志信息,特别是对于那些在 频繁出现 的错误日志应当引起警惕,需要去仔细地结合产生错误的代码段进行回溯确认是否是造成当前服务不稳定的元凶,Node.js 性能平台 也实现了一个简单的错误日志回溯 + 告警的系统,本书第二部分会更详细说明。系统指标如果在上述的错误日中没有看到可疑的信息(实际上错误日志以及本节的系统指标排查先后顺序并无固定,大家可以视自己的需求进行),那么接下来我们就应该关注下问题是不是因为服务器或者 Node.js 应用本身的负载到了极限导致的问题。一些比较常见的大家需要关注的系统指标如下所示:CPU & MemoryDisk 磁盘占用率I/O 负载TCP 连接状态下面逐一讲解这些可能存在问题的系统指标。I. CPU & Memory使用 top 命令来观察和 Node.js 应用进程的 CPU 和 Memory 负载情况。一般来说,对于 CPU 很高 Node.js 进程,我们可以使用 Node.js 性能平台 提供的 CPU Profiling 工具来在线 Dump 出当前的 Javascript 运行情况,进而找到热点代码进行优化,具体在本书第二部分会有更详细地说明。那么对于 Memory 负载很高的情况,正常来说就是发生了内存泄漏(或者有预期之外的内存分配导致溢出),那么同样的我们可以用性能平台提供的工具来在线 Dump 出当前的 Javascript 堆内存和服务化的分析来结合你的业务代码找到产生泄漏的逻辑。这里需要注意的是,目前性能平台能够进行详尽分析的地方集中在你的 JS 代码上,对于完全是 C++ 扩展执行的或者完全的 V8/Libuv 底层执行(这部分功能后面会补上)的逻辑,以及不分配在 V8 Heap 上的内存,性能平台目前没有更好的办法来进行分析处理。而实际上在我们遇到的案例中,大家编写的 JS 代码出问题占了绝大部分,也就是性能平台目前针对 JS 部分比较完善的在线 Dump + 服务化分析基本上能够解决开发者 95% 甚至以上的问题了。II. Disk 磁盘占用率使用 df 命令可以观察当前的磁盘占用情况,这个也是非常常见的问题,很多开发者会忽略对服务器磁盘的监控告警,当我们的日志/核心转储等大文件逐渐将磁盘打满到 100% 的时候,Node.js 应用很可能会无法正常运行,Node.js 性能平台 目前也提供了对磁盘的监控,在本书第二部分同样会有更详细地说明。III. I/O 负载使用 top/iostat 和 cat /proc/${pid}/io 来查看当前的 I/O 负载,这一项的负载很高的话,也会使得 Node.js 应用出现卡死等情况。IV. TCP 连接状态绝大部分的 Node.js 应用实际上是 Web 应用,每个用户的连接都会创建一个 Socket 连接,在一些异常情况下(比如遭受半连接攻击或者内核参数设置不合理),服务器上会有大量的 TIME_WAIT 状态的连接,而大量的 TIME_WAIT 积压会导致 Node.js 应用的卡死(内核无法为新的请求分配创建新的 TCP 连接),我们可以使用 netstat -ant|awk ‘/^tcp/ {++S[$NF]} END {for(a in S) print (a,S[a])}’ 命令来确认这个问题。核心转储(Core dump)线上 Node.js 应用故障往往也伴随着进程的 Crash,借助于一些守护进程的自检重启拉起,我们的服务依旧在运行,但是我们不应该去忽略这些意外的 Crash —— 当流量增大或者造成服务器的问题用户访问被别有用心之人抓住时,我们集群就变得岌岌可危了。绝大部分情况下,会造成 Node.js 应用 Crash 掉的错误日志往往并不会记录到我们的错误日志文件中,幸运的是,服务器内核提供了一项机制帮助我们在应用 Crash 时自动地生成核心转储(Core dump)文件,让开发者可以在事后进行分析还原案发现场。核心转储核心转储(Core dump)实际上是我们的应用意外崩溃终止时,计算机自动记录下进程 Crash 掉那一刻的内存分配信息、Program counter 以及堆栈指针等关键信息来生成核心转储文件,因此获取到核心转储文件后,我们可以通过 MDB、GDB、LLDB 等工具即可实现解析诊断实际进程的 Crash 原因。生成文件触发核心转储生成转储文件目前主要有两种方式:I. 设置内核参数使用 ulimit -c unlimited 打开内核限制,并且考虑到默认运行模式下,Node.js 对 JS 造成的 Crash 是不会触发核心转储动作的,因此我们可以在 Node 应用启动时加上参数 –abort-on-uncaught-exception 来对出现未捕获的异常时也能让内核触发自动的核心转储动作。II. 手动调用手动调用 gcore <pid> (可能需要 sudo 权限)的方式来手动生成,因为此时 Node.js 应用依旧在运行中,所以实际上这种方式一般用于 「活体检验」,用于 Node.js 进程假死状态 下的问题定位。这里需要注意的是,以上的生成核心转储的操作都 并没有那么安全务必记得对服务器磁盘进行监控和告警**。获取到 Node.js 应用生成的核心转储文件后,我们可以借助于 Node.js 性能平台 提供的在线 Core dump 文件分析功能进行分析定位进程 Crash 的原因了,具体用法会在本书第二部分进行说明。小结本节从常见的几个服务器问题点,给大家对线上 Node.js 应用出现故障时如何去排查定位有了一些大概的印象,本章也是后续内容的一个预备知识,了解了这部分内容,才能在后面的一些实战案例中明白为何我们忽略了其它而选择详尽地服务化分析其中的一些要点。而核心转储的深入分析则能够帮助我们解决 Node.js 应用的绝大部分底层故障,因为其可以还原出问题 JavaScript 代码和引发问题的参数,功能非常地强大。本文作者:奕钧阅读原文本文为云栖社区原创内容,未经允许不得转载。 ...

April 11, 2019 · 1 min · jiezi

Nginx 外的另一选择,轻量级开源 Web 服务器 Tengine 发布新版本

新版发布近日,轻量级开源 Web 服务器 Tengine 发布了2.3.0版本,新增如下特性:ngx_http_proxy_connect_module,该模块让 Tengine 可以用于正向代理场景,支持对 CONNECT 方法请求的处理;HTTP2 Server粒度控制 新增 HTTP2指令,可针对 listen 相同端口的 server 进行个性化开启与关闭 HTTP2;Stream模块支持 server_name 指令,可在 SSL 场景下,基于 SNI 识别出域名,让四层SSL 转发支持特定的 server 块配置;加强 limit_req 模块功能,可以基于请求粒度动态设置限速大小,更多详细变更日志请参考limit_req 变更日志;注意事项需要注意的是,本次 Tengine 升级 core 代码至 Nginx 官方的1.15.9版本(2019年2月26日发布),由于 Tengine 的部分功能 Nginx 官方已经实现,所以 Tengine 2.3.0 弃用了自身实现的部分配置指令,由此带来的不兼容性,列举如下:废弃 Tengine 自身实现的 reuse_port 指令,使用 Nginx官方 的reuseport。升级方法:将events 配置块里面的 reuse_port on|off 注释掉,在对应的监听端口后面加 reuseport 参数,详细的操作文档,请参考limit_req 变更日志 。废弃 Tengine 的 dso_tool 工具以及 dso 配置指令。若之前有使用 Tengine 的 dso 功能,则可以切换到 Nginx官方 的 load_module 指令,详细操作文档,请参考Nginx 官方文档1和Nginx 官方文档2。移除 Tengine 加强版 slice 模块到 modules,默认使用 Nginx 官方的 slice 功能。如果依然需要使用 Tengine 的 slice,那么编译slice时请使用–add-module=modules/ngx_http_slice_module,否则使用 –with-http_slice_module 编译参数;Tengine 自身实现的模块,已全部剥离到 modules 目录下。如果需要使用那个模块,请使用 –add-module=modules/ 的方式进行编译。limit_req 的请求计数逻辑和官方保持一致,去除 limit_req_zone 中任何一个变量值为空,跳过请求计数的逻辑。关于 TengineTengine 是基于 Nginx 开发的轻量级开源 Web 服务器,作为阿里巴巴七层流量入口的核心系统,支撑着阿里巴巴双11等大促活动的平稳度过,并提供了智能的流量转发策略、HTTPS 加速、安全防攻击、链路追踪等众多高级特性,同时秉着软硬件结合的的性能优化思路,在高性能、高并发方面取得了重大突破。自开源以来,Tengine 已获得来自67位 contributors 的1390个 commits,他们分别来自淘宝、搜狗,美团、Nginx 等企业。据不完全统计,目前已有 200多家企业在通过 Tengine 来实现 Web 服务、负载均衡、代理服务、防攻击和访问限制等功能,包括傲世堂、小米网、聚美优品、河狸家、旺旺集团、杭州思华、中国博客联盟、SuperID、联想网盘、华兴资本、猿题库、蓝奏网盘、HoukeYun、云智慧等。目前,Tengine 正通过 Ingress Controller 和 K8s 打通,这让 Tengine 具备了动态感知某个服务整个生命周期的能力。未来,Tengine 将定期开源内部通用组件功能模块,并同步 Nginx 官方的最新代码,丰富开发者们的开源 Web 服务器选项。本文作者:王发康(花名:毅松) GitHub ID @wangfakang ,Tengine 开源项目 maintainer,阿里巴巴技术专家,负责阿里巴巴WEB统一接入层的开发及维护。本文作者:中间件小哥阅读原文本文为云栖社区原创内容,未经允许不得转载。 ...

April 4, 2019 · 1 min · jiezi

Cloud Toolkit 部署应用到阿里云轻量应用服务器

在之前的文章《在 Intellij IDEA 中部署 Java 应用到 阿里云 ECS》中讲解了如何将一个本地应用部署到阿里云 ECS 上去,有些读者反馈目前正在使用阿里云轻量应用服务器,咨询是否可以通过 Cloud Toolkit 插件将应用部署到这些服务器上去?最新版本的 Cloud Toolkit 已经发布,完全支持啦。由于阿里云 ECS 云助手只能支持 VPC 网络机器,因此,轻量应用服务器只能通过 Host 模式手动添加机器,采用标准 SSH 协议来进行部署添加服务器如上图所示,在菜单Tools - Alibaba Cloud - Alibaba Cloud View - Host中打开机器视图界面,如下图:点击右上角Add Host按钮,出现添加机器界面设置服务器的 SSH 账号部署在 IntelliJ IDEA 中,鼠标右键项目工程名,在出现的菜单中点击 Alibaba Cloud - Deploy to Host…,会出现如下部署窗口:在 Deploy to Host 对话框设置部署参数,然后单击 Deploy,即可执行初次部署。部署参数说明:Deploy File:部署文件包含两种方式。Maven Build:如果当前工程采用 Maven 构建,可以使用 Cloud Toolkit 直接构建并部署。Upload File:如果当前工程并非采用 Maven 构建,或者本地已经存在打包好的部署文件,可以选择并直接上传本地的部署文件。Target Deploy host:在下拉列表中选择Tag,然后选择要部署的服务器。Deploy Location :输入在 ECS 上部署路径,如 /root/tomcat/webapps。Commond:输入应用启动命令,如 sh /root/restart.sh。表示在完成应用包的部署后,需要执行的命令 —— 对于 Java 程序而言,通常是一句 Tomcat 的启动命令。本文作者:银时阅读原文本文为云栖社区原创内容,未经允许不得转载。 ...

April 3, 2019 · 1 min · jiezi

在 IntelliJ IDEA 中部署应用到服务器

在之前的文章《在 Intellij IDEA 中部署 Java 应用到 阿里云 ECS》中讲解了如何将一个本地应用部署到阿里云 ECS 上去,有些读者反馈目前还有一些测试机器是在经典网络,甚至是在本地机房中,咨询是否可以通过 Cloud Toolkit 插件将应用部署到这些服务器上去?最新版本的 Cloud Toolkit 已经发布,完全支持啦。本地开发无论是编写云端运行的,还是编写本地运行的 Java 应用程序,代码编写本身并没有特别大的变化,因此本文采用一个及其基础的样例《在 Web 页面打印 HelloWorld 的 Java Servlet 》为例,做参考。public class IndexServlet extends HttpServlet { private static final long serialVersionUID = -112210702214857712L; @Override public void doGet( HttpServletRequest req, HttpServletResponse resp ) throws ServletException, IOException { PrintWriter writer = resp.getWriter(); //Demo:通过 Cloud Toolkit ,高效的将本地应用程序代码修改,部署到云上。 writer.write(“Deploy from alibaba cloud toolkit. 2018-10-24”); return; } @Override protected void doPost( HttpServletRequest req, HttpServletResponse resp ) throws ServletException, IOException { return; }}源代码下载上述代码就是一个标准的 Java 工程,用于在 Web 页面上打印一串“Hello World”的文案。安装插件阿里云提供了基于 Intellij IDEA 的插件,以方便开发人员能够高效的将本地 IDE 中编写的应用程序,极速部署到服务器中去。插件主页:https://www.aliyun.com/product/cloudtoolkit阿里云的这个 IntelliJ IDEA 插件的安装过程,和普通的插件大同小异,这里不再赘述,读者请自行安装。添加服务器如上图所示,在菜单 Tools - Alibaba Cloud - Alibaba Cloud View - Host中打开机器视图界面,如下图:点击右上角Add Host按钮,出现添加机器界面部署在 IntelliJ IDEA 中,鼠标右键项目工程名,在出现的菜单中点击 Alibaba Cloud - Deploy to Host…,会出现如下部署窗口:在 Deploy to Host 对话框设置部署参数,然后单击 Deploy,即可执行初次部署。部署参数说明:Deploy File:部署文件包含两种方式。Maven Build:如果当前工程采用 Maven 构建,可以使用 Cloud Toolkit 直接构建并部署。Upload File:如果当前工程并非采用 Maven 构建,或者本地已经存在打包好的部署文件,可以选择并直接上传本地的部署文件。Target Deploy host:在下拉列表中选择Tag,然后选择要部署的服务器。Deploy Location :输入在 ECS 上部署路径,如 /root/tomcat/webapps。Commond:输入应用启动命令,如 sh /root/restart.sh。表示在完成应用包的部署后,需要执行的命令 —— 对于 Java 程序而言,通常是一句 Tomcat 的启动命令。本文作者:银时阅读原文本文为云栖社区原创内容,未经允许不得转载。 ...

April 2, 2019 · 1 min · jiezi

Vue-CLI 3.x 自动部署项目至服务器

前言平时部署前端项目流程是:先部署到测试环境ok后再发布到生产环境上,部署到测试环境用 xshell 连上服务器,然后用 xftp 连接服务器,然后本地 build 项目,接着把 build 好的文件通过 xftp 上传到服务器上,整个流程感觉稍有繁琐,重复。本教程讲解的是 Vue-CLI 3.x 脚手架搭建的vue项目, 利用scp2自动化部署到静态文件服务器 Nginx一 安装scp2scp2是一个基于ssh2增强实现,纯粹使用JavaScript编写。而ssh2就是一个使用nodejs对于SSH2的模拟实现。scp,是secure copy的缩写, scp是Linux系统下基于SSH登陆进行安全的远程文件拷贝命令。这里我们就用这个功能,在Vue编译构建成功之后,将项目推送至测试/生产环境,以方便测试,提高效率。安装scp2:npm install scp2 –save-dev二、配置测试/生产环境 服务器SSH远程登陆账号信息1. 在项目根目录下, 创建 .env.dev 文件 (测试环境变量)VUE_APP_SERVER_ID变量表示 当前需部署的测试服务器ID为0// .env.dev文件中VUE_APP_SERVER_ID=02. 在项目根目录下, 创建 .env.prod 文件 (生产环境变量)VUE_APP_SERVER_ID变量表示 当前需部署的生产服务器ID为1// .env.prod文件中VUE_APP_SERVER_ID=13. 在项目根目录下, 创建 deploy/products.js 文件/* 读取env环境变量 /const fs = require(‘fs’);const path = require(‘path’);// env 文件 判断打包环境指定对应的服务器idconst envfile = process.env.NODE_ENV === ‘prod’ ? ‘../.env.prod’ : ‘../.env.dev’;// env环境变量的路径const envPath = path.resolve(__dirname, envfile);// env对象const envObj = parse(fs.readFileSync(envPath, ‘utf8’));const SERVER_ID = parseInt(envObj[‘VUE_APP_SERVER_ID’]);function parse(src) { // 解析KEY=VAL的文件 const res = {}; src.split(’\n’).forEach(line => { // matching “KEY’ and ‘VAL’ in ‘KEY=VAL’ // eslint-disable-next-line no-useless-escape const keyValueArr = line.match(/^\s([\w.-]+)\s=\s*(.)?\s$/); // matched? if (keyValueArr != null) { const key = keyValueArr[1]; let value = keyValueArr[2] || ‘’; // expand newlines in quoted values const len = value ? value.length : 0; if (len > 0 && value.charAt(0) === ‘”’ && value.charAt(len - 1) === ‘"’) { value = value.replace(/\n/gm, ‘\n’); } // remove any surrounding quotes and extra spaces value = value.replace(/(^[’"]|[’"]$)/g, ‘’).trim(); res[key] = value; } }); return res;}/* *定义多个服务器账号 及 根据 SERVER_ID 导出当前环境服务器账号 */const SERVER_LIST = [ { id: 0, name: ‘A-生产环境’, domain: ‘www.prod.com’,// 域名 host: ‘46.106.38.24’,// ip port: 22,// 端口 username: ‘root’, // 登录服务器的账号 password: ‘Rock@sz18!’,// 登录服务器的账号 path: ‘/mdm/nginx/dist’// 发布至静态服务器的项目路径 }, { id: 1, name: ‘B-测试环境’, domain: ’test.xxx.com’, host: ‘XX.XX.XX.XX’, port: 22, username: ‘root’, password: ‘xxxxxxx’, path: ‘/usr/local/www/xxx_program_test/’ }];module.exports = SERVER_LIST[SERVER_ID];三、使用scp2库,创建自动化部署脚本在项目根目录下, 创建 deploy/index.js 文件const scpClient = require(‘scp2’);const ora = require(‘ora’);const chalk = require(‘chalk’);const server = require(’./products’);const spinner = ora(‘正在发布到’ + (process.env.NODE_ENV === ‘prod’ ? ‘生产’ : ‘测试’) + ‘服务器…’);spinner.start();scpClient.scp( ‘dist/’, { host: server.host, port: server.port, username: server.username, password: server.password, path: server.path }, function (err) { spinner.stop(); if (err) { console.log(chalk.red(‘发布失败.\n’)); throw err; } else { console.log(chalk.green(‘Success! 成功发布到’ + (process.env.NODE_ENV === ‘prod’ ? ‘生产’ : ‘测试’) + ‘服务器! \n’)); } });四、添加 package.json 中的 scripts 命令, 自定义名称为 “deploy”,发布到测试环境命令为 npm run deploy:dev,生产环境为 npm run deploy:prod “scripts”: { “serve”: “vue-cli-service serve –mode dev”, “build”: “vue-cli-service build –mode prod”, “deploy:dev”: “npm run build && cross-env NODE_ENV=dev node ./deploy”, “deploy:prod”: “npm run build && cross-env NODE_ENV=prod node ./deploy”, },ps 这里用到了cross_env 得安装 npm i –save-dev cross-env cross-env能跨平台地设置及使用环境变量,这里用来设置是生产环境还是测试环境。图解结束语欢迎指正,Vue学习群493671066 欢迎大家加入我的前端学习交流群一起学习进步。参考文章 https://www.cnblogs.com/sufai… ...

April 1, 2019 · 2 min · jiezi

手把手教你使用TF服务将TensorFlow模型部署到生产环境

摘要: 训练好的模型不知道如何布置到生产环境?快来学习一下吧!介绍将机器学习(ML)模型应用于生产环境已成为一个火热的的话题,许多框架提供了旨在解决此问题的不同解决方案。为解决这一问题,谷歌发布了TensorFlow(TF)服务,以期待解决将ML模型部署到生产中的问题。本文提供了一个关于服务于预先训练的卷积语义分割网络的实践教程。阅读本文后,你将能够使用TF服务来部署和向TF训练的深度CNN发出请求等操作。另外,本文将概述TF服务的API及其工作原理。如果你想学习本教程并在计算机上运行示例,请完整了解本文。但是,如果你只想了解TensorFlow服务,你可以专注于前两部分。TensorFlow服务库-概述首先我们需要花一些时间来了解TF Serving如何处理ML模型的整个生命周期。在这里,我们将介绍TF服务的主要构建块,本部分的目标是提供TF服务API的介绍。如需深入了解,请访问TF服务文档页面。TensorFlow服务由一些抽象组成,这些抽象类用于不同任务的API,其中最重要的是Servable,Loader,Source和Manager,让我们来看看他们之间是如何互动的:简单来说,当TF Serving识别磁盘上的模型时,Source组件就开始工作啦,整个服务生命周期也算开始了,Source组件负责识别应加载的新模型。实际上,它会密切关注文件系统,以确定新模型版本何时到达磁盘。当它看到新版本模型时,它会为该特定版本的模型创建一个Loader。总之,Loader几乎了解模型的所有内容,包括如何加载以及如何估计模型所需的资源,例如请求的RAM和GPU内存。Loader还有一个指向磁盘上模型的指针以及用于加载它的所有必要的元数据。但是有一个问题:加载器不允许加载模型。创建Loader后,Source会将其作为Aspired Version发送给Manager。收到模型的Aspired Version后,Manager继续执行服务过程。这里有两种可能性,一个是推送第一个模型版本进行部署,在这种情况下,Manager将确保所需的资源可用,完成后,Manager会授予Loader加载模型的权限;第二是我们推出现有模型的新版本,在这种情况下,管理员必须先咨询版本策略插件,然后再继续操作,版本策略确定如何进行加载新模型版本的过程。具体来说,在第一种情况下,我们可以确保我们的系统始终可用于传入客户的请求。此时,我们同时加载了两个模型版本,只有在加载完成后,Manager才会卸载旧版本,并且可以安全地在模型之间切换。另一方面,如果我们想通过不使用额外缓冲区来节省资源,我们可以选择保留数据。最后,当客户端请求模型的handle时,管理器返回Servable的handle。在接下来的部分中,我们将介绍如何使用TF服务提供卷积神经网络(CNN)。导出服务模型为TensorFlow构建的ML模型提供服务的第一步是确保它的格式正确,为此,TensorFlow提供了SavedModel类。SavedModel是TensorFlow模型的通用序列化格式,如果你熟悉TF,则可以使用TensorFlow Saver来保留模型的变量。TensorFlow Saver提供了将模型的检查点文件保存到磁盘或从磁盘恢复的功能。实际上,SavedModel包装了TensorFlow Saver,它是导出TF模型进行服务的标准方式。SavedModel object有一些很好的功能。首先,它允许你将多个元图保存到单个SavedModel对象,换句话说,它允许我们为不同的任务提供不同的图表。例如,假设你刚刚完成了模型的训练。在大多数情况下,要执行推理,你的图表不需要某些特定于训练的操作。这些操作可能包括优化器的变量,学习速率调度张量,额外的预处理操作等。此外,你可能希望为移动部署提供量化版本的图形。在此环境中,SavedModel允许你使用不同的配置保存图形。在我们的例子中,我们有三个不同的图形和相应的标签,如“训练”、“推理”和“移动”。此外,这三个图形为了提升内存效率还共享相同的变量集。就在不久前,如果我们想在移动设备上部署TF模型时,我们需要知道输入和输出张量的名称,以便向模型提供数据或从模型获取数据。这需要强制程序员在图的所有张量中搜索他们所需的张量。如果张量没有正确命名,那么任务可能非常繁琐。为了简化操作,SavedModel提供对SignatureDefs的支持,SignatureDefs定义了TensorFlow支持的计算的签名。它确定了计算图的正确输入和输出张量,也就是说使用这些签名,你可以指定用于输入和输出的确切节点。要使用其内置的服务API,TF Serving要求模型包含一个或多个SignatureDefs。要创建此类签名,我们需要提供输入,输出和所需方法名称的定义,输入和输出表示从字符串到TensorInfo对象的映射。在这里,我们定义了默认张量,用于向图表输入数据和从图表接收数据。目前,有三种服务API:分类,预测和回归。每个签名定义都与特定的RPC API相匹配,Classification SegnatureDef用于Classify RPC API,Predict SegnatureDef用于Predict RPC API等等依此类推。对于分类签名,必须有输入张量(接收数据)和两个可能的输出张量中的至少一个:类或分数。Regression SignatureDef只需要一个张量用于输入,另一个用于输出。最后,Predict signature允许动态数量的输入和输出张量。此外,SavedModel支持数据存储,以用于ops初始化依赖于外部文件的情况,它还具有在创建SavedModel之前清除设备的机制。现在,让我们看看我们如何在实践中做到这一点。设置环境在开始之前,我们需要从Github克隆此TensorFlow DeepLab-v3。DeepLab是谷歌最好的语义分割ConvNet,网络可以将图像作为输入并输出类似掩模的图像,该图像将某些对象与背景分开。该版本的DeepLab在Pascal VOC分段数据集上进行了训练,因此,它可以分割和识别多达20个类。如果你想了解有关语义分段和DeepLab-v3的更多信息,请查看深入深度卷积语义分段网络和Deeplab_V3。与服务相关的所有文件都存在于:./deeplab_v3/serving/。在那里,你会发现两个重要的文件:deeplab_saved_model.py和deeplab_client.ipynb。在进一步研究之前,请务必下载Deeplab-v3预训练模型。前往上面的GitHub存储库,单击checkpoints链接,你应该有一个名为tboard_logs /的文件夹,其中包含16645 /文件夹。现在,我们需要创建两个Python虚拟环境,一个用于Python 3,另一个用于Python 2,请确保安装必要的依赖项。你可以在serving_requirements.txt和client_requirements.txt文件中找到它们。你可能很好奇为什么需要两个Python env,因为我们的模型DeepLab-v3是在Python 3下开发的,而TensorFlow Serving Python API仅针对Python 2发布。因此,要导出模型并运行TF服务,我们使用Python 3 env 。请注意,你可以使用bazel中的Serving API放弃Python 2 env。有关更多详细信息,请参阅TF服务实例。完成这一步后,让我们从真正重要的事情开始吧。实例教程TensorFlow提供了一个易于使用的高级实用程序类使用SavedModel,类名为SavedModelBuilder。SavedModelBuilder类提供了保存多个元图,关联变量和数据的功能。让我们来看一个如何导出Deep Segmentation CNN模型进行服务的运行示例。如上所述,要导出模型,我们使用啦SavedModelBuilder类。它将生成SavedModel协议缓冲区文件以及模型的变量和资源。让我们剖析一下代码:# Create SavedModelBuilder class# defines where the model will be exportedexport_path_base = FLAGS.export_model_direxport_path = os.path.join( tf.compat.as_bytes(export_path_base), tf.compat.as_bytes(str(FLAGS.model_version)))print(‘Exporting trained model to’, export_path)builder = tf.saved_model.builder.SavedModelBuilder(export_path)SavedModelBuilder接收(作为输入)保存模型数据的目录。这里,export_path变量是为了连接export_path_base和model_version。因此,不同的模型版本将保存在export_path_base文件夹内的单独目录中。假设我们在生产中有我们模型的基础版本,但我们想要部署它的新版本。因为我们已经提高了模型的准确性,并希望为我们的客户提供这个新版本。要导出同一模型的不同版本,我们只需将FLAGS.model_version设置为更高的整数值即可。然后将在export_path_base文件夹中创建一个不同的文件夹(保存我们模型的新版本)。现在,我们需要指定模型的输入和输出Tensors。为此,我们使用SignatureDefs,签名定义了我们要导出的模型类型。它提供了从字符串(逻辑Tensor名称)到TensorInfo对象的映射。我们的想法是,客户端可以引用签名定义的逻辑名称,而不是引用输入/输出的实际张量名称。为了服务语义分段CNN,我们将创建一个预测签名。请注意,build_signature_def()函数采用输入和输出张量的映射以及所需的API。SignatureDef需要指定:输入,输出和方法名称,我们期望输入有三个值:一图像,另外两个张量指定其尺寸(高度和宽度)。对于输出,我们只定义了一个结果-分段输出掩码。# Creates the TensorInfo protobuf objects that encapsulates the input/output tensorstensor_info_input = tf.saved_model.utils.build_tensor_info(input_tensor)tensor_info_height = tf.saved_model.utils.build_tensor_info(image_height_tensor)tensor_info_width = tf.saved_model.utils.build_tensor_info(image_width_tensor)# output tensor infotensor_info_output = tf.saved_model.utils.build_tensor_info(predictions_tf)# Defines the DeepLab signatures, uses the TF Predict API# It receives an image and its dimensions and output the segmentation maskprediction_signature = ( tf.saved_model.signature_def_utils.build_signature_def( inputs={‘images’: tensor_info_input, ‘height’: tensor_info_height, ‘width’: tensor_info_width}, outputs={‘segmentation_map’: tensor_info_output}, method_name=tf.saved_model.signature_constants.PREDICT_METHOD_NAME))请注意,字符串‘image’,‘height’,‘width’和‘segmentation_map’不是张量。相反,它们是引用实际张量input_tensor,image_height_tensor和image_width_tensor的逻辑名称。因此,它们可以是你喜欢的任何唯一字符串。此外,SignatureDefs中的映射与TensorInfo protobuf对象有关,而与实际张量无关。要创建TensorInfo对象,我们使用实用程序函数:tf.saved_model.utils.build_tensor_info(tensor)。现在我们调用add_meta_graph_and_variables()函数来构建SavedModel协议缓冲区对象,然后我们运行save()方法,它会将模型的快照保存到包含模型变量和资源的磁盘。builder.add_meta_graph_and_variables( sess, [tf.saved_model.tag_constants.SERVING], signature_def_map={ ‘predict_images’: prediction_signature, })# export the modelbuilder.save(as_text=True)print(‘Done exporting!’)现在我们可以运行deeplab_saved_model.py来导出我们的模型。如果一切顺利,你将看到文件夹./serving/versions/1,请注意,“1”表示模型的当前版本。在每个版本子目录中,你将看到以下文件:·saved_model.pb或saved_model.pbtxt,这是序列化的SavedModel文件。它包括模型的一个或多个图形定义,以及签名定义。·变量,该文件夹包含图形的序列化变量。现在,我们已准备好启动我们的模型服务器。为此,请运行:$ tensorflow_model_server –port=9000 –model_name=deeplab –model_base_path=<full/path/to/serving/versions/>该model_base_path指的是输出模型保存,另外,我们不在路径中指定版本文件夹,模型版本控制由TF服务处理。生成客户端请求客户端代码非常简单,看一下:deeplab_client.ipynb。首先,我们读取要发送到服务器的图像并将其转换为正确的格式。接下来,我们创建一个gRPC存根,存根允许我们调用远程服务器的方法。为此,我们将实例化prediction_service_pb2模块的beta_create_PredictionService_stub类。此时,存根保持调用远程过程的必要逻辑,就像它们是本地的一样。现在,我们需要创建和设置请求对象。由于我们的服务器实现了TensorFlow Predict API,因此我们需要解析Predict请求。要发出Predict请求,首先,我们从predict_pb2模块中实例化PredictRequest类。我们还需要指定model_spec.name和model_spec.signature_name参数。该名称参数是当我们推出的服务器定义的“模型名称”的说法,而signature_name是指分配给逻辑名称signature_def_map()的参数add_meta_graph()函数。# create the RPC stubchannel = implementations.insecure_channel(host, int(port))stub = prediction_service_pb2.beta_create_PredictionService_stub(channel)# create the request object and set the name and signature_name paramsrequest = predict_pb2.PredictRequest()request.model_spec.name = ‘deeplab’request.model_spec.signature_name = ‘predict_images’# fill in the request object with the necessary datarequest.inputs[‘images’].CopyFrom( tf.contrib.util.make_tensor_proto(image.astype(dtype=np.float32), shape=[1, height, width, 3]))request.inputs[‘height’].CopyFrom(tf.contrib.util.make_tensor_proto(height, shape=[1]))request.inputs[‘width’].CopyFrom(tf.contrib.util.make_tensor_proto(width, shape=[1]))接下来,我们必须提供服务器签名中定义的输入数据。请记住,在服务器中,我们定义了一个Predict API来预期图像以及两个标量(图像的高度和宽度)。为了将输入数据提供给请求对象,TensorFlow提供了实用程序tf.make_tensor_proto(),此方法是从Python/numpy创建的TensorProto对象,我们可以使用它将图像及其尺寸提供给请求对象。看起来我们已经准备好调用服务器了。为此,我们调用Predict()方法(使用存根)并将请求对象作为参数传递。gRPC支持:同步和异步调用。因此,如果你在处理请求时想要做一些工作,我们可以调用Predict.future()而不是Predict()。# sync requestsresult_future = stub.Predict(request, 30.)# For async requests# result_future = stub.Predict.future(request, 10.)# Do some work…# result_future = result_future.result()现在我们可以获取并享受结果。本文作者:【方向】阅读原文本文为云栖社区原创内容,未经允许不得转载。 ...

March 27, 2019 · 1 min · jiezi

node之本地服务器图片上传

在自己做一个简单的后台管理系统时,用的是node作本地数据库,然后用了Element-ui的upload组件来实现图片的上传,中间有遇到那么点小坑,这里记录下,比较坑的一点就是,不知道文件的命名不能带空格,然后改了好久1.index.vue文件这里的话,就是简单点的使用图形界面框架Element-ui的上传组件,然后,action就是服务器端的地址,我这里使用了代理,将localhost:8080代理到你使用node作为服务器的地址就可以了<template> <div class=“avatar”> <img :src=“avatar?avatar:defaultImg” /> </div> <el-upload class=“upload-demo” drag action=“http://localhost:8080/api/upload” :show-file-list=“false” :on-success=“uploadImgSuccess” > <i class=“el-icon-upload”></i> <div class=“el-upload__text”>将文件拖到此处,或<em>点击上传</em></div> </el-upload></template><script>import defaultImg from ‘@/assets/img/avatar.png’export default{ data() { return { avatar: ’’ } }, methods: { uploadImgSuccess(res) { this.avatar = res.result.url; } }}</script>2.代理文件我这里使用的是vue-cli3脚手架来搭建的项目,所以,自己在项目的根目录下创建一个vue.config.js来做一些配置module.exports = { devServer: { port: 8080, headers: { }, inline: true, overlay: true, stats: ’errors-only’, proxy: { ‘/api’: { target: ‘http://127.0.0.1:3000’, changeOrigin: true // 是否跨域 } } },};3.node服务器端文件这里很重要的一点就是设置静态资源目录app.use(’/serverImage’, express.static(path.join(__dirname, ‘serverImage’)));对图片上传进行了方法的封装const fs = require(‘fs’);const path = require(‘path’);/* formidable用于解析表单数据,特别是文件上传 /const formidable = require(‘formidable’);/ 用于时间格式化 /const formatTime = require(‘silly-datetime’);/ 图片上传 /module.exports = (req, res) => { / 创建上传表单 / let form = new formidable.IncomingForm(); / 设置编码格式 / form.encoding = ‘utf-8’; / 设置上传目录(这个目录必须先创建好) / form.uploadDir = path.join(__dirname, ‘../serverImage’); / 保留文件后缀名 / form.keepExtensions = true; / 设置文件大小 */ form.maxFieldsSize = 2 * 1024 1024; / 格式化form数据 / form.parse(req, (err, fields, files) => { let file = files.file; / 如果出错,则拦截 / if(err) { return res.send({‘status’: 500, msg: ‘服务器内部错误’, result: ‘’}); } if(file.size > form.maxFieldsSize) { fs.unlink(file.path); return res.send({‘status’: -1, ‘msg’: ‘图片不能超过2M’, result: ‘’}); } / 存储后缀名 / let extName = ‘’; switch (file.type) { case ‘image/png’: extName = ‘png’; break; case ‘image/x-png’: extName = ‘png’; break; case ‘image/jpg’: extName = ‘jpg’; break; case ‘image/jpeg’: extName = ‘jpg’; break; } if(extName.length == 0) { return res.send({‘status’: -1, ‘msg’: ‘只支持jpg和png格式图片’, result: ‘’}); } / 拼接新的文件名 / let time = formatTime.format(new Date(), ‘YYYYMMDDHHmmss’); let num = Math.floor(Math.random() * 8999 + 10000); let imageName = ${time}_${num}.${extName}; let newPath = form.uploadDir + ‘/’ + imageName; / 更改名字和路径 / fs.rename(file.path, newPath, (err) => { if(err) { return res.send({‘status’: -1, ‘msg’: ‘图片上传失败’, result: ‘’}); } else { return res.send({‘status’: 200, ‘msg’: ‘图片上传成功’, result: {url: http://localhost:3000/serverImage/${imageName}}}); } }) })};方法的调用const express = require(’express’);const router = express.Router();const uploadImg = require(’./uploadImg’);/ 上传图片 /router.post(’/upload’, (req, res) => { uploadImg(req, res);});module.exports = router;服务器端入口文件const express = require(’express’);const app = express();const path = require(‘path’);/ body-parser是一个HTTP请求体解析的中间件 * 使用这个模块可以解析JSON、Raw、文本、URL-encoded格式的请求体 * /const bodyParser = require(“body-parser”);const dataBaseOperate = require(’./database/operate’);/ 以application/json格式解析数据 /app.use(bodyParser.json());/ 以application/x-www-form-urlencoded格式解析数据 /app.use(bodyParser.urlencoded({ extended: false }));/ 设置静态资源目录 */app.use(’/serverImage’, express.static(path.join(__dirname, ‘serverImage’)));app.use(’/api’, dataBaseOperate);app.listen(3000, () => { console.log(‘server is listening to http://localhost:3000’)});4.小结下对于接口文件的返回,这里使用了body-parser这个中间件来对node返回的body进行json格式的解析很重要的一点就是设置静态资源目录,不然的话就会报错,找不到文件或者文件夹设置静态资源目录,用于存储服务器端的静态资源文件app.use(’/serverImage’, express.static(path.join(__dirname, ‘serverImage’)));然后就是对文件的命名不能出现空格文件的链接可以使用本地服务器端的url地址正在努力学习中,若对你的学习有帮助,留下你的印记呗(点个赞咯^_^)往期好文推荐:判断ios和Android及PC端webpack打包(有面试题)纯css实现瀑布流(multi-column多列及flex布局)实现单行及多行文字超出后加省略号 ...

March 26, 2019 · 2 min · jiezi

Matchvs多节点功能上线

为了满足不同区域的用户需求,Matchvs现已正式上线多节点功能(正式版),本次上线的服务器节点包括北京、上海、广州三个国内节点。部分游戏类型(如fps、格斗及竞速类等)对于延迟容忍极低,就近节点连接可以有效降低延迟。Matchvs开放了自选多节点服务,开发者可以根据游戏要求给游戏开通该服务。开通多节点服务后,可以实现:1.玩家根据节点延迟情况,手动切换节点进行游戏。2.游戏里可以根据匹配情况,自动做节点切换策略。需注意是,玩家会在各节点分别匹配。若游戏内玩家数量过少,可以让游戏内自动做节点切换策略,以兼顾匹配成功率与低延时。若游戏对延时要求不高(如棋牌,回合制游戏等),则不建议您开启多节点服务。1. 多节点开通教程如需开启多节点服务,可以前往控制台 - 游戏列表 - 设置:成功启用后,即可对接 SDK 多节点功能,gameServer 无变化。在 Matchvs SDK中 使用接口获取节点信息,并切换到指定的节点。2. 多节点接口说明initinit 接口和之前的 init 接口是同一个,这里只是在 init 接口中新增了一个参数 threshold,只有传了该参数,才能获取节点列表和使用指定节点登录。getNodeList获取节点列表信息。在 init 成功后才能使用,并且init必须传入 threshold参数。否则返回值为 null。engine.getNodeList()无请求参数返回值说明 登录接口和前面 API文档描述的登录接口是同一个。只是加了一个 nodeID 参数,如果不传这个参数或者传入的参数为0,login 则使用默认节点登录。否则会使用指定的 nodeID登录,nodeID 必须是从 getNodeList 接口获取的有效ID。changeNode切换到指定节点中,切换节点只能在拥有多个节点的情况下使用,并且只能切换到 getNodeList 获取到的节点中。所有在 init 的时候设置好 threshold 参数。切换节点是指在使用 login 接口登录了默认节点后,想换一个节点就可以使用 changNode 接口切换到指定节点,所以,要使用 changeNode 接口必须是在登录后。engine.changeNode(args)返回值说明开发者如需体验过节点功能,需要下载SDK v3.7.9及以上版本,后续其它国内与国外的区域节点也将陆续上线。返回值说明开发者如需体验过节点功能,需要下载SDK v3.7.9及以上版本,后续其它国内与国外的区域节点也将陆续上线。Matchvs,24H轻松打造标准多人实时在线游戏,一个SDK解决服务器购买、联网&数据库开发、后期运维、高并发稳定问题。

March 13, 2019 · 1 min · jiezi

2019阿里云开年Hi购季域名与商标分会场全攻略!

2019阿里云云上Hi购季活动已经于2月25日正式开启,从已开放的活动页面来看,活动分为三个阶段: 2月25日-3月04日的活动报名阶段、3月04日-3月16日的新购满返+5折抢购阶段、3月16日-3月31日的续费抽豪礼+5折抢购阶段。做为整个Hi购季非常重要的一个分会场——域名与商标分会场,3月04开放售卖!下面,云栖社区小编就为各位开发者分享该会场的攻略:丨域名与商标分会场活动阵地:https://www.aliyun.com/acts/product-section-2019/domain丨关键词:低至5折、报名购买参与满返、最高返¥200丨该会场必买爆款清单一、热门产品专区行业TOP爆款,限时劲爆优惠域名回购咨询服务费特惠活动规则1、【活动对象】阿里云官网注册会员用户。2、【活动时间】2019年3月1日至2019年3月31日3、【活动规则】(1)、活动期间,用户通过阿里云官网提交域名回购需求,可享受服务咨询费0.01元/个优惠价格。(2)、本活动中的“服务咨询费”的优惠价格仅为需求订单价格,不包括用户购买域名的价格。4、【名词及解释】(1)、“阿里云官网”,是指包含域名为www.aliyun.com的网站以及阿里云客户端,如APP,但阿里云国际站,包括alibabacloud.com以及所有下属页面和jp.aliyun.com以及所有下属页面除外。(2)、除非有相反证据证明外,用户参与活动所获得的全部权益和相应责任,均归属于参与活动的该阿里云账号所对应的实名认证主体。(3)、活动中的“天”、“工作日”等均指该日的0点至24点(北京时间)。(4)、阿里云可以根据活动的实际情况对活动规则进行变动或调整,相关变动或调整将公布在活动页面上,并于公布时即时生效;但不影响用户在活动规则调整前已经获得的权益。二、商标服务享满返全场满返云产品通用代金券自助注册申请:满600返50满1000返100满2000返200(封顶)专家辅助申请、担保注册申请、商标续展:满2000返2001分钱委托阿里云回购心仪域名回购咨询服务费0.01元商标满返活动规则1、【活动对象】满足以下全部条件的阿里云会员用户:(1)、阿里云官网注册会员;(2)、通过域名与商标分会场活动页面主动报名,领取参与活动资格。2、【活动时间】2019年3月1日—2019年3月31日。3、【活动规则】(1)、活动期间,用户新购商标服务产品,且一次性有效消费金额达到如下级别的,可获得对应金额的云产品通用代金券:①一次性购买商标自助注册服务满600元,返50元云产品通用代金券,②一次性购买商标自助注册服务满1000元,返100元云产品通用代金券,③一次性购买商标自助注册服务满2000元,返200元云产品通用代金券(封顶)。④一次性购买商标指定服务(专家辅助申请、担保注册申请)满2000元及以上的,可获得200元云产品通用代金券。(2)、用户参与本活动所获得的代金券,将于活动结束后7个工作日内统一发放至对应的阿里云账户。代金券自发放之日起1个月内有效,过期自动作废。(3)、代金券仅限用户用于本账户下的新购、升级预付费云产品使用(不包括域名、云通信、虚拟主机、云市场产品、专有云产品),不得转让或出售,或以其他方式换取利益(4)、本活动仅适用于主动报名用户,未报名参加活动的用户在活动期间的消费金额均不享受返代金券优惠。(5)、本活动不与其他活动或优惠叠加适用。(6)、用户参加活动所购买的相关产品及所获得的相应权益,仅限本账号使用,不得转让、出售或以其他方式换取利益。(7)、除特殊情况外,用户参加本活动购买的产品,不支持退订。如因特殊原因发生退订的,退订前需交回通过本活动所享受的相关权益,例如:补足差价、退还已使用的代金券金额、交回奖品等。(8)、如用户在活动中存在隐瞒、虚构、作弊、欺诈或通过其他非正常手段规避活动规则、获取不当利益的行为,例如:作弊领取、恶意套现、网络攻击、虚假交易等,阿里云有权收回相关权益、取消用户的活动参与资格,撤销违规交易,必要时追究违规用户的法律责任。(9)、活动名称仅为方便用户理解参考使用,不具有效力,实际活动内容以具体活动规则为准。4、【名词及解释】(1)、“阿里云官网”,是指包含域名为www.aliyun.com的网站以及阿里云客户端,如APP,但阿里云国际站,包括alibabacloud.com以及所有下属页面和jp.aliyun.com以及所有下属页面除外。(2)、本活动中的“指定商标服务”,是指“专家辅助申请服务”、“担保注册申请服务”两种商标服务。(3)、“有效消费金额”,是指用户的实际付现消费金额。有效消费金额不包括:用户使用代金券、优惠券、提货券等非实付方式的消费金额;具体活动规则中明确排除的其他消费金额(如有);退款金额等。(4)、“一次性有效消费金额”,是指单个订单中所包括指定商标服务的实际付现消费金额的总和。(5)、“云产品”,是指阿里云官网售卖的国内节点(不含香港)的产品和服务,但不包括域名、虚拟主机、云市场产品 、专有云产品,云通信产品。(6)、除非有相反证据证明外,用户参与活动所获得的全部权益和相应责任,均归属于参与活动的该阿里云账号所对应的实名认证主体。(7)、活动中的“天”、“工作日”等均指该日的0点至24点(北京时间)。(8)、阿里云可以根据活动的实际情况对活动规则进行变动或调整,相关变动或调整将公布在活动页面上,并于公布时即时生效;但不影响用户在活动规则调整前已经获得的权益。三、域名限时折扣联合放价狂欢,注.cn免费送.top域名.cn域名,活动价≥5个,19元/首年;≥50个,16元/首年,注.cn即送同前缀.top域名.com,55元/首年,新用户25元/首年.xin,活动价32元/首年,劲省56元.shop,活动价13元/首年,劲省29元.co,活动价30/2年,劲省280元.网址,活动价1400元/首年,劲省1400元.ltd,活动价9元/首年,劲省14元.art,活动价17元/首年,劲省8元域名注册优惠活动规则1、【活动对象】阿里云官网注册会员用户。2、【活动时间】2019年3月1日至2019年3月31日3、【活动规则】(1)、活动期间,用户新注册/续费指定后缀的域名,且符合相应条件的,可享受不同的优惠价格,包括:①用户通过单个订单批量新注册.cn英文域名的,可享受如下首年注册价格优惠:5个≤单笔订单.cn英文域名新注册量<50个,首年注册优惠价为19元/个;单笔订单.cn英文域名新注册量≥50个,首年注册优惠价为16元/个。②用户新注册/续费.xin域名,可享受如下优惠价格优惠:新注册.xin域名,首年注册优惠价为32元/个;续费.xin域名,续费优惠价格为39元/个/年。(2)、活动期间,用户新注册.cn域名的,可同时以0元/首年的价格注册同前缀.top域名,具体如下:①单域名注册,在域名check结果页,可一键添加同前缀.cn和.top域名到域名购物车,.top域名0元注册;②批量查询注册,使用基础版查询时,也可一键添加同前缀.cn和.top域名到域名购物车,.top域名0元注册;③域名控制台–批量操作–域名批量注册导入的.cn域名不能享受该活动,域名特殊大客户不能享受该活动。④如同前缀.top域名已被注册的,用户不再享受本活动福利;⑤用户单独分别注册.cn域名和同前缀的.top域名的,将不能享受本活动福利。(3)、本活动中的“新注册域名”的优惠价格不包括用户通过删除预订方式注册的域名。(4)、本活动结束后2小时内仍未完成支付的订单将自动关闭,优惠价格失效。(5)、本活动不与其他活动或优惠(例如:代金券、口令等)叠加适用。(6)、由于域名产品的特殊性,用户一旦完成域名新注册、续费,均不支持退订。(7)、如用户在活动中存在隐瞒、虚构、作弊、欺诈或通过其他非正常手段规避活动规则、获取不当利益的行为,例如:作弊领取、恶意套现、网络攻击、虚假交易等,阿里云有权收回相关权益、取消用户的活动参与资格,撤销违规交易,必要时追究违规用户的法律责任。(8)、活动名称仅为方便用户理解参考使用,不具有效力,实际活动内容以具体活动规则为准。4、【名词及解释】(1)、“阿里云官网”,是指包含域名为www.aliyun.com的网站以及阿里云客户端,如APP,但阿里云国际站,包括alibabacloud.com以及所有下属页面和jp.aliyun.com以及所有下属页面除外。(2)、“白金词域名(溢价域名)”,是各个域名注册局判断具有升值潜力的精品高价域名,其注册、续费价格均高于普通域名。(3)、本活动中涉及“打折”、“折扣”、“×折”或“省××元”,是指将本活动期间的域名注册/续费价格,与该域名在无任何活动期间的日常注册/续费价格进行比较后,所获得的比较结果。(4)、活动涉及的“划线价格”,通常是指该产品曾经展示过的销售价,并非原价,仅供参考。但具体活动页面单独对划线价格进行说明的,以其表述为准。(5)、除非有相反证据证明外,用户参与活动所获得的全部权益和相应责任,均归属于参与活动的该阿里云账号所对应的实名认证主体。(6)、活动中的“天”、“工作日”等均指该日的0点至24点(北京时间)。(7)、阿里云可以根据活动的实际情况对活动规则进行变动或调整,相关变动或调整将公布在活动页面上,并于公布时即时生效;但不影响用户在活动规则调整前已经获得的权益。四、白金词5折起低至5折,.xyz6-9数字域名仅4元/首年彰显品牌地位,黄金流量入口.art,5.5折,.beer,5.5折.xin,8折.ltd,8.5折.ink,8.8折.design,8.8折五、狂欢已“种草”,有问题咨询怎么办?面对如此折扣力度,丰富的促销活动,如果有问题建议一定要提前向云小二询问,避开购买高峰期,售前咨询:95187转1。云小二会为大家提供全方位的购买咨询、精准的配置推荐 、灵活的价格方案、1对1的贴心服务。阅读原文本文为云栖社区原创内容,未经允许不得转载。

March 13, 2019 · 1 min · jiezi

Serverless 风暴来袭,前端工程师如何应对?

阿里妹导读:尽管大部分前端的工作并不涉及server,但最近半年serverless这个词汇以及其引发的热烈的讨论,深深触动了阿里巴巴高级前端技术专家伐薪。作为接触前端十余载的老开发,伐薪认为serverless可能会是接下来引起前端领域革命性变化的技术之一。今天,伐薪将为大家梳理serverless的历史发展进程以及对前端的影响,希望对前端工程师有所启发。上图是serverless 这个词最近5年在 google 的搜索趋势,可以看到最近半年已经达到巅峰。历史上前端领域的重要技术革命Ajax 的诞生先来回顾一下前端技术领域的重要历史节点,第一个节点是2005年,google的Jesse James Garrett 发表了一篇文章——《Ajax:Web应用程序的新方法》,首次发布了Ajax 这个新的词汇(准确说并不是新的技术,只是新的词汇),当时我还在读大二,虽然ajax不是什么新的技术,只是对XmlHttpRequest等技术的包装,但是这个技术被google宣传之后成为全球web开发的标杆,间接促进了富客户端应用(RIA)和单页应用(SPA)的流行,这些应用大都具备丝滑般的体验(局部刷新),并一直伴随着web 2.0的发展,ajax的深入人心,使得前端js的工作更加复杂和重要,专业分工越来越细,间接促进了专职的前端开发人员这一角色诞生,在此之前,web开发并不区分服务端和浏览器端的工作,因此ajax是前端领域的第一次重要事件。Nodejs 对前端规范化和工程化的促进接下来对前端变化最大的一个里程碑事件是2009年诞生的 nodejs(包括common js及npm)的出现和流行,它对前端领域的重要意义并不仅仅是让前端可以快速用js写server那么简单,个人认为它最大的贡献反而是commonjs、npm以及其便捷开发体验促进的前端工程化,它使得前端开始从刀耕火种的和传统软件工程格格不入的部署方式,发展为接近传统企业应用的研发模式,在此之前,前端开发在资源引用、依赖管理以及模块规范上缺乏有效的工具和标准,但是nodejs流行以后,基于commonjs的模块及npm的包部署和依赖管理成为主流(类似java的maven体系),并诞生了多种基于nodejs开发的cli工具辅助前端开发(如grunt、gulp),npm目前是全球最大的包管理仓库,并且成为前端项目的包依赖管理事实标准。而webpack的出现,又使得前端代码的部署更加简便,让前端可以以类似java jar包的形式发布应用(bundle),而不管项目中是何种类型的资源。React 的组件化及vdom理念第三个革命性事件是2013年开始出现的react,尽管web components标准在此之前早已发布,但是真正让组件化理念深入人心并且应用最广的库是react,它还至少有两点特性足以让它成为历史上最具前瞻性的前端库,第一个特性是vdom的出现,在此之前,所有的ui库,都直接与dom关联,但是react在UI创建与渲染引擎之间,增加了一个中间层——vdom(一个使用轻量级json描写UI结构的协议),除了改善了其本身的dom diff性能之外,还有一个重大意义就是UI的编写与渲染开始分离,一次编写,多端渲染的UI得以实现,这个多端包括server端、移动端、pc端以及其他需要展示UI的设备,之后的react native以及weex都是这一分层思想的受益者。除了vdom之外,react还有一个重要的理念非常超前,即UI是一个函数(类),函数输入一个state,一定返回确定的视图,在此之前,大部分框架和库,都会把UI分离成一个html片段(通常支持模板写法以渲染数据),一个为该html片段绑定事件的js,尽管这样比较好理解,但是react对UI这种抽象却反映了UI的实际本质,并且这种函数式理念,在后面可以看到,将与faas及serverless技术产生美妙的碰撞。react 的诞生对此后,甚至此前的框架和库都产生了深远的影响,包括不限于angular和vue都陆续采纳了它很多技术思想,并且成为前端开发领域目前已经趋于稳定的屈指可数的几个技术选型之一。再来总结一下,ajax使得前端的角色逐渐分离出来,nodejs促进了前端的开发模式向传统编程语言靠近(工程化),react的出现,基本结束了后端常常对前端”技术变化快“的吐槽,至此,前端的技术体系逐步成熟和标准化。serverless 理念与前端的关系那么为什么说下一次对前端技术领域有较大影响的理念是serverless呢,事实上,尽管serverless这个词汇由亚马逊提出来还不到几年,但是这个理念并不是什么爆炸性的新理念,在早期,cdn还不普及的时候,web工程师会把js资源和视图文件(可能是静态也可能是动态的)传到服务器,那个时候前端是需要关心服务器的,但是cdn及回源策略的普及,工程及搭建系统的大规模使用,使得前端可以快速把一个js或者静态文件扔到cdn节点,通过回源机制(cdn回源到一个动态服务),半动态的视图层渲染也成为可能,在这整个过程,前端开发无需关心任何服务器的知识,也不知道cdn有多少节点,如何做负载均衡,做gslb的,也不需要知道qps多少,一个cdn可以放各种业务各种开发的资源,可以说cdn是serverless理念的的先行者。回到应用部署,在前几年nodejs刚流行的时期,已有开发者意识到应用与机器的部署与运维成本对业务方会是个问题,出现了一些容器化的思想,比如cbu在15年出的naga,在这个naga容器里,业务逻辑是一个个插件,容器负责请求的路由分发,负载及稳定性管理,业务方只需要编写并上传最直接的业务代码即可,对业务方来说是实现了serverless的理念,因为naga的维护者帮你解决了部署及运维的问题。再说对前端息息相关的页面搭建系统以及bff层,无论是各种搭建系统(如斑马、积木盒子、TMS),还是基于graphQl的平台,还是通过web ide快速编写api gateway的产品——如cbu的mbox,都让业务开发只关心业务逻辑,无需关心部署运维知识,它们一定程度上体现了serverless的理念。serverless 将对前端的影响综上所述,前端早已与serverless产生了联系,但是很多人还没感知,接下来,serverless显示化地爆发将给前端带来更为深远的影响,主要体现在三个方面。前端将会重新回归到web应用工程师这一职能在最前面说了,前端是社会分工的细化,大约起源于2007年左右,在此之前是没有专门的前端开发角色的,通常称作web工程师或网站工程师,早期的网页大都是服务器渲染,使用asp、php、jsp等server page技术,js仅仅是web工程师需要掌握的小小技能之一,但是随着web 2.0及互联网、移动互联网、电子商务的发展,需要专门的人专注于编写具备很好兼容性和体验的UI,因此逐渐产生了专注于浏览器及移动端的前端工程师。但是前端技术领域逐渐趋于稳定,伴随着十几年的发展,各种开箱即用的库、垂直方案以及工程手段唾手可得,甚至目前出现了一些辅助工具可以把设计师的视觉稿生成UI代码,前端可以安心并且以非常低的成本编写UI和业务逻辑,而不用耗费大量精力在选型、造轮、还原视觉、处理兼容性、性能优化、调试和部署上,这种情况,前后端工种分离造成的协同成本反而放大了,因为在前后端角色分离的情况下,后端往往还会充当bff层的角色,比如为前端表现层封装各种api gateway,经常出现相互等待、联调协议的情况,而且bff层通常只是一些数据的加工,其他的角色经过短期的培训可以快速上手,因此前端一直在尝试接入到server端的bff层。在15年前端开始推广使用nodejs来部署应用,阿里内外也出现了不少nodejs的框架,如业界的express,在生产环境,包括给买家、商家以及内部人员使用的系统,有不少使用了nodejs,但是到今年2019年,再来回顾一下,发现这个数字并没有超出预期。造成这一现象的原因,个人认为归根到底还是因为分工太细导致的前端对服务器知识的缺乏,nodejs本身的定位是服务器技术,本质上在服务器要面对的问题与java无异,现有的前端jd招聘的人才,鲜有能在服务器上工作游刃有余的人,除非专门招的nodejs人才,server服务的长期运行会暴露很多问题,比如接口很慢,进程core,cpu飙升,内存泄漏等,另外负载均衡、扩缩容,高并低延等知识,大部分前端都是没有这些经验的。云计算的本质就是要让业务开发专注于业务逻辑,业务之下的硬件及软件设施都是按需采买,开箱即用,而serverless理念及相关技术,将使得开发人员不再需要关心应用及机器的问题,甚至连流量能不能撑住也不用关心了,它能自动扩缩容,因此,未来web开发人员的运维成本会大幅降低,前端也可介入到bff层的开发,而后端可以聚焦于数据处理、业务逻辑与算法。这一变革符合研发效能提升的背景,未来的云设施将会做得非常厚,非常专业、稳定,而前台开发人员可以快速地,最低成本地在云设施上建立业务逻辑,前端和服务器的前端(对整个请求链路来说,前端是相对的,只要离客户请求更近的角色都可以称自己为前端),分工将没那么明确,以前的浏览器端的前端,将逐步承担一部分服务器端接入层以及bff层的工作,返璞归真,回到历史上曾经的web开发工程师角色,这是对前端最大的一个变革。当然,serverless技术让前端回归到传统的web层,不代表前端不用掌握服务器知识了,掌握操作系统内核及网络编程知识仍有助于你编写高性能、高可用的业务应用。实时SSR将成为展示端UI的主要开发模式最早的web开发,其实处理UI都是以服务器渲染为主,比如perl、php等动态网页技术,但是在前端逐渐成为一个工种开始负责了绝大部分UI开发,并且技术域逐渐缩小到客户端范围之后,网页静态化以及客户端的渲染逐渐成为主流。但是这种模式对用户体验肯定是有问题的,导致了较多的白屏时间,而由于新的前端库如react和vue在vdom这层的抽象,服务器渲染的技术成本更低,因此SSR在最近几年,又逐步开始流行。但是SSR的难点恰恰是前面说的,服务器端人才的匮乏,虽然nodejs和vdom的普及提升了SSR的实施效率,但由于服务器知识的缺乏,通常只有少部分具备综合知识的前端会深入的实践这一领域。serverless技术的普及将把这个问题消除掉,借助于serverless技术,前端可以快速搭建一个ssr的场景,在服务器取数,在服务器渲染,直出html给到客户端,而不用关心这个渲染服务能否扛得住流量,会不会挂掉,这些事情云设施供应商会去解决。在前面说过,react有一个核心理念就是把UI看成函数,如果说一个页面是多个组件组成的,那一个组件是函数,我们可以把一个页面看成是多个函数的组合,不同函数的组合,组合成不同的导购场景,如果把一个函数看成一个微服务,一个场景就是微服务的聚合,这恰恰是faas的理念。通过serverless低成本地实时ssr,可以让客户体验更好,借助算法和大数据,还可以快速实现UI的千人n面,构建真正的导购大脑。基于场景的云开发(web ide)将成为主流开发模式在提到serverless技术的时候,有一个关联的领域不得不提,那就是web ide,很多互联网大型企业把一个web ide当成了云的基础设施并且大力投资,这是为何?个人认为有两个原因。第一个是因为serverless目前在业界使用以垂直场景为主,他们有一个共同点,就是代码足够标准、规范,场景较为垂直,代码复杂度不是很大,而且借助web ide可以快速地与云平台结合,做到一键发布,因此这种场景,是比较适合轻量的在线编码到部署全链路打通的。另一个原因是,目前所有的云设施解决的是业务运行问题,但是软件开发有一个非常大但是大部分人可能会忽略的痛点,那就是环境问题,相信很多人都有那种clone别人的项目但是废了九牛二虎之力都无法启动的问题,因为要装各种环境啊?另外就是和别人联调的时候,是不是因为各种环境部署缺失的问题,联调效率很低?借助容器如docker等技术,软件的运行及调试环境,可以快速地移植给别人复用,而目前基于js的代码编辑器已经非常强大,vscode editor就是基于js编写并且沉淀出一个库 Monaco Editor,因此可以说,大部分认为web ide可能在语法提示、智能感知上比不上本地ide的想法是过时了。同时web ide可以快速地与平台集成,深入定制,打通业务平台,一键部署,极大地提升研发效率。web ide还能解决跨地办公的问题,因为解决了环境准备这一老大难问题,你可以在家里,在公司,甚至在火车上,快速编写并交付代码。因此未来的paas平台,都将关联一个深度定制的web ide,需要编写业务逻辑时,一个连接跳转到web ide即可编码,完全无需关心本地环境问题,做到真正的envless。比如你要开发一个TMS模块,那么点击”新建“,跳到了web ide,代码会帮你初始化好,点击运行,会在云端启动服务器运行该组件,编写好之后,一键即可发布到TMS。对于各种faas、api gateway系统以及其他云服务,都会一样,web ide将成为企业云化的基础设施。尽管阿里云目前还未发布媲美cloud9以及coding.net的web ide,但是很欣喜地看到集团内部已经涌现出一些优秀的产品,如aone的ide,以及数据平台的app studio,其体验已经接近业界顶级水准。结语在云计算领域,serverless将会掀起一场革命,即使看起来与这一领域关联不大的前端,也会经受即ajax、nodejs以及react之后的又一重大变革,你做好应对了吗?本文作者:伐薪阅读原文本文来自云栖社区合作伙伴“阿里技术”,如需转载请联系原作者。

March 13, 2019 · 1 min · jiezi

微服务的消费 | 从0开始构建SpringCloud微服务(11)

照例附上项目github链接本项目实现的是将一个简单的天气预报系统一步一步改造成一个SpringCloud微服务系统的过程。本章主要讲解微服务的消费。微服务的消费模式微服务的消费模式主要有:服务直连模式客户端发现模式服务端发现模式下面我们主要讲解客户端发现模式,以及服务端发现模式。客户端发现模式客户端发现模式的具体流程如下:1)服务实例启动后,将自己的位置信息提交到服务注册表中。2)客户端从服务注册表进行查询,来获取可用的服务实例。3)客户端自行使用负载均衡算法从多个服务实例中选择出一个。服务端发现模式服务端发现模式与客户端发现模式的区别在于:服务端发现模式的负载均衡由负载均衡器(独立的)来实现,客户端不需要关心具体调用的是哪一个服务。微服务的消费者下面我们价格介绍一些常见的微服务的消费者。HttpClientHttpClient是常见的微服务的消费者,它是Apache Jakarta Common 下的子项目,可以用来提供高效的、最新的、功能丰富的支持 HTTP 协议的客户端编程工具包,并且它支持 HTTP协议最新的版本和建议。RibbonRibbon是一个基于HTTP和TCP的客户端负载均衡工具,它基于Netflix Ribbon实现。通过Spring Cloud的封装,可以让我们轻松地将面向服务的REST模版请求自动转换成客户端负载均衡的服务调用。Ribbon常与Eureka结合使用。在典型的分布式部署中,Eureka为所有的微服务提供服务注册,Ribbon提供服务消费的客户端,含有许多负载均衡的算法。FeignFeign是一个声明式的Web Service客户端,它的目的就是让Web Service调用更加简单。Feign提供了HTTP请求的模板,通过编写简单的接口和插入注解,就可以定义好HTTP请求的参数、格式、地址等信息。而Feign则会完全代理HTTP请求,我们只需要像调用方法一样调用它就可以完成服务请求及相关处理。Feign整合了Ribbon和Hystrix(关于Hystrix我们后面再讲),可以让我们不再需要显式地使用这两个组件。总起来说,Feign具有如下特性:可插拔的注解支持,包括Feign注解和JAX-RS注解;支持可插拔的HTTP编码器和解码器;支持Hystrix和它的Fallback;支持Ribbon的负载均衡;支持HTTP请求和响应的压缩。集成Feign本节我们主要讲解如何集成Feign,实现微服务的消费功能。添加配置pom.xml配置文件,添加如下依赖。 <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-feign</artifactId> </dependency> application.yml文件,添加如下配置服务的名称与工程的名称一致,并且设置请求一个服务的connect与read的超时时间。spring: application: name: micro-weather-eureka-client-feigneureka: client: service-url: defaultZone: http://localhost:8761/eureka/feign: client: config: feignName: connectTimeout: 5000 readTimeout: 5000添加注解添加@EnableFeignClients注解,启动Feign功能。package com.demo;import org.springframework.boot.SpringApplication;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.boot.web.servlet.ServletComponentScan;import org.springframework.cloud.client.discovery.EnableDiscoveryClient;import org.springframework.cloud.netflix.feign.EnableFeignClients;import org.springframework.scheduling.annotation.EnableScheduling;//@ServletComponentScan(basePackages=“com.demo.web.servlet”)@SpringBootApplication@EnableDiscoveryClient@EnableScheduling@EnableFeignClientspublic class Sifoudemo02Application { public static void main(String[] args) { SpringApplication.run(Sifoudemo02Application.class, args); }}创建Feign客户端创建一个Feign客户端,通过其CityClient的接口,可以调用城市数据API微服务mas-weather-city-eureka中的cities接口,返回城市列表。package com.demo.service;import java.util.List;import org.springframework.cloud.netflix.feign.FeignClient;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import com.demo.vo.City;//创建一个Feign客户端 获取城市数据微服务中的城市列表信息@FeignClient(“msa-weather-city-eureka”)public interface CityClient { @RequestMapping(value="/cities",method=RequestMethod.GET) List<City> listCity()throws Exception;}使用Feign客户端@RestControllerpublic class CityController{ @Autowired private CityClient cityClient; @GetMapping("/cities") public List<City> listCity(){ List<City> cityList=cityClient.listCity(); return cityList; }}测试先启动Eureka服务端,然后启动被请求的微服务——城市数据API微服务,最后启动Feign客户端。 ...

March 11, 2019 · 1 min · jiezi

实现简单的Tomcat | Tomcat原理学习(1)

缘起用了那么久tomcat,突然觉得自己对它或许并没有想象中的那么熟悉,所以趁着放假我研究了一下这只小猫咪,实现了自己的小tomcat,写出这篇文章同大家一起分享!照例附上github链接。项目结构项目结构如下:实现细节创建MyRequest对象首先创建自定义的请求类,其中定义url与method两个属性,表示请求的url以及请求的方式。其构造函数需要传入一个输入流,该输入流通过客户端的套接字对象得到。输入流中的内容为浏览器传入的http请求头,格式如下:GET /student HTTP/1.1Host: localhost:8080Connection: keep-alivePragma: no-cacheCache-Control: no-cacheUpgrade-Insecure-Requests: 1User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.117 Safari/537.36Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,/;q=0.8Accept-Encoding: gzip, deflate, brAccept-Language: zh-CN,zh;q=0.9Cookie: Hm_lvt_eaa22075ffedfde4dc734cdbc709273d=1549006558; _ga=GA1.1.777543965.1549006558通过对以上内容的分割与截取,我们可以得到该请求的url以及请求的方式。package tomcat.dome;import java.io.IOException;import java.io.InputStream;//实现自己的请求类public class MyRequest { //请求的url private String url; //请求的方法类型 private String method; //构造函数 传入一个输入流 public MyRequest(InputStream inputStream) throws IOException { //用于存放http请求内容的容器 StringBuilder httpRequest=new StringBuilder(); //用于从输入流中读取数据的字节数组 byte[]httpRequestByte=new byte[1024]; int length=0; //将输入流中的内容读到字节数组中,并且对长度进行判断 if((length=inputStream.read(httpRequestByte))>0) { //证明输入流中有内容,则将字节数组添加到容器中 httpRequest.append(new String(httpRequestByte,0,length)); } //将容器中的内容打印出来 System.out.println(“httpRequest = [ “+httpRequest+” ]”); //从httpRequest中获取url,method存储到myRequest中 String httpHead=httpRequest.toString().split("\n")[0]; url=httpHead.split("\s")[1]; method=httpHead.split("\s")[0]; System.out.println(“MyRequests = [ “+this+” ]”); } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getMethod() { return method; } public void setMethod(String method) { this.method = method; } }创建MyResponse对象创建自定义的响应类,构造函数需要传入由客户端的套接字获取的输出流。定义其write方法,像浏览器写出一个响应头,并且包含我们要写出的内容content。package tomcat.dome;import java.io.IOException;import java.io.OutputStream;//实现自己的响应类public class MyResponse { //定义输出流 private OutputStream outputStream; //构造函数 传入输出流 public MyResponse(OutputStream outputStream) { this.outputStream=outputStream; } //创建写出方法 public void write(String content)throws IOException{ //用来存放要写出数据的容器 StringBuffer stringBuffer=new StringBuffer(); stringBuffer.append(“HTTP/1.1 200 OK\r\n”) .append(“Content-type:text/html\r\n”) .append("\r\n") .append("<html><head><title>Hello World</title></head><body>") .append(content) .append("</body><html>"); //转换成字节数组 并进行写出 outputStream.write(stringBuffer.toString().getBytes()); //System.out.println(“sss”); outputStream.close(); } }创建MyServlet对象由于我们自己写一个Servlet的时候需要继承HttpServlet,因此在这里首先定义了一个抽象类——MyServlet对象。在其中定义了两个需要子类实现的抽象方法doGet和doSet。并且创建了一个service方法,通过对传入的request对象的请求方式进行判断,确定调用的是doGet方法或是doPost方法。package tomcat.dome;//写一个抽象类作为servlet的父类public abstract class MyServlet { //需要子类实现的抽象方法 protected abstract void doGet(MyRequest request,MyResponse response); protected abstract void doPost(MyRequest request,MyResponse response); //父类自己的方法 //父类的service方法对传入的request以及response //的方法类型进行判断,由此调用doGet或doPost方法 public void service(MyRequest request,MyResponse response) throws NoSuchMethodException { if(request.getMethod().equalsIgnoreCase(“POST”)) { doPost(request, response); }else if(request.getMethod().equalsIgnoreCase(“GET”)) { doGet(request, response); }else { throw new NoSuchMethodException(“not support”); } }}创建业务相关的Servlet这里我创建了两个业务相关类:StudentServlet和TeacherServlet。package tomcat.dome;import java.io.IOException;//实现自己业务相关的Servletpublic class StudentServlet extends MyServlet{ @Override protected void doGet(MyRequest request, MyResponse response) { //利用response中的输出流 写出内容 try { //System.out.println("!!!!!!!!!!!!!!!!!!"); response.write(“I am a student.”); //System.out.println(“9999999999999999”); }catch(IOException e) { e.printStackTrace(); } } @Override protected void doPost(MyRequest request, MyResponse response) { //利用response中的输出流 写出内容 try { response.write(“I am a student.”); }catch(IOException e) { e.printStackTrace(); } }}package tomcat.dome;import java.io.IOException;//实现自己业务相关的Servletpublic class TeacherServlet extends MyServlet{ @Override protected void doGet(MyRequest request, MyResponse response) { //利用response中的输出流 写出内容 try { response.write(“I am a teacher.”); }catch(IOException e) { e.printStackTrace(); } } @Override protected void doPost(MyRequest request, MyResponse response) { //利用response中的输出流 写出内容 try { response.write(“I am a teacher.”); }catch(IOException e) { e.printStackTrace(); } }}创建映射关系结构ServletMapping该结构实现的是请求的url与具体的Servlet之间的关系映射。package tomcat.dome;//请求url与项目中的servlet的映射关系public class ServletMapping { //servlet的名字 private String servletName; //请求的url private String url; //servlet类 private String clazz; public String getServletName() { return servletName; } public void setServletName(String servletName) { this.servletName = servletName; } public String getUrl() { return url; } public void setUrl(String url) { this.url = url; } public String getClazz() { return clazz; } public void setClazz(String clazz) { this.clazz = clazz; } public ServletMapping(String servletName, String url, String clazz) { super(); this.servletName = servletName; this.url = url; this.clazz = clazz; }}映射关系配置对象ServletMappingConfig配置类中定义了一个列表,里面存储着项目中的映射关系。package tomcat.dome;import java.util.ArrayList;import java.util.List;//创建一个存储有请求路径与servlet的对应关系的 映射关系配置类public class ServletMappingConfig { //使用一个list类型 里面存储的是映射关系类Mapping public static List<ServletMapping>servletMappings=new ArrayList<>(16); //向其中添加映射关系 static { servletMappings.add(new ServletMapping(“student”,"/student", “tomcat.dome.StudentServlet”)); servletMappings.add(new ServletMapping(“teacher”,"/teacher", “tomcat.dome.TeacherServlet”)); }}主角登场 MyTomcat!在服务端MyTomcat中主要做了如下几件事情:1)初始化请求的映射关系。2)创建服务端套接字,并绑定某个端口。3)进入循环,用户接受客户端的链接。4)通过客户端套接字创建request与response对象。5)根据request对象的请求方式调用相应的方法。6)启动MyTomcat!package tomcat.dome;import java.io.IOException;import java.io.InputStream;import java.io.OutputStream;import java.net.ServerSocket;import java.net.Socket;import java.util.HashMap;import java.util.Map;//Tomcat服务器类 编写对请求做分发处理的相关逻辑public class MyTomcat { //端口号 private int port=8080; //用于存放请求路径与对应的servlet类的请求映射关系的map //相应的信息从配置类中获取 private Map<String, String>urlServletMap=new HashMap<>(16); //构造方法 public MyTomcat(int port) { this.port=port; } //tomcat服务器的启动方法 public void start() { //初始化请求映射关系 initServletMapping(); //服务端的套接字 ServerSocket serverSocket=null; try { //创建绑定到某个端口的服务端套接字 serverSocket=new ServerSocket(port); System.out.println(“MyTomcat begin start…”); //循环 用于接收客户端 while(true) { //接收到的客户端的套接字 Socket socket=serverSocket.accept(); //获取客户端的输入输出流 InputStream inputStream=socket.getInputStream(); OutputStream outputStream=socket.getOutputStream(); //通过输入输出流创建请求与响应对象 MyRequest request=new MyRequest(inputStream); MyResponse response=new MyResponse(outputStream); //根据请求对象的method分发请求 调用相应的方法 dispatch(request, response); //关闭客户端套接字 socket.close(); } } catch (IOException e) { e.printStackTrace(); } } //初始化请求映射关系,相关信息从配置类中获取 private void initServletMapping() { for(ServletMapping servletMapping:ServletMappingConfig.servletMappings) { urlServletMap.put(servletMapping.getUrl(), servletMapping.getClazz()); } } //通过当前的request以及response对象分发请求 private void dispatch(MyRequest request,MyResponse response) { //根据请求的url获取对应的servlet类的string String clazz=urlServletMap.get(request.getUrl()); //System.out.println("====="+clazz); try { //通过类的string将其转化为对象 Class servletClass=Class.forName(“tomcat.dome.StudentServlet”); //实例化一个对象 MyServlet myServlet=(MyServlet)servletClass.newInstance(); //调用父类方法,根据request的method对调用方法进行判断 //完成对myServlet中doGet与doPost方法的调用 myServlet.service(request, response); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } } //main方法 直接启动tomcat服务器 public static void main(String[] args) { new MyTomcat(8080).start(); } }测试结果 ...

March 10, 2019 · 3 min · jiezi

2019阿里云开年Hi购季云安全分会场全攻略!

2019阿里云云上Hi购季活动已经于2月25日正式开启,从已开放的活动页面来看,活动分为三个阶段: 2月25日-3月04日的活动报名阶段、3月04日-3月16日的新购满返+5折抢购阶段、3月16日-3月31日的续费抽豪礼+5折抢购阶段。做为整个Hi购季非常重要的一个分会场——云安全会场,3月04开放售卖!下面,云栖社区小编就为各位开发者分享该会场的攻略:丨云安全会场活动阵地:https://promotion.aliyun.com/…丨关键词:基础安全套餐、折扣专区、新品0元试用丨该会场必买爆款清单一、基础安全套餐1)安骑士,ECS贴身安全护卫主机安全软件,1年(不含网页防篡改)。2)DDoS防护包,网络攻击防护保障,1个月。3)SSL证书,网站Https,防劫持篡改1年 Geo Trust通配符。4)网站威胁扫描,资产检测和漏洞扫描,1年(体验版)。多买多赚哦!二、等保合规套餐一站式备齐等保二级、三级防护需求!购买3款及以上产品(年付)即可享受满减!最低612元1年!!!满5万减5千,满10万减1万,最高减10万!!!三、业务安全场景1)身份认证(二要素)核对姓名+身份证号是否一致2)实人认证人脸生物识别是否一致使用门禁、打卡、酒店、网吧3)网站内容识别识别涉政涉暴涉黄文本、图片、视频、音频4)交易风险识别识别羊毛党套利、刷单、撞库、恶意注册防业务欺诈企业账户、登录、营销、交易四、折扣专区1)网站威胁扫描系统网站关联资产检测、漏洞扫描。年付3折!!!活动价:21600.00/年。劲省¥50400.00/年!2)内容安全-站点检测提供首页监测全站检测的内容安全服务。年付5折!!!活动价:2500.00/年。劲省¥2500.00/年!3)实人认证基于实人可信模型进行自真实身份核验年付8折!!!活动价:40000.00/年。劲省¥10000.00/年!4)云防火墙云上网络可视和业务系统隔离,帮助完成VM、业务系统之间的流量管控和微隔离。年付7折!!!活动价:23520.00/年。劲省¥10080.00/年五、新品试用1)内容安全丰富的图片、文字、音视频内容识别服务新品0元使用!!!免费试用链接:https://promotion.aliyun.com/…2)敏感数据保护帮助客户发现、分类和保护敏感信息或文件。新品0元使用!!!申请公测链接:https://cn.aliyun.com/product…3)爬虫风险管理检测防控网络爬虫,解决航空占座、电商黄牛、撞库、刷票风险。4)高防DNS实时攻击检测,异常流量处理,2T防御带宽,适用互联网科技、金融服务机构、跨国集团等超大型公司。六、详细规则(一)、活动对象符合以下全部条件的阿里云用户:1、阿里云官网已实名认证的注册会员用户;2、在活动期间访问过的采购季相关活动页面的用户。(二)、活动时间2019年3月4日至2019年3月31日。(三)、活动规则1、云安全产品新购优惠折扣。①活动期内,用户通过活动页面购买指定云安全产品,可享受相应的优惠折扣。(具体以活动页面实际展示为准)②本活动仅限新购,续费升级不能享受优惠折扣。③本活动中的优惠折扣价格不支持其他优惠活动、代金券的叠加适用。④用户参加本活动购买的特价产品及服务,仅限本账号使用,不得转让、出售或用于牟利。2、小用户套餐包①活动期间,符合条件的用户通过活动页面购买基础安全包时,可享受不同的优惠折扣(具体以活动页面实际展示为准)。②本活动仅限小用户专享。“小用户”是指参加活动时,其阿里云账号下保有1-5台ECS服务器的用户。③用户的1个阿里云账号,仅可参加1次活动。3、等保合规套餐满减优惠①活动期间,用户一次性购买活动页面等保合规套餐专区指定产品中的任意三款产品(年付),且有效消费金额达到一定金额的,可享受相应的满减优惠,最高减10万。具体如下:满5万元减5千;满10万元减1万;满20万元减2万;满30万元减3万;满40万元减4万;满50万元减5万;满60万元减6万;满70万元减7万;满80万元减8万;满90万元减9万;满100万元减10万。②本活动仅限新购,续费或升级不能享受满减。③用户须通过购物车一键下单,分开购买指定产品的累计金额不能享受满减。4、新产品试用①活动期间,用户可通过活动页面,获得阿里云新推出的云安全产品一定期限的免费试用机会(具体以活动页面实际展示为准)。②用户的1个阿里云账号下,就每一款新产品仅限1次试用机会。③用户务必了解,试用产品不承诺稳定性,因此用户不应将其用于正式的业务活动,以免造成损失后果。5、除另有说明外,本会场所有活动不与其他优惠活动叠加适用。6、用户参加活动所购买的相关产品及所获得的相应权益,仅限本账号使用,不得转让、出售或以其他方式换取利益。7、除特殊情况外,用户参加本活动购买的产品,不支持退订。如因特殊原因发生退订的,退订前需交回通过本活动所享受的相关权益,例如:补足差价、退还已使用的代金券金额、交回奖品等。8、如用户在活动中存在隐瞒、虚构、作弊、欺诈或通过其他非正常手段规避活动规则、获取不当利益的行为,例如:作弊领取、恶意套现、网络攻击、虚假交易等,阿里云有权收回相关权益、取消用户的活动参与资格,撤销违规交易,必要时追究违规用户的法律责任。9、活动名称仅为方便用户理解参考使用,不具有效力,实际活动内容以具体活动规则为准。(四)、名词及解释1、“阿里云官网”,是指包含域名为www.aliyun.com的网站以及阿里云客户端,如APP,但阿里云国际站,包括alibabacloud.com以及所有下属页面和jp.aliyun.com以及所有下属页面除外。2、活动中涉及“打折”、“折扣”、“×折”或“省××元”,是指将本活动期间的某款产品的活动价格,与无任何活动期间的相同产品/的日常最小单位售价(例如:月价),按相同购买时长进行比较后,所获得的比较结果。3、“购物车方式购买”、“一次性购买”,是指用户通过勾选购物车内云产品、统一结算的方式同时完成多个云产品购买。4、“有效消费金额”,是指用户的实际付现消费金额。有效消费金额不包括:用户使用代金券、优惠券等非实付方式的消费金额;具体活动规则中明确排除的其他消费金额;退款金额等。5、除非有相反证据证明外,用户参与活动所获得的全部权益和相应责任,均归属于参与活动的该阿里云账号所对应的实名认证主体。6、活动中的“天”、“工作日”等均指该日的0点至24点(北京时间)。7、阿里云可以根据活动的实际情况对活动规则进行变动或调整,相关变动或调整将公布在活动页面上,并于公布时即时生效;但不影响用户在活动规则调整前已经获得的权益。七、狂欢已“种草”,有问题咨询怎么办?面对如此折扣力度,丰富的促销活动,如果有问题建议一定要提前向云小二询问,避开购买高峰期,售前咨询:95187转1。云小二会为大家提供全方位的购买咨询、精准的配置推荐 、灵活的价格方案、1对1的贴心服务。阅读原文本文为云栖社区原创内容,未经允许不得转载。

March 6, 2019 · 1 min · jiezi

2019阿里云开年Hi购季云通信分会场全攻略!

2019阿里云云上Hi购季活动已经于2月25日正式开启,从已开放的活动页面来看,活动分为三个阶段: 2月25日-3月04日的活动报名阶段、3月04日-3月16日的新购满返+5折抢购阶段、3月16日-3月31日的续费抽豪礼+5折抢购阶段。做为整个Hi购季非常重要的一个分会场——云通信会场,今日开放售卖!下面,云栖社区小编就为各位开发者分享该会场的攻略:丨云通信会场活动阵地:https://promotion.aliyun.com/ntms/act/product-section-2019/communication.html丨关键词:短信套餐包、0.028元/条、新人礼包、套餐折上折丨该会场必买爆款清单一、国内通用套餐包1.活动对象满足以下条件的阿里云用户:阿里云官网已实名认证的注册会员用户。2.活动时间2019年2月25日-2019年3月31日3.活动规则1)活动期间,用户通过相关具体活动页面,按照活动规则参与活动的可享受相应的代金券满减优惠待遇。2)满减代金券具体优惠内容如下:活动期间,短信套餐包订单金额满1800减100,满17000减1000,满32000减2000,满90000减6000。3)用户参加活动所购买的相关产品及所获得的相应权益,仅限本账号使用,不得转让、出售或以其他方式换取利益。4)活动期间,阿里云新老客户均可领取。同一用户同一面额满减券仅限领取一张。5)满减券仅限在国内通用短信套餐包购买时使用,购买内通用短信套餐包时直接减免。每个订单只能使用一张满减券。6)除特殊情况外,用户参加本活动购买的产品,不支持退订。如因特殊原因发生退订的,退订前需交回通过本活动所享受的相关权益,例如:补足差价、退还已使用的代金券金额、交回奖品等。7)如用户在活动中存在隐瞒、虚构、作弊、欺诈或通过其他非正常手段规避活动规则、获取不当利益的行为,例如:作弊领取、恶意套现、网络攻击、虚假交易等,阿里云有权收回相关权益、取消用户的活动参与资格,撤销违规交易,必要时追究违规用户的法律责任。8)活动名称仅为方便用户理解参考使用,不具有效力,实际活动内容以具体活动规则为准。二、云通信新人礼包①个人版新人礼包,支付9.9元即可获得400条国内短信包。②企业版新人礼包,支付19.9元即可获得700条国内短信+30条国际短信+30分钟语音通知 +30分钟号码隐私保护通话时长+30兆物联网+5000次号码认证。三、物联网无线连接服务以下4款产品享75折优惠,其他物联网产品享9折优惠四、场景套餐折上折(一)社区服务通信场景居民在手机上使用短信验证码服务或号码认证服务成功注册并登录社区服务APP,同时完成下单。社区服务云端系统获取下单信息,然后以语音通知或短信通知方式,将订单发送给提供服务的商家。服务提供商接单后,通过号码隐私保护服务隐藏双方号码,与终端用户互相联系。其他场景可广泛应用于电商、物流外卖、中介服务、用车出行等场景。套餐点此查看:https://promotion.aliyun.com/ntms/act/product-section-2019/communication.html(二)物联网通信场景产品描述物联网流量卡及模组合约是云通信基于物联网行业场景进行的流量卡和模组合约套餐服务,总补贴金额3000万,预购从速。建议使用场景充电桩、智能售货机、GPS行业、多媒体。活动声明模组补贴金额有限,所以属于预订业务,发货周期在3周左右。套餐点此查看:https://promotion.aliyun.com/ntms/act/product-section-2019/communication.html五、狂欢已“种草”,有问题咨询怎么办?面对如此折扣力度,丰富的促销活动,如果有问题建议一定要提前向云小二询问,避开购买高峰期,售前咨询:95187转1。云小二会为大家提供全方位的购买咨询、精准的配置推荐 、灵活的价格方案、1对1的贴心服务。阅读原文本文为云栖社区原创内容,未经允许不得转载。

March 5, 2019 · 1 min · jiezi

2019阿里云开年Hi购季必抢!爆爆爆爆爆爆爆款清单来了!

摘要: 鸡冻人心的三月开年Hi购季来了,根本不知道该买哪款?这次就给大家列一波口碑爆款!鸡冻人心的三月开年Hi购季来了个个摩拳擦掌为了算清楚能省多少钱颓废多年的数学水平仿佛在这个节日回到了高考前夕好物很多看得眼花缭乱,头昏脑胀根本不知道该买哪款这次就给大家列一波口碑爆款还有很多满返优惠和续费豪礼主会场爆款清单看上的赶紧先报名,不然到时候抢不到啦报名地址: https://www.aliyun.com/acts/product-section-2019/home?utm_content=g_1000043978新用户分会场爆款清单点此查看详情:https://www.aliyun.com/acts/product-section-2019/home?utm_content=g_1000043978阅读原文

March 1, 2019 · 1 min · jiezi

2019阿里云开年Hi购季满返活动火热报名中!

2019阿里云云上采购季活动已经于2月25日正式开启,从已开放的活动页面来看,活动分为三个阶段: 2月25日-3月04日的活动报名阶段、3月04日-3月16日的新购满返+5折抢购阶段、3月16日-3月31日的续费抽豪礼+5折抢购阶段。整个大促活动包含1个主会场和七个分会场。主会场将为大家带来新购满返和超值折扣热门产品。七大分会场包含基础云产品会场、域名会场、云通信会场、新用户会场、云安全会场、中小企业会场和开发者会场。那么,在每年开年的这个大幅度优惠促销月,怎样才能花最少的钱配置最特惠的云服务?云栖社区特为各位开发者奉献出省钱大法如下:丨活动阵地:https://www.aliyun.com/acts/product-section-2019/home?utm_content=g_1000042898丨关键词:Hi购季、新购满返、5折、续费抽豪礼社区小编仔细梳理了下活动规则,给大家作为借鉴参考:一、满返先报名,特惠提前知时间:2月25日-3月04日活动对象:1、阿里云官网已实名认证的注册会员用户;2、通过本活动页面点击“立即报名”,主动确认参与活动。本活动仅适用于主动报名用户,未报名参加活动的用户在活动期间的消费不享受返代金券优惠。3.4-3.15期间,累计新购、升级预付费云产品(1年及以内),消费满3000元即返!最高返7500元代金券!马上点此报名:https://www.aliyun.com/acts/product-section-2019/home详细活动规则:1、活动期间,用户在阿里云官网新购、升级时长1年及以内的预付费云产品,且累计有效消费金额满3000元的,即可获得对应金额的阿里云云产品代金券。具体如下:累计有效消费金额3000-9999元,每满1000返80;累计有效消费金额10000-29999元,每满5000返600;累计有效消费金额30000元及以上,每满5000返750,最高封顶7500。2、上述“有效消费金额”不包括:用户购买已享受5折及以下优惠折扣产品的消费金额、用户购买储值卡的金额、用户使用代金券支付的非实付消费金额、用户购买后又退款所产生的退款金额。3、本活动仅适用于主动报名用户,未报名参加活动的用户在活动期间的消费不享受返代金券优惠。4、同一用户使用多个阿里云账号参与本活动的,仅向其中有效消费金额最高的一个阿里云账号返回相应额度的代金券。5、用户参与本活动所获得的代金券,将于2019年4月1日0点-24点前统一发放至对应的阿里云账户。代金券的使用有效期截至2019年4月30日24点,过期自动作废。6、代金券仅限用户用于本账户下的新购、升级预付费云产品使用,不得转让或出售,或以其他方式换取利益。7、除特殊情况外,用户参加本活动购买的产品,不支持退订。如因特殊原因发生退订的,退订前需交回通过本活动所享受的相关权益,例如:补足差价、退还已使用的代金券金额、交回奖品等。8、如用户在活动中存在隐瞒、虚构、作弊、欺诈或通过其他非正常手段规避活动规则、获取不当利益的行为,例如:作弊领取、恶意套现、网络攻击、虚假交易等,阿里云有权收回相关权益、取消用户的活动参与资格,撤销违规交易,必要时追究违规用户的法律责任。9、活动名称仅为方便用户理解参考使用,不具有效力,实际活动内容以具体活动规则为准。于公布时即时生效;但不影响用户在活动规则调整前已经获得的权益。二、特惠产品抢先知晓多款云产品超值特惠,低至5折!据观察,2月25日刚刚上线两大分会场:新用户会场及云通信分会场,其他场次预计将陆续开启,请持续关注避免错失良机,云栖社区也将持续推出玩转各大分会场攻略,重重优惠,总有一款适合你!狂欢阵地直通车:新用户会场:https://www.aliyun.com/acts/product-section-2019/new-users?utm_content=g_1000042899云通信分会场:https://promotion.aliyun.com/ntms/act/product-section-2019/communication.html?utm_content=g_1000042900三、新老用户幸运抽奖阿里云注册用户专享,每个用户活动期间可抽奖1次!点此参与:https://www.aliyun.com/acts/product-section-2019/yq-lottery?utm_content=g_1000042901活动时间:2月25日-3月31日活动对象:阿里云官网已实名认证的注册会员用户;活动规则:1、活动期间,用户登录阿里云账号后,即可在活动指定页面参与抽奖,同一用户仅限1次抽奖机会。2、本活动奖品包括天猫超市满减购物券、饿了么满减红包、淘票票电影满减券,包括:①天猫超市满减购物券:A、满199减100购物券,支持日用百货、休闲食品商品;B、满99减50元购物券,支持休闲食品、个护家清商品。②饿了么满减红包:满30元减3元③淘票票电影满减券:满35元减5元3、用户中奖后,须在活动页面点击“领取”,且填写准确有效的淘宝账号,奖品将发放至用户填写的该淘宝账号,无效账号信息可能导致发放失败。如用户在活动期内未完成淘宝账号绑定或未点击领取的,视为放弃领取奖品。四、狂欢已“种草”,有问题咨询怎么办?面对如此折扣力度,丰富的促销活动,如果有问题建议一定要提前向云小二询问,避开购买高峰期,售前咨询:95187转1。云小二会为大家提供全方位的购买咨询、精准的配置推荐 、灵活的价格方案、1对1的贴心服务。阅读原文

February 25, 2019 · 1 min · jiezi

一致性协议浅析:从逻辑时钟到Raft

前言春节在家闲着没事看了几篇论文,把一致性协议的几篇论文都过了一遍。在看这些论文之前,我一直有一些疑惑,比如同样是有Leader和两阶段提交,Zookeeper的ZAB协议和Raft有什么不同,Paxos协议到底要怎样才能用在实际工程中,这些问题我都在这些论文中找到了答案。接下来,我将尝试以自己的语言给大家讲讲这些协议,使大家能够理解这些算法。同时,我自己也有些疑问,我会在我的阐述中提出,也欢迎大家一起讨论。水平有限,文中难免会有一些纰漏门也欢迎大家指出。逻辑时钟逻辑时钟其实算不上是一个一致性协议,它是Lamport大神在1987年就提出来的一个想法,用来解决分布式系统中,不同的机器时钟不一致可能带来的问题。在单机系统中,我们用机器的时间来标识事件,就可以非常清晰地知道两个不同事件的发生次序。但是在分布式系统中,由于每台机器的时间可能存在误差,无法通过物理时钟来准确分辨两个事件发生的先后顺序。但实际上,在分布式系统中,只有两个发生关联的事件,我们才会去关心两者的先来后到关系。比如说两个事务,一个修改了rowa,一个修改了rowb,他们两个谁先发生,谁后发生,其实我们并不关心。那所谓逻辑时钟,就是用来定义两个关联事件的发生次序,即‘happens before’。而对于不关联的事件,逻辑时钟并不能决定其先后,所以说这种‘happens before’的关系,是一种偏序关系。图和例子来自于这篇博客此图中,箭头表示进程间通讯,ABC分别代表分布式系统中的三个进程。逻辑时钟的算法其实很简单:每个事件对应一个Lamport时间戳,初始值为0如果事件在节点内发生,时间戳加1如果事件属于发送事件,时间戳加1并在消息中带上该时间戳如果事件属于接收事件,时间戳 = Max(本地时间戳,消息中的时间戳) + 1这样,所有关联的发送接收事件,我们都能保证发送事件的时间戳小于接收事件。如果两个事件之间没有关联,比如说A3和B5,他们的逻辑时间一样。正是由于他们没有关系,我们可以随意约定他们之间的发生顺序。比如说我们规定,当Lamport时间戳一样时,A进程的事件发生早于B进程早于C进程,这样我们可以得出A3 ‘happens before’ B5。而实际在物理世界中,明显B5是要早于A3发生的,但这都没有关系。逻辑时钟貌似目前并没有被广泛的应用,除了DynamoDB使用了vector clock来解决多版本的先后问题(如果有其他实际应用的话请指出,可能是我孤陋寡闻了),Google的Spanner 也是采用物理的原子时钟来解决时钟问题。但是从Larmport大师的逻辑时钟算法上,已经可以看到一些一致性协议的影子。Replicated State Machine说到一致性协议,我们通常就会讲到复制状态机。因为通常我们会用复制状态机加上一致性协议算法来解决分布式系统中的高可用和容错。许多分布式系统,都是采用复制状态机来进行副本之间的数据同步,比如HDFS,Chubby和Zookeeper。所谓复制状态机,就是在分布式系统的每一个实例副本中,都维持一个持久化的日志,然后用一定的一致性协议算法,保证每个实例的这个log都完全保持一致,这样,实例内部的状态机按照日志的顺序回放日志中的每一条命令,这样客户端来读时,在每个副本上都能读到一样的数据。复制状态机的核心就是图中 的Consensus模块,即今天我们要讨论的Paxos,ZAB,Raft等一致性协议算法。PaxosPaxos是Lamport大神在90年代提出的一致性协议算法,大家一直都觉得难懂,所以Lamport在2001又发表了一篇新的论文《Paxos made simple》,在文中他自己说Paxos是世界上最简单的一致性算法,非常容易懂……但是业界还是一致认为Paxos比较难以理解。在我看过Lamport大神的论文后,我觉得,除去复杂的正确性论证过程,Paxos协议本身还是比较好理解的。但是,Paxos协议还是过于理论,离具体的工程实践还有太远的距离。我一开始看Paxos协议的时候也是一头雾水,看来看去发现Paxos协议只是为了单次事件答成一致,而且答成一致后的值无法再被修改,怎么用Paxos去实现复制状态机呢?另外,Paxos协议答成一致的值只有Propose和部分follower知道,这协议到底怎么用……但是,如果你只是把Paxos协议当做一个理论去看,而不是考虑实际工程上会遇到什么问题的话,会容易理解的多。Lamport的论文中对StateMachine的应用只有一个大概的想法,并没有具体的实现逻辑,想要直接把Paxos放到复制状态机里使用是不可能的,得在Paxos上补充很多的东西。这些是为什么Paxos有这么多的变种。Basic-PaxosBasic-Paxos即Lamport最初提出的Paxos算法,其实很简单,用三言两语就可以讲完,下面我尝试着用我自己的语言描述下Paxos协议,然后会举出一个例子。要理解Paxos,只要记住一点就好了,Paxos只能为一个值形成共识,一旦Propose被确定,之后值永远不会变,也就是说整个Paxos Group只会接受一个提案(或者说接受多个提案,但这些提案的值都一样)。至于怎么才能接受多个值来形成复制状态机,大家可以看下一节Multi-Paxos.Paxos协议中是没有Leader这个概念的,除去Learner(只是学习Propose的结果,我们可以不去讨论这个角色),只有Proposer和Acceptor。Paxos并且允许多个Proposer同时提案。Proposer要提出一个值让所有Acceptor答成一个共识。首先是Prepare阶段,Proposer会给出一个ProposeID n(注意,此阶段Proposer不会把值传给Acceptor)给每个Acceptor,如果某个Acceptor发现自己从来没有接收过大于等于n的Proposer,则会回复Proposer,同时承诺不再接收ProposeID小于等于n的提议的Prepare。如果这个Acceptor已经承诺过比n更大的propose,则不会回复Proposer。如果Acceptor之前已经Accept了(完成了第二个阶段)一个小于n的Propose,则会把这个Propose的值返回给Propose,否则会返回一个null值。当Proposer收到大于半数的Acceptor的回复后,就可以开始第二阶段accept阶段。但是这个阶段Propose能够提出的值是受限的,只有它收到的回复中不含有之前Propose的值,他才能自由提出一个新的value,否则只能是用回复中Propose最大的值做为提议的值。Proposer用这个值和ProposeID n对每个Acceptor发起Accept请求。也就是说就算Proposer之前已经得到过acceptor的承诺,但是在accept发起之前,Acceptor可能给了proposeID更高的Propose承诺,导致accept失败。也就是说由于有多个Proposer的存在,虽然第一阶段成功,第二阶段仍然可能会被拒绝掉。下面我举一个例子,这个例子来源于这篇博客假设有Server1,Server2, Server3三个服务器,他们都想通过Paxos协议,让所有人答成一致他们是leader,这些Server都是Proposer角色,他们的提案的值就是他们自己server的名字。他们要获取Acceptor1~3这三个成员同意。首先Server2发起一个提案【1】,也就是说ProposeID为1,接下来Server1发起来一个提案【2】,Server3发起一个提案【3】.首先是Prepare阶段:假设这时Server1发送的消息先到达acceptor1和acceptor2,它们都没有接收过请求,所以接收该请求并返回【2,null】给Server1,同时承诺不再接受编号小于2的请求; 紧接着,Server2的消息到达acceptor2和acceptor3,acceptor3没有接受过请求,所以返回proposer2 【1,null】,并承诺不再接受编号小于1的消息。而acceptor2已经接受Server1的请求并承诺不再接收编号小于2的请求,所以acceptor2拒绝Server2的请求; 最后,Server3的消息到达acceptor2和acceptor3,它们都接受过提议,但编号3的消息大于acceptor2已接受的2和acceptor3已接受的1,所以他们都接受该提议,并返回Server3 【3,null】; 此时,Server2没有收到过半的回复,所以重新取得编号4,并发送给acceptor2和acceptor3,此时编号4大于它们已接受的提案编号3,所以接受该提案,并返回Server2 【4,null】。接下来进入Accept阶段,Server3收到半数以上(2个)的回复,并且返回的value为null,所以,Server3提交了【3,server3】的提案。 Server1在Prepare阶段也收到过半回复,返回的value为null,所以Server1提交了【2,server1】的提案。 Server2也收到过半回复,返回的value为null,所以Server2提交了【4,server2】的提案。 Acceptor1和acceptor2接收到Server1的提案【2,server1】,acceptor1通过该请求,acceptor2承诺不再接受编号小于4的提案,所以拒绝; Acceptor2和acceptor3接收到Server2的提案【4,server2】,都通过该提案; Acceptor2和acceptor3接收到Server3的提案【3,server3】,它们都承诺不再接受编号小于4的提案,所以都拒绝。 此时,过半的acceptor(acceptor2和acceptor3)都接受了提案【4,server2】,learner感知到提案的通过,learner开始学习提案,所以server2成为最终的leader。Multi-Paxos刚才我讲了,Paxos还过于理论,无法直接用到复制状态机中,总的来说,有以下几个原因Paxos只能确定一个值,无法用做Log的连续复制由于有多个Proposer,可能会出现活锁,如我在上面举的例子中,Server2的一共提了两次Propose才最终让提案通过,极端情况下,次数可能会更多提案的最终结果可能只有部分Acceptor知晓,没法达到复制状态机每个instance都必须有完全一致log的需求。那么其实Multi-Paxos,其实就是为了解决上述三个问题,使Paxos协议能够实际使用在状态机中。解决第一个问题其实很简单。为Log Entry每个index的值都是用一个独立的Paxos instance。解决第二个问题也很简答,让一个Paxos group中不要有多个Proposer,在写入时先用Paxos协议选出一个leader(如我上面的例子),然后之后只由这个leader做写入,就可以避免活锁问题。并且,有了单一的leader之后,我们还可以省略掉大部分的prepare过程。只需要在leader当选后做一次prepare,所有Acceptor都没有接受过其他Leader的prepare请求,那每次写入,都可以直接进行Accept,除非有Acceptor拒绝,这说明有新的leader在写入。为了解决第三个问题,Multi-Paxos给每个Server引入了一个firstUnchosenIndex,让leader能够向向每个Acceptor同步被选中的值。解决这些问题之后Paxos就可以用于实际工程了。Paxos到目前已经有了很多的补充和变种,实际上,之后我要讨论的ZAB也好,Raft也好,都可以看做是对Paxos的修改和变种,另外还有一句流传甚广的话,“世上只有一种一致性算法,那就是Paxos”。ZABZAB即Zookeeper Atomic BoardCast,是Zookeeper中使用的一致性协议。ZAB是Zookeeper的专用协议,与Zookeeper强绑定,并没有抽离成独立的库,因此它的应用也不是很广泛,仅限于Zookeeper。但ZAB协议的论文中对ZAB协议进行了详细的证明,证明ZAB协议是能够严格满足一致性要求的。ZAB随着Zookeeper诞生于2007年,此时Raft协议还没有发明,根据ZAB的论文,之所以Zookeeper没有直接使用Paxos而是自己造轮子,是因为他们认为Paxos并不能满足他们的要求。比如Paxos允许多个proposer,可能会造成客户端提交的多个命令没法按照FIFO次序执行。同时在恢复过程中,有一些follower的数据不全。这些断论都是基于最原始的Paxos协议的,实际上后来一些Paxos的变种,比如Multi-Paxos已经解决了这些问题。当然我们只能站在历史的角度去看待这个问题,由于当时的Paxos并不能很好的解决这些问题,因此Zookeeper的开发者创造了一个新的一致性协议ZAB。ZAB其实和后来的Raft非常像,有选主过程,有恢复过程,写入也是两阶段提交,先从leader发起一轮投票,获得超过半数同意后,再发起一次commit。ZAB中每个主的epoch number其实就相当于我接下来要讲的Raft中的term。只不过ZAB中把这个epoch number和transition number组成了一个zxid存在了每个entry中。ZAB在做log复制时,两阶段提交时,一个阶段是投票阶段,只要收到过半数的同意票就可以,这个阶段并不会真正把数据传输给follower,实际作用是保证当时有超过半数的机器是没有挂掉,或者在同一个网络分区里的。第二个阶段commit,才会把数据传输给每个follower,每个follower(包括leader)再把数据追加到log里,这次写操作就算完成。如果第一个阶段投票成功,第二个阶段有follower挂掉,也没有关系,重启后leader也会保证follower数据和leader对其。如果commit阶段leader挂掉,如果这次写操作已经在至少一个follower上commit了,那这个follower一定会被选为leader,因为他的zxid是最大的,那么他选为leader后,会让所有follower都commit这条消息。如果leader挂时没有follower commit这条消息,那么这个写入就当做没写完。由于只有在commit的时候才需要追加写日志,因此ZAB的log,只需要append-only的能力,就可以了。另外,ZAB支持在从replica里做stale read,如果要做强一致的读,可以用sync read,原理也是先发起一次虚拟的写操作,到不做任何写入,等这个操作完成后,本地也commit了这次sync操作,再在本地replica上读,能够保证读到sync这个时间点前所有的正确数据,而Raft所有的读和写都是经过主节点的RaftRaft是斯坦福大学在2014年提出的一种新的一致性协议。作者表示之所以要设计一种全新的一致性协议,是因为Paxos实在太难理解,而且Paxos只是一个理论,离实际的工程实现还有很远的路。因此作者狠狠地吐槽了Paxos一把:Paxos协议中,是不需要Leader的,每个Proposer都可以提出一个propose。相比Raft这种一开始设计时就把选主和协议达成一致分开相比,Paxos等于是把选主和propose阶段杂糅在了一起,造成Paxos比较难以理解。最原始的Paxos协议只是对单一的一次事件答成一致,一旦这个值被确定,就无法被更改,而在我们的现实生活中,包括我们数据库的一致性,都需要连续地对log entry的值答成一致,所以单单理解Paxos协议本身是不够的,我们还需要对Paxos协议进行改进和补充,才能真正把Paxos协议应用到工程中。而对Paxos协议的补充本身又非常复杂,而且虽然Paxos协议被Lamport证明过,而添加了这些补充后,这些基于Paxos的改进算法,如Multi-Paxos,又是未经证明的。第三个槽点是Paxos协议只提供了一个非常粗略的描述,导致后续每一个对Paxos的改进,以及使用Paxos的工程,如Google的Chubby,都是自己实现了一套工程来解决Paxos中的一些具体问题。而像Chubby的实现细节其实并没有公开。也就是说要想在自己的工程中使用Paxos,基本上每个人都需要自己定制和实现一套适合自己的Paxos协议。因此,Raft的作者在设计Raft的时候,有一个非常明确的目标,就是让这个协议能够更好的理解,在设计Raft的过程中,如果遇到有多种方案可以选择的,就选择更加容易理解的那个。作者举了一个例子。在Raft的选主阶段,本来可以给每个server附上一个id,大家都去投id最大的那个server做leader,会更快地达成一致(类似ZAB协议),但这个方案又增加了一个serverid的概念,同时在高id的server挂掉时,低id的server要想成为主必须有一个等待时间,影响可用性。因此Raft的选主使用了一个非常简单的方案:每个server都随机sleep一段时间,最早醒过来的server来发起一次投票,获取了大多数投票即可为主。在通常的网络环境下,最早发起投票的server也会最早收到其他server的赞成票,因此基本上只需要一轮投票就可以决出leader。整个选主过程非常简单明了。除了选主,整个Raft协议的设计都非常简单。leader和follower之间的交互(如果不考虑snapshot和改变成员数量)一共只有2个RPC call。其中一个还是选主时才需要的RequestVote。也就是说所有的数据交互,都只由AppendEntries 这一个RPC完成。理解Raft算法,首先要理解Term这个概念。每个leader都有自己的Term,而且这个term会带到log的每个entry中去,来代表这个entry是哪个leader term时期写入的。另外Term相当于一个lease。如果在规定的时间内leader没有发送心跳(心跳也是AppendEntries这个RPC call),Follower就会认为leader已经挂掉,会把自己收到过的最高的Term加上1做为新的term去发起一轮选举。如果参选人的term还没自己的高的话,follower会投反对票,保证选出来的新leader的term是最高的。如果在time out周期内没人获得足够的选票(这是有可能的),则follower会在term上再加上1去做新的投票请求,直到选出leader为止。最初的raft是用c语言实现的,这个timeout时间可以设置的非常短,通常在几十ms,因此在raft协议中,leader挂掉之后基本在几十ms就能够被检测发现,故障恢复时间可以做到非常短。而像用Java实现的Raft库,如Ratis,考虑到GC时间,我估计这个超时时间没法设置这么短。在Leader做写入时也是一个两阶段提交的过程。首先leader会把在自己的log中找到第一个空位index写入,并通过AppendEntries这个RPC把这个entry的值发给每个follower,如果收到半数以上的follower(包括自己)回复true,则再下一个AppendEntries中,leader会把committedIndex加1,代表写入的这个entry已经被提交。如在下图中,leader将x=4写入index=8的这个entry中,并把他发送给了所有follower,在收到第一台(自己),第三台,第五台(图中没有画index=8的entry,但因为这台服务器之前所有的entry都和leader保持了一致,因此它一定会投同意),那么leader就获得了多数票,再下一个rpc中,会将Committed index往前挪一位,代表index<=8的所有entry都已经提交。至于第二台和第四台服务器,log内容已经明显落后,这要么是因为前几次rpc没有成功。leader会无限重试直到这些follower和leader的日志追平。另外一个可能是这两台服务器重启过,处于恢复状态。那么这两台服务器在收到写入index=8的RPC时,follower也会把上一个entry的term和index发给他们。也就是说prevLogIndex=7,prevLogTerm=3这个信息会发给第二台服务器,那么对于第二台服务器,index=7的entry是空的,也就是log和leader不一致,他会返回一个false给leader,leader会不停地从后往前遍历,直到找到一个entry与第二台服务器一致的,从这个点开始重新把leader的log内容发送给该follower,即可完成恢复。raft协议保证了所有成员的replicated log中每个index位置,如果他们的term一致,内容也一定一致。如果不一致,leader一定会把这个index的内容改写成和leader一致。其实经过刚才我的一些描述,基本上就已经把Raft的选主,写入流程和恢复基本上都讲完了。从这里,我们可以看出Raft一些非常有意思的地方。第一个有意思的地方是Raft的log的entry是可能被修改的,比如一个follower接收了一个leader的prepare请求,把值写入了一个index,而这个leader挂掉,新选出的leader可能会重新使用这个index,那么这个follower的相应index的内容,会被改写成新的内容。这样就造成了两个问题,首先第一个,raft的log无法在append-only的文件或者文件系统上去实现,而像ZAB,Paxos协议,log只会追加,只要求文件系统有append的能力即可,不需要随机访问修改能力。第二个有意思的地方是,为了简单,Raft中只维护了一个Committed index,也就是任何小于等于这个committedIndex的entry,都是被认为是commit过的。这样就会造成在写入过程中,在leader获得大多数选票之前挂掉(或者leader在写完自己的log之后还没来得及通知到任何follower就挂掉),重启后如果这个server继续被选为leader,这个值仍然会被commit永久生效。因为leader的log中有这个值,leader一定会保证所有的follower的log都和自己保持一致。而后续的写入在增长committedIndex后,这个值也默认被commit了。举例来说,现在有5台服务器,其中S2为leader,但是当他在为index=1的entry执行写入时,先写到了自己的log中,还没来得及通知其他server append entry就宕机了。 当S2重启后,任然有可能被重新当选leader,当S2重新当选leader后,仍然会把index=1的这个entry复制给每台服务器(但是不会往前移动Committed index)此时S2又发生一次写入,这次写入完成后,会把Committed index移动到2的位置,因此index=1的entry也被认为已经commit了。这个行为有点奇怪,因为这样等于raft会让一个没有获得大多数人同意的值最终commit。这个行为取决于leader,如果上面的例子中S2重启后没有被选为leader,index=1的entry内容会被新leader的内容覆盖,从而不会提交未经过表决的内容。虽然说这个行为是有点奇怪,但是不会造成任何问题,因为leader和follower还是会保持一致,而且在写入过程中leader挂掉,对客户端来说是本来就是一个未决语义,raft论文中也指出,如果用户想要exactly once的语义,可以在写入的时候加入一个类似uuid的东西,在写入之前leader查下这个uuid是否已经写入。那么在一定程度上,可以保证exactly once的语义。Raft的论文中也比较了ZAB的算法,文中说ZAB协议的一个缺点是在恢复阶段需要leader和follower来回交换数据,这里我没太明白,据我理解,ZAB在重新选主的过程中,会选择Zxid最大的那个从成为主,而其他follower会从leader这里补全数据,并不会出现leader从follower节点补数据这一说。后话目前,经过改进的Paxos协议已经用在了许多分布式产品中,比如说Chubby,PaxosStore,阿里云的X-DB,以及蚂蚁的OceanBase,都选用了Paxos协议,但他们都多多少少做了一些补充和改进。而像Raft协议,普遍认为Raft协议只能顺序commit entry,性能没有Paxos好,但是TiKV中使用了Raft,其公开的文章宣传对Raft做了非常多的优化,使Raft的性能变的非常可观。阿里的另外一个数据库PolarDB,也是使用了改进版的Parallel-Raft,使Raft实现了并行提交的能力。相信未来会有更多的基于Paxos/Raft的产品会面世,同时也对Raft/Paxos也会有更多的改进。参考文献《Time, clocks, and the ordering of events in a distributed system》《Implementing fault-tolerant services using the state machine approach- A tutorial》《Paxos Made Simple》《Paxos made live- An engineering perspective》《Multi-Paxos》(Standford大学的一个ppt)《Zab- High-performance broadcast for primary-backup systems》《In search of an understandable consensus algorithm》(raft)本文作者:正研阅读原文本文为云栖社区原创内容,未经允许不得转载。 ...

February 19, 2019 · 1 min · jiezi

这个情人节,工程师用阿里云来试着表达不一样的爱意

年轻的时候谈的恋爱就像TCP链接,恋爱时三次握手即可,可分手时却分了四次。而常常久久的爱情,更像是icmp协议,无论对方身在何处,无论是否是可靠连接,无论你何时去ping她/他,她/他都默默地响应你。这篇文章就是说说,如何在内核中增加几行代码,让你的女神/男神当ping你(的服务器)的时候,来传达表达你的爱。效果如下(左边为ping的结果,需要破解ascii码转换为对应字符,右边为使用tcpdump抓包直接读取的信息):对于UNIX_LIKE系统来说,如果ping的发送内容与接收内容不同,会显示不同的部分,那么就让你的女神或者男神,慢慢将ASCII码解析成你想告诉她/他的话吧。或者告诉她/他,使用tcpdump来直接抓包隐藏在ping中的悄悄话。(对于windows来说本人没有充分测试,只是知道不会像unix_like系统一样直接显示出请求消息和回显消息的不同,所以需要大家抓包认真提取信息)一、ICMP协议这些你需要了解:学过计算机网络的一定知道,一个网络包的封装主要由多个属于不同网络协议层的报文头和用户数据共同组成:链路层报文头+网络层IP报文头+传输层报文头+携带的内容+帧尾。而ICMP报文在整个以太帧位于如下位置: 上图显示的是一个未分片ICMP报文或者是一个较长ICMP报文的第一个IP分片的报文(被分片的报文中不会带有ICMP报头)。RFC792(https://tools.ietf.org/html/r…)中定义了11种ICMP报文类型,通过ICMP报头8bit"类型"字段进行区分。并且每种"类型“会和其”代码"字段以及报文头的最后4字节,共同表达每种报文类型所表示的信息。这些ICMP报文类型被主要分为差错报文和查询报文:查询报文主要包括:回送请求(TYPE8),回送应答(TYPE0),地址掩码或时间戳的请求/应答等差错报文主要包括:目标主机不可达(TYPE3),超时,源抑制,路由重定向等 ping作为ICMP协议最为典型的运用,主要和回送请求,和回送应答这两个类型相关,这也是本文主要关心的两个类型。当然,当主机不可达或者网络路由不可达出现的时候,ping会收到路由器传来的TYPE为3的目标主机不可达的报文(我们可以通过tcpdump抓包获取)。对于其他的类型,有兴趣的同学可以自行学习,如icmp重定向攻击,洪水攻击都是利用了ICMP协议进行的网络攻击。二、动手写一个简单的ping,了解Linux ping作为本文的主角之一ping,有必要动手写一个简单的ping,帮助我们更好的理解整个请求应答的过程。我本人的测试机器centos 7中使用的是iputils这个工具进行ping操作,所以我们可以从iputils源码入手学习如何写一个简单的ping。学习过c网络编程的一定都了解socket套接字这个概念。对于ping来说发送请求和接受应答也同样是通过套接字来完成。只不过,ICMP协议虽然在内核中和TCP、UDP相似属于L4层协议,但是本质是附属于IP协议的网络层协议,所以需要使用原始套接字(SOCK_RAW)构建套接字,而非TCP或UDP使用的流式套接字(SOCK_STREAM)和数据包式套接字(SOCK_DGRAM)。SOCK_RAW的用途在于用户可以自定义填充IP报文头,并且对于ICMP报文自定义填充ICMP报文头。下面一张图,展示了代码中整个ping的逻辑发送以及处理应答的逻辑。具体代码可以参考这个:https://github.com/xiaobaidemu/myping/blob/master/ping.c 整个流程非常简单,需要说明的是,对于ping 127.0.0.1来说,程序极有可能先收到type为0的回显请求报文,再收到type为8的回显应答报文。这是因为icmp报文可以同时被内核接收处理,也会被原始套接字接收处理,如下为Understanding Linux Network Internals书中所述。三、添加内核代码前,你只需要知道一个结构体和icmp.c理解了ping的整个过程,接下来就是需要修改内核来传达你想说的话。但是最重要的是,需要分析出修改的位置,即回显应答可能发送的字节在内核代码中的位置。这里有一个非常重要的结构体——struct sk_buff,其定义位于<include/linux/skbuff.h>。内核中sk_buff结构体做到了可以不使用拷贝或删除的方式,使得数据在各层协议之间传输——即移动指针头的方式,具体为在处理不同的协议头时,代表协议头的指针,指向的是不同数据区域(如从L2到L4层协议,分别指向二层mac头,三层IP头,四层传输头)。以下是几个比较重要和混淆的字段说明,结合示意图说明: 上图简单说明了四个指针和指向区域之间的关系。另外对于data_len和len的关系,如果假设icmp报文比较小,ip层不会对其分片,那么data_len即为0,而len即为当前协议头长度+数据报文长度。关于data_len和len之间的关系涉及到skb_shared_info这个结构体的相关内容,因为和文章中心关系不大,有兴趣的同学可以自行查阅一下文章来学习http://blog.51cto.com/weiguozhihui/1586777https://0x657573.wordpress.com/2010/11/22/the-relation-between-skb-len-and-skb-data_len-and-what-they-represent/https://blog.csdn.net/farmwang/article/details/54233975 上述内容中data指针和表征协议层数据长度的len,和后文中修改的sk_buff指向的数据直接相关。另外sk_buff关联了众多其他结构体,这里只简要的讲解部分重要的字段含义,更为具体详细的说明可以参考Understanding Linux Network Internal第二章或者https://blog.csdn.net/YuZhiHui_No1/article/details/38666589系列文章进行更深入学习。 了解了sk_buff结构体,之后需要定位处理icmp协议的文件在哪里。icmp.c位于内核目录中net/ipv4/icmp.c中,且ICMP协议通常是静态编译至内核中,而非通过模块配置的。这里我从Understanding Linux Network Internal这本书中抠出来一张Big Picture,来简要说明一下对于ping发出的回显请求,sk_buff结构体对象是如何在icmp中众多函数中传递。首先ip_local_deliver_finish会传递ICMP消息到icmp_rcv, icmp_rcv会解析icmp报头中类型字段,对于属于查询报文的类型(如type8)会传递给icmp_reply, 而对于差错报文会传递给icmp_send处理,并且ICMP协议也会和其他诸如TCP/UDP协议进行交互传递信息。对于ping进程发出的请求,会先传递给icmp_echo函数进行处理。而icmp_echo正是处理ping请求很重要的一步,内核会把请求中附带的数据报文部分原封不动的拷贝并发送回源主机。因此我们可以在icmp_echo函数中,添加进我们"爱的语句"。static bool icmp_echo(struct sk_buff skb){ struct net net; net = dev_net(skb_dst(skb)->dev); if (!net->ipv4.sysctl_icmp_echo_ignore_all) { struct icmp_bxm icmp_param; icmp_param.data.icmph = icmp_hdr(skb); icmp_param.data.icmph.type = ICMP_ECHOREPLY; icmp_param.skb = skb; //———–添加开始———– char sentence1[] = “I LOVE U, xxxx.”; char sentence2[] = “I MISS U, xxxx.”; char sentence3[] = “Happy Valentine’s Day!”; int sentence_len_list[] = {sizeof(sentence1), sizeof(sentence2), sizeof(sentence3)}; char sentence_list[] = {sentence1, sentence2, sentence3}; int sentence_index = icmp_param.data.icmph.un.echo.sequence % 3; if(skb->len >= 16 + sentence_len_list[sentence_index]) { char tmp = (char)(skb->data+16); char* target_sentence = sentence_list[sentence_index]; int i=0; for(;i<sentence_len_list[sentence_index];++i) { tmp[i] = target_sentence[i]; } for(;i < skb->len-16;++i) { tmp[i] = 0; } } //———–添加结束———— icmp_param.offset = 0; icmp_param.data_len = skb->len; icmp_param.head_len = sizeof(struct icmphdr); icmp_reply(&icmp_param, skb); } /* should there be an ICMP stat for ignored echos? */ return true;}上述代码中icmp_bxm结构体包含了在后续icmp消息传递过程中的所有需要的信息,包括icmp报文头,sk_buff对象,icmp 报文payload大小等。需要注意的是,由于icmp_rcv已经解析过sk_buff中属于icmp协议的报文头部分,所以参数中skb->data指向的是icmp数据部分,即不包含报文头,而skb->len也只有icmp数据部分的长度。假设ping请求中所带的数据部分为56字节,则此时skb->len大小为56。由于ping数据部分的前16字节为携带的是发送是struct timeval对象——发送时的时间,所以在真实替换时,从data指向的数据部分的第16个字节开始,用memcpy复制到对应区域,或者如上例子傻傻的循环赋值即可。上面代码所表示的就是根据echo请求中seq_id循环回复上述三句话。当然有创意的小伙伴可以增加更多表达难度。四、创建一个阿里云ECS服务器,十分钟完成所有修改分析完了整个icmp处理流程,和修改方法,我们只需要创建一个阿里云ECS,并简单编译修改后的内核即可。具体流程如下:阿里云创建任意规格服务器(大规格可以加快内核编译速度,此处创建一个4vcpu服务器),使用centos作为os下载linux内核代码,并解压放置到/usr/src/kernels目录下,本文使用的是4.20.6内核版本。编译前基于原centos系统中/boot目录下的config文件,生成编译配置项,根据此编译项来定制内核。拷贝原配置文件至内核文件目录 sudo cp /boot/config-3.10.0-693.el7.x86_64 ./.config;执行make oldconfig,生成新的.config文件编译源码:make -j 4 ,可能编译过程中缺少某些库,此时yum安装缺少的库,如openssl-devel, elfutils-libelf-devel安装内核模块:make modules_install -j 4拷贝内核和配置文件至/boot目录,并生成System.map文件:make install -j 4更新引导:grub2-mkconfig -o /boot/grub2/grub.cfg修改默认默认启动引导内核:修改/etc/default/grub文件,将GRUB_DEFAULT设为0,0表示第一个启动项,即为最新编译的内核。重启服务器:reboot 至此告诉你的女神/男神,你想说的话都在ping中。部分参考文章:Understanding Linux Network Internal 第2章&第25章https://www.geeksforgeeks.org/ping-in-c/https://medium.freecodecamp.org/building-and-installing-the-latest-linux-kernel-from-source-6d8df5345980https://github.com/iputils/ip…本文作者:贺小白同学阅读原文本文为云栖社区原创内容,未经允许不得转载。 ...

February 18, 2019 · 1 min · jiezi

virtono年付9.95欧元英国机房VPS测评:速度又快又稳

virtono ,是一个成立于2014年的国外VPS商家,目前在罗马尼亚、荷兰、美国迈阿密、德国法兰克福、英国都有数据中心,其中罗马尼亚是自建的机房。之前virtono支持支付宝和paypal付款,现在开始又支持微信支付,相信会有不少国人用户愿意尝试。VPS小学生也测评过paypal美国迈阿密机房,表现的可以说非常出色。因为之前已经测评过virtono美国迈阿密机房VPS了,这里VPS小学生就入手这款1核CPU、512M内存、20G SSD硬盘、1个IPv4、1TB月流量、OpenVZ架构、年付9.95欧元、英国机房的超低价VPS,和大家分享下virtono英国VPS的性能。同款地址:http://www.vpsxxs.com/goto/7wj9首先看下硬件配置:virtono英国机房硬件测试硬件还是老样子,CPU单核频率还低,处理器有点弱,512M的内存默认1G的Swap内存还不错。20G的硬盘,读写速度虽然不是很优秀不过还不错,可以看到是OpenVZ架构的。国外下载速度也不错,当然我们更关心的是国内下载速度。可以看到各个测试点国内下载速度很平均,而且基本都在30M以上,非常棒的表现了,上传速度差一点,但是也基本都在10M以上,表现很不错。看下到国内的延迟:virtono英国机房ping毕竟不是亚洲机房也不是美国机房,平均延迟260ms,不过这个成绩对于英国机房很不错了,之前测试virtono美国迈阿密机房的时候延迟也是这个数。看下具体的路由图:virtono英国机房电信路由virtono英国机房联通路由virtono英国机房移动路由可以看到电信是直连欧洲,然后经过葡萄牙到英国,联通是从美国到欧洲再到英国,移动也是到欧洲之后再到英国。还好都是小绕,并没有全球绕。看下具体看视频的速度:virtono英国机房看youtube果然不如美国机房,之前测试virtono美国迈阿密机房的时候速度上2万,这只有5000出头,不过看1080P已经很流畅了。虽然CPU弱,但是内存虚拟内存也够用,硬盘也不少,就安装个建站面板试试:virtono英国机房安装宝塔面板可以看到内存占用非常少,还有18G硬盘空间,在安装默认的LNMP环境之后CPU负载倒也不大,只是之前硬件测试的时候能看出来频率还是低,不过用来搭建一般的网站够用了。以上就是VPS小学生对virtono英国机房VPS的测评,可以看到硬件除了CPU差点意思之外其他都很不错,路由对于英国机房来说很不错了,尤其是测试下载速度各个节点都比较快还稳定,只是可以看到IP是罗马尼亚广播过去的,并不是英国原生IP,想看BBC之类的就没希望了,不过用来看youtube的同时用来建站,还是非常适合的。当然virtono还有其他几个机房,有机会VPS小学也会做出测评!

January 30, 2019 · 1 min · jiezi

HostBastic法国OVH机房VPS测评:自带480G DDOS防御的无限流量VPS

之前VPS小学生和大家分享过HostBastic圣诞节七折优惠活动,HostBastic主要经营OVH法国机房,最大的特点当然是OVH自带的防御光环了,现在能打得过OVH自带的480G DDOS防御的还真没几个。只是OVH到中国大陆的线路一直比较糟糕,不知道HostBastic的高防VPS的线路具体表现如何,这里VPS小学生就测试下前几天圣诞节购买的HostBastic这款月付1.39欧元高防VPS的性能。同款详情http://www.vpsxxs.com/goto/93aa 优惠码XMAS2018需要注意的是,HostBastic的服务器在流量用完之后并不扣费或者关机,而是变成10mbps的端口,理论下载速度1M多,够一般网站用了。首先看下硬件配置:hostbastic硬件测试从硬件测试结果来看,CPU的频率倒是挺高的,256M的内存没有虚拟内存,如果是建站使用的话建议用一键代码添加512M的Swap内存。5G硬盘本来就小,这硬盘读写速度标准的石头盘啊,够硬。如果大量的读写硬盘这速度不够用啊。不过5G硬盘容量估计也没大量读写硬盘的机会。国外下载速度比较低,看一下国内下载速度:国内下载速度国内下载速度虽然不高,但是保底还不错,联通电信速度都基本够用,移动的有点勉强。再看一下国内ping值:hostbastic国内ping好巧,正好也是300ms的延迟,之前VPS小学生测评QuickClickHosting法国OVH机房的时候也是这个延迟,不多不少正好300ms,看来OVH这点倒是挺“稳定”的。看下具体的路由图:hostbastic电信路由hostbastic联通路由hostbastic移动路由可以看到电信到美国绕了一圈、联通绕到加拿大,移动也是绕的美国,OVH法国机房依然还是这么绕路。既然是建站用的,就测试一下HostBastic掉包率:hostbastic掉包率掉包率3%,表现的还不错,可以看到VPS小学生本地联通的延迟349ms比较高啊。既然是建站的,其实内存只有256M更适合用军哥LNMP这种一键环境包,不过VPS小学生习惯用可视化面板了,那就还装个宝塔面板试试:hostbastic安装宝塔面板因为内存小,所以重新装了debian系统然后再安装的宝塔面板,可以看到内存占用还是很少的。CPU使用率和负载也都不高,就是硬盘太小了,搭建一两个小网站还行,图片附件多了就不太够用了。以上就是VPS小学生对HostBastic法国OVH机房VPS的测评,可以看到硬件特别是硬盘又小读写速度比较差,内存又小,用来建站多少有些吃力,不过优势就在于是KVM架构了,可以折腾的地方比较多,比如安装BBR加速之类的。下载速度因为机房的原因并不快,不过掉包率还算比较低,用来建站还是比较稳定的。使用法国OVH机房的也都是看中机房自带的防御DDOS攻击,算是比较低廉的防御方法。只是价格其实并不是特别优惠,当然对于有些必须用KVM系统的朋友来说,HostBastic法国OVH机房还是非常好的选择的。

January 19, 2019 · 1 min · jiezi

IDE 插件新版本发布,开发效率 “biu” 起来了

近日,Cloud Toolkit正式推出了面向 IntelliJ 和 Eclipse 两个平台的新款插件,本文挑选了其中三个重大特性进行解读,点击文末官网跳转链接,可查看详细的版本说明。本地应用一键部署到任何机器上IDE 内置的命令行终端文件上传到服务器添加机器到 IntelliJ 或 Eclipse 中需要重点提下的是,虽然这个插件是阿里云官方插件,但了解到我们的开发者,还有不少原来的机器,以及线下环境,因此,这个插件不仅仅适用于阿里云 ECS,任何支持标准 SSH 协议的机器,都适用滴!在 IntelliJ 或 Eclipse,可以通过插件提供的图形引导界面,将机器配置到 IDE 中去。内置终端 Terminal在 IDE 内,开发者可以直接通过内置的终端 Terminal,即可一键快速登陆远程服务器。部署应用到远程服务器Cloud Toolkit 帮助开发者将本地应用程序一键部署到线下自有 VM,或阿里云 ECS、EDAS 和 Kubernetes 中去。当您每次修改完代码后,是否正在经历反复地打包?采用 SCP 工具上传?使用XShell或SecureCRT登陆服务器?替换部署包?重启?现在开始,请把这些重复繁琐的工作交给 Cloud Toolkit 吧!部署到 ECS完成编码后,无需在一系列运维工具之间切换,只需在 Cloud Toolkit 的图形界面上选择目标 ECS 实例,即可将应用部署至 ECS 指定目录部署到线下自有 VM支持 SSH 标准协议,你甚至可以将应用部署到任意机器中去部署到 EDAS针对阿里云 EDAS 开发者, 可以将本地代码和云端应用进行关联,实现自动化的部署部署到 Kubernetes针对阿里云 Kubernetes 开发者, 可以将本地代码和云端容器进行关联,实现自动化的镜像上传和部署文件上传Cloud Toolkit 帮助开发者在 IDE 内,一键将本地或者远程 URL 文件上传到服务器指定目录下去,无需在各种 FTP、SCP 工具之间频繁切换。更为重要的是,文件上传完毕后,还支持命令执行,比如:文件解压缩、程序启动等。官网https://toolkit.aliyun.com文档中心https://yq.aliyun.com/articles/665049需求Bug反馈https://www.wenjuan.com/s/emIFb2/本文作者:银时,Cloud Toolkit产品经理,《从Paxos到ZooKeeper》作者。立即点击下载官网:https://toolkit.aliyun.com本文作者:中间件小哥阅读原文本文为云栖社区原创内容,未经允许不得转载。

January 17, 2019 · 1 min · jiezi

如何“神还原”数据中心? 阿里联合NTU打造了工业级精度的仿真沙盘!

阿里妹导读:如何保障数据中心的稳定运行,是多年来一直困扰业界的难题。机房环境如果发生未预期变化,可能造成难以估计的损失。所以我们希望能构建一个“变更沙盘”,在真实变更之前,操作人员可以先在沙盘中进行试变更,若变更效果在预期内,再对真实环境进行变更,从而尽可能减少变更导致的机房故障。近期,阿里巴巴-南大联合研究院联合实现并上线完成了一个高精度,可连接实时监控系统、基于CFD的变更沙盘系统。本系统在off-the-shelf CFD软件上实现了工业级精度的变更沙盘测试和验证。今天,我们就来观摩这个从零到一的尝试。项目背景随着阿里巴巴业务不断拓展,其数据中心规模也越来越大。相应地,数据中心内的日常演练、运营优化等变更操作越来越频繁;而规模增加导致环境的复杂程度呈指数增长,变更是否可能导致故障,仅凭专家经验,已经越来越难以判断。同时,数据中心变更故障可能造成的业务影响也越来越大,可能造成的损失已难以估计。所以,机房运营人员急需一个标准化的、可靠的机房变更安全验证系统,帮助他们获知变更产生的具体效果会是如何,是否影响生产安全,是否有更合理的变更建议。对于电力变更,可以从电力拓扑图着手构建变更沙盘。但暖通变更,涉及到气流组织变化、热力变化,这些东西看不见也摸不着,传统的方式难以模拟出现实世界中的变化。IDC运营优化团队对此进行了一系列调研工作,认为利用计算流体力学(ComputationalFluid Dynamics,简称CFD)进行机房仿真是较为可能达到生产标准的一种方式。现有的类似的解决方案利用计算流体力学(Computational Fluid Dynamics,简称CFD)进行机房仿真是检查不同变更对机房的热力学影响的通用解决方案。CFD建模可以通过搭建物理模型,载入现实中的热力学设置(冷热量,空调server风速等)来计算一个包间内部的气流分布和温度情况。CFD模拟有较为成熟的技术积累,并被广泛应用与热力学和空气动力学领域。在数据中心领域,也有从包间到芯片级的CFD模拟应用。但由于其精度限制,一般只用于前期设计和规划。应用CFD建立沙盘系统的挑战:1)现有商业CFD软件可以根据对包间进行仿真,得到机房的热力分布、气流动向。但该软件通常应用于设计阶段,采用设计阶段的粗略数据进行模拟,对真实操作情况的还原度较低,温度预测精度仅能达到3度或以上,不能满足用于变更沙盘的精度需求。2)当前CFD软件以人工交互为主,缺少对自动化操作的支持,不能满足自动获取数据和返回结果的需求。大量的操作只能通过人机交互进行,效率低下。3)建模所需要的数据真实性问题。由于模型的准确性与其所采用的模拟设置与实际是否一致息息相关,因此获取的模拟设置信息(如功耗,空调设置信息等)准确性非常关键。通常这些信息是在设计阶段确定的,也有部分是运行时获得的。这些数据只有进行精细的核实才能保证建模的精度(反过来建模的过程可以反推设计实施情况和数据的标准化过程)。我们的解决方案阿里巴巴联合新加坡南洋理工大学(NTU)计算机科学与工程学院文勇刚教授团队,依托阿里巴巴-南大联合研究院平台,通过接近1年的研究,开发和测试,实现并上线完成了一个高精度,可连接实时监控系统的基于CFD的变更沙盘系统。本系统在off-the-shelf CFD软件上实现了工业级精度的变更沙盘测试和验证。本次项目选定了某个机房包间作为技术试点,并在对该机房的物理建模,模型校准和工程落地上进行了紧密合作。1)物理建模:该过程主要将包间内各物理结构设置到模型,提供仿真基础。以达到最好还原度为准则,我们实现了下面所述方面的建模操作:结构建模:对机房结构、墙、通风口、天花板、管道进行设置IT部署建模:机列、机柜、机位设置环境建模:空调设备、传感器设置设备建模:按厂商型号导入服务器模型2)模型校准模型校准的主要原则需要达到下述3个方面的真实还原:机房冷热温度来源:校准中需要确认模型中冷热量与实际一致。机房气流变化原因:校准中需要保证冷热风气流与实际一致。温度测量数据:校准中需要保证模型预测温度与实际一致。为了保证模型可以到工业级精度,项目团队进行了大量的数据核准和模型调整工作。这些工作全方位地对整个机房的相关信息和设置进行了梳理和核实,并形成了完整的标准化校准文档,为以后建模推广打下了坚实的基础。这些校准操作可以分为2类:第1类:数据核准服务器核准(包含:少数服务器U位冲突、服务器功耗校准)传感器核准(包含:空调供风温度、转速和冷热通道传感器位置、数据)第2类:模型调整热气泄露设置调整,热气泄露会导致冷通道温度升高。机柜模拟模式调整,设置为细粒度模拟模式。Server风量设置调整,精确设置server风速以符合实际需求。依托大量的传感器数据,通过上述校准操作,最终模型达到了设计阶段CFD使用未有过的精度。这些精度来源于我们精确地还原各项硬件的布置,各个操作的数据核准和细粒度的server风速校准。3)工程落地如图所示为沙盘系统的流程图。在模型达到预期精度后,团队进一步解决了CFD模拟的自动化问题。通过接入阿里巴巴自研的数据中心实时监控系统(DCIM),我们获取到实时的服务器功耗、空调出风温度和风机转速等数据,通过6Sigma开放SDK将数据写入CFD模型,从而使得模型能够实时模拟包间内真实情况。此外,一旦仿真计算完成后,我们将计算结果从模型中导出,回传到监控系统,从而完成一次仿真计算的闭环。如此,我们实现了将沙盘系统整合进入DCIM系统,并且全程操作可以自动化进行,为将来沙盘系统的应用和推广打下了坚实基础。最终成果:1)精度达标:模型采用真实的监控数据作为输入,并计算模拟的目标传感器测温与实际的传感器测温之间的平均绝对误差(MAE)来作为模型的准确性的测量依据。经过长时间观察(采用不同时刻的数据进行验证),模型模拟精度均能达到阿里巴巴数据中心建设标准要求。理论上可以替代冷热通道传感器,进行数据中心生产包间环境监控。2)成功落地:目前该模型已经成功接入DCIM系统,可以自动从DCIM中抓取数据,返回结果。当前模拟的时耗为大约1小时,通过升级6Sigma License规格未来有希望提升到10分钟。接入该实时CFD模拟系统意味着阿里自研DCIM系统成为世界上唯一有高精度实时CFD模拟模块的数据中心云维管理系统。变更沙盘系统的价值包间可视化:由原来的2D、数字的方式,升级为3D、图形数字结合的展现方式,包括实际布局、热力情况、气流情况,从而可以让机房经理与设施专家能更直观、全面、迅速地了解机房的整体情况,更快发现包间暖通环境问题,辅助优化现场供冷分配与气流组织。故障发现:可以厘米级别监测包间内的温度,快速发现温升(局部热点),从而具备更快、更强的风险识别能力,防止出现大范围的机房温升事件。设计验证:建模过程所需要的物理设置信息通常决定于设计阶段。建模过程中得到的误差反馈信息可以直接验证设计与实施的差别。设计优化(变更指引):沙盘系统可以模拟不同设计下数据中心的操作情况,从而可以用于设计上的优化和数据中心变更的先验平台。暖通控制推荐:可以通过尝试不同空调设置应用到当前环境,得到温度控制最佳、能耗最低的空调设置,实现包间内供冷可靠、智能的控制。业务调度推荐:根据详细的机房温度分布情况,结合功耗水位数据,可以向业务调度系统提供调度参考,使得业务分布更均匀,机房温度分布也更加均匀,降低制冷能耗,提升服务器健康度。未来展望未来合作的方向之一是对变更沙盘系统进行产业级推广和验证,目标是做出业界标准。使得变更沙盘系统可以应用与阿里数据中心的更多机房,去验证设计和优化管理控制。未来,我们希望将系统沙盘推广到整个暖通系统,覆盖到机房外的制冷设备,实现全链条模拟。从而实现整个制冷系统的设计验证和控制优化。综上,变更沙盘系统将可以显著促进数据中心设计到运维的自动化水平,为实现更稳定更高效的数据中心运维提供支撑。这是一次从零到一的尝试,我们构建了第一个可实时的、高精度的暖通变更系统,帮助数据中心运维人员能够判断一次变更是否可能造成故障,从而减少由变更导致的故障。进一步,我们可以给出具体的变更后环境变化,给出变更建议,甚至能够实现自动变更。如此,我们将离机房无人值守的目标越来越近。本文作者:阿里&NTU阅读原文本文来自云栖社区合作伙伴“阿里技术”,如需转载请联系原作者。

January 15, 2019 · 1 min · jiezi

Google Cloud 释放外网IP

Google Cloud 释放外网IP 来自Google Cloud 一年免费版的受益者近几日突然发现上推的时候,访问情况不稳,时断时续,而且出现了访问速度急速下降的问题,就比如说在推特看小视频,以前缓冲几乎是秒级别,现在就会卡顿顿的,看的不爽,自然心情也就不好。 Google Cloud 比 vultr 好一点的地方是服务器的IP可以单独配置,这样就可以既保留我服务器上的资源也可以同时避免被墙的尴尬。 第一步 在自己的 Compute Engine 中修改服务器的外网IP为 “空” 或者 “临时” ,目的是为了释放外网IP做准备。⬇点击修改按钮,进入修改模式⬇修改外部IP为“空”或“临时”⬇记得在底部点击保存按钮,这时外部IP是无占用状态第二步 释放外网IP⬇进入VPC网络 ⬇点击选中需要释放的IP,点击右上角“释放” 第三步 重新创建IP,回到第一步骤修改的状态,点击外部IP之后有一项是创建外部IP,创建即可。

December 24, 2018 · 1 min · jiezi

阿里云学生优惠,云服务器月付9.5元起

阿里云+校园推出的学生优惠活动,又名云翼计划,云计算普惠校园计划,助力学生的辉煌明天!完成学生认证后(24以下自动认为是学生),可享最低9.5元/月的100%CPU性能服务器,是拿来学习Linux技术,或者建议个人服务器/个人网站的不二选择。阿里云学生优惠注意:这款优惠活动是针对学生的,在购买前需要完成学生认证(支持支付宝的一键认证),如果你是24周岁以下,那么自动获得学生身份。活动地址:阿里云学生优惠(云翼计划)依次选择页面的弹性计算 -> 学生专享 服务器9.5元/月:之后就可以看到阿里云的学生优惠产品,包括2款:①轻量应用服务器/100% CPU性能/1核/2G/5M带宽/1000G流量/40G SSD;②云服务器ECS/100% CPU性能/1核/2G/1M带宽/40G SSD。个人比较推荐轻量应用服务器那一款,5M的带宽峰值做一个站已经算比较快的了,满足小几千IP没有问题,1000G流量基本是不可能用完的:阿里云学生优惠注意点此次优惠必须是学生才能参加。在购买前需要完成学生认证,可以直接认证(提供学校信息,个人信息,学号等),可以支付宝学生认证直接授权,或者是24岁以下直接获得学生身份。原文地址:阿里云学生优惠:云翼计划,云服务器9.5元起

December 20, 2018 · 1 min · jiezi

新手也能看懂,消息队列其实很简单

该文已加入开源项目:JavaGuide(一份涵盖大部分Java程序员所需要掌握的核心知识的文档类项目,Star 数接近 16k)。地址:https://github.com/Snailclimb/JavaGuide.本文内容思维导图:消息队列其实很简单 “RabbitMQ?”“Kafka?”“RocketMQ?”…在日常学习与开发过程中,我们常常听到消息队列这个关键词。我也在我的多篇文章中提到了这个概念。可能你是熟练使用消息队列的老手,又或者你是不懂消息队列的新手,不论你了不了解消息队列,本文都将带你搞懂消息队列的一些基本理论。如果你是老手,你可能从本文学到你之前不曾注意的一些关于消息队列的重要概念,如果你是新手,相信本文将是你打开消息队列大门的一板砖。一 什么是消息队列 我们可以把消息队列比作是一个存放消息的容器,当我们需要使用消息的时候可以取出消息供自己使用。消息队列是分布式系统中重要的组件,使用消息队列主要是为了通过异步处理提高系统性能和削峰、降低系统耦合性。目前使用较多的消息队列有ActiveMQ,RabbitMQ,Kafka,RocketMQ,我们后面会一一对比这些消息队列。 另外,我们知道队列 Queue 是一种先进先出的数据结构,所以消费消息时也是按照顺序来消费的。比如生产者发送消息1,2,3…对于消费者就会按照1,2,3…的顺序来消费。但是偶尔也会出现消息被消费的顺序不对的情况,比如某个消息消费失败又或者一个 queue 多个consumer 也会导致消息被消费的顺序不对,我们一定要保证消息被消费的顺序正确。 除了上面说的消息消费顺序的问题,使用消息队列,我们还要考虑如何保证消息不被重复消费?如何保证消息的可靠性传输(如何处理消息丢失的问题)?……等等问题。所以说使用消息队列也不是十全十美的,使用它也会让系统可用性降低、复杂度提高,另外需要我们保障一致性等问题。二 为什么要用消息队列 我觉得使用消息队列主要有两点好处:1.通过异步处理提高系统性能(削峰、减少响应所需时间);2.降低系统耦合性。如果在面试的时候你被面试官问到这个问题的话,一般情况是你在你的简历上涉及到消息队列这方面的内容,这个时候推荐你结合你自己的项目来回答。 《大型网站技术架构》第四章和第七章均有提到消息队列对应用性能及扩展性的提升。(1) 通过异步处理提高系统性能(削峰、减少响应所需时间) 如上图,在不使用消息队列服务器的时候,用户的请求数据直接写入数据库,在高并发的情况下数据库压力剧增,使得响应速度变慢。但是在使用消息队列之后,用户的请求数据发送给消息队列之后立即 返回,再由消息队列的消费者进程从消息队列中获取数据,异步写入数据库。由于消息队列服务器处理速度快于数据库(消息队列也比数据库有更好的伸缩性),因此响应速度得到大幅改善。 通过以上分析我们可以得出消息队列具有很好的削峰作用的功能——即通过异步处理,将短时间高并发产生的事务消息存储在消息队列中,从而削平高峰期的并发事务。 举例:在电子商务一些秒杀、促销活动中,合理使用消息队列可以有效抵御促销活动刚开始大量订单涌入对系统的冲击。如下图所示: 因为用户请求数据写入消息队列之后就立即返回给用户了,但是请求数据在后续的业务校验、写数据库等操作中可能失败。因此使用消息队列进行异步处理之后,需要适当修改业务流程进行配合,比如用户在提交订单之后,订单数据写入消息队列,不能立即返回用户订单提交成功,需要在消息队列的订单消费者进程真正处理完该订单之后,甚至出库后,再通过电子邮件或短信通知用户订单成功,以免交易纠纷。这就类似我们平时手机订火车票和电影票。(2) 降低系统耦合性 我们知道如果模块之间不存在直接调用,那么新增模块或者修改模块就对其他模块影响较小,这样系统的可扩展性无疑更好一些。 我们最常见的事件驱动架构类似生产者消费者模式,在大型网站中通常用利用消息队列实现事件驱动结构。如下图所示: 消息队列使利用发布-订阅模式工作,消息发送者(生产者)发布消息,一个或多个消息接受者(消费者)订阅消息。 从上图可以看到消息发送者(生产者)和消息接受者(消费者)之间没有直接耦合,消息发送者将消息发送至分布式消息队列即结束对消息的处理,消息接受者从分布式消息队列获取该消息后进行后续处理,并不需要知道该消息从何而来。对新增业务,只要对该类消息感兴趣,即可订阅该消息,对原有系统和业务没有任何影响,从而实现网站业务的可扩展性设计。 消息接受者对消息进行过滤、处理、包装后,构造成一个新的消息类型,将消息继续发送出去,等待其他消息接受者订阅该消息。因此基于事件(消息对象)驱动的业务架构可以是一系列流程。 另外为了避免消息队列服务器宕机造成消息丢失,会将成功发送到消息队列的消息存储在消息生产者服务器上,等消息真正被消费者服务器处理后才删除消息。在消息队列服务器宕机后,生产者服务器会选择分布式消息队列服务器集群中的其他服务器发布消息。备注: 不要认为消息队列只能利用发布-订阅模式工作,只不过在解耦这个特定业务环境下是使用发布-订阅模式的。除了发布-订阅模式,还有点对点订阅模式(一个消息只有一个消费者),我们比较常用的是发布-订阅模式。 另外,这两种消息模型是 JMS 提供的,AMQP 协议还提供了 5 种消息模型。三 使用消息队列带来的一些问题系统可用性降低: 系统可用性在某种程度上降低,为什么这样说呢?在加入MQ之前,你不用考虑消息丢失或者说MQ挂掉等等的情况,但是,引入MQ之后你就需要去考虑了!系统复杂性提高: 加入MQ之后,你需要保证消息没有被重复消费、处理消息丢失的情况、保证消息传递的顺序性等等问题!一致性问题: 我上面讲了消息队列可以实现异步,消息队列带来的异步确实可以提高系统响应速度。但是,万一消息的真正消费者并没有正确消费消息怎么办?这样就会导致数据不一致的情况了!四 JMS VS AMQP4.1 JMS4.1.1 JMS 简介 JMS(JAVA Message Service,java消息服务)是java的消息服务,JMS的客户端之间可以通过JMS服务进行异步的消息传输。JMS(JAVA Message Service,Java消息服务)API是一个消息服务的标准或者说是规范,允许应用程序组件基于JavaEE平台创建、发送、接收和读取消息。它使分布式通信耦合度更低,消息服务更加可靠以及异步性。ActiveMQ 就是基于 JMS 规范实现的。4.1.2 JMS两种消息模型①点到点(P2P)模型 使用队列(Queue)作为消息通信载体;满足生产者与消费者模式,一条消息只能被一个消费者使用,未被消费的消息在队列中保留直到被消费或超时。比如:我们生产者发送100条消息的话,两个消费者来消费一般情况下两个消费者会按照消息发送的顺序各自消费一半(也就是你一个我一个的消费。)② 发布/订阅(Pub/Sub)模型 发布订阅模型(Pub/Sub) 使用主题(Topic)作为消息通信载体,类似于广播模式;发布者发布一条消息,该消息通过主题传递给所有的订阅者,在一条消息广播之后才订阅的用户则是收不到该条消息的。4.1.3 JMS 五种不同的消息正文格式 JMS定义了五种不同的消息正文格式,以及调用的消息类型,允许你发送并接收以一些不同形式的数据,提供现有消息格式的一些级别的兼容性。StreamMessage – Java原始值的数据流MapMessage–一套名称-值对TextMessage–一个字符串对象ObjectMessage–一个序列化的 Java对象BytesMessage–一个字节的数据流4.2 AMQP AMQP,即Advanced Message Queuing Protocol,一个提供统一消息服务的应用层标准 高级消息队列协议(二进制应用层协议),是应用层协议的一个开放标准,为面向消息的中间件设计,兼容 JMS。基于此协议的客户端与消息中间件可传递消息,并不受客户端/中间件同产品,不同的开发语言等条件的限制。RabbitMQ 就是基于 AMQP 协议实现的。4.3 JMS vs AMQP对比方向JMSAMQP定义Java API协议跨语言否是跨平台否是支持消息类型提供两种消息模型:①Peer-2-Peer;②Pub/sub提供了五种消息模型:①direct exchange;②fanout exchange;③topic change;④headers exchange;⑤system exchange。本质来讲,后四种和JMS的pub/sub模型没有太大差别,仅是在路由机制上做了更详细的划分;支持消息类型支持多种消息类型 ,我们在上面提到过byte[](二进制)总结:AMQP 为消息定义了线路层(wire-level protocol)的协议,而JMS所定义的是API规范。在 Java 体系中,多个client均可以通过JMS进行交互,不需要应用修改代码,但是其对跨平台的支持较差。而AMQP天然具有跨平台、跨语言特性。JMS 支持TextMessage、MapMessage 等复杂的消息类型;而 AMQP 仅支持 byte[] 消息类型(复杂的类型可序列化后发送)。由于Exchange 提供的路由算法,AMQP可以提供多样化的路由方式来传递消息到消息队列,而 JMS 仅支持 队列 和 主题/订阅 方式两种。五 常见的消息队列对比对比方向概要吞吐量万级的 ActiveMQ 和 RabbitMQ 的吞吐量(ActiveMQ 的性能最差)要比 十万级甚至是百万级的 RocketMQ 和 Kafka 低一个数量级。可用性都可以实现高可用。ActiveMQ 和 RabbitMQ 都是基于主从架构实现高可用性。RocketMQ 基于分布式架构。 kafka 也是分布式的,一个数据多个副本,少数机器宕机,不会丢失数据,不会导致不可用时效性RabbitMQ 基于erlang开发,所以并发能力很强,性能极其好,延时很低,达到微秒级。其他三个都是 ms 级。功能支持除了 Kafka,其他三个功能都较为完备。 Kafka 功能较为简单,主要支持简单的MQ功能,在大数据领域的实时计算以及日志采集被大规模使用,是事实上的标准消息丢失ActiveMQ 和 RabbitMQ 丢失的可能性非常低, RocketMQ 和 Kafka 理论上不会丢失。总结:ActiveMQ 的社区算是比较成熟,但是较目前来说,ActiveMQ 的性能比较差,而且版本迭代很慢,不推荐使用。RabbitMQ 在吞吐量方面虽然稍逊于 Kafka 和 RocketMQ ,但是由于它基于 erlang 开发,所以并发能力很强,性能极其好,延时很低,达到微秒级。但是也因为 RabbitMQ 基于 erlang 开发,所以国内很少有公司有实力做erlang源码级别的研究和定制。如果业务场景对并发量要求不是太高(十万级、百万级),那这四种消息队列中,RabbitMQ 一定是你的首选。如果是大数据领域的实时计算、日志采集等场景,用 Kafka 是业内标准的,绝对没问题,社区活跃度很高,绝对不会黄,何况几乎是全世界这个领域的事实性规范。RocketMQ 阿里出品,Java 系开源项目,源代码我们可以直接阅读,然后可以定制自己公司的MQ,并且 RocketMQ 有阿里巴巴的实际业务场景的实战考验。RocketMQ 社区活跃度相对较为一般,不过也还可以,文档相对来说简单一些,然后接口这块不是按照标准 JMS 规范走的有些系统要迁移需要修改大量代码。还有就是阿里出台的技术,你得做好这个技术万一被抛弃,社区黄掉的风险,那如果你们公司有技术实力我觉得用RocketMQ 挺好的kafka 的特点其实很明显,就是仅仅提供较少的核心功能,但是提供超高的吞吐量,ms 级的延迟,极高的可用性以及可靠性,而且分布式可以任意扩展。同时 kafka 最好是支撑较少的 topic 数量即可,保证其超高吞吐量。kafka 唯一的一点劣势是有可能消息重复消费,那么对数据准确性会造成极其轻微的影响,在大数据领域中以及日志采集中,这点轻微影响可以忽略这个特性天然适合大数据实时计算以及日志收集。参考:《Java工程师面试突击第1季-中华石杉老师》本文作者:snailclimb阅读原文本文为云栖社区原创内容,未经允许不得转载。 ...

December 19, 2018 · 1 min · jiezi

一天超2000次,阿里如何打响音视频超时空战役?

阿里妹导读:在阿里,音视频会议已经成为跨地区沟通、开会以及招聘的首选方式。据悉,目前阿里巴巴的办公网络与音视频会议已经覆盖全球33个国家和地区,其中,音视频会议在过去3个月平均每天召开超过2000余场。在使用如此频繁、覆盖面如此之广的音视频场景中,如何满足全球各地使用者的不同需求,保障交流的顺畅?下面,我们一起来探讨、研究。音视频行业的发展音视频行业发展迅速,经历了1970年代的黑白时代、1980年代的数字化时代、1990年代的数字标清时代、2006-2015年代的高清时代,2016年逐步开始以融合通信为主的行业趋势,高质量(4K,高清,高帧率,HDR)、多场景(点播,直播,实时通讯)、云化(硬件软件化,平台云化)和行业化已经成为当下音视频行业的发展趋势。音视频行业未来的发展趋势,在我看来就是云+端+服务。云:平台云化,从PaaS到SaaS,从私有公有云,一切都是基于云的服务。端:兼容各种终端,PSTN和VOIP,会议室设备,手机,PC,Web,Android终端等。服务:包括短信,语音,IM,音视频,呼叫中心,云客服和附加AI服务等多种服务。目前,音视频已广泛应用于包括B2B(企业与企业间、企业内部间)、C2C(用户与用户间),以及B2C(企业和用户间)。根据著名Cisco的VNI(Virtual Network Index)预测,到2021年,地球上将有46亿互联网用户,271亿联网设备,82%互联网的流量是视频。每一秒钟将会有一百万分钟的视频内容被创建,其中4K高清的内容会增加30%,相当于每个月生成71亿部DVD影片,直播的需求也会大幅增长15倍。从视频本身发展的趋势看也是一路狂奔向高清、CIP、4CIP、720P、1080P、UHD4K和8K;加上高帧率FPS 120-160FPS、HDR(High Dynamic Range)、宽色域(Wide Color Gamut),一切发展变化都是为了给人一种身临其境的Immersive体验。当然还有VR、AR、360视频,这所有的一切都意味着更多的视频数据流将被生成和消费。网络环境让我们需不断完善音视频服务如果网络带宽是无限且畅通无阻的,那世界将是多么美好。但网络并不是一马平川的。有时像十一长假堵车,有时像乡间泥泞小道,而且还有可能布满大坑。根据Silver-Peak跨美国和欧洲的网络健康报告发现,网络传输的延时、抖动和丢包是普遍存在现象。有时网络状况就像天气一样令人难以捉摸。虽然网络的平均丢包率只有0.34%,但个别情况下可以达到2.2%;而且丢包从来都不是均匀的,是突发性的Burst,网络延迟可能会超过平均值300多倍。这些极端的网络情况对音视频的传输和用户体验来说,都是极大挑战。网络和音视频流量的供求矛盾,网络传输的不确定和不完善的残酷现实,倒逼着我们不断完善和监控音视频服务。音视频内容从生产到消费的过程会经历不同环节,且链路较长,其中涉及的技术也较多,下面将主要对其中的视频编码,网络构架进行解析。视频编码视频编码标准的选择视频编码标准作为视频技术的核心,在过去几个世纪出现过很多不同标准,但最终被市场采纳主要为以下两套体系:一套是标准化体系的H264、H265 和正在制定中的VVC;另一套是开源无版税的VP8、VP9和AOM(Alliance for Open Meida)的AV1。阿里巴巴是AOM的成员也同时积极参与VVC的制定,对于视频编码的核心不能被掐住发展的咽喉。针对不同场景的不同编码需求视频不同的应用场景(如:点播、直播、实时通讯),决定了在每一个应用场景底下对编码的不同需求。对点播而言最重要的是编码效率,如何有效节约带宽。直播对延时有要求,但是是在秒级的,对编码的速度和稳定性的需求也比点播高。实时通讯对“点对点”的延时要求最高,同时它对稳定性和容错性的要求也很高,这需要通过平衡编码效率来实现。如何配对编码率与分辨率视频编码以前简单地采用固定压缩参数,固定码率和固定分辨率,对于HLS和MPEG-DASH的ABR(Adaptive Bitrate),也用固定编码率和分辨率来配对。这就无法满足不同视频对码率的不同需求。1M的720P动画片看起来可能已经不错了,但是1M的720P动作片看起来就会很糊。但对于ABR,编码率和分辨率也是一个动态平衡的过程。在低码率的情况下用低分辨率以减少块状效果(blocking effects),当码率的提高到一定程度时提升分辨率,包围不同分辨率RD曲线的就是凸包(Convex Hall)。曲线中的交叉点就是理性的编码率和分辨率配对。如何确定视频质量的衡量指标但怎么确定曲线中的交叉点呢?这需要有衡量视频质量的指标。通常的视频指标包括主观的MOS分和客观指标比如PSNR,SSIM和VMAF。阿里巴巴的视频质量指标,不但结合了通用的客观指标,也同时考虑了影响播放质量的的卡顿和网络状况。如何进行自适应编码自适应编码(Content Adaptive Encoding)是视频编码的一大趋势。从One-size-fit-all的单一编码参数、码率和分辨率配对,到根据视频内容的复杂度进行定制化的编码参数适配。自适应编码可以针对单个视频、场景、GOP,甚至是Frame用不同的压缩参数进行动态调整,这样最大限度优化视频质量、节约带宽。这种自适应优化最重要的就是视频质量的衡量指标。一旦定义好可用的指标,就可以围绕它进行不同层次的优化。对于自适应编码,机器学习可以大有用处。比如利用机器学习针对不同的视频特征,找到对应优化的编码参数。人脑占人身体的比例不大,但是消耗人体大约1/3的能量,人的基因特性决定了大脑只会关注画面中重要区域,忽略不重要的区域。利用这种ROI(Region of Interest)进行编码,就可以在保持视频主观质量的情况下减少编码率。比如人脸和文字是经验意义下的ROI的例子。音视频服务器网络架构实时音视频服务器的网络架构,除了MESH外,还有MCU(Multi-point Control Unit)和SFU(Selectiveforward Unit)两种。MCU是集中的媒体处理服务,优势在于可以对媒体和信令进行控制和转换,如对媒体进行转码、转流、混屏、分流,对信令进行转换,对媒体包进行路由优化等等。MCU可以减低Client端的CPU和对网络带宽的需求,但是MCU的缺点也较明显,那就是服务器CPU的开销以及带来的延迟。相对MCU来说,目前更流行的架构是SFU,它主要的好处是简单、低时延、高吞吐,缺点是对client端的带宽要求比较高,client上传一路或者多路流同时下载多路流。SFU的客户端可以发单流、多流(Simulcast)和SVC。根据运用场景的不同,客户端发流策略也不同。在阿里巴巴的音视频会议系统中,采用的是一种SFU+MCU的混合模式,以保证最大的兼容性。这种SFU和MCU级联的策略保证对各类客户端的最大灵活性。此外媒体服务器在不同区域可以进行级联,客户端就近入会、就近补包,减低第一公里和最后一公里对音视频质量的影响。网络带宽评估网络带宽评估是实时通话的关键技术。阿里巴巴在这方面进行了很多针对会议室场景的优化。并且通过评估算法可以在服务器端快速发布,不用等待更新客户端软件。在弱网不可避免的情况下,通过合理的带宽分配,确保音频优先传输,同时及时把弱网信息传达给用户,同样可以得到用户理解,提升用户体验。后记音视频提供的是服务,不是单点的QoS,用户的最终体验不是简单的抗丢包率、卡顿率的指标,而是端到端的体验。所以不仅需要我们在事先创造一个良好的音视频环境,更需要我们对整体链路进行质量监控。除了能及时发现问题,快速响应外,还能帮助我们不断发现与创造更多新业务场景。通过把业务数据化,再根据数据来指导业务,这样才能让音视频的服务体验达到极致。本文作者:致凡阅读原文本文来自云栖社区合作伙伴“ 阿里技术”,如需转载请联系原作者。

December 18, 2018 · 1 min · jiezi

每一个工程师都要学的安全测试,老板再也不用担心服务器被黑

本文由云+社区发表本篇包含了XSS漏洞攻击及防御详细介绍,包括漏洞基础、XSS基础、编码基础、XSS Payload、XSS攻击防御。第一部分:漏洞攻防基础知识XSS属于漏洞攻防,我们要研究它就要了解这个领域的一些行话,这样才好沟通交流。同时我建立了一个简易的攻击模型用于XSS漏洞学习。1. 漏洞术语了解一些简单术语就好。VULVulnerability漏洞,指能对系统造成损坏或能借之攻击系统的Bug。POCProof of Concept,漏洞证明;可以是可以证明漏洞存在的文字描述和截图,但更多的一般是证明漏洞存在的代码;一般不会破坏存在漏洞的系统。EXPexploit,漏洞利用;利用漏洞攻击系统的代码。Payload(有效攻击负载)是包含在你用于一次漏洞利用(exploit)中的攻击代码。PWN是一个黑客语法的俚语词 ,是指攻破设备或者系统。0DAY漏洞和0DAY攻击零日漏洞或零时差漏洞(Zero-dayexploit)通常是指还没有补丁的安全漏洞。零日攻击或零时差攻击(Zero-dayattack)则是指利用这种漏洞进行的攻击。零日漏洞不但是黑客的最爱,掌握多少零日漏洞也成为评价黑客技术水平的一个重要参数。CVE漏洞编号Common Vulnerabilities and Exposures,公共漏洞和暴露,为广泛认同的信息安全漏洞或者已经暴露出来的弱点给出一个公共的名称。可以在https://cve.mitre.org/网站根据漏洞的CVE编号搜索该漏洞的介绍。也可以在中文社区http://www.scap.org.cn/上搜索…2. 漏洞攻击模型1.png上图为一个简单的攻击模型。攻击就是将Payload通过注入点注入到执行点执行的过程。过程顺畅就表明这个漏洞被利用了。第二部分:XSS基础知识基础知识看完,现在我们可以开始接触了解XSS基础了。XSS基础不好就不用研究了,大家没用共同语言。1. 什么是XSS?XSS全称Cross-site scripting,跨站脚本攻击。攻击者通过网站注入点注入恶意客户端可执行解析的Payload,当被攻击者访问网站时Payload通过客户端执行点执行来达到某些目的,比如获取用户权限、恶意传播、钓鱼等行为。2. XSS的分类不了解分类其实很难学好XSS,大家对XSS分类有很多误解,而且很多文章上都解释错的,这里我给出一个相对好的XSS分类。2.1 按照Payload来源划分存储型XSSPayload永久存在服务器上,所以也叫永久型XSS,当浏览器请求数据时,包含Payload的数据从服务器上传回并执行。过程如图:2.png存储型XSS例子:发表帖子内容包含Payload->存入数据库->被攻击者访问包含该帖子的页面Payload被执行反射型XSS又称非持久型XSS,第一种情况:Payload来源在客户端然后在客户端直接执行。第二种情况:客户端传给服务端的临时数据,直接回显到客户端执行。过程如图:3.png反射型XSS例子 :传播一个链接,这个链接参数中包含Payload->被攻击者访问这个链接Payload在客户端被执行。在客户端搜索框输入包含payload的内容->服务端回显一个页面提示搜索内容未找到,payload就被执行了。2.2 按照Payload的位置划分DOM-based XSS由客户端JavaScript代码操作DOM或者BOM造成Payload执行的漏洞。由于主要是操作DOM造成的Payload执行,所以叫做DOM-based XSS,操作BOM同样也可以造成Payload执行,所以这个名词有些不准确,其实叫JavaScript-based XSS更好。DOM-based的Payload不在html代码中所以给自动化漏洞检测带来了困难。过程如图:4.png反射型DOM-based XSS的例子:在客户端搜索框输入包含payload的内容->服务端回显一个页面提示搜索内容未找到,payload就被执行了。存储型DOM-based XSS的例子:从服务端接口中获取包含Payload的内容->JavaScript通过操作DOM、BOM造成Payload执行HTML-based XSSPayload包含在服务端返回的HTML中,在浏览器解析HTML的时候执行。这样的漏洞易于做自动化漏洞检测,因为Payload就在HTML里面。当然HTML-based XSS也有反射型和存储型的。过程如图:5.png反射型HTML-based XSS的例子:在客户端搜索框输入包含payload的内容->服务端回显一个页面提示搜索内容未找到,payload包含在HTML被执行。存储型HTML-based XSS的例子:发表帖子内容包含Payload->存入数据库->被攻击者访问包含该帖子的页面Payload在HTML页面中被执行3. XSS的攻击目的及危害很多写出不安全代码的人都是对漏洞的危害没有清晰的认识,下图是2017 OWASP 网络威胁Top10:6_头图 自截取.jpg可以看到XSS在网络威胁中的地位举足轻重。3.1 目的cookie劫持篡改网页,进行钓鱼或者恶意传播网站重定向获取用户信息3.2 危害传播类危害系统安全威胁第三部分:XSS攻击的Payload这部分我们分析下攻击模型中的Payload,了解Payload必须了解编码,学习好JS也必须要了解好编码。要想真正做好网络安全编码是最基本的。1. 编码基础编码部分是最重要的虽然枯燥但必须要会。后面很多变形的Payload都建立在你的编码基础。这里通16进制编码工具让你彻底学会编码。1.1 编码工具16进制查看器:方便查看文件16进制编码MAC:HEx Friendwindows: HxD编辑器Sublime:可以通过Sublime将文件保存不同编码类型7.jpg1.2 ASCII定义:美国信息交换标准代码,是基于拉丁字母的一套计算机编码系统,主要用于显示现代英语和其他西欧语言。编码方式:属于单子节编码。ASCII码一共规定了128个字符的编码,只占用了一个字节的后面7位,最前面的1位统一规定为0。0~31及127(共33个)是控制字符或通信专用字符。32~126(共95个)是字符(32是空格。1.3 ISO-8859-1(Latin1)定义:Latin1是ISO-8859-1的别名,ISO-8859-1收录的字符除ASCII收录的字符外,还包括西欧语言、希腊语、泰语、阿拉伯语、希伯来语对应的文字符号。欧元符号出现的比较晚,没有被收录在ISO-8859-1当中。编码方式:ISO-8859-1编码是单字节编码,向下兼容ASCII,其编码范围是0x00-0xFF,0x00-0x7F之间完全和ASCII一致,0x80-0x9F之间是控制字符,0xA0-0xFF之间是文字符号。注意:ISO-8859-1编码表示的字符范围很窄,无法表示中文字符。但是,由于是单字节编码,和计算机最基础的表示单位一致,所以很多时候,仍旧使用ISO-8859-1编码来表示。比如,虽然”中文”两个字不存在iso8859-1编码,以gb2312编码为例,应该是”d6d0 cec4”两个字符,使用iso8859-1编码的时候则将它拆开为4个字节来表示:”d6 d0 ce c4”(事实上,在进行存储的时候,也是以字节为单位处理的)。所以mysql中latin1可以表示任何编码的字符。Latin1与ASCII编码的关系:完全兼容ASCII。1.4 Unicode编码(UCS-2)Code Point: 码点,简单理解就是字符的数字表示。一个字符集一般可以用一张或多张由多个行和多个列所构成的二维表来表示。二维表中行与列交叉的点称之为码点,每个码点分配一个唯一的编号,称之为码点值或码点编号。BOM(Byte Order Mark):字节序,出现在文件头部,表示字节的顺序,第一个字节在前,就是”大端方式”(Big-Endian),第二个字节在前就是”小端方式”(Little-Endian)。在Unicode字符集中有一个叫做”ZERO WIDTH NO-BREAK SPACE“的字符,它的码点是FEFF。而FFFE在Unicode中是不存在的字符,所以不应该出现在实际传输中。在传输字节流前,我们可以传字符”ZERO WIDTH NO-BREAK SPACE“表示大小端,因此字符”ZERO WIDTH NO-BREAK SPACE“又被称作BOM。BOM还可以用来表示文本编码方式,Windows就是使用BOM来标记文本文件的编码方式的。Mac上文件有没有BOM都可以。例如:u00FF :00是第一个字节,FF是第二个字节。和码点表示方式一样属于大端方式。Unicode编码字符集:旨在收集全球所有的字符,为每个字符分配唯一的字符编号即代码点(Code Point),用 U+紧跟着十六进制数表示。所有字符按照使用上的频繁度划分为 17 个平面(编号为 0-16),即基本的多语言平面和增补平面。基本的多语言平面又称平面 0,收集了使用最广泛的字符,代码点从 U+0000 到 U+FFFF,每个平面有 216=65536 个码点;Unicode编码:Unicode 字符集中的字符可以有多种不同的编码方式,如 UTF-8、UTF-16、UTF-32、压缩转换等。我们通常所说的Unicode编码是UCS-2 将字符编号(同 Unicode 中的码点)直接映射为字符编码,亦即字符编号就是字符编码,中间没有经过特别的编码算法转换。是定长双字节编码:因为我们UCS-2只包括本的多语言平面(U+0000 到 U+FFFF)。UCS-2的BOM:大端模式:FEFF。小端模式:FFFE。文件保存成UTF-16 BE with BOM相当于UCS-2的大端模式,可以看到16进制开头为FEFFLatin1与Unicode编码的关系:Latin1对应于Unicode的前256个码位。8.png1.5 UTF-16定义及编码:UTF-16是Unicode的其中一个使用方式,在Unicode基本多文种平面定义的字符(无论是拉丁字母、汉字或其他文字或符号),一律使用2字节储存。而在辅助平面定义的字符,会以代理对(surrogate pair)的形式,以两个2字节的值来储存。是双字节编码。UTF-16与UCS-2的关系:UTF-16可看成是UCS-2的父集。在没有辅助平面字符(surrogate code points)前,UTF-16与UCS-2所指的是同一的意思。但当引入辅助平面字符后,就称为UTF-16了。现在若有软件声称自己支援UCS-2编码,那其实是暗指它不能支援在UTF-16中超过2bytes的字集。对于小于0x10000的UCS码,UTF-16编码就等于UCS码。UTF-16的BOM:大端模式:FEFF。小端模式:FFFE。1.6 UTF-8定义及编码:UTF-8就是在互联网上使用最广的一种Unicode的实现方式,这是为传输而设计的编码,并使编码无国界,这样就可以显示全世界上所有文化的字符了。UTF-8最大的一个特点,就是它是一种变长的编码方式。它可以使用14个字节表示一个符号,根据不同的符号而变化字节长度,当字符在ASCII码的范围时,就用一个字节表示,保留了ASCII字符一个字节的编码作为它的一部分,注意的是unicode一个中文字符占2个字节,而UTF-8一个中文字符占3个字节)。从unicode到utf-8并不是直接的对应,而是要过一些算法和规则来转换。Unicode符号范围UTF-8编码方式(十六进制)0000 0000-0000 007F0xxxxxxx0000 0080-0000 07FF110xxxxx 10xxxxxx0000 0800-0000 FFFF1110xxxx 10xxxxxx 10xxxxxx0001 0000-0010 FFFF11110xxx 10xxxxxx 10xxxxxx 10xxxxxxUTF8的BOM:EFBBBF。UTF-8不存在字符序列的问题,但是可以用用BOM表示这个文件是一个UTF-8文件。文件保存成UTF-8 BE with BOM,可以看到16进制开头为EFBBBF9.png1.7 GBK/GB2312定义及编码:GB2312是最早一版的汉字编码只包含6763汉字,GB2312只支持简体字而且不全,显然不够用。GBK编码,是对GB2312编码的扩展,完全兼容GB2312标准,支持简体字繁体字,包含全部中文字符。GBK编码采用单双字节编码方案,单字节和Latin1一致,双字节是汉字部分,其编码范围:8140-FEFE,剔除xx7F码位,共23940个码位。GBK与Latin1的关系:GBK单字节编码区和Latin1编码一致。GBK与Unicode的关系:GBK与Unicode字符集编码不同但是兼容的。如"汉"的Unicode值与GBK虽然是不一样的,假设Unicode为a040,GBK为b030,但是可以对应转化的。汉字的Unicode区:4E00-u9FA5。GBK与UTF-8:GBK汉字采用双字节编码比在UTF-8中的三字节要小。但是UTF-8更通用。GBK与UTF-8转化:GBK—> Unicode —> UTF82. 前端中的编码有了编码基础就可以来认识一下前端中的编码,这样你才能真正认识Payload。我这里的应该是总结最全的。2.1 Base64Base64可以用来将binary的字节序列数据编码成ASCII字符序列构成的文本。使用时,在传输编码方式中指定Base64。使用的字符包括大小写拉丁字母各26个、数字10个、加号+和斜杠/,共64个字符及等号=用来作为后缀用途。所以总共65个字符。将3字节的数据,先后放入一个24位的缓冲区中,先来的字节占高位。数据不足3字节的话,于缓冲器中剩下的比特用0补足。每次取出6bit对原有数据用Base64字符作为编码后的输出。编码若原数据长度不是3的倍数时且剩下1个输入数据,则在编码结果后加2个=;若剩下2个输入数据,则在编码结果后加1个=。可以看出Base64编码数据大约是原来数据的3/4。标准的Base64并不适合直接放在URL里传输,因为URL编码器会把标准Base64中的/和+字符变为形如%XX的形式,而这些%号在存入数据库时还需要再进行转换,因为ANSI SQL中已将%号用作通配符。为解决此问题,可采用一种用于URL的改进Base64编码,它不在末尾填充=号,并将标准Base64中的+和/分别改成了-和_,这样就免去了在URL编解码和数据库存储时所要做的转换,避免了编码信息长度在此过程中的增加,并统一了数据库、表单等处对象标识符的格式。window.btoa/window.atob base64编码(binary to ascii)和解码仅支持Latin1字符集。2.2 JS转义字符js字符字符串中包含一些反斜杠开头的特殊转义字符,用来表示非打印符、其他用途的字符还可以转义表示unicode、Latin1字符。转义字符含义’单引号”双引号&和号\反斜杠n换行符r回车符t制表符b退格符f换页符n … nnn由一位到三位八进制数(1到377)指定的Latin-1字符xnn以16进制nn(n:0F)表示一个Latin1字符。x41表示字符Aunnnn以16进制nnnn(n:0F)表示一个Unicode字符。只限于码点在u0000uFFFF范围内u{n} … u{nnnnnn}Unicode码点值表示一个Unicode字符特别注意:换行符n在innerHTML使用只会展示一个空格并不会换行。通过n、u和x可以代表任意unicode字符和Latin1字符。通过这个可以对js加密保证js安全和进行隐蔽攻击。例子:function toUnicode(theString) { //字符串转换为unicode编码字符串,切记这个字符串是复制用的,不是让你拿来直接执行的。 var unicodeString = ‘’; for (var i = 0; i < theString.length; i++) { var theUnicode = theString.charCodeAt(i).toString(16).toUpperCase(); while (theUnicode.length < 4) { theUnicode = ‘0’ + theUnicode; } theUnicode = ‘\u’ + theUnicode; unicodeString += theUnicode; } return unicodeString;}var xssStr = “alert(‘xss’)";var xssStrUnicode = toUnicode(xssStr);//输出:"\u0061\u006C\u0065\u0072\u0074\u0028\u0027\u0078\u0073\u0073\u0027\u002"eval("\u0061\u006C\u0065\u0072\u0074\u0028\u0027\u0078\u0073\u0073\u0027\u002”); //弹出xss弹窗2.3 URL编码RFC 1738做出规定”只有字母和数字0-9a-zA-Z、一些特殊符号”$-.+!’(),”不包括双引号、以及某些保留字,才可以不经过编码直接用于URL”。所以当链接中包含中文或者其他不符合规定的字符的时候都需要经过编码的。然而由于浏览器厂商众多,对url进行编码的形式多种多样,如果不对编码进行统一处理,会对代码开发造成很大的影响,出现乱码现象。URL编码规则:需要编码的字符转换为UTF-8编码,然后在每个字节前面加上%。例如:‘牛’–>UTF-8编码E7899B–>URL编码是%E7%89%9BJS为我们提供了3个对字符串进行URL编码的方法:escape ,encodeURI,encodeURIComponentescape:由于eccape已经被建议放弃所以大家就不要用了encodeURI:encodeURI不编码的82个字符:!#$&’()+,/:;=?@-.0-9a-zA-Z,从中可以看不会对url中的保留字符进行编码,所以适合url整体编码encodeURIComponent:这个对于我们来说是最有用的一个编码函数,encodeURIComponent不编码的字符有71个:!, ‘,(,),*,-,.,_,,0-9,a-z,A-Z。可以看出对url中的保留字进行的编码,所以当传递的参数中包含这些url中的保留字(@,&,=),就可以通过这个方法编码后传输这三个方法对应的解码方法: unescape、decodeURI、decodeURIComponent2.4 HTML字符实体HTML中的预留字符必须被替换为字符实体。这样才能当成字符展示,否则会当成HTML解析。字符实体编码规则:转义字符 = +ascii码; = &实体名称;XSS字符串需要防御字符的实体转换表:10.png转化方法:function encodeHTML (a) { return String(a) .replace(/&/g, “&”) .replace(/</g, “<”) .replace(/>/g, “>”) .replace(/"/g, “”") .replace(/’/g, “’”);};2.5 页面编码页面编码设置:<meta charset=“UTF-8”><meta http-equiv=“Content-Type” content=“text/html; charset=utf-8” />脚本编码设置:<script type=“text/javascript” src=“myscripts.js” charset=“UTF-8”></script>注意:要想JS即可在UTF-8中正常使用又可以在GBK中正常使用,可以对JS中所有包含中文的字符串做字符转义。例子:alert(“网络错误”); //弹出网络错误alert("\u7f51\u7edc\u9519\u8bef"); //弹出网络错误3. Payload的分类现在可以认识Payload的了,我不得不说这里对Payload的分类可以很好的让你认识Payload。也帮助你更好的对应到执行点。3.1 原子Payload最低层级的Payload。javascript代码片段可在eval、setTimeout、setInterval中直接执行,也可通过HTML等构成高阶Payloadjavascript:javascript伪协议结构:javascript:+js代码。可以在a标签的href属性被点击和window.location.href赋值的时候执行。DATA URI协议DATA URI结构:data:, 。DATA URI数据在包含在iframe的src属性和object data属性中将会变成可执行的Payload.字符串转义变种javascript代码片段unicode或者Latin-1表示字符串。eval("\u0061\u006C\u0065\u0072\u0074\u0028\u0027\u0078\u0073\u0073\u0027\u002"); //可执行的JS3.2 纯HTMLPayload这种Payload特点不具有可执行的JS,但是存在传播风险,可以把别的站点注入到被攻击网站。包含链接跳转的HTML片段主要是传播危害<a href=“http://ha.ck”>哈哈,我来钓鱼了</a>3.3 包含原子Payload的HTML片段Payloadscript标签片段script标签片段这种Payload可以引入外部JS或者可直接执行的script。这种Payload一般不能通过直接复制给innerHTML执行,不过在IE上可以。不过通过document.write是可以执行。例子:// Payload原始值:data:text/html,<script>alert(‘xss’);</script>var inputStr ="<script>alert(‘xss’);</script>";document.write(inputStr);包含事件处理的HTML片段例如:包含img的onerror, svg的onload,input的onfocus等的HTML片段,都可以变成可执行的Payload。var inputStr ="<img src=x onerror=alert(‘xss’);>"; var inputStr ="<svg/onload=alert(‘xss’)>"; var inputStr ="<input autofocus onfocus=alert(‘xss’)>"; xssDom.innerHTML = inputStr;包含可执行JS属性的HTML片段javascript伪协议xssLink.setAttribute(“href”,“javascript:alert(‘xss’)”)//点击可触发var inputStr = “javascript:alert(‘xss’)";window.location.href = inputStr;DATA URI例子:// Payload原始值:data:text/html,<script>alert(‘xss’);</script>//var inputStr = ‘<iframe src=“data:text/html,<script>alert(“xss”);</script>"></iframe>’;// var inputStr = ‘<object data=“data:text/html;base64,ZGF0YTp0ZXh0L2h0bWwsPHNjcmlwdD5hbGVydCgneHNzJyk7PC9zY3JpcHQ+"></object>’;xssDom.innerHTML = inputStr; //弹出alert(“xss”)这里只是介绍了主要的Payload,还有很多不常见的Payload。第四部分:XSS攻击模型分析这部分我们根据漏洞攻击模型分析一下XSS的执行点和注入点。分析这两点其实就是找漏洞的过程。1. XSS漏洞执行点页面直出Dom客户端跳转链接: location.href / location.replace() / location.assign()取值写入页面:innerHTML、document.write及各种变种。这里主要会写入携带可执行Payload的HTML片段。脚本动态执行:eval、setTimeout()、setInterval()不安全属性设置:setAttribute。不安全属性前面见过:a标签的href、iframe的src、object的dataHTML5 postMessage来自不安全域名的数据。有缺陷的第三方库。2. XSS漏洞注入点看看我们可以在哪些位置注入我们的Payload服务端返回数据用户输入的数据链接参数:window.location对象三个属性href、search、search客户端存储:cookie、localStorage、sessionStorage跨域调用:postMessage数据、Referer、window.name上面内容基本包含了所有的执行点和注入点。对大家进行XSS漏洞攻防很有帮助。第五部分 XSS攻击防御策略1. 腾讯内部公共安全防御及应急响应接入公共的DOM XSS防御JS内部漏洞扫描系统扫描腾讯安全应急响应中心:安全工作者可以通过这个平台提交腾讯相关的漏洞,并根据漏洞评级获得奖励。重大故障应急响应制度。2. 安全编码2.1 执行点防御方法执行点防御页面直出Dom服务端XSS过滤客户端跳转链接域名白名单(例如:只允许qq.com域)、链接地址XSS过滤取值写入页面客户端XSS过滤脚本动态执行确保执行Js字符串来源可信|| 不安全属性设置 | 内容XSS过滤,包含链接同客户端跳转链接 ||HTML5 postMessage|origin限制来源|| 有缺陷的第三方库 | 不使用2.2 其他安全防御手段对于Cookie使用httpOnly在HTTP Header中使用Content Security Policy3. 代码审查总结XSS检查表做代码自测和检视4. 自动化检测XSS漏洞的工具手工检测XSS漏洞是一件比较费时间的事情,我们能不能写一套自动检测XSS自动检测工具。竟然我知道了注入点、执行点、Payload自动化过程是完全有可能的。XSS自动化检测的难点就在于DOM型XSS的检测。因为前端JS复杂性较高,包括静态代码分析、动态执行分析都不容易等。第六部分 总结上面内容文字比较多,看完还是很累的,总结起来就一句话:安全大于一切,不要心存侥幸,希望以上内容对您有帮助,不过以上内容仅代表个人理解,如有不对欢迎指正讨论。此文已由作者授权腾讯云+社区发布 ...

December 18, 2018 · 2 min · jiezi

数字IT基础-数据采集总线

数字化运营基础在如今“双十一”不再是线上活动的代名词,而逐步变为一场线上线下同时进行的消费者盛宴。销售、运营、物流、生产商等都在开足马力在各大渠道备战,据统计:消费者在期间被平均推送200+活动消息消费者会花几个小时比较、提前筛选自己中意产品除了线上外,90%线下店铺都挂出针对双十一运营活动双十一触客渠道也呈现多样化,例如:网络店铺、短信、邮件、微信公众账号、派单与Kitty板、自提柜、智能设备(例如天猫精灵点单)、多媒体设备(例如电视或机顶盒购物)等。面对如此多的渠道和销售方式,运营和销售如何有效掌控,并通过数字化方式进行运营是一项硬能力。让我们来看几个例子:例子1:新用户引流互联网经典书籍《上瘾:构建习惯养成的产品》把用户获取过程分为4个阶段:触发、行动、奖励、投入。作为最开始的触发环节,给用户群发消息是最有效的手段之一。但如何衡量转化效果呢?我们可以在推广信息中做一个埋点,把用户点击短信带上关联信息,例如设计一个如下的URL,其中放入2个关键参数:t: 代表发送的批次编号,也可以作为渠道的标识m:代表发送的短信号码html://mywebsite.com/new?t=1002&m=13860394XX当用户点点击消息访问站点时,我们在服务端访问日志中会自动记录对应信息:202.168.1.209 - - [02/Feb/2016:17:44:13+0800] “GEThtml://mywebsite.com/new?t=1002&m=13860394XX HTTP/1.1” 200 209 - “Mozilla/5.0(Macintosh; Intel Mac OS X10_11_3) AppleWebKit/537.36(KHTML, like Gecko)Chrome/48.0.2564.97 Safari/537.36"这样我们就能获得推广效果和转化率:例子2:线上购买意图捕捉在获取客户后,下一步是让用户付诸于行动。用户在浏览商品时,会有页面的停留,阅读,比较和加入购物车等操作。可以借助Web Tracking和Serve端埋点来进行静态与动态数据采集。在静态网页和浏览器埋点:<img src=‘http://${project}.${sls-host}/logstores/${logstore}/track_ua.gif?APIVersion=0.6.0&key1=val1&key2=val2’/> 通过JS埋点:在完成数据埋点后,我们可以在日志服务分析功能中,获得每个环节的点击数和转化数字,以衡量购买阶段的效果。Web Tracking链接:https://help.aliyun.com/docum…服务端埋点链接:https://help.aliyun.com/docum…数据采集挑战从上面例子来看,数据采集是数字化IT的基础。让我们来看一个典型的数据采集架构:购买一批机器搭建网络服务器为服务器搭建负载均衡设备在网络服务器(例如Nginx)模块中使用Kafka等中间件写入数据该方案通过无状态设计解决了高可用,按需扩容等问题,也是众多厂商采用的方案,在理想状态下运行得非常好。但在现实过程中,往往会遇到如下挑战:作为用户最终的目标是为了分析数据。但这些问题的存在,需要在业务、规模与增长上消耗大量人力、精力和物力,干了不一定干得好。日志服务LogHub功能阿里云日志服务(Log Service,/原SLS)是针对实时数据一站式服务,其中的LogHub模块就是专为数据采集定制的功能,该功能有如下特点:30+实时采集手段LogHub提供30+种开箱即用的数据采集手段,包括直接和云产品打通的日志、移动端、服务端、程序、SDK、网页、嵌入端等,以下我们分别介绍下最常用的四种与试用场景:1.1 Logtail(部署量最大Agent)Logtail安装在X86设备上,通过中央服务器进行管控,只需点点鼠标或API就能够在几秒钟内对百万机器下达数据采集指令。Logtail目前每天有几百万的运行实例,适配所有Linux版本、Window、Docker、K8S等环境;支持几十种数据源对接,关于Logtail功能可以参见介绍文档。得益于阿里巴巴集团场景的不断锤炼,Logtail和开源Agent(例如Fluentd、Logstash、Beats)相比,性能、资源消耗、可靠性和多组合隔离等硬指标上较为领先。可以满足国内最大的直播网站、最大的教育类网站、最大的金融类网站的苛刻要求。和开源Agent主要差距在于日志格式的丰富性(当前Logtail版本已支持Logstash、Beats协议,既可以将这些开源插件无缝跑在Logtail之上)。2018年Logtail针对Docker/K8S等场景做了非常多的适配工作,包括:一条命令一个参数即可实现部署,资源自动初始化支持CRD方式配置,支持K8S控制台、kubectl、kube api等,与K8S发布、部署无缝集成K8S RBAC鉴权,日志服务STS鉴权管理可以自豪地说,Logtail方案是K8S下所有Agent中最全,最完整的之一,感兴趣可以参见LC3视角:Kubernetes下日志采集、存储与处理技术实践 :1.2 C Producer Library系列(面向嵌入式设备新秀) 除X86机器外,我们可能会面对各种更底层IoT/嵌入式设备。针对这种场景,LogHub推出C Producer Library系列SDK,该SDK可以定位是一个“轻量级Logtail”,虽没有Logtail实时配置管理机制,但具备除此之外70%功能,包括:多租户概念:可以对多种日志(例如Metric,DebugLog,ErrorLog)进行优先级分级处理,同时配置多个客户端,每个客户端可独立配置采集优先级、目的project/logstore等支持上下文查询:同一个客户端产生的日志在同一上下文中,支持查看某条日志前后相关日志并发发送,断点续传:支持缓存上线可设置,超过上限后日志写入失败专门为IoT准备功能:本地调试:支持将日志内容输出到本地,并支持轮转、日志数、轮转大小设置细粒度资源控制:支持针对不同类型数据/日志设置不同的缓存上线、聚合方式日志压缩缓存:支持将未发送成功的数据压缩缓存,减少设备内存占用关于C Producer Library的更多内容参见目录:https://yq.aliyun.com/article…目前针对不同的环境(例如网络服务器、ARM设备、以及RTOS等设备)从大到小我们提供了3种方案: 在X86以及ARM设备测试场景中,C-Producer系列SDK能在稳定服务情况下,极大优化性能和内存空间占用,胜任只有4KB运行内存的火火兔场景(Brick版本)。使用C Producer系列的客户有: 百万日活的天猫精灵、小朋友们最爱的故事机火火兔、 遍布全球的码牛、钉钉路由器、 兼容多平台的视频播放器、 实时传输帧图像的摄像头等。这些智能SDK每天DAU超百万,遍布在全球各地的设备上,一天传输百TB数据。关于C Producer Library 的细节可以参考这篇文章: 智能设备日志利器:嵌入式日志客户端(C Producer)发布。服务端多地域支持 客户端问题解决了后,我们来看看服务端。LogHub 是阿里云化基础设施,在全球阿里云所有Region都有部署。确保无论业务在哪个Region开展,都可以选择就近的Region。例如欧盟、新加坡等国家有相关的法律约束数据不能出境,对于这类场景我们可以选择合适的数据中心来提供服务。对于同Region下ECS、Docker等服务,我们可以直接使用同Region服务进行处理,节省跨洋传输的成本。全球加速网络 对全球化业务而言,用户可能分布在全球各地(例如游戏,App、物联网等场景),但在构建数仓业务的过程中,我们往往需要对数据进行集中化处理。例如一款移动App用户散布在全国各省市将日志采集中心定在杭州,那对于西南(例如成都)用户而言,远程进行日志传输的延时和质量难以保障将日志采集中心定在成都,那对位于东部和东北用户又难以权衡,更不用说中国的三大运营商链路质量的影响 2018年6月初LogHub 联合 CDN 推出了一款全球自动上传加速方案:“基于阿里云CDN硬件资源,全球数据就近接入边缘节点,通过内部高速通道路由至LogHub,大大降低网络延迟和抖动 ”。只需简单配置即可构建起快速、稳定的全球数据采集网络,任意LogHub SDK都可以通过Global域名获得自动加速的支持。 在我们测试case中,经过全球7个区域对比整体延时下降50%,在中东,欧洲、澳洲和新加坡等效果明显。除了平均延时下降外,整体稳定性也有较大提升(参见最下图,几乎没有任何抖动)。确保如何在世界各地,只要访问一个统一域名,就能够高效、便捷将数据采集到期望Region内。服务端弹性伸缩 在解决网络接入问题后,我们把问题聚焦在服务端流量这个问题上。熟悉Kafka都知道,通过Partition策略可以将服务端处理资源标准化:例如定义一个标准的单元Partition或Shard(例如每个Shard固定5MB/S写,10MB/S读)。当业务高峰期时,可以后台Split Shard以获取2倍的吞吐量。这种方法看起来很工程化,但在使用过程中有两个难以绕开的现实问题:业务无法预测:事先无法准确预估数据量,预设多少个shard才合适呢人的反应滞后:数据量随时会突增,人不一定能够及时处理,长时间超出服务端负载能力会有数据丢失风险 针对以上情况,LogHub提供了全球首创Shard自动分裂功能:在用户开启该功能后,后台系统实时监控每个shard的流量,如果发现一个shard的写入在一段时间内,有连续出现超过shard处理能力的情况,会触发shard的自动分裂,时刻保障业务流量。更多细节可以参考这篇文章: 支持Shard自动分裂丰富上下游生态与场景支持LogHub也提供丰富上下游与生态对接,包括各种主流流计算、数据仓库等引擎支持:采集端:Logstash、Beats、Log4J等实时消费端(流计算):Flink/Blink、Storm、Samza等存储端(数仓):Hadoop、Spark、Presto、Hive等通过LogHub与日志服务其他功能+产品组合,可以轻松支撑安全、运营、运维和研发对于数据处理的各种场景需求,更多可以参考学习路径 和 用户手册。写在最后日志服务是阿里自产自用的产品,在双十一、双十二和新春红包期间承载阿里云/蚂蚁全站、阿里电商板块、云上几千商家数据链路,每日处理来自百万节点几十PB数据,峰值流量达到每秒百GB, 具备稳定、可靠、低成本,生态丰富等特性。

December 17, 2018 · 1 min · jiezi

2018阿里云双12年终大促主会场全攻略

摘要: 双12官方攻略出炉!2018阿里云双12年终大促活动已经于12月7日正式开启,从已开放的活动页面来看,活动分为两个阶段: 12月7日-12月23日的拉新返现阶段和12月24日-12月28日的TOP100英雄榜PK阶段。活动核心亮点:老会员拉新可享25%返现+最高2.5万奖金,拉新前100赢大奖!新会员购买云产品2折起!在双12这个大促活动中,怎样才能花最少的钱配置最特惠的云服务?云栖社区特为各位开发者奉献出省钱大法如下:丨活动阵地:https://m.aliyun.com/act/team1212丨关键词:拉新、2折起、25%返现、TOP100赢大奖社区区小编仔细梳理了下活动规则,给大家作为借鉴参考:一、活动对象及福利1、阿里云官网已完成实名认证的注册会员均可参与本活动。2、企业账号和合作伙伴关联账号下的阿里云账号,仅可参与首购云产品优惠活动,如进行分享拉新将不能获得返佣、额外现金奖励。(一)老用户专属福利今年双12主会场活动,对于老用户来说真是最实实在在的优惠,这种好机会岂容错过?!福利1: 云产品提货券老用户成为邀请者成功拉新人数达到一定级别的,就可获得相应的云产品提货券,具体如下:l 拉新1人,可获得1核2G、3个月时长的T5云服务器提货券。l 拉新2人,可获得1核2G、4个月时长的T5云服务器提货券。l 拉新3人,可获得1核2G、5个月时长的T5云服务器提货券。l 拉新4人,可获得1核2G、6个月时长的T5云服务器提货券。l 拉新5人,可获得1核2G、12个月时长的T5云服务器提货券。l 拉新6人,可获得1核2G、12个月时长的T5云服务器提货券+1核1G、3个月时长的数据库MySQL提货券。l 拉新7人及以上,可获得1核2GT5、12个月时长的T5云服务器提货券+1核1G、6个月时长的数据库MySQL提货券。福利2: 现金奖励活动期间,邀请者的累计拉新金额达到相应等级的,除领取返利外,还可享受额外的现金奖励,具体如下:l 累计拉新金额达20,000元,额外奖励300元。l 累计拉新金额达50,000元,额外奖励1,000元。l 累计拉新金额达100,000元,额外奖励3,000元。l 累计拉新金额达200,000元,额外奖励8,000元。l 累计拉新金额达500,000元,额外奖励25,000元。福利3:拉新TOP100赢iPhoneXS、大疆无人机等大奖活动期间,邀请者中拉新人数最多的前100名,还将获得对应的实物礼品奖励,具体如下:l 第1-5名,iPhoneXS 256G各1个,价值人民币10099元。l 第6-10名,iPad Pro 64G各1个,价值人民币6499元。l 第11-20名,大疆 Mavic Air各1架,价值人民币4999元。l 第21-35名,任天堂switch各1个,价值人民币3200元。l 第36-60名,樱桃MX8.0机械键盘各1个,价值人民币1530元。l 第61-100名,索尼无线头戴耳机各1个,价值人民币1099元。(二)新用户专属福利新用户须完成云产品购买后,方可获得参与以上拉新活动的资格。二、新老用户如何参与如果您是老用户,点击活动页面老会员拉新按钮,登录阿里云账户。您将获得1个属于您的分享链接,将链接分享给您的好友。拉新人数越多,购买金额越高,奖励越多!如果您是新用户,点击活动页面新会员特惠按钮,注册登录阿里云账户。您必须完成云产品购买后,方可获得跟老用户一样的拉新福利。12月24日开始,至12月28日,个人英雄榜单将陆续公布,大家加油起来吧!努力冲刺进TOP100,赢取终极大奖!阅读原文

December 10, 2018 · 1 min · jiezi

服务器小白的我,是如何成功将 node+mongodb 项目部署在服务器上并进行性能优化的

前言本文讲解的是:做为前端开发人员,对服务器的了解还是小白的我,是如何一步步将 node+mongodb 项目部署在阿里云 centos 7.3 的服务器上,并进行性能优化,达到页面 1 秒内看到 loading ,3 秒内看到首屏内容的。搭建的项目是采用了主流的前后端分离思想的,这里只讲 服务器环境搭建与性能优化。效果请看 http://乐趣区.cn/main.html1. 流程开发好前端与后端程序。购买服务器与域名服务器上安装所需环境(本项目是 node 和 mongodb )服务器上开放端口与设置规则用 nginx、apache 或者tomcat 来提供HTTP服务或者设置代理上传项目代码 或者 用码云或者 gihub 来拉取你的代码到服务器上启动 express 服务器优化页面加载2. 内容细节2.1 开发好前端与后端程序开发好前端与后端程序,这个没什么好说的,就是开发!开发!开发!再开发!2.2 购买服务器与域名本人一直觉得程序员应该有一个自己的个人网站,拥有自己的域名与服务器。学知识或者测试项目的时候可以用来测试。阿里云有个专供学生的云翼计划 阿里云学生套餐,入门级的云服务器原价1400多,学生认证后只要114一年,非常划算。还是学生的,直接购买;不是学生了,有弟弟、妹妹的,可以用他们的大学生身份,购买,非常便宜实用(我购买的就是学生优惠套餐)。当然阿里云服务器在每年双 11 时都有很大优惠,也很便宜,选什么配置与价格得看自己的用处。服务器预装环境可以选择 CentOS 或者 windows server,,为了体验和学习 linux 系统,我选择了CentOS。再次是购买域名 阿里域名购买,本人也是在阿里云购买的。域名是分 国际域名与国内域名的,国际域名是不用备案的,但是国内的域名是必须 ICP备案的 阿里云ICP代备案管理系统,不然不能用,如果是国内域名,如何备案域名,请自己上网查找教程。当然如果你的网站只用来自己用的话,可以不用买域名,因为可以通过服务器的公网 ip 来访问网站内容的。如果购买了域名了,还要设置域名映射到相应的公网 ip ,不然也不能用。3. 服务器上安装所需环境(本项目是 node 和 mongodb )3.1 登录服务器因本人用的是 MacBook Pro ,所以直接打开 mac 终端,通过下面的命令行连接到服务器。root 是阿里云服务器默认的账号名,连接时候会叫你输入密码,输入你购买时设置的或者后来设置的密码。ssh root@47.106.20.666 //你的服务器公网 ip,比如 47.106.20.666如图:window 系统的,请用 Putty 或 Xshell 来登录,可以参考一下这篇文章 把 Node.js 项目部署到阿里云服务器(CentOs)一般在新服务器创建后,建议先升级一下 CentOS:yum -y update常用的 Linux 命令cd 进入目录cd .. 返回上一个目录ls -a 查看当前目录mkdir abc 创建abc文件夹mv 移动或重命名rm 删除一个文件或者目录3.2 安装 node升级常用库文件, 安装 node.js 需要通过 g++ 进行编译。yum -y install gcc gcc-c++ autoconf跳转到目录:/usr/local/src,这个文件夹通常用来存放软件源代码:cd /usr/local/src下载 node.js 源码,也可以使用 scp 命令直接上传,因为下载实在太慢了:下载地址:Downloads,请下载最新的相应版本的源码进行下载,本人下载了 v10.13.0 版本的。https://nodejs.org/dist/v10.13.0/node-v10.13.0.tar.gz下载完成后解压:tar -xzvf node-v10.13.0.tar.gz进入解压后的文件夹:cd node-v10.13.0执行配置脚本来进行预编译处理:./configure编译源代码,这个步骤花的时间会很长,大概需要 5 到 10 分钟:make编译完成后,执行安装命令,使之在系统范围内可用:make install安装 express 推荐 global 安装npm -g install express建立超级链接, 不然 sudo node 时会报 “command not found"sudo ln -s /usr/local/bin/node /usr/bin/nodesudo ln -s /usr/local/lib/node /usr/lib/nodesudo ln -s /usr/local/bin/npm /usr/bin/npmsudo ln -s /usr/local/bin/node-waf /usr/bin/node-waf通过指令查看 node 及 npm 版本:node -vnpm -vnode.js 到这里就基本安装完成了。3.2 安装 mongodb下载地址:mongodb下载时,请选对相应的环境与版本,因为本人的服务器是 CentOS ,其实本质就是 linux 系统,所以选择了如下图环境与目前最新的版本。mongodb :软件安装位置:/usr/local/mongodb数据存放位置:/home/mongodb/data数据备份位置:/home/mongodb/bak日志存放位置:/home/mongodb/logs下载安装包> cd /usr/local> wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-4.0.4.tgz解压安装包,重命名文件夹为 mongodbtar zxvf mongodb-linux-x86_64-4.0.4.tgzmv mongodb-linux-x86_64-4.0.4 mongodb在 var 文件夹里建立 mongodb 文件夹,并分别建立文件夹 data 用于存放数据,logs 用于存放日志mkdir /var/mongodbmkdir /var/mongodb/datamkdir /var/mongodb/logs打开 rc.local 文件,添加 CentOS 开机启动项:vim /etc/rc.d/rc.local// 不懂 vim 操作的请自行查看相应的文档教程,比如: vim 模式下,要 按了 i 才能插入内容,输入完之后,要按 shift 加 :wq 才能保存退出。将 mongodb 启动命令追加到本文件中,让 mongodb 开机自启动:/usr/local/mongodb/bin/mongod –dbpath=/var/mongodb/data –logpath /var/mongodb/logs/log.log -fork启动 mongodb/usr/local/mongodb/bin/mongod –dbpath=/var/mongodb/data –logpath /var/mongodb/logs/log.log -fork看到如下信息说明已经安装完成并成功启动:forked process: 18394all output going to: /var/mongodb/logs/log.logmongodb 默认的端口号是 27017。如果你数据库的连接要账号和密码的,要创建数据库管理员,不然直接连接即可。在 mongo shell 中创建管理员及数据库。切换到 admin 数据库,创建超级管理员帐号use admindb.createUser({ user: “用户名”, pwd:“登陆密码”, roles:[{ role: “userAdminAnyDatabase”, db: “admin” }] })切换到要使用的数据库,如 taodb 数据库,创建这个数据库的管理员帐号use taodbdb.createUser({ user: “用户名”, pwd:“登陆密码”, roles:[ { role: “readWrite”, db: “taodb” }] //读写权限 })重复按两下 control+c ,退出 mongo shell。到这里 mongodb 基本已经安装设置完成了。备份与恢复 请看这篇文章:MongoDB 备份(mongodump)与恢复(mongorestore)安装 node 与 mongodb 也可以参考这篇文章:CentOs搭建NodeJs服务器—Mongodb安装3.3 服务器上开放端口与设置安全组规则如果你只放静态的网页,可以参考这个篇文章 通过云虚拟主机控制台设置默认首页但是我们是要部署后台程序的,所以要看以下的内容:安全组规则是什么鬼授权安全组规则可以允许或者禁止与安全组相关联的 ECS 实例的公网和内网的入方向和出方向的访问。 阿里云安全组应用案例文档80 端口是为 HTTP(HyperText Transport Protocol) 即超文本传输协议开放的,浏览器 HTTP 访问 IP 或域名的 80 端口时,可以省略 80 端口号如果我们没有开放相应的端口,比如我们的服务要用到 3000 ,就要开放 3000 的端口,不然是访问不了的;其他端口同理。端口都配置对了,以为能用公网 IP 进行访问了么 ? 小兄弟你太天真了 …还有 防火墙 这一关呢,如果防火墙没有关闭或者相关的端口没有开放,也是不能用公网 IP 进行访问网站内容的。和安全组端口同理,比如我们的服务要用到的是 3000 端口,就要开放 3000 的端口,不然是访问不了的;其他端口同理。出于安全考虑还是把防火墙开上,只开放相应的端口最好。怎么开放相应的端口 ? 看下面两篇文章足矣,这里就不展开了。1. 将nodejs项目部署到阿里云ESC服务器,linux系统配置80端口,实现公网IP访问2. centos出现“FirewallD is not running”怎么办3.4 用 nginx、apache 或者 tomcat 来提供 HTTP 服务或者设置代理我是用了 nginx 的,所以这里只介绍 nginx 。安装 nginx 请看这两篇文章:1. Centos7安装Nginx实战2. 阿里云Centos7安装Nginx服务器实现反向代理开启 ngnx 代理进入到目录位置cd /usr/local/nginx在 nginx 目录下有一个 sbin 目录,sbin 目录下有一个 nginx 可执行程序。./nginx关闭 nginx./nginx -s stop重启./nginx -s reload基本的使用就是这样子了。如下给出我的 nginx 代理的设置:我的两个项目是放在 /home/blog/blog-react/build/; 和 /home/blog/blog-react-admin/dist/; 下的,如果你们的路径不是这个,请修改成你们的路径。#user nobody;worker_processes 1;#error_log logs/error.log;#error_log logs/error.log notice;#error_log logs/error.log info;#pid logs/nginx.pid;events { worker_connections 1024;}http { include mime.types; default_type application/octet-stream; #log_format main ‘$remote_addr - $remote_user [$time_local] “$request” ’ # ‘$status $body_bytes_sent “$http_referer” ’ # ‘"$http_user_agent” “$http_x_forwarded_for”’; #access_log logs/access.log main; sendfile on; #tcp_nopush on; #keepalive_timeout 0; keepalive_timeout 65; #gzip on; # 如果port_in_redirect为off时,那么始终按照默认的80端口;如果该指令打开,那么将会返回当前正在监听的端口。 port_in_redirect off; # 前台展示打开的服务代理 server { listen 80; server_name localhost; #charset koi8-r; #access_log logs/host.access.log main; #root /home/blog; location / { root /home/blog/blog-react/build/; index index.html; try_files $uri $uri/ @router; autoindex on; } location @router{ rewrite ^.$ /index.html last; } location /api/ { proxy_set_header X-Real-IP $remote_addr; proxy_pass http://47.106.136.114:3000/ ; } gzip on; gzip_buffers 32 4k; gzip_comp_level 6; gzip_min_length 200; gzip_types text/css text/xml application/javascript; gzip_vary on; #error_page 404 /404.html; # redirect server error pages to the static page /50x.html # error_page 500 502 503 504 /50x.html; location = /50x.html { root html; } } # HTTPS server # 管理后台打开的服务代理 server { listen 4444; server_name localhost; # charset koi8-r; # ssl_certificate cert.pem; # ssl_certificate_key cert.key; # ssl_session_cache shared:SSL:1m; # ssl_session_timeout 5m; # ssl_ciphers HIGH:!aNULL:!MD5; # ssl_prefer_server_ciphers on; location / { root /home/blog/blog-react-admin/dist/; index index.html index.htm; try_files $uri $uri/ @router; autoindex on; } location @router{ rewrite ^.$ /index.html last; } location /api/ { proxy_set_header X-Real-IP $remote_addr; proxy_pass http://47.106.136.114:3000/ ; } gzip on; gzip_buffers 32 4k; gzip_comp_level 6; gzip_min_length 200; gzip_types text/css text/xml application/javascript; gzip_vary on; error_page 500 502 503 504 /50x.html; }}我是开了两个代理的:前台展示打开的服务代理和管理后台打开的服务代理,这个项目是分开端口访问的。比如:我的公网 ip 是 47.106.20.666,那么可以通过 http://47.106.20.666 即可访问前台展示,http://47.106.20.666:4444 即可访问管理后台的登录界面。至于为什么要写这样的配置:try_files $uri $uri/ @router;location @router{ rewrite ^.*$ /index.html last; }因为进入到文章详情时或者前端路由变化了,再刷新浏览器,发现浏览器出现 404 。刷新页面时访问的资源在服务端找不到,因为 react-router 设置的路径不是真实存在的路径。所以那样设置是为了可以刷新还可以打到对应的路径的。刷新出现 404 问题,可以看下这篇文章 react,vue等部署单页面项目时,访问刷新出现404问题3.5 上传项目代码,或者用码云、 gihub 来拉取你的代码到服务器上我是创建了码云的账号来管理项目代码的,因为码云上可以创建免费的私有仓库,我在本地把码上传到 Gitee.com 上,再进入服务器用 git 把代码拉取下来就可以了,非常方便。具体请看:码云(Gitee.com)帮助文档 V1.2git 的安装请看: CentOS 7.4 系统安装 git如果不想用 git 进行代码管理,请用其他可以连接服务器上传文件的软件,比如 FileZilla。3.6 启动 express 服务启动 express 服务,我用了 pm2, 可以永久运行在服务器上,且不会一报错 express 服务就挂了,而且运行中还可以进行其他操作。安装:npm install -g pm2切换当前工作目录到 express 应用文件夹下,执行 pm2 命令启动 express 服务:pm2 start ./bin/www比如我操作项目时的基本操作:cd /home/blog/blog-nodepm2 start ./bin/www // 开启pm2 stop ./bin/www // 关闭pm2 list //查看所用已启动项目:3.7 页面加载优化再看刚刚的 nginx 的一些配置:server { gzip on; gzip_buffers 32 4k; gzip_comp_level 6; gzip_min_length 200; gzip_types text/css text/xml application/javascript; gzip_vary on; }这个就是利用 ngonx 开启 gzip,亲测开启之后,压缩了接近 2/3 的文件大小,本来要 1M 多的文件,开启压缩之后,变成了 300k 左右。还有其他的优化请看这篇文章 React 16 加载性能优化指南,写的很不错,我的一些优化都是参考了这个篇文章的。做完一系列的优化处理之后,在网络正常的情况下,页面首屏渲染由本来是接近 5 秒,变成了 3 秒内,首屏渲染之前的 loading 在 1 秒内可见了。4. 项目地址本人的个人博客项目地址:前台展示: https://github.com/乐趣区/blog-react管理后台:https://github.com/乐趣区/blog-react-admin后端:https://github.com/乐趣区/blog-nodeblog:https://github.com/乐趣区/blog本博客系统的系列文章:react + node + express + ant + mongodb 的简洁兼时尚的博客网站react + Ant Design + 支持 markdown 的 blog-react 项目文档说明基于 node + express + mongodb 的 blog-node 项目文档说明服务器小白的我,是如何将node+mongodb项目部署在服务器上并进行性能优化的5. 最后对 全栈开发 有兴趣的朋友,可以扫下方二维码,关注我的公众号,我会不定期更新有价值的内容。微信公众号:乐趣区分享 前端、后端开发 等相关的技术文章,热点资源,全栈程序员的成长之路。关注公众号并回复 福利 便免费送你视频资源,绝对干货。福利详情请点击: 免费资源分享–Python、Java、Linux、Go、node、vue、react、javaScript ...

November 26, 2018 · 4 min · jiezi

用POLARDB构建客到智能餐饮系统实践

在新零售成为大趋势的今天,餐饮行业也加入到这一浪潮之中。智能餐饮系统将帮助餐饮行业从多个维度提升自己的运营能力和收益,而打造智能餐饮系统SaaS化能力也成为了目前的一个热点。本文中果仁软件联合创始人&研发副总赵亚南就为大家带来了关于使用阿里云POLARDB构建客到智能餐饮系统实践分享。本次分享中,首先介绍了“客到云餐饮”这款SaaS化产品,其次介绍随着业务发展所需要面对的挑战,以及“客到”为什么要选择POLARDB。第三将讲述使用POLARDB的解决方案以及迁移的整个过程所做的实践,最后将分享将数据库架构升级到POLARDB之后的效果。果仁软件与“客到云餐饮”背景介绍果仁软件早在2008年就是淘宝服务平台的第一批软件开发商,当时做了“麦多多”产品,也正是因为这款产品,果仁软件成为了阿里云的第一批客户。在使用阿里云的过程中也逐渐更多地了解了这些云产品,目前整体的技术架构都是基于阿里云的。使用阿里云产品为果仁软件带来的好处就是节省了大量运维成本,能够使技术团队更加专注于自身产品和业务的开发上。四年前,基于使用阿里云的经验和对于软件的理解,果仁软件参与到了餐饮行业的SaaS化软件“客到云餐饮”开发中。客到主要实现了SaaS化餐饮解决方案,包括了点餐、收银、财务以及后厨管理和营销、员工绩效考核等。“客到”通过智能化、数字化的餐饮服务软件,可以帮助餐厅更好地提升经营效率和服务质量,让客户真正地享受到餐饮行业所带来的服务。智能化点餐以及收银能够帮助餐厅很好地降低了人力成本和时间成本,智能化餐饮系统能够让餐厅的工作人员直接在报表中看到所有的流水信息,使得对账工作更加轻松简单。餐厅的厨师本身就非常忙碌,那么借助智能化后厨管理就能帮助厨师有序地制作菜品,进而提升后厨效率。会员营销是SaaS化中常用的功能,但是对于餐饮行业,传统会员营销方式并不能有效地吸引顾客,而借助智能系统,餐厅可以开展店内店外的智能营销,使得活动更加高效,为餐厅带来更多的资金流。很多餐饮企业越来越注意实时化的信息,对于报表的实时性要求更高。因此,餐饮行业的SaaS化就可以从这样的切入点开展。此外,“客到”在用户体验上也做了精细化设置,比较简洁、实用。而通过软件与智能硬件的配合,就能够更好地赋能餐饮行业。“客到”借助阿里云的SaaS化发展之路餐饮行业的特点就是业务峰值比较高,特别是午餐和晚餐时段这一点就体现的更为明显。通过阿里云后台的云监控可以看到在这两个时间段,几乎在瞬间系统压力就会大幅度提升,这就需要系统能够很好地应对峰值情况。此外,周末的晚上会比平时出现更大的峰值,能够达到平时的2到3倍。而且餐厅的订单数据量也是非常大的,正常的一家中餐厅每餐大概会销售200到250单,一些快餐厅甚至会达到1000到2000单。这样如果服务1万家餐厅,订单量就能达到每天100万,每年订单量就会达到7、8亿。结合菜单的明细数据,这样的数据量是非常大的。而且由于涉及到订单、会员以及促销等信息,因此表结构也会比较大,而且在高峰的时候这些业务都会出现高并发。此外,由于餐厅的特点,因此对于系统的稳定性要求非常高,基本上可以说是“365*24”小时的可用性要求。因为很多餐厅不仅提供中餐和晚餐,还会提供夜宵和早餐。之前用户量小时,就可以等待用户没有的时候进行发布新版本,而当用户量增大之后发现,这样的空闲时段已经不存在了。在最初设计餐饮软件的时候,认为只要餐厅有网络就完全可以实现SaaS化。但是后来发现在业务高峰的时候,即使带宽足够,但是在访问云端数据的时候还是非常差,甚至中断而影响业务。基于这样的情况,客到实现了本地的架构调整,能够实现即使断网也不影响业务流程的继续运行,用户对于网络情况可以实现无感知,这一点在友商内能够做到的也并不多,因此也收获了较好的口碑。随着业务发展量越来越大,用户量也越来越多,需求不断增加,业务的逻辑也越来越复杂。随着多种点餐方式以及多种下单场景的增加,对于业务调整的及时性要求越来越高。此外,产品线也越来越丰富,从3个产品飞速扩展得到8个产品。而随着业务量的增长,历史数据也飞速增长,有时候会因为云端的“慢SQL”出现卡顿,暴露出一些隐藏的问题。通过阿里云监控,及时地感知到高峰时期的CPU、内存等的报警信息,进而增加服务器或者服务器组的处理。针对于上述出现的问题,经常会做一些相应的分析。从页面的加载、前端再到后台数据库都会进行排查。在系统优化方面,会每天排查出慢SQL进行优化,包括RDS也会存在慢查询的统计,虽然慢查询并不会影响业务的正常运转,但是总会带来一些不好的用户体验。针对于以上的情况,需要增加一些索引机制以及缓存层等,对于一些历史数据进行归档,对于一些业务进行拆分,减少单表的压力,同时使得业务架构更加清晰。虽然以上的技术问题并不会影响业务的正常运转,但是有限的研发精力总是被这些技术问题所牵绊,就会影响技术团队开发新的需求和功能的速度和效率。特别是对于创业公司而言,研发效率和用户需求是最为注重的关键点。因此更加希望将技术精力集中在产品业务的开发中,做好产品,服务好客户。如果能够通过更好的技术方式和产品减少非主线研发的工作量也是各个公司以及架构师所需要考虑的。也就是说除了需要解决当前问题,还需要能够支撑起两年之内的业务扩展,虽然中间也会经历架构演变,但是对于架构师而言,需要做到心里有底。此外,好的产品一定能够提供好的性能,同时在费用上需要做到可控和可预算。为大家简单分享一下“客到”基于阿里云的架构设计。首先,从用户开始访问开始,阿里云提供了域名解析服务和CDN加速以及网络安全方面的Web应用防火墙。经过域名解析之后就到了前端的服务器,而通过负载均衡器将会将前置服务器和后置服务器再次分离,进而解决应用层面的并发请求量。应用服务器为了解决Session共享问题可以应用Redis解决,实现单机出现宕机不影响用户使用,从而实现高可用。同时Redis缓存可以有效缓解数据库层面的压力,但是在使用的时候也需要注意其自身的特点,比如带宽限制以及逻辑上需要和存储层保持一致。存储层之前使用RDS,现在换用了POLARDB,之前通过一台主RDS和几个RDS只读节点就基本上解决了关系型存储,可以对于订单的历史数据完成异步的备份。对于文件和图片等的存储可以放在阿里云OSS之上,这样比放在磁盘上更加节省成本。在安全方面,使用最多的就是云监控产品,这样就可以实现问题的提前监控预警。在设计架构的时候,架构师需要不断地梳理架构,这样在进行架构演进的时候就可以容易地分析和判断架构是否可以迁移。“客到”数据库架构向POLARDB迁移实践在进行架构迁移的可行性分析的时候,首先要把现在架构的情况,涉及到的业务以及运行的主机、ECS以及OSS都需要进行风险评估。所以在实际进行系统迁移的时候需要首先进行评估。之后为了打消研发和产品对于采用新技术和产品的顾虑,就需要做充分的准备和测试,比如对于应用POLARDB而言,需要对于性能进行充分测试,比如100%兼容MySQL,还需要对于业务进行全流程测试,在测试完成之后需要第一时间进行测试反馈。在迁移之后需要进行效果评估,“客到”在迁移到POLARDB之后发现页面响应速度得到了80%的提升,复杂SQL处理性能得到了200%的提升,而费用则降低了20%。而且整个迁移过程只使用了1个多小时,生产环境目前平稳运行,并且业务代码没有做任何修改,只做了配置文件的简单替换。最后为大家分享在数据库架构迁移过程中需要注意的两个关键点,第一点就是VPC的迁移,POLARDB使用的是VPC网络连接,那么在迁移的时候就需要做好网络规划,需要把握好时间点。此外,需要注意白名单的变化,因为在整个网络架构发生变化的时候,外网IP的变动有可能影响到第三方接口调用。本文作者:桐碧2018阅读原文本文为云栖社区原创内容,未经允许不得转载。

November 16, 2018 · 1 min · jiezi

厌倦了“正在输入…”的客服对话,是时候pick视频客服了

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦本文由腾讯云视频发表于云+社区专栏关注公众号“腾讯云视频”,一键获取 技术干货 | 优惠活动 | 视频方案什么?! 我在某宝买的Dior999口红,竟然给我发错颜色了?拆开快递包裹的那一刹那,我整个人都气炸了,立马拿出手机,平时花几个步骤才能找到的客服入口,一下子就被我找到了:你们家是怎么着,第一次遇到这种事情,我买的是Dior999,你们给我发错色号了!很生气!千叮咛万嘱咐,结果你们还给我弄错了!对方:正在输入中……我盯着眼前的对话框,足足有30s,屏幕上像复制粘贴似的来了这么一段话:亲,对于您的经历,我们感到非常抱歉!已经转给售后:小丽 处理了呢我……似乎在生活中,大家对“正在输入……”这几个字,生理般的厌恶,尤其是面对客服的时候,2C尚且如此,那么比这还难的2B服务呢?一家做IT企业服务的公司,通常会有销售、售前、售后、研发部门。我们只讨论客服体系,也就是售前和售后的部分。那么如何做好售前和售后呢?售前和售后在公司中处于什么样的地位?摆在我们面前,有两条路服务指标量化,KPI引导工作售前的业绩,与销售金额、KA客户数高度捆绑,岗位职责上,更加明确了范围:需求了解、功能演示、解决方案、上线部署/测试对接、上线培训/产品培训。对于400客服,接通率、有效通话时长等。对于官网工单的一线支持、二线支持,case响应时间、平均case受理时长、投服率等。冷冰冰的数字KPI,机械化的运作。一些感性的做法官网开始建设文档与资源,甚至问答栏目,社区论坛等,企图借助客户间的“帮助”与“推荐”,缓解售前与售后的压力。本质上,售前和售后都是在做服务,售前是企业后端与客户之间的沟通桥梁,售后侧重于获得客户满意度,进而让客户愿意为企业做其他事情,比如购买使用、复购、推荐等。区别于传统的线下服务,以及线上工单、在线客服的服务,市场上出现了一种新型的客服形式——视频客服,通过小程序视频通话,用户与客服面对面沟通,服务人员通过视频指导用户操作,解决问题,提升厂商口碑。举个例子售前环节,比如一家在线教育企业,用户从官网初步了解某个课程的内容介绍,留下联系方式后,会受到电销人员的电话访问。经过初步的沟通后,用户觉得要更深入的了解产品,便会联系视频客服,通过视频通话,用户可以看到客服人员演示的课程内容,以及听到更全面的介绍。再举个汽车厂商的例子,人们想要购买车的时候,可能会通过2种主要途径来了解车型,1种是网上查阅资料,进行比价等,1种是直接到线下店面,找销售沟通。这一来二去,基本上心里会有个底,再加上资深朋友的咨询。但有个问题,总会在快要下决心决定买的时候,记不起车子的型号或样子。而这个时候,通过视频通话的方式,连接客服人员,便不用再多跑一趟,视频客服会带着你详细的了解车型和性能特点等。这些企业业务中,都有个通用的共同特点:用户往往是从感知产品、对产品感兴趣、用户开始做各家对比、决策购买,而视频客服的角色,往往出现在,用户对产品感兴趣,想要进一步收集信息以便做好决策的时候。再看售后环节,这里同样举个汽车厂商的例子,比如用户开车的时候,车除了问题,需要报障,一般会打电话给修理人员,这种时候,要是能让修理人员来到现场,亲自帮忙看看就好了。于是,视频客服的角色,就出现了。用户通过视频通话,可以听到维修人员远程指挥,做初步的应急处理,同时,维修人员也能看到车的状况。可能行车过程中出故障这种事情,一般人遇不到。那么,再举个大家熟悉的例子——维修电脑。相信大家都有这种经历,自己电脑出了问题,着急打电话找IT部门,然后IT支持会耐心和你讲解,甚至远程控制你的电脑帮你解决问题。远程控制电脑,是件很危险的事情。这个事实,视频客服就可以起到很好的作用。通过视频通话,你可以根据IT支持的引导,进而操作,IT支持人员也可以看到你操作过程以及操作后的效果,整个问题解决过程,会顺畅起来。更生活的例子,如电器维修,空调维修,冰箱维修等等,在维修人员不方便到场的时候,视频客服,便起了作用。在这些企业业务中,也有个共同点:用户遇到问题,并且情况比较紧急,需要马上解决的时候,或者是问题难以用文字、图片的形式,进行描述的时候,采用视频通话的形式,可以显著的提升解决问题的效率。那么,这位神秘的视频客服,是怎么来的呢?市面上有通用的第三方解决方案么?视频客服的由来视频客服,是腾讯云的一款产品——实时音视频,当中的一个案例实践。“ 腾讯实时音视频 腾讯实时音视频(Tencent-RTC)是腾讯云基于 QQ 十多年来在音视频通话技术上积累,提供全平台互通高品质实时视频通话服务的一款产品;支持微信小程序/H5页面/APP/PC客户端等接入方式之间互通,通过本方案可快速从零开始搭建出实时音视频通信平台,很好的应用于在线教育、保险定损、远程医疗与微警务等场景。”总结下来,有3个特点支持在微信公众号,微信小程序,手机 QQ,腾讯浏览器使用音视频通话。提供全平台互通的高品质视频通话能力,兼容互动直播SDK方式接入。抗丢包率与抗网络抖动性能较强,弱网环境下保证高质量的音频通信。问答游戏体系结构相关阅读团战开黑必备“良药”了解一下!再也不用担心网吧开黑队友听不清了!3行代码,为QQ轻游戏加上语音互动能力 【每日课程推荐】机器学习实战!快速入门在线广告业务及CTR相应知识

October 16, 2018 · 1 min · jiezi

一文拆解Faas的真实案例

欢迎大家前往腾讯云+社区,获取更多腾讯海量技术实践干货哦~本文来自腾讯云技术沙龙,本次沙龙主题为Serverless架构开发与SCF部署实践 刘敏洁:具有多年云计算行业经验,曾任职于华为、UCloud等企业担任产品开发、产品经理。目前负责腾讯云API生态的推广,帮助开发者进行API网关与无服务器函数、容器、微服务等产品的结合使用,提供完整解决方案。这次我们主要介绍面向于API网关和SCF深度结合应用,API网关与SCF结合可以形成比较完整的Serverless方案。今天的内容分为四部分:第一,API网关这个产品本身的简单介绍和一些能力。第二,API网关和SCF也就是是我们无服务器函数结合使用的时候提供了哪些能力跟它结合方便大家使用。第三,在比较常用的场景中我们整体的使用架构以及现在客户真正使用的案例。最后是大家关心的费用问题。我们做API网关这个产品的初衷不单单是一定说跟SCF强绑定的,是在用户使用中,遇到了很多问题。那么最开始我们为什么会做这个产品?在场大家多数都是做开发的应该很清楚了,比如前端的调用方式越来越多了,后端的部署方式越来越多了,可以用自己的物理机,可以买一个云主机,可以搞一个容器,可以像使用现在更新的微服务,无服务器计算。那么在这种复杂的情况下前端和后端的耦合就会造成业务上在扩容,在做一些新的业务增加的时候变得麻烦。那么此时,解耦就变得异常重要。市面上也有一些API网关这样的开源产品,但是运维的成本,费用问题也会分摊到每个开发同学身上,既然如此我们就在想何不做一个以服务的形式提供API网关能力的产品给客户呢。所以有了今天给大家介绍的API网关这样一款产品。API网关在一般场景下怎么使用的?有一个很简单的电商例子,多数情况下客户后端有很多的业务模块,有商品、用户这些常用的业务模块。如果在以前,可能是前端的APP,小程序,直接调用这些模块,后端也是以API形式提供给前端调用的。但是前端需要理解每个模块的API。现在我们提供API网关服务,客户在使用API网关后,我们建议客户把他们的每个业务模块跟我们API网关进行对接。由API网关统一输出一个API提供给前端调用。包括前面说的小程序,外部API,都是这样的一种可以在前端调用的方式。其实用一句话来总结一下,我们API网关这个服务是什么呢?就是API的一个托管服务,可以对多种后端能力进行统一的管理,输出无状态服务的API给到前端调用。用户可以在API网关上创建API,发布API,上线、下线等。包括建成限流,监控这样的一些能力,这些能力在解耦过程中都是非常需要的。这里总结了几个比较大的能力点:首先,统一鉴权认证,这是非常重要安全防护的能力。API转化和隐藏,像参数,位置,名称都可以做转化和映射,经过映射后真正的调用者不一定拿到这些后端的真实数据。流控和配额也是常见的能力,通常后端业务资源其实是有限的,所以前端需要将API的QPS和配额做限制。另外还有输出API能力,现在腾讯云提供了API市场,如果用户后台有一些业务,有一些能力,有一些数据,想通过API提供出去给第三方伙伴直接进行售卖,都可以通过这个网关输出到API网关进行直接售卖。自动化文档和SDK这个能力呢,其实是针对方便调用者进行调用的,如果我们有了业务后再手写文档,这个工作量也很大,所以API网关可以自动帮助客户生成文档,还有SDK供客户调用。强负载能力,腾讯云API网关依赖于腾讯大的负载平台,可以应对大的突发请求不惧怕大的负载,性能方面是很有保证的。最后,API网关可以对API进行安全防护,对调用API原IP做白名单。这里其实是比较完整的流转方式。API网关分两种角色:一个是发布API的人,一个是调用API的人,他们可能是同一些人,也可能是分别两拨人。发布者先把API发布到API网关中,参数,认证,鉴权,映射等等都需要进行配置,发布者配置后可以直接在API网关控制台上进行调试,在控制台上看看这个通不通,后台响应正不正常,Ok不Ok。如果调试都成功了进行API的发布。发布后就可以把API提供给调用者了。那么API网关怎么提供API给调用者呢?我们的服务其实是以域名的形式提供给调用者的。我们会提供默认的二级域名。当然客户有自己的域名,也可以把这个域名绑到我们二级域名上。另外API网关可以生成文档SDK,提供给调用者。调用者直接使用文档、SDK可以方便的调用。调用后,前端请求到API网关后,API网关会根据之前发布的配置做一些认证,鉴权这样一些基础的校验。到后端我们会做参数的映射,最终把这个请求发到后端业务。其实后端可以对接很多云服务,像SCF,像其他云服务统统都是可以对接的。当然今天主角是无服务器函数,所以我们主要讲一下对接到SCF。对接后它会拉起它的服务响应,根据响应看是不是做一些映射,最后把结果丢会调用者。在这个过程中发布者可以看到监控的信息是怎样,也可以查询到调用。如果调用失败,或者有什么错误,是前端的还是后端的,整个日志都是可以查询到的。这是一个比较完整的流程。我们现在可以看一下API怎么跟SCF结合使用。其实很简单,前面是API网关做一个触发器。用触发器的形式来触发SCF后端的函数。然后SCF做一些计算处理,结束后它可能落到后边的像数据库这些服务,在图中的没有画出来。这种方式现在APP,小程序都是很常用的,包括给第三方合作伙伴,就是它们直接提供API给第三方合作伙伴,不走任何的平台,这种都是非常常用的一种方式。安全与限流,刚刚在我们整个功能里其实有做了一个简单的说明。这里分几块说:第一,我们提供认证能力。认证的能力像密钥对是现在常用的认证方式,我们在网关上生成密钥对,把这个提供给调用者。这个密钥对常用是服务器端对服务器端。也有像用OAuth这种单点登录,客户有自己认证服务器的,我们也是支持的,可以去用API网关对接认证服务器。认证服务器去对调用做认证鉴权,然后我们在做一些校验。这是对整个认证管理做一个安全性的保障。其实还有刚才说的源IP黑白名单。这个常见于大家内部用的,比如我是一个大的公司,内部几个部门之间用。另外限流的部分,当后端业务能承载的QPS有限的时候,在API这边做一个限流控制,如果超过这个QPS,就把这个调用丢掉,后端不会过载。CORS,现在跨域的调用非常多的,比如电商,还有一些WEB页,像CSS、JS静态调用,访问时需要浏览器跨域调用。当请求是跨域请求时,API网关会根据发布者的配置做一些处理,比如配置支持跨域,API网关会把这个CORS头去。直接响应回来后我们再把CORS头放回响应中。这完成的是跨域调用。这样的话其实对SCF开发者会比较方便使用,就不用再操心跨域的问题。响应集成这种也是常见的使用,用户开发小程序时的场景也是响应集成可能比较常用到。比如在对接前面的接口时,需要把SCF抽取成真正的HTTP格式请求返回给前端。API网关与SCF之间同样为HTTP请求,SCF函数返回的响应在响应透传模式时,会被全部放进API网关的响应body中,返回给调用者。这样的话可以直接对接很多已经有一些规范,已经有一些接口的,像小程序这种,会不适用这种方式。那么就需要API网关把SCF的响应抽取为一个标准HTTP的respond返回个标准接口。Websocket能力算是在函数计算里的一个难点,因为本身函数不是常驻的,比如说这个函数跑一跑,在没有触发的时候,可能有一个时间段过去后,目前的资源就释放掉了,下次再触发的时候再拉起来,这很难跟前端保持长连接。那我们怎么帮SCF处理长连接问题的呢?API网关会帮每一个前端的调用者生成一个唯一的ID,这个ID就注册到后面客户的业务函数里。当客户业务函数需要推送的时候,他只要带到这个唯一ID给API网关,API网关就会将这个唯一ID的消息丢给前端,这样我们唯一ID和前面的连接保持了长连接,也保证了后端推送的正确性。举个例子,一个聊天室,有三个人聊天,范冰冰,李晨和黄晓明。他们三个都有唯一ID。黄晓明发出来一句话,后面的函数收到这句话,并且要把他说的话推送给范冰冰和李晨,那么通过唯一ID,可以识别到三个人,后端业务将黄晓明ID的聊天语句推送到API网关,告诉API网关要将此信息推送给范冰冰和李晨ID的前端,API网关收到信息后,则将此信息推送到与范冰冰李晨的客户端保持的长连接中,他们就看到了这条信息。这就是处理Websocket长连接的方式。开放到API市场上,刚才我们也简单说了一下,其实很多能力,我们自己一些能力和数据想直接开放出去给别人,但是并不想做一个页面,计费流程,那么可以放到API市场来进行售卖。其实后端业务放到SCF上是提供服务的一种方式,这样有些用户业务是放在API市场上来进行售卖的。这是把我们技术能力变现的一种方式。文档与SDK刚才也说了很多,这里再来介绍一下。如果用户配了10个API,API网关会帮用户生成这10个API的文档和SDK。swagger文档有点像代码式的文档另外还有普通文字描述的API文档,这两种我们都能生成。生成后可以直接下载下来提供给别人。SDK中有鉴权相关的代码,调用者使用时把自己的参数填进去,对调用者来说更方便。高并发,这里我们还是想强调一下,API网关可以扛住非常非常大的并发请求。当用户请求的并发量极大时,并且有大量HTTPS时,大量请求十分消耗CPU。ABI网关的高性能,及时HTTPS请求的异步处理,可以应对高并发场景,保证服务可用。场景方面,刚才说的是一些具体功能,我们能帮SCF做哪些具体的能力。在整体结构的使用场景这里做一些介绍,这里是小程序公众号,电商这种业务场景现在使用的一些客户的架构,客户的很多业务模块放到SCF上面,然后用API网关作为API服务提供出去。前端无论是小程序还是APP只要有鉴权,有密钥对都可以来进行调用。后端根据自己的业务去跟MySQL等能力来进行对接。刚刚这种方式,像乐凯撒是一个很典型的例子。他们把他们的菜单系统,还有微信支付都放在SCF上面。前端会对接一些固有的HTTP接口,所以用了我们的响应集成的能力,就是API网关帮他抽取成一个标准的HTTP响应返回给前面的调用者。另外因为有很多图片静态资源,他们也使用了跨域能力,这样后端上线的时候非常快。乐凯撒现在有一个小程序用户可以直接在上面下单买披萨,这个小程序中的很多能力是使用上述架构完成的。他们的ERP也有一些后台的系统,也是直接在SCF上进行后台计算,用API网关直接出接口。其实很多能力可以复用,那么API本身就可以进行复用。这样的开发流程,会让整个上线过程非常的迅速。现在用的多的还有AI推理和翻译。用户将自身的计算模型,翻译模型等放在SCF上,每次通过API网关触发来触发计算。API网关将请求带来的数据给到后端,并对每个请求做鉴权认证或ACL管理保障使用的安全性。比较典型的就是搜狗,搜狗在这里其实有一个翻译推理的模型,放在SCF上, SCF跑在GPU上,然后通过API网关做触发。这里用API网关主要是想做前后的解耦。因为搜狗的业务本身解耦是C++写的,所有的请求都是用http的方式传递,请求端和后台解耦合后,很多后端业务不再需要用python重写。荔枝微课是一个在线教育课程。它的情况是,后端SCF跑了一个模型计算。每次当客户在他的页面上搜某个课程。它的前端会把这个课程,用户感兴趣的课程信息,包括客户的ID,之前的一些信息带到后端带给SCF。SCF模型拿到了客户信息,它本身也会有一些自己的原有的信息,这些信息结合起来,再根据其算法进行计算。最后得出的结论,这个客户喜欢某些课程,再把这个课程推送到前端来,最终展示在WEB页上。在这个中间,其实API网关和SCF解耦的时候,对API网关的模型调用,需要有安全保证的,就是有不同IP的时候有源IP调用,还有密钥对的鉴权对后端进行安全保障。另外如果说这个SCF或者调用有任何问题的话,监控报警也是可以快速让我感知到这个模型的状态。最后看一下费用,我们费用也是有很大力度减免的,每月有一百万次的免费调用。网络费用跟公网的的价格是一样的,调用次数0.04元/万次。目前没有收费,预计到年底收费。但是整个资源费用是非常便宜的,所以如果有想试用的同学不用很犹豫。 Q:主要想请问涉及到有时候有自己的线上环境和我们的测试环境,我想知道我们现在如果使用你们的API网关还有SCF,我们怎么去部署这样两套环境?怎么样去完成像我们现在使用的这些持续集成,怎么结合到我现有的产品?因为我目前看到的展示都是基于控制台,没有看到说基于CLI的操作,所以想了解一下。A:其实我们API网关有环境管理和版本管理。版本管理也分了环境,测试环境这些标准环境。后续还会开放这些环境让用户自定义这些环境。CLI部分我理解需要在公台操作,还是命令行操作,本身跟我提不提供环境管理,版本能力应该是两个事情。所以CLI后续会提供。但是本身需要的开发和测试环境我们已经分环境提供。Q:新的代码更新后要上线到SCF上怎么部署?A:后面我们会做一个工具,在这个工具上,比如CLI,可以一键上传,并且配一些API网关。目前这个都在开发中。Q:怎么样买服务器便宜,怎么样买按调用次数的偏移?A:这个还是需要你本身业务来计算一下。比如说我这个业务就是一个触发型的业务,我如果用一个CPM或者物理机部署的话,如果常驻型的话需要占到多少钱,这个钱其实是固定的,每个月需要多少钱。但是如果我知道这个业务是触发型,假如每天就调用一万次,这个也是能算出来的钱。这个钱一比较就很简单就出来了。但是这个都得基于你本身业务的调用量和你本身业务后端消耗资源的情况来进行计算的。所以我没法儿给你一个直接的值。如果真的需要一个常驻的业务,一天二十四小时一直在跑的话,其实这个也是要看,这二十四小时在跑的,我对我本身的服务器我的消耗情况,比如说我买完了一台服务器,市面上的服务器可能就那么多,或者说CPM就那么多,即便买了最小的4核服务器都没跑满,如果计算很轻量没法儿跑满的话,用SCF也会很划算。但是需要大量的,可能用本身的传统的方式会比较简单。Q:在调用的稳定性,延时方面Serverless会有优势吗?A:其实调用的稳定性是我们服务稳定性的保障,这个不用担心,因为我们有承诺。至于延时,是有很多因素影响的,如果你是公网调用,这基于网络的一些情况。如果说API网关到SCF结合的话,本身API网关和SCF可以走内网和公网。API网关本身的延时是在毫秒级别,这个我们测试过的,还是很小的。如果部署一个服务器或者资源,你到那个网络之间的延时,你自己本身原来延时是多少还是要算一下。我可以告诉你我们的延时本身是多少,在可测的环境下我们的延时是多少。但是到你们具体的网络环境下还是要具体测量的。本文PPT附件请点击原文下载。问答Serverless:如何删除一个函数? 相关阅读多个场景中的AI落地实践低于0.01%的极致Crash率是怎么做到的? 【每日课程推荐】机器学习实战!快速入门在线广告业务及CTR相应知识

September 7, 2018 · 1 min · jiezi