Hero Image
全局变量加锁的优化

#golang #cache_line 开发中不可避免地会遇到需要对全局变量加锁的情况,而一旦并发量高了之后,加锁的变量有可能变成服务的性能瓶颈所在。所以千方百计地寻找优化方法。 改变锁的类型 如果业务中的全局变量是读多写少的应用场景,我们可以将互斥锁改为读写锁。即读取时对变量加读锁,这样可以支持多个线程并发读取同一个变量。而只有变量需要修改时才加写锁,保证写的时候不会被其他线程读取到错误的值。 互斥锁: func DoWork() { lock.Lock() defer lock.Unlock() // do something... } 读写锁: func Read() { lock.RLock() defer lock.RUnlock() // read global variable } func Write() { lock.Lock() defer lock.Unlock() // write global variable } 降低锁住的代码块长度 在Go中,我们常常会利用defer关键字的特性,写出如下的代码: func Write() { lock.Lock() defer lock.Unlock() // do something... } 但在实际代码中,如果对全局变量读写前后会有较长时间去做其他工作的情况下,就会造成极大的性能损耗。加锁之后没有立即对全局变量进行读写,或者对全局变量读写完之后没有立即释放锁,都会使其他线程没有办法立即抢到锁,从而拉低了整个系统的并发性能。 根据这个逻辑,可以将上述代码改成如下格式: func Write() { // do something... lock.Lock() // read or write global variable lock.Unlock() // do something.

Hero Image
HTTP笔记

#http-code http协议(超文本传输协议) 是客户端和服务器端两者通信共同遵循的一些规则。主要内容是定义了客户端如何向服务器请求资源,服务器如何响应客户端请求。 请求中的POST与GET方法的区别 get是从服务器上获取数据,post是向服务器传送数据。 在客户端,Get方式在通过URL提交数据,数据在URL中可以看到;POST方式,数据放置在HTML HEADER内提交。 对于get方式,服务器端用Request.QueryString获取变量的值,对于post方式,服务器端用Request.Form获取提交的数据。 GET方式提交的数据最多只能有1024字节,而POST则没有此限制。 安全性问题。正如在(1)中提到,使用 GET 的时候,参数会显示在地址栏上,而 Post 不会。所以,如果这些数据是中文数据而且是非敏感数据,那么使用 GET;如果用户输入的数据不是中文字符而且包含敏感数据,那么还是使用 post为好。 HTTP 1.0 HTTP 1.0规定浏览器与服务器只保持短暂的连接,浏览器的每次请求都需要与服务器建立一个TCP连接,服务器完成请求处理后立即断开TCP连接 当一个网页文件中包含了很多图像的地址的时候,那就需要很多次的HTTP请求和响应,每次请求和响应都需要一个单独的连接,每次连接只是传输一个文档和图像,上一次和下一次请求完全分离。即使图像文件都很小,但是客户端和服务器端每次建立和关闭连接却是一个相对比较费时的过程,并且会严重影响客户机和服务器的性能。当一个网页文件中包含JS文件,CSS文件等内容时,也会出现类似上述的情况。 HTTP 1.1 为了克服HTTP 1.0的这个缺陷,HTTP 1.1支持持久连接(HTTP/1.1的默认模式使用带流水线的持久连接),在一个TCP连接上可以传送多个HTTP请求和响应,减少了建立和关闭连接的消耗和延迟。一个包含有许多图像的网页文件的多个请求和应答可以在一个连接中传输,但每个单独的网页文件的请求和应答仍然需要使用各自的连接。 HTTP 1.1还允许客户端不用等待上一次请求结果返回,就可以发出下一次请求,但服务器端必须按照接收到客户端请求的先后顺序依次回送响应结果,以保证客户端能够区分出每次请求的响应内容,这样也显著地减少了整个下载过程所需要的时间。 在HTTP 1.1,request和response头中都有可能出现一个connection的头,此header的含义是当client和server通信时对于长链接如何进行处理。 在HTTP 1.1中,client和server都是默认对方支持长链接的, 如果client使用HTTP 1.1协议,但又不希望使用长链接,则需要在header中指明connection的值为close;如果server方也不想支持长链接,则在response中也需要明确说明connection的值为close。不论request还是response的header中包含了值为close的connection,都表明当前正在使用的tcp链接在当天请求处理完毕后会被断掉。以后client再进行新的请求时就必须创建新的tcp链接了。 HTTP 1.1在继承了HTTP 1.0优点的基础上,也克服了HTTP 1.0的性能问题。 HTTP 1.1通过增加更多的请求头和响应头来改进和扩充HTTP 1.0的功能。如,HTTP 1.0不支持Host请求头字段,浏览器无法使用主机头名来明确表示要访问服务器上的哪个WEB站点,这样就无法使用WEB服务器在同一个IP地址和端口号上配置多个虚拟WEB站点。在HTTP 1.1中增加Host请求头字段后,WEB浏览器可以使用主机头名来明确表示要访问服务器上的哪个WEB站点,这才实现了在一台WEB服务器上可以在同一个IP地址和端口号上使用不同的主机名来创建多个虚拟WEB站点。HTTP 1.1的持续连接,也需要增加新的请求头来帮助实现,例如,Connection请求头的值为Keep-Alive时,客户端通知服务器返回本次请求结果后保持连接;Connection请求头的值为close时,客户端通知服务器返回本次请求结果后关闭连接。HTTP 1.1还提供了与身份认证、状态管理和Cache缓存等机制相关的请求头和响应头。HTTP 1.0不支持文件断点续传,RANGE:bytes是HTTP 1.1新增内容,HTTP 1.0每次传送文件都是从文件头开始,即0字节处开始。RANGE:bytes=XXXX表示要求服务器从文件XXXX字节处开始传送,这就是我们平时所说的断点续传。 HTTP 1.1和HTTP 1.0协议的区别 缓存处理 带宽优化及网络连接的使用 错误通知的管理 消息在网络中的发送 互联网地址的维护 安全性及完整性 HTTP 1.x和HTTP 2协议的区别 二进制分帧:HTTP 2采用二进制格式传输数据,而非HTTP 1.x的文本格式 头部压缩:头部表在HTTP 2的连接存续期内始终存在,由客户端和服务器共同渐进地更新。请求一发送了所有的头部字段,第二个请求则只需要发送差异数据,这样可以减少冗余数据,降低开销 多路复用:直白的说就是所有的请求都是通过一个TCP连接并发完成。HTTP 1.x虽然通过pipeline也能并发请求,但是多个请求之间的响应会被阻塞的,所以pipeline至今也没有被普及应用,而HTTP 2做到了真正的并发请求。同时,流还支持优先级和流量控制。 服务器推送:服务端能够更快的把资源推送给客户端。例如服务端可以主动把JS和CSS文件推送给客户端,而不需要客户端解析HTML再发送这些请求。当客户端需要的时候,它已经在客户端了。 HTTP 2主要是HTTP 1.

Hero Image
Redis缓存相关问题

#redis #cache #db 缓存一致性 形成原因 数据增删修操作造成的缓存内容与持久层内容的不一致 解决办法 先更新缓存后更新数据库:更新缓存后程序异常终止或持久化失败导致数据未持久化 先更新数据库后更新缓存:更新数据库后程序异常终止或更新缓存失败导致缓存数据与数据库不一致。解决办法:先更新缓存,后将数据修改操作写入持久化队列,比如Kafka,让下游服务执行持久化操作 缓存穿透 针对多个key 形成原因 缓存穿透是指查询一个不存在的数据,由于缓存是不命中时,去存储层(如MySQL)查找数据。如果从存储层查不到数据没有写入缓存,这将导致这个不存在的数据每次请求都要到存储层去查询,导致缓存穿透。流量一旦大了之后,容易导致DB宕机,进而影响整个业务。利用不存在的key频繁攻击应用,这就是漏洞。 解决办法 使用布隆过滤器,如果从DB中没有查到则添加到布隆过滤器中。但由于布隆过滤器中存储的内容是不能修改的,需要注意使用场景。如果当前查询不存在的key以后会出现再实际数据中,使用布隆过滤器会导致改条数据无法查询到。 缓存不存在的key,如果从DB中没有查询到该数据,则将对应的key写入缓存中,并加一个合适的过期时间。value内容写一个不存在的标记,当程序读到该内容后,即知道这条key不存在对应的内容直接返回,不会将流量打入存储层。 缓存雪崩 多个key相同的过期时间 形成原因 缓存雪崩是指多个key在相同时间过期,导致缓存在某一时刻同时失效。请求全部转发到DB,DB瞬时压力过高宕机导致服务不可用。 解决办法 使用队列,将需要缓存的数据发往一个统一的队列中,依次写缓存。 随机过期时间,比如一个key需要缓存一小时,则在一小时的基础上随机±5分钟,这样可以一定程度上解决一批key集中过期的问题 缓存击穿 针对一个key 形成原因 某个设置了过期时间的key,在过期后某一时间有大量并发请求进来。而在第一个请求进来,从DB中查完还没来得及写入缓存中时后面的并发请求也进来了,就会造成同一个key并发访问DB,瞬间打垮存储层。 一般突然出现的热点key容易造成这种问题。 解决办法 使用分布式互斥锁,当一个key在缓存中没有查询到时,先去抢这个key的锁,抢到则去存储层进行查询,没有抢到则去缓存中查询,根据实际情况如果一次没有查找到可以循环查找几次(毕竟查数据库需要耗时)。 其他 数据的缓存策略,有时也需要根据实际业务来设定。比如一些热点key设置为永不过期,但永不过期也会给缓存的存储带来压力,而给key设置过期时间,又会带来以上几种问题。抑或是缓存设置永不过期,使用异步线程定期删除一些没有访问的key。 写代码的时候需要一个指导思想,但同时亦不可死搬教条。

Hero Image
OAuth 2.0扩展协议PKCE

#oauth PKCE全称是Proof Key for Code Exchange,在2015年发布,它是OAuth 2.0核心的一个扩展协议,所以可以和现有的授权模式结合使用,比如Authorization Code+PKCE, 这也是最佳实践,PKCE最初是为移动设备应用和本地应用创建的, 主要是为了减少公共客户端的授权码拦截攻击。 在最新的OAuth 2.1规范中,推荐所有客户端都使用PKCE,而不仅仅是公共客户端,并且移除了Implicit隐式和Password模式,那之前使用这两种模式的客户端怎么办? 是的,现在都可以尝试使用Authorization Code+PKCE的授权模式。那PKCE为什么有这种魔力呢? 实际上它的原理是客户端提供一个自创建的证明给授权服务器,授权服务器通过它来验证客户端,把访问令牌(access_token)颁发给真实的客户端而不是伪造的。 客户端类型 上面说到了PKCE主要是为了减少公共客户端的授权码拦截攻击,那就有必要介绍下两种客户端类型了。 OAuth 2.0核心规范定义了两种客户端类型, confidential 机密的, 和 public 公开的, 区分这两种类型的方法是, 判断这个客户端是否有能力维护自己的机密性凭据 client_secret。 confidential 对于一个普通的web站点来说,虽然用户可以访问到前端页面,但是数据都来自服务器的后端api服务,前端只是获取授权码code,通过code换取access_token这一步是在后端的api完成的,由于是内部的服务器,客户端有能力维护密码或者密钥信息,这种是机密的的客户端。 public 客户端本身没有能力保存密钥信息,比如桌面软件,手机App,单页面程序(SPA),因为这些应用是发布出去的,实际上也就没有安全可言,恶意攻击者可以通过反编译等手段查看到客户端的密钥,这种是公开的客户端。 在OAuth 2.0授权码模式(Authorization Code)中,客户端通过授权码code向授权服务器获取访问令牌(access_token)时,同时还需要在请求中携带客户端密钥(client_secret),授权服务器对其进行验证,保证access_token颁发给了合法的客户端,对于公开的客户端来说,本身就有密钥泄露的风险,所以就不能使用常规OAuth 2.0的授权码模式,于是就针对这种不能使用client_secret的场景,衍生出了Implicit隐式模式,这种模式从一开始就是不安全的。在经过一段时间之后,PKCE扩展协议推出,就是为了解决公开客户端的授权安全问题。 授权码拦截攻击 上面是OAuth 2.0授权码模式的完整流程,授权码拦截攻击就是图中的C步骤发生的,也就是授权服务器返回给客户端授权码的时候,这么多步骤中为什么C步骤是不安全的呢?在OAuth 2.0核心规范中,要求授权服务器的anthorize endpoint和token endpoint必须使用TLS(安全传输层协议)保护,但是授权服务器携带授权码code返回到客户端的回调地址时,有可能不受TLS的保护,恶意程序就可以在这个过程中拦截授权码code,拿到code之后,接下来就是通过code向授权服务器换取访问令牌access_token,对于机密的客户端来说,请求access_token时需要携带客户端的密钥client_secret,而密钥保存在后端服务器上,所以恶意程序通过拦截拿到授权码code也没有用,而对于公开的客户端(手机App,桌面应用)来说,本身没有能力保护client_secret,因为可以通过反编译等手段,拿到客户端client_secret,也就可以通过授权码code换取access_token,到这一步,恶意应用就可以拿着token请求资源服务器了。 state参数,在OAuth 2.0核心协议中,通过code换取token步骤中,推荐使用state参数,把请求和响应关联起来,可以防止跨站点请求伪造-CSRF攻击,但是state并不能防止上面的授权码拦截攻击,因为请求和响应并没有被伪造,而是响应的授权码被恶意程序拦截。 PKCE 协议流程 PKCE协议本身是对OAuth 2.0的扩展,它和之前的授权码流程大体上是一致的。区别在于,在向授权服务器的authorize endpoint请求时,需要额外的code_challenge和code_challenge_method参数,向token endpoint请求时,需要额外的code_verifier参数,最后授权服务器会对这三个参数进行对比验证,通过后颁发令牌。 原理分析 上面我们说了授权码拦截攻击,它是指在整个授权流程中,只需要拦截到从授权服务器回调给客户端的授权码code,就可以去授权服务器申请令牌了,因为客户端是公开的,就算有密钥client_secret也是形同虚设,恶意程序拿到访问令牌后,就可以光明正大的请求资源服务器了。 PKCE是怎么做的呢?既然固定的client_secret是不安全的,那就每次请求生成一个随机的密钥(code_verifier),第一次请求到授权服务器的authorize endpoint时,携带code_challenge和code_challenge_method,也就是code_verifier转换后的值和转换方法,然后授权服务器需要把这两个参数缓存起来,第二次请求到token endpoint时,携带生成的随机密钥的原始值(code_verifier),然后授权服务器使用下面的方法进行验证: plain code_challenge = code_verifier sha256 code_challenge = BASE64URL-ENCODE(SHA256(ASCII(code_verifier))) 通过后才颁发令牌,那向授权服务器authorize endpoint和token endpoint发起的这两次请求,该如何关联起来呢?通过授权码code即可,所以就算恶意程序拦截到了授权码code,但是没有code_verifier,也是不能获取访问令牌的,当然PKCE也可以用在机密(confidential)的客户端,那就是client_secret+code_verifier双重密钥了。 参考连接 oauth文档

Hero Image
网络IO演进历程

网络IO模型演进历程 阻塞IO BIO(Blocking IO) 非阻塞IO NIO(Nonblocking IO) IO多路复用第一版 select/poll/epoll 异步IO AIO(Async IO) BIO 阻塞 IO,顾名思义当用户发生了系统调用后,如果数据未从网卡到达内核态,内核态数据未准备好,此时会一直阻塞。直到数据就绪,然后从内核态拷贝到用户态再返回。 BIO缺点,能支持的并发连接数比较少: 一台服务器能分配的线程数是有限的 大量线程频繁切换上下文会影响性能 核心矛盾:一个client分配一个线程是因为处理客户端读写是阻塞式的,为避免该阻塞影响接受后续新的client的连接,所以将阻塞逻辑交由单独的线程处理。 NIO 非阻塞 IO:见名知意,就是在第一阶段(网卡-内核态)数据未到达时不等待,然后直接返回。因此非阻塞 IO 需要不断的用户发起请求,轮询内核。 优点 将socket设为非阻塞后,在读取时如果数据未就绪就直接返回。可以通过一个线程管理多个client连接。 缺点 需要不断轮询内核,数据是否已经就绪,会造成很多无效的,太频繁的系统调用(system call)而造成资源浪费。 select/poll/epoll select 和 poll 的区别 select 能处理的最大连接,默认是 1024 个,可以通过修改配置来改变,但终究是有限个;而 poll 理论上可以支持无限个 select 和 poll 在管理海量的连接时,会频繁的从用户态拷贝到内核态,比较消耗资源 epoll对文件描述符的操作有两种模式: LT(level trigger)和 ET(edge trigger)。 LT模式:当 epoll_wait 检测到描述符事件发生并将此事件通知应用程序,应用程序可以不立即处理该事件。下次调用 epoll_wait 时,会再次响应应用程序并通知此事件。 ET模式:当 epoll_wait 检测到描述符事件发生并将此事件通知应用程序,应用程序必须立即处理该事件。如果不处理,下次调用 epoll_wait 时,不会再次响应应用程序并通知此事件。 简言之:边沿触发仅触发一次,水平触发会一直触发。 epoll高效的本质在于: 减少了用户态和内核态的文件句柄拷贝 减少了对可读可写文件句柄的遍历 mmap 加速了内核与用户空间的信息传递,epoll是通过内核与用户mmap同一块内存,避免了无谓的内存拷贝 IO性能不会随着监听的文件描述的数量增长而下降 使用红黑树存储fd,以及对应的回调函数,其插入,查找,删除的性能不错,相比于hash,不必预先分配很多的空间 - select poll epoll 操作方式 遍历 遍历 回调 底层实现 数组 链表 哈希表 IO效率 每次调用都进行线性遍历,时间复杂度为O(n) 每次调用都进行线性遍历,时间复杂度为O(n) 事件通知方式,每当fd就绪,系统注册的回调函数就会被调用,将就绪fd放到rdllist里面。时间复杂度O(1) 最大连接数 1024(x86)或 2048(x64) 无上限 无上限 fd拷贝 每次调用select,都需要把fd集合从用户态拷贝到内核态 每次调用poll,都需要把fd集合从用户态拷贝到内核态 调用epoll_ctl时拷贝进内核并保存,之后每次epoll_wait不拷贝 AIO 参考连接 Chapter 6.

Hero Image
k8s中通过Headless连接StatefulSet

#kubernetes #k8s 连接一些多实例的服务(比如Kafka、ES)时,通常是在client端做负载均衡。 假如这种集群又恰好跑在k8s中,如果是普通业务类型的服务,通常是创建一个Service来做为一个代理去访问不同实例,从而达到负载均衡的目的。 但是诸如如:Kafka、ES类型的服务,还用Service来做负载均衡,显然就不那么合理了(诚然,Kafka、ES这种东西多半是不会跑在k8s上的,这里只是作为一个引子,不在本文讨论的范畴)。 实验环境 多实例服务whoami在kube-test-1的命名空间下 多实例服务whoami以StatefulSet方式部署,设置为3个实例,会自动创建whoami-0、whoami-1以及whoami-2三个Pod 给StatefulSet创建Headless类型的Service 模拟客户端使用Nginx镜像,部署在kube-test-2的命名空间下(使用curl命令模拟) 本实验创建资源使用的k8s dashboard,创建的资源默认放在选中的明明空间下,因此yml文件中未指定namespace。 Server cluster 服务端模拟相关资源在kube-test-1下创建 StatefulSet 使用traefik/whoami镜像来模拟服务端 这里使用StatefulSet的方式创建服务端。spec.replicas设为3,此时会自动创建whoami-0、whoami-1以及whoami-2三个Pod。 apiVersion: apps/v1 kind: StatefulSet metadata: name: whoami labels: app: whoami spec: replicas: 3 selector: matchLabels: app: whoami serviceName: whoami template: metadata: name: whoami labels: app: whoami spec: containers: - name: whoami image: traefik/whoami ports: - containerPort: 80 注意这里的spec.serviceName必须与下面的Service名字相同,否则调用时候pod的subdomain只能使用IP $ k get pod -n kube-test-1 -o wide | grep whoami whoami-0 1/1 Running 0 29m 10.

Hero Image
Hadoop生态组件

#hadoop 最近在学习大数据相关的东西,看了HDFS,Hive,HBas,Spark相关的东西,总结一下Hadoop生态中常见的组件。 HDFS(hadoop分布式文件系统) HDFS是hadoop体系中数据存储管理的基础。他是一个高度容错的系统,能检测和应对硬件故障。 有以下几个角色: client:切分文件,访问HDFS,与那么弄得交互,获取文件位置信息,与DataNode交互,读取和写入数据。 namenode:master节点,在hadoop1.x中只有一个,管理HDFS的名称空间和数据块映射信息,配置副本策略,处理客户 端请求。 DataNode:slave节点,存储实际的数据,汇报存储信息给namenode。 secondary namenode:辅助namenode,分担其工作量:定期合并fsimage和fsedits,推送给namenode;紧急情况下和辅助恢复namenode,但其并非namenode的热备。 mapreduce(分布式计算框架) mapreduce是一种计算模型,用于处理大数据量的计算。其中map对应数据集上的独立元素进行指定的操作,生成键-值对形式中间,reduce则对中间结果中相同的键的所有值进行规约,以得到最终结果。 jobtracker:master节点,只有一个,管理所有作业,任务/作业的监控,错误处理等,将任务分解成一系列任务,并分派给tasktracker。 tacktracker:slave节点,运行 map task和reducetask;并与jobtracker交互,汇报任务状态。 map task:解析每条数据记录,传递给用户编写的map()并执行,将输出结果写入到本地磁盘(如果为map—only作业,则直接写入HDFS)。 reduce task:从map 它深刻地执行结果中,远程读取输入数据,对数据进行排序,将数据分组传递给用户编写的reduce函数执行。 hive(基于hadoop的数据仓库) 由Facebook开源,最初用于解决海量结构化的日志数据统计问题。 hive定于了一种类似sql的查询语言(hql)将sql转化为mapreduce任务在hadoop上执行。 hbase(分布式列存数据库) hbase是一个针对结构化数据的可伸缩,高可靠,高性能,分布式和面向列的动态模式数据库。和传统关系型数据库不同,hbase采用了bigtable的数据模型: 增强了稀疏排序映射表(key/value)。其中,键由行关键字,列关键字和时间戳构成,hbase提供了对大规模数据的随机,实时读写访问,同时,hbase中保 存的数据可以使用mapreduce来处理,它将数据存储和并行计算完美结合在一起。 zookeeper(分布式协作服务) 解决分布式环境下的数据管理问题:统一命名,状态同步,集群管理,配置同步等。 sqoop(数据同步工具) sqoop是sql-to-hadoop的缩写,主要用于传统数据库和hadoop之间传输数据。数据的导入和导出本质上是mapreduce程序,充分利用了MR的并行化和容错性。 pig(基于hadoop的数据流系统) 定义了一种数据流语言-pig latin,将脚本转换为mapreduce任务在hadoop上执行。通常用于离线分析。 mahout(数据挖掘算法库) mahout的主要目标是创建一些可扩展的机器学习领域经典算法的实现,旨在帮助开发人员更加方便快捷地创建只能应用程序。mahout现在已经包含了聚类,分类, 推荐引擎(协同过滤)和频繁集挖掘等广泛使用的数据挖掘方法。除了算法是,mahout还包含了数据的输入/输出工具,与其他存储系统(如数据库,mongoDB或 Cassandra)集成等数据挖掘支持架构。 flume(日志收集工具) cloudera开源的日志收集系统,具有分布式,高可靠,高容错,易于定制和扩展的特点。他将数据从产生,传输,处理并写入目标的路径的过程抽象为数据流,在 具体的数据流中,数据源支持在flume中定制数据发送方,从而支持收集各种不同协议数据。 资源管理器的简单介绍(YARN和mesos) 随着互联网的高速发展,基于数据 密集型应用 的计算框架不断出现,从支持离线处理的mapreduce,到支持在线处理的storm,从迭代式计算框架到 流式处理框 架s4,…,在大部分互联网公司中,这几种框架可能都会采用,比如对于搜索引擎公司,可能的技术方法如下:网页建索引采用mapreduce框架,自然语言处理/ 数据挖掘采用spark,对性能要求到的数据挖掘算法用mpi等。公司一般将所有的这些框架部署到一个公共的集群中,让它们共享集群的资源,并对资源进行统一使 用,这样便诞生了资源统一管理与调度平台,典型的代表是mesos和yarn。 其他的一些开源组件: cloudrea impala: 一个开源的查询引擎。与hive相同的元数据,SQL语法,ODBC驱动程序和用户接口,可以直接在HDFS上提供快速,交互式SQL查询。impala不再使用缓慢的 hive+mapreduce批处理,而是通过与商用并行关系数据库中类似的分布式查询引擎。可以直接从HDFS或者Hbase中用select,join和统计函数查询数据,从而 大大降低延迟。 spark: spark是个开源的数据 分析集群计算框架,最初由加州大学伯克利分校AMPLab,建立于HDFS之上。spark与hadoop一样,用于构建大规模,延迟低的数据分析 应用。spark采用Scala语言实现,使用Scala作为应用框架。 spark采用基于内存的分布式数据集,优化了迭代式的工作负载以及交互式查询。 与hadoop不同的是,spark与Scala紧密集成,Scala象管理本地collective对象那样管理分布式数据集。spark支持分布式数据集上的迭代式任务,实际上可 以在hadoop文件系统上与hadoop一起运行(通过YARN,MESOS等实现)。 storm storm是一个分布式的,容错的计算系统,storm属于流处理平台,多用于实时计算并更新数据库。storm也可被用于“连续计算”,对数据流做连续查询,在计算 时将结果一流的形式输出给用户。他还可被用于“分布式RPC”,以并行的方式运行昂贵的运算。 kafka kafka是由Apache软件基金会开发的一个开源流处理平台,由Scala和Java编写。Kafka是一种高吞吐量的分布式发布订阅消息系统,它可以处理消费者规模的 网站中的所有动作流数据。 这种动作(网页浏览,搜索和其他用户的行动)是在现代网络上的许多社会功能的一个关键因素。 这些数据通常是由于吞吐量的要求 而通过处理日志和日志聚合来解决。 对于像Hadoop的一样的日志数据和离线分析系统,但又要求实时处理的限制,这是一个可行的解决方案。Kafka的目的是通 过Hadoop的并行加载机制来统一线上和离线的消息处理,也是为了通过集群来提供实时的消息