融数数据基于Kubernetes的微服务治理和构建平台

 

 

 

DNS:

A——IP地址

CName ——主机名

PTR——与A相反

SRV——DNS SRV是DNS记录中一种,用来指定服务地址。与常见的A记录、cname不同的是,SRV中除了记录服务器的地址,还记录了服务的端口,并且可以设置每个服务地址的优先级和权重。访问服务的时候,本地的DNS resolver从DNS服务器查询到一个地址列表,根据优先级和权重,从中选取一个地址作为本次请求的目标地址。

 

 

 

我们都知道 CAP 是 Eric Brewer 提出的分布式系统三要素:
强一致性 (Consistency)
可用性 (Availability)
分区容忍性 (Partition Tolerance)

几乎所有的服务发现和注册方案都是 CP 系统,也就是说满足了在同一个数据有多个副本的情况下,对于数据的更新操作达到最终的效果和操作一份数据是一样的,但是在出现网络分区(分区间的节点无法进行网络通信)这样的故障的时候,在节点之间恢复通信并且同步数据之前,一些节点将会无法提供服务(一些系统在节点丢失的情况下支持 stale reads )。

 

 

 

服务发现之 Etcd VS Consul

 

值得注意的是,分布式系统中的数据分为控制数据和应用数据。使用etcd的场景默认处理的数据都是控制数据,对于应用数据,只推荐数据量很小,但是更新访问频繁的情况。

 

 

抄自这里

 

************************************************************************************************

网上找来找去都是zk和etcd的比较,和consul的比较很少,这个感觉还算靠谱,也在别的地方看到过对consul的吐槽,记录下

************************************************************************************************

 

导语

在分布式微服务架构中,一个应用可能由一组职责单一化的服务组成。这时候就需要一个注册服务的机制,注册某个服务或者某个节点是可用的,还需要一个发现服务的机制来找到哪些服务或者哪些节点还在提供服务。

在实际应用中,通常还都需要一个配置文件告诉我们一些配置信息,比如数据连接的地址,redis 的地址等等。但很多时候,我们想要动态地在不修改代码的情况下得到这些信息,并且能很好地管理它们。

有了这些需求,于是发展出了一系列的开源框架,比如 ZooKeeper, Etcd, Consul 等等。

这些框架一般会提供这样的服务:

服务注册
主机名,端口号,版本号,或者一些环境信息。

服务发现
可以让客户端拿到服务端地址。

一个分布式的通用 k/v 存储系统
基于 Paxos 算法或者 Raft 算法

领导者选举 (Leader Election)

其它一些例子:
分布式锁 (Distributed locking)
原子广播 (Atomic broadcast)
序列号 (Sequence numbers)

我们都知道 CAP 是 Eric Brewer 提出的分布式系统三要素:
强一致性 (Consistency)
可用性 (Availability)
分区容忍性 (Partition Tolerance)

几乎所有的服务发现和注册方案都是 CP 系统,也就是说满足了在同一个数据有多个副本的情况下,对于数据的更新操作达到最终的效果和操作一份数据是一样的,但是在出现网络分区(分区间的节点无法进行网络通信)这样的故障的时候,在节点之间恢复通信并且同步数据之前,一些节点将会无法提供服务(一些系统在节点丢失的情况下支持 stale reads )。

ZooKeeper 作为这类框架中历史最悠久的之一,是由 Java 编写。Java 在许多方面非常伟大,然而对于这种类型的工作还是显得有些沉重,也正因为其复杂性和对新鲜事物的向往,我们第一时间就放弃了选择它。

本文将从协议和应用层来比较 Etcd 和 Consul,并最终给出了笔者的偏好。

Etcd

Etcd 是一个使用 go 语言写的分布式 k/v 存储系统。考虑到它是 coreos 公司的项目,以及在 GitHub 上的 star 数量 (9000+),Google 著名的容器管理工具 Kuberbetes 就是基于 Etcd 的。我们最先考虑的就是它。

在介绍 Etcd 之前,我们需要了解一些基本的概念。我们知道在单台服务器单个进程中维护一个状态是很容易的,读写的时候不会产生冲突。即便在多进程或者多线程环境中,使用锁机制或者协程(coroutine)也可以让读写有序地进行。但是在分布式系统中,情况就会复杂很多,服务器可能崩溃,节点间的机器可能网络不通等等。所以一致性协议就是用来在一个集群里的多台机器中维护一个一致的状态。

很多的分布式系统都会采用 Paxos 协议,但是 Paxos 协议难以理解,并且在实际实现中差别比较大。所以 Etcd 选择了 Raft 作为它的一致性协议。Raft 是 Diego Ongaro 和 John Ousterhout 在 ‘In Search of an Understandable Consensus Algorithm’ 中提出的。它在牺牲很少可用性,达到相似功能的情况下,对 Paxos 做了很大的优化,并且比 Paxos 简单易懂很多。

它主要集中在解决两个问题:

领导者选举(Leader Election)
Raft 先通过领导选举选出一个 Leader,后续的一致性维护都由 Leader 来完成,这就简化了一致性的问题。Raft 会保证一个时间下只会有一个 Leader,并且在超过一半节点投票的情况下才会被选为 Leader。当 Leader 挂掉的时候,新的 Leader 将会被选出来。

日志复制 (Log Replication)
为了维护状态,系统会记录下来所有的操作命令日志。Leader 在收到客户端操作命令后,会追加到日志的尾部。然后 Leader 会向集群里所有其它节点发送 AppendEntries RPC 请求,每个节点都通过两阶段提交来复制命令,这保证了大部分的节点都能完成。

在实际的应用中,一般 Etcd 集群以 5 个或者 7 个为宜,可以忍受 2 个或者 3 个节点挂掉,为什么不是越多越好呢?是出于性能的考虑,因为节点多了以后,日志的复制会导致 CPU 和网络都出现瓶颈。

Etcd 的 API 比较简单,可以对一个目录或者一个 key 进行 GET,PUT,DELETE 操作,是基于 HTTP 的。Etcd 提供 watch 某个目录或者某个 key 的功能,客户端和 Etcd 集群之间保持着长连接 (long polling)。基于这个长连接,一旦数据发生改变,客户端马上就会收到通知,并且返回的结果是改变后的值和改变前的值,这一点在实际应用中会很有用(这也是后面的 Consul 的槽点之一)。

Etcd 的 watch 和在一般情况下不会漏掉任何的变更。因为 Etcd 不仅存储了当前的键值对,还存储了最近的变更记录,所以如果一个落后于当前状态的 watch 还是可以通过遍历历史变更记录来获取到所有的更新。Etcd 还支持 CompareAndSwap 这个原子操作,首先对一个 key 进行值比较,只有结果一致才会进行下一步的赋值操作。利用这个特性就像利用 x86 的 CAS 实现锁一样可以实现分布式锁。

在 Etcd 中有个 proxy 的概念,它其实是个转发服务器,启动的时候需要指定集群的地址,然后就可以转发客户端的请求到集群,它本身不存储数据。一般来说,在每个服务节点都会启动一个 proxy,所以这个 proxy 也是一个本地 proxy,这样服务节点就不需要知道 Etcd 集群的具体地址,只需要请求本地 proxy。之前提到过一个 k/v 系统还应该支持 leader election,Etcd 可以通过 TTL (time to live) key 来实现。

Consul

Consul 和 Etcd 一样也有两种节点,一种叫 client (和 Etcd 的 proxy 一样) 只负责转发请求,另一种是 server,是真正存储和处理事务的节点。

Consul 使用基于 Serf 实现的 gossip 协议来管理从属关系,失败检测,事件广播等等。gossip 协议是一个神奇的一致性协议,之所以取名叫 gossip 是因为这个协议是模拟人类中传播谣言的行为而来。要传播谣言就要有种子节点,种子节点每秒都会随机向其它节点发送自己所拥有的节点列表,以及需要传播的消息。任何新加入的节点,就在这种传播方式下很快地被全网所知道。这个协议的神奇就在于它从设计开始就没想要信息一定要传递给所有的节点,但是随着时间的增长,在最终的某一时刻,全网会得到相同的信息。当然这个时刻可能仅仅存在于理论,永远不可达。

Consul 使用了两个不同的 gossip pool,分别叫做 LAN 和 WAN,这是因为 Consul 原生支持多数据中心。在一个数据中心内部,LAN gossip pool 包含了这个数据中心所有的节点,包括 proxy 和 servers。WAN pool 是全局唯一的,所有数据中心的 servers 都在这个 pool 中。这两个 pool 的区别就是 LAN 处理的是数据中心内部的失败检测,事件广播等等,而 WAN 关心的是跨数据中心的。除了 gossip 协议之外,Consul 还使用了 Raft 协议来进行 leader election,选出 leader 之后复制日志的过程和 Etcd 基本一致。

回到应用层面上来说,Consul 更像是一个 full stack 的解决方案,它不仅提供了一致性 k/v 存储,还封装了服务发现,健康检查,内置了 DNS server 等等。这看上去非常美好,简直可以开箱即用。于是,我们初步选定了 Consul 作为我们的服务发现和动态配置的框架。但现实往往是冰冷的,在深入研究它的 API 之后发现了比较多的坑,可能设计者有他自己的考虑。

在使用获取所有 services 的 API 的时候返回的只是所有服务的名字和 tag,如果想要每个服务的具体信息,你还需要挨个去请求。这在客户端就会十分不方便,因为在笔者看来,获取所有服务的列表以及具体信息应该是一个很常见的需求,并且请求的次数越少越好。

如果 watch 服务是否有变化,当值发生改变的时候,返回的结果居然是相当于重新读取所有 services,没有能够体现出服务信息的变化,这会导致客户端很难进行更新操作。

健康检查是 Consul 的内置功能,在注册一个服务的时候可以加上自定义的健康检查,这听上去很不错。但是如果你忘记给你某个服务加上健康检查,那它在各种 API 的返回结果中变得难以预料。

结语

在折腾了数天之后,最终我们决定回归 Etcd,事实证明这个决定是正确的。我们基于 Etcd 实现了稳定的服务发现和动态配置功能,当然还有一些比较细节的问题没有在文中阐述,欢迎一起探讨。

 

传输层安全 (TLS) 是 SSL 的继承协议。TLS 是 SSL 的升级版。其工作方式与 SSL 极为相似,都是通过加密来保护数据和信息的传输。尽管 SSL 的应用仍然非常广泛,在业内这两个术语通常可以互换使用。

 

隧道协议(Tunneling Protocol)是一类网络协议,它是一种数据包封装技术,它是将原始IP包(其报头包含原始发送者和最终目的地)封装在另一个数据包(称为封装的IP包)的数据净荷中进行传输。使用隧道的原因是在不兼容的网络上传输数据,或在不安全网络上提供一个安全路径。隧道协议通常(但并非总是)在一个比负载协议还高的层级,或同一层。

--------------------- 

备注:说白了,通过网络隧道技术,使隧道两端的网络组合成一个更大的内部网络。

 

 

 

 

终止协议意味着客户端使用期望的协议连接代理服务器,比如TLS或HTTP/2,然后代理服务器再去连接应用服务器、数据库服务器等,但不需要使用相同的协议,如下图所示。

https://box.kancloud.cn/2015-11-13_56455e89a4a1f.png

 

使用独立的服务器终止协议意味着使用多服务器架构。多服务器可能是多个物理服务器、多个虚拟服务器,或者AWS这样的云环境中的多个虚拟服务器实例。多服务器就比单服务器复杂,或者比应用服务器/数据库服务器的组合复杂。不过,多服务器架构有很多好处,而且很多流量大的网站也必须用这种架构。

配置了服务器或者虚拟服务器之后,很多事情都成为可能。新服务器可以分担其他服务器的负载,可用于负载平衡、静态文件缓存和其他用途。另外,也可以让添加和替换应用服务器或其他服务器更容易。

NGINX和NGINX Plus经常被用来终止TLS和HTTP/2协议、负载平衡。已有环境不必改动,除非要把NGINX服务器挪到前端。

 

Service 实现了基于 iptables 的分布式负载均衡

iptables 是 Linux 防火墙工作在用户空间的管理工具,是 netfilter/iptables IP 信息包过滤系统是一部分,用来设置、维护和检查 Linux 内核的 IP 数据包过滤规则。

iptables 可以检测、修改、转发、重定向和丢弃 IP 数据包。其代码已经内置于内核中,并且按照不同的目的被组织成表(table)的集合。表由一组预先定义的链 (chain) 组成,链包含遍历顺序规则。每一条规则包含条件匹配和相应的动作(称为目标),如果条件匹配为真,该动作会被执行。

 

 

 

 
谷歌计算引擎(GCE)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

 

融数数据基于Kubernetes的微服务治理和构建平台.pdf

 
 
 
 
第一代监控:Zipkin + Brave

Dapper:小型ORM之王

 

pinpoint分布式性能监控工具(docker安装)

在做性能压测的时候,你是不是有只能看到测试报告?

在做性能压测的时候,你是不是想知道每一个方法执行了多长时间?

Pinpoint几乎可以帮助你查看你想看到的每一个细节。

 

Pinpoint是什么?

Pinpoint是一款全链路分析工具,提供了无侵入式的调用链监控、方法执行详情查看、应用状态信息监控等功能。基于GoogleDapper论文进行的实现,与另一款开源的全链路分析工具Zipkin类似,但相比Zipkin提供了无侵入式、代码维度的监控等更多的特性。 Pinpoint支持的功能比较丰富,可以支持如下几种功能:

  • 服务拓扑图:对整个系统中应用的调用关系进行了可视化的展示,单击某个服务节点,可以显示该节点的详细信息,比如当前节点状态、请求数量等
  • 实时活跃线程图:监控应用内活跃线程的执行情况,对应用的线程执行性能可以有比较直观的了解
  • 请求响应散点图:以时间维度进行请求计数和响应时间的展示,拖过拖动图表可以选择对应的请求查看执行的详细情况
  • 请求调用栈查看:对分布式环境中每个请求提供了代码维度的可见性,可以在页面中查看请求针对到代码维度的执行详情,帮助查找请求的瓶颈和故障原因。
  • 应用状态、机器状态检查:通过这个功能可以查看相关应用程序的其他的一些详细信息,比如CPU使用情况,内存状态、垃圾收集状态,TPS和JVM信息等参数。

Java在1.5引入java.lang.instrument,你可以由此实现一个Java agent,通过此agent来修改类的字节码即改变一个类。

 

Pinpoint是一个分析大型分布式系统的平台,提供解决方案来处理海量跟踪数据。

 

Pinpoint, 2012年七月开始开发,在2015年1月作为一个开源项目启动, 是一个为大型分布式系统服务的n层架构跟踪平台。 Pinpoint的特点如下:

  • 分布式事务跟踪,跟踪跨分布式应用的消息
  • 自动检测应用拓扑,帮助你搞清楚应用的架构
  • 水平扩展以便支持大规模服务器集群
  • 提供代码级别的可见性以便轻松定位失败点和瓶颈
  • 使用字节码增强技术,添加新功能而无需修改代码

 

无法识别从Node1发送的第N个消息和Node2接收到的N'消息之间的关系——Google dapper实现了一个简单的解决方案来解决这个问题。这个解决方案通过在发送消息时添加应用级别的标签作为消息之间的关联。例如,在HTTP请求中的HTTP header中为消息添加一个标签信息并使用这个标签跟踪消息。

 

 

 

Pinpoint中的数据结构

Pinpoint中,核心数据结构由Span, Trace, 和 TraceId组成。

  • Span: RPC (远程过程调用/remote procedure call)跟踪的基本单元; 当一个RPC调用到达时指示工作已经处理完成并包含跟踪数据。为了确保代码级别的可见性,Span拥有带SpanEvent标签的子结构作为数据结构。每个Span包含一个TraceId。
  • Trace: 多个Span的集合; 由关联的RPC (Spans)组成. 在同一个trace中的span共享相同的TransactionId。Trace通过SpanId和ParentSpanId整理为继承树结构.
  • TraceId: 由 TransactionId, SpanId, 和 ParentSpanId 组成的key的集合. TransactionId 指明消息ID,而SpanId 和 ParentSpanId 表示RPC的父-子关系。
    • TransactionId (TxId): 在分布式系统间单个事务发送/接收的消息的ID; 必须跨整个服务器集群做到全局唯一.
    • SpanId: 当收到RPC消息时处理的工作的ID; 在RPC请求到达节点时生成。
    • ParentSpanId (pSpanId): 发起RPC调用的父span的SpanId. 如果节点是事务的起点,这里将没有父span - 对于这种情况, 使用值-1来表示这个span是事务的根span。

Google Dapper 和 NAVER Pinpoint在术语上的不同

Pinpoint中的术语"TransactionId"和google dapper中的术语"TraceId"有相同的含义。而Pinpoint中的术语"TraceId"引用到多个key的集合。



作者:小清新同学
链接:https://www.jianshu.com/p/a803571cd570
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

Dapper 和 Zipkin, Twitter的一个分布式系统跟踪平台, 生成随机TraceIds (Pinpoint是TransactionIds) 并将冲突情况视为正常。然而, 在Pinpiont中我们想避免冲突的可能,因此实现了上面描述的系统。有两种选择:一是数据量小但是冲突的可能性高,二是数据量大但是冲突的可能性低。我们选择了第二种。

 

AgentId:64位长度整型

 

可能有更好的方式来处理transaction。我们起先有一个想法,通过中央key服务器来生成key。如果实现这个模式,可能导致性能问题和网络错误。因此,大量生成key被考虑作为备选。后面这个方法可能被开发。现在采用简单方法。在pinpoint中,TransactionId被当成可变数据来对待。

 

 

使用字节码增强技术,我们就不必担心暴露跟踪API而可以持续改进设计,不用考虑依赖关系。

——就是可以瞎JB变了撒

 

 

针对 PinPoint 的扩展和改造:

- 通信机制异步化调整;

- 探针引导程序 premain 改造;

- gRPC 探针;

 

 

DDD领域驱动/CQRS读写分离/ES事件溯源 这些前沿的时髦的技术理念汇聚在一次,落地到一套完整实现方案。这就是Axon

 

Command执行过程:

  • Command通过org.axonframework.commandhandling.CommandBus分发,其中DistributedCommandBus实现了分布式的派发,它可以适配SpringCloud. 主要逻辑是通过
    AggregateIdentifier做一致性HASH。确保次对同一个聚合根发到同一台机器,这样保证了缓存的命中。Aggregate本质上在应用内缓存了当前状态,如果该服务宕机。另一台机器会通过事件溯源重新构造出当前状态。
  • Command的事务处理:Axon通过UnitofWork控制一致性,其中嵌入了JDBC事务。并且在回滚时会清除Aggregate缓存,下次会重新加载。
  • 当然对于远程的子事务无法保证一致性。这是个大的隐患

Saga最终一致性,补偿机制。

  • Saga的理念没问题,当是实现起来问题很大。
  • 一个是每个command都要创建event非常繁琐,并且saga来来回回非常多
  • 另一个是没有考虑到幂等,本地宕机,状态,分布事务等细节的处理。自己实现也不灵活
  • 确保分布式事务一致性是个非常繁琐的事情,请参考转账交易这件小事,是如何被程序员玩坏的.

说说其他实现困难的情况

  • 如果Aggregate存在继承关系,或者实现一些通用的行为接口。框架并不支持
  • 无法实现延迟触发的功能
  • 对大量聚合实现批量操作不太容易
  • 几乎所有的操作都要靠command触发,然后转成event,非常繁琐。

取其思想,寻找替代

在交易中的订单模型,本质上就是ES中的Event. 账户余额是用订单累加出来的。只不过订单不止记录事件。还用来记录更新审核状态,系统状态,事务状态等,不那么纯粹。通过订单回溯账户状态是个人工过程而不是自动的。

  • 在这方面,Axon对事件的存储采用统一的表,事件序列化到表中,并不有利于数据库的查看。需要额外的记录一个查询视图
  • 快照模型也在交易对账中有所体现。每日对账后生成当日的一个快照,第二天的交易从快照开始累计

Command模型配合只insert没有update的操作,可以在高并发下实现无锁处理。这个可以通过Kafka。或者数据库先插入,后异步读取处理的方式来实现。

充血模型是Axon的一个特色。不过并不难实现。通过自定义一个SpringCloud LoadBalancer Rule 实现哈希一致也可以实现。另外传统的失血模型使用无状态服务更简单,它可以在数据库层面通过一致性hash来存储数据,比如mongodb。对于订单这样的单一记录低频操作完全可以处理。对于同一记录的高频处理Axon也是有其优势的,不过Akka可能也是不错的选择

Saga异常难写,在网络异常,幂等,重试方面并不友好

总结:DDD领域驱动/CQRS读写分离/ES事件溯源,这些思想都很棒,但是并不用拘泥于特定的实现。Axon对于学习这些概念具有非常大的帮助,但是在实践的过程中并不高效、灵活



作者:黄大海
链接:https://www.jianshu.com/p/4a7854e4b8f2
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

 

Reveno是一个全新的无锁事务处理框架,它支持JVM平台,并基于CQRS及事件溯源模式实现。虽然它只是一个简单而强大的工具,但在性能方面也毫不逊色。所有事务都被持久化为只读的日志,并且可以通过按顺序重演事件的方式恢复领域模型的最新状态。所有的运行时操作都是在内存中执行的,从而使其吞吐量可达到每秒种几百万次事务的数量级,平均延迟时间则限制在微秒级。虽然Reveno的功能如此强大,但它仍然是一个通用目的的框架,涵盖了大量不同种类的用例,并提供了丰富的引擎配置选项。举例来说,你可以调整它的持久性配置,在极其随意(为了提高系统吞吐量)与高度受限(对于数据丢失的情况具有较低的容忍度)之间进行选择。

对于不同的用例来说,其需求也是千差万别的。作为一个通用框架,它需要考虑所有不同的可能性。在本文中,我将通过示例为读者展现如何使用Reveno框架开发一个简单的交易系统。

首先让我们来了解一下Reveno如何处理你的领域模型。作为一个基于CQRS的框架,Reveno会将你的领域切分为 事务模型与查询模型 。对这两个模型的定义没有任何限制,你无需使用任何强制性的注解、基类,甚至不需要实现Serializable接口,只需使用最简单的POJO就可以完成任务。

没有任何一种单一的途径能够应对所有不同的用例,因此应用程序的设计者需要决定如何处理事务模型的回滚操作。Reveno为实现模型对象提供了两种主要方式:可变与不可变模型。这两种方式各有不同的底层处理机制,并且各有其优缺点。在Java中,不可变对象的开销很低,并且无需进行同步操作,这种方式目前 非常流行 。Reveno能够非常高效地处理不可变对象,但每种使用不可变类型的领域都会产生额外的垃圾对象,Reveno也不例外。因此,如果你能够接受一些额外的GC开销,那么就应当将这种方式作为默认的选择。反之,如果使用可变模型,那么在进行事务运行时,就要为已使用的对象生成额外的序列化快照,而这将影响到你的性能。幸运的是,如果你坚持使用可变模型,并且仍需要保证性能的最大化及GC影响的最小化,那么你可以选择一种额外的可变模型特性,“补偿行为”(Compensating Actions)。简单来说,补偿行为是指在实现常规的事务处理函数时,一并实现的一种手动回滚行为。如果读者想了解这方面的更多细节,请参考 Reveno的官方文档页面 。

 
 
 
 
 
 
 

 

 


Kubernetes 的核心概念讲解

入门Kubernetes 是非常困难的,因为这会涉及到许多的概念和新理念,本文以图文并茂的形式总结了Kubernetes 中的核心概念。

 

它本不必如此困难?

掌握Kubernetes 是非常困难的,因为互联网上有如此多的信息,有时候很难找到理解Kubernetes 核心信息,当我们看到 kubernetes.io 站点上概念页面和文档如此密集时更会如此。在本文中,我们将会探索Kubernetes 的核心概念,以便于获取关于它的基础知识,这样我们就可以一起揭开Kubernetes 的神秘面纱。 

什么是Kubernetes

Kubernetes 提供了基础设置和构造,帮助我们的团队构建适用于开发和部署的可用平台。用户可以通过图形化的用户界面以及命令式和声明式命令行接口管理Kubernetes 集群,Kubernetes 旨在管理容器化应用程序和服务的整个生命周期。

借助Kubernetes,我们可以扩展和收缩应用程序、执行滚动部署并管理由哪些服务处理特定的请求。它还提供了一个可扩展的开发框架,允许我们的团队扩展核心的Kubernetes 原语(primitive)以满足个性化的需求。同时,它还支持创建自己的概念。

但是,与大多数框架一样,它的缺点之一是缺少许多现成的功能,无法被视为交钥匙(turn-key)解决方案。在标准发行版中,它不包含服务如何相互通信的方法(甚至不包含网络组件!),因此存在其他的发行版,另外我们也可以构建自己的版本。

容器

容器是独立、可执行的软件,它包含了运行所需的所有内容,比如代码、库和所有的外部依赖。它会确保运行的内容是完全相同的,即便是位于不同的环境中也是如此。这是通过将要运行的代码与它的运行上下文隔离开实现的。

Linux 中,这是通过使用名为cgroups API 来分割Linux 内核的一个子集来实现的。这种方式提供了与操作系统的高度隔离,但不会带来像虚拟化环境(如VMWareKVM 等)那样的性能损耗。

 

Pod

pod Kubernetes 中最基本的对象。

pod 是容器的集合,它们共享存储和网络,并且具备如何运行它们的规范。每个pod 会分配自己的IP 地址。pod 中的容器会共享这个IP 地址、端口空间,并且能够使用localhost 实现彼此查找。

pod 应该被视为短暂存活的原子单元。

 

Replicaset

根据给定的模板,replicaset 可以运行pod

replicaset 并不会直接使用,但是需要理解这种资源,因为在Kubernetes 构建应用的时候,它是基础的构建块。

(按照指令)replicaset 可以按需扩展和收缩pod 的数量。

 

Service

因为pod 是短期存活的(replicaset 通过扩展和收缩pod 的数量实现这一点),那么这就带来了一个问题,现在,除非使用非常复杂的逻辑,否则我们几乎不可能引用单个pod 以便于跟踪拓扑结构的变化。

Service 通过在pod 之上提供抽象来解决这个问题,它提供了一个可寻址的方法来与pod 进行通信

Service 操作的是OSI 模型之中的IP 之上的TCP/UDP)。

 

Deployment

Deployment 管理replicaset,可以在应用的不同版本间执行滚动更新。

这是最常用的资源类型,它通过一个接口提供了对replicaset pod 的抽象。

 

在更新Deployment 的时候,换句话说,也就是部署应用的新版本,Deployment 控制器会创建一个新的replicaset,并管理新版本替换旧版本的滚动更新。

 

Kubernetes 1.11 版本中,Deployment 目前不会自动处理回滚。

ConfigMap

设计良好的应用应该遵循十二要素应用宣言,应用的配置应该保存到环境中。尽管现在通用的安全实践指出,在环境中存储配置可能会导致私密的意外泄漏,因为一些应用程序在失败时会暴露了它们的环境信息,但是无论如何,如果配置随环境(开发、staging、生产)而变化的话,那么就应该将它们与要构建的应用分开进行存储。

ConfigMaps 允许将配置文件作为环境变量或文件系统挂载到Pod ,从而解决了这个问题。

 

Secret

Secret ConfigMap 非常类似,顾名思义,它们对应的是“Secret”信息。

 

Daemonset

Daemonset 会确保所有的节点都运行特定的Pod。如果要在所有节点上运行像日志代理(如fluentd这样的内容的话,这是非常有用的。

 

它还能够通过使用Taints 忽略特定的节点。

Kubernetes之Taints与Tolerations 污点和容忍

作者:Flywithmeto 2018-04-10 来源:51CTO

        NodeAffinity节点亲和性,是Pod上定义的一种属性,使Pod能够按我们的要求调度到某个Node上,而Taints则恰恰相反,它可以让Node拒绝运行Pod,甚至驱逐Pod。

        Taints(污点)是Node的一个属性,设置了Taints(污点)后,因为有了污点,所以Kubernetes是不会将Pod调度到这个Node上的,

       于是Kubernetes就给Pod设置了个属性Tolerations(容忍),只要Pod能够容忍Node上的污点,那么Kubernetes就会忽略Node上的污点,就能够(不是必须)把Pod调度过去。

        因此 Taints(污点)通常与Tolerations(容忍)配合使用。

 

Ingress

在大多数情况下,Service Pod IP 地址只能在Kubernetes 集群中进行访问。Service 是与互联网流量隔离的。

“Ingress 是一组规则集合,它允许入站的连接访问集群Service

它可以用于负载平衡、终止TLS、为外部提供可路由的URL 等等。Ingress 只是另外一种Kubernetes 资源,但是,在大多数情况下需要有一个Ingress 控制器,如Nginx Træfik 等。

Kubernetes 是一个自动化容器编排平台,能够允许应用程序在大型平台上大规模运行,这些平台可以包含不同处理器体系结构和操作系统的组合,这完全由实现者决定。

借助这些核心概念,Kubernetes 可以Pod 安排到适当的节点上,以确保Pod 的最大密度,这会由Kubernetes 实现的多种算法来控制,比如Bin Packing,从而实现更高的硬件利用率

参考资料:

[1] https://medium.com/google-cloud/kubernetes-configmaps-and-secrets-68d061f7ab5b

[2] https://medium.com/google-cloud/kubernetes-configmaps-and-secrets-part-2-3dc37111f0dc

[3] https://kubernetes.io/docs/concepts/configuration/secret/

[4] https://kubernetes.io/docs/tasks/administer-cluster/encrypt-data/

本文最初发表于 云原生计算基金会 官方博客,由InfoQ 中文站翻译分享。


Kubernetes GitBook

 

https://kubernetes.feisky.xyz/he-xin-yuan-li/architecture

 

Kubernetes 提供了两种探针(Probe,支持 exec、tcp 和http 方式)来探测容器的状态:

Kubelet使用liveness probe(存活探针)来确定何时重启容器。例如,当应用程序处于运行状态但无法做进一步操作,liveness探针将捕获到deadlock,重启处于该状态下的容器,使应用程序在存在bug的情况下依然能够继续运行下去(谁的程序还没几个bug呢)。

Kubelet使用readiness probe(就绪探针)来确定容器是否已经就绪可以接受流量。只有当Pod中的容器都处于就绪状态时kubelet才会认定该Pod处于就绪状态。该信号的作用是控制哪些Pod应该作为service的后端。如果Pod处于非就绪状态,那么它们将会被从service的load balancer中移除。

 

一个 Kubernetes 集群由分布式存储  etcd、控制节点 controller 以及服务节点 Node 组成。

 

Play-with-k8s 提供了一个免费的k8s 体验环境

K8s playground

 

K8s 借鉴了 Borg -> Omega 的设计理念(谷歌),比如 Pod、Service、Labels 和 单 Pod 单IP等。

容器的资源隔离特性使得谷歌的资源使用率远远高出业界同行。例如,Borg使用容器将对延迟敏感、面向用户的任务和批量任务放在相通的物理机上,并会为它们预留更多的资源,这样可以解决load spikes、fail-over等问题。容器提供的资源管理工具使这些得以实现,稳定的内核层面的资源隔离也使进程之间不互相干扰。我们通过在研发Borg的同时加强Linux容器的方式来获得成功。然而,隔离并不是完美的,容器在内核操作系统不能管理的资源隔离方面鞭长莫及,比如level 3 processor caches、内存带宽、以及容器需要被一个额外的安全层支持以抵抗云端的各种恶意攻击。
 

Kubernetes 主要由以下几个核心组件组成:

  • etcd 保存了整个集群的状态;

  • kube-apiserver 提供了资源操作的唯一入口,并提供认证、授权、访问控制、API 注册和发现等机制;

  • kube-controller-manager 负责维护集群的状态,比如故障检测、自动扩展、滚动更新等;

  • kube-scheduler 负责资源的调度,按照预定的调度策略将 Pod 调度到相应的机器上;

  • kubelet 负责维持容器的生命周期,同时也负责 Volume(CVI)和网络(CNI)的管理;

  • Container runtime 负责镜像管理以及 Pod 和容器的真正运行(CRI),默认的容器运行时为 Docker;

  • kube-proxy 负责为 Service 提供 cluster 内部的服务发现和负载均衡;

除了核心组件,还有一些推荐的 Add-ons:

  • kube-dns 负责为整个集群提供 DNS 服务

  • Ingress Controller 为服务提供外网入口

  • Heapster 提供资源监控

  • Dashboard 提供 GUI

  • Federation 提供跨可用区的集群

  • Fluentd-elasticsearch 提供集群日志采集、存储与查询

分层架构:

Kubernetes 设计理念和功能其实就是一个类似 Linux 的分层架构,如下图所示

 

  • 核心层:Kubernetes 最核心的功能,对外提供 API 构建高层的应用,对内提供插件式应用执行环境

  • 应用层:部署(无状态应用、有状态应用、批处理任务、集群应用等)和路由(服务发现、DNS 解析等)

  • 管理层:系统度量(如基础设施、容器和网络的度量),自动化(如自动扩展、动态 Provision 等)以及策略管理(RBAC、Quota、PSP、NetworkPolicy 等)

  • ——(k8s实践利用storageclass实现pvc的动态provision(volume使用ceph rbd))

  • ——存储(Storage)是运行有状态容器的关键要素,Kubernetes提供了强大的原语来管理存储。动态卷配置(Dynamic provisioning)是Kubernetes的独有功能,它可以根据需要动态的创建存储卷。在动态配置之前,集群管理员必须手动调用云/存储服务提供商的接口来配置新的存储卷,然后创建PersistentVolume对象以在Kubernetes中表示和使用他们。通过动态配置,可以实现两个步骤的自动化,无须集群管理员预先配置存储资源,而是使用StorageClass对象制定的供应商来动态配置存储资源,具体请参考用户指南)。StorageClass本质上是为底层存储提供者描绘了蓝图,以及各种参数,例如磁盘类型(例如固态和标准磁盘)。

    ——Quota

    Resource Quotas

    资源配额(Resource Quotas)是用来限制用户资源用量的一种机制。

    它的工作原理为

    资源配额应用在 Namespace 上,并且每个 Namespace 最多只能有一个 ResourceQuota 对象 开启计算资源配额后,创建容器时必须配置计算资源请求或限制(也可以用 LimitRange 设置默认值) 用户超额后禁止创建新的资源

    开启资源配额功能

    首先,在 API Server 启动时配置准入控制 --admission-control=ResourceQuota 然后,在 namespace 中创建一个 ResourceQuota 对象

    资源配额的类型

    计算资源,包括 cpu 和 memory
    • cpu, limits.cpu, requests.cpu
    • memory, limits.memory, requests.memory
    存储资源,包括存储资源的总量以及指定 storage class 的总量
    • requests.storage:存储资源总量,如 500Gi
    • persistentvolumeclaims:pvc 的个数
    • .storageclass.storage.k8s.io/requests.storage
    • .storageclass.storage.k8s.io/persistentvolumeclaims
    • requests.ephemeral-storage 和 limits.ephemeral-storage (需要 v1.8+)
    对象数,即可创建的对象的个数
    • pods, replicationcontrollers, configmaps, secrets
    • resourcequotas, persistentvolumeclaims
    • services, services.loadbalancers, services.nodeports

    ——PSP:Pod安全策略;

  • ——

  • 接口层:kubectl 命令行工具、客户端 SDK 以及集群联邦

  • 生态系统:在接口层之上的庞大容器集群管理调度的生态系统,可以划分为两个范畴

    • Kubernetes 外部:日志、监控、配置管理、CI、CD、Workflow、FaaS、OTS 应用、ChatOps 等

    • Kubernetes 内部:CRI、CNI、CVI、镜像仓库、Cloud Provider、集群自身的配置和管理等

    • ——OTS:off the shell?

    • —— 

  •  

  • 核心组件:

核心API:

 

生态系统:


Etcd 是 CoreOS 基于 Raft 开发的分布式 key-value 存储,可用于服务发现、共享配置以及一致性保障(如数据库选主、分布式锁等)。

 

DaemonSet 保证在每个 Node 上都运行一个容器副本,常用来部署一些集群的日志、监控或者其他系统管理应用。典型的应用包括:

  • 日志收集,比如 fluentd,logstash 等

  • 系统监控,比如 Prometheus Node Exporter,collectd,New Relic agent,Ganglia gmond 等

  • 系统程序,比如 kube-proxy, kube-dns, glusterd, ceph 等

 

PersistentVolume (PV) 和 PersistentVolumeClaim (PVC) 提供了方便的持久化卷:PV 提供网络存储资源,而 PVC 请求存储资源。这样,设置持久化的工作流包括配置底层文件系统或者云数据卷、创建持久性数据卷、最后创建 PVC 来将 Pod 跟数据卷关联起来。PV 和 PVC 可以将 pod 和数据卷解耦,pod 不需要知道确切的文件系统或者支持它的持久化引擎。

 

Kubernetes 在设计之初就充分考虑了针对容器的服务发现与负载均衡机制,提供了 Service 资源,并通过 kube-proxy 配合 cloud provider 来适应不同的应用场景。随着 kubernetes 用户的激增,用户场景的不断丰富,又产生了一些新的负载均衡机制。目前,kubernetes 中的负载均衡大致可以分为以下几种机制,每种机制都有其特定的应用场景:

  • Service:直接用 Service 提供 cluster 内部的负载均衡,并借助 cloud provider 提供的 LB 提供外部访问

  • Ingress Controller:还是用 Service 提供 cluster 内部的负载均衡,但是通过自定义 Ingress Controller 提供外部访问

  • Service Load Balancer:把 load balancer 直接跑在容器中,实现 Bare Metal 的 Service Load Balancer

  • Custom Load Balancer:自定义负载均衡,并替代 kube-proxy,一般在物理部署 Kubernetes 时使用,方便接入公司已有的外部服务

 

网络插件:

https://kubernetes.feisky.xyz/cha-jian-kuo-zhan/network

  •  

 

Cilium是一个基于 eBPF 和 XDP 的高性能容器网络方案,提供了 CNI 和 CNM 插件。

 

 

Frakti是一个基于Kubelet CRI的运行时,它提供了hypervisor级别的隔离性,特别适用于运行不可信应用以及多租户场景下。Frakti实现了一个混合运行时:

  • 特权容器以Docker container的方式运行

  • 而普通容器则以hyper container的方法运行在VM内

 

 

服务治理:
 

一般准则

  • 分离构建和运行环境

  • 使用dumb-int等避免僵尸进程

  • 不推荐直接使用Pod,而是推荐使用Deployment/DaemonSet等

  • 不推荐在容器中使用后台进程,而是推荐将进程前台运行,并使用探针保证服务确实在运行中

  • 推荐容器中应用日志打到stdout和stderr,方便日志插件的处理

  • 由于容器采用了COW,大量数据写入有可能会有性能问题,推荐将数据写入到Volume中

  • 不推荐生产环境镜像使用latest标签,但开发环境推荐使用并设置imagePullPolicyAlways

  • 推荐使用Readiness探针检测服务是否真正运行起来了

  • 使用activeDeadlineSeconds避免快速失败的Job无限重启

  • 引入Sidecar处理代理、请求速率控制和连接控制等问题

 

分离构建和运行环境

注意分离构建和运行环境,直接通过Dockerfile构建的镜像不仅体积大,包含了很多运行时不必要的包,并且还容易引入安全隐患,如包含了应用的源代码。

可以使用Docker多阶段构建来简化这个步骤。

 

 COW:copy on write 技术 https://juejin.im/post/5bd96bcaf265da396b72f855

写入时复制(英语:Copy-on-write,简称COW)是一种计算机程序设计领域的优化策略。其核心思想是,如果有多个调用者(callers)同时请求相同资源(如内存或磁盘上的数据存储),他们会共同获取相同的指针指向相同的资源,直到某个调用者试图修改资源的内容时,系统才会真正复制一份专用副本(private copy)给该调用者,而其他调用者所见到的最初的资源仍然保持不变。这过程对其他的调用者都是透明的(transparently)。此作法主要的优点是如果调用者没有修改该资源,就不会有副本(private copy)被建立,因此多个调用者只是读取操作时可以共享同一份资源。

 

 

 

 

Istio:

Istio 提供了强大的流量管理功能,如智能路由、服务发现与负载均衡、故障恢复、故障注入等。

流量管理的功能由 Pilot 配合 Envoy 负责,并接管进入和离开容器的所有流量:

  • 流量管理的核心组件是 Pilot,负责管理和配置服务网格中的所有 Envoy 实例

  • 而 Envoy 实例则负责维护负载均衡以及健康检查信息,从而允许其在目标实例之间智能分配流量,同时遵循其指定的路由规则

 

Istio 提供了 RBAC 访问控制、双向 TLS 认证以及密钥管理等安全管理功能。

 

Mixer 为应用程序和基础架构后端之间提供了一个通用的策略控制层,负责先决条件检查(如认证授权)、配额管理并从 Envoy 代理中收集遥测数据等。

Mixer 是高度模块化和可扩展的组件。他的一个关键功能就是把不同后端的策略和遥测收集系统的细节抽象出来,使得 Istio 的其余部分对这些后端不知情。Mixer 处理不同基础设施后端的灵活性是通过使用通用插件模型实现的。每个插件都被称为 Adapter,Mixer通过它们与不同的基础设施后端连接,这些后端可提供核心功能,例如日志、监控、配额、ACL 检查等。通过配置能够决定在运行时使用的确切的适配器套件,并且可以轻松扩展到新的或定制的基础设施后端。

-> 类似 AOP的概念?

 

度量管理:

新增指标

Istio 支持 自定义指标、日志以及 TCP 指标。可以通过指标配置来新增这些度量,每个配置包括三方面的内容:

  1. 从 Istio 属性中生成度量实例,如logentry 、metrics 等。

  2. 创建处理器(适配 Mixer),用来处理生成的度量实例,如 prometheus。

  3. 根据一系列的股则,把度量实例传递给处理器,即创建 rule。

什么是Prometheus?

Prometheus是由SoundCloud开发的开源监控报警系统和时序列数据库(TSDB)。Prometheus使用Go语言开发,是Google BorgMon监控系统的开源版本。
2016年由Google发起Linux基金会旗下的原生云基金会(Cloud Native Computing Foundation), 将Prometheus纳入其下第二大开源项目。
Prometheus目前在开源社区相当活跃。
Prometheus和Heapster(Heapster是K8S的一个子项目,用于获取集群的性能数据。)相比功能更完善、更全面。Prometheus性能也足够支撑上万台规模的集群。

Prometheus的特点

  • 多维度数据模型。
  • 灵活的查询语言。
  • 不依赖分布式存储,单个服务器节点是自主的。
  • 通过基于HTTP的pull方式采集时序数据。
  • 可以通过中间网关进行时序列数据推送。
  • 通过服务发现或者静态配置来发现目标服务对象。
  • 支持多种多样的图表和界面展示,比如Grafana等。

官网地址:https://prometheus.io/

Serverless

即无服务器架构,将大家从服务器中解放了出来,只需要关注业务逻辑本身。用户只需要关注数据和业务逻辑,无需维护服务器,也不需要关心系统的容量和扩容。Serverless 本质上是一种更简单易用的 PaaS,包含两种含义:

仅依赖云端服务来管理业务逻辑和状态的应用或服务,一般称为 BaaS (Backend as a Service) 事件驱动且短时执行应用或服务,其主要逻辑由开发者完成,但由第三方管理(比如 AWS Lambda),一般称为 FaaS (Function as a Service)。目前大火的 Serverless 一般是指 FaaS。

引入 serverless 可以给应用开发者带来明显的好处

  • 用户无需配置和管理服务器

  • 用户服务不需要基于特定框架或软件库

  • 部署简单,只需要将代码上传到 serverless 平台即可

  • 完全自动化的横向扩展

  • 事件触发,比如 http 请求触发、文件更新触发、时间触发、消息触发等

  • 低成本,比如 AWS Lambda 按执行时间和触发次数收费,在代码未运行时无需付费

当然,serverless 也并非银弹,也有其特有的局限性

  • 无状态,服务的任何进程内或主机状态均无法被后续调用所使用,需要借助外部数据库或网络存储管理状态

  • 每次函数调用的时间一般都有限制,比如 AWS Lambda 限制每个函数最长只能运行 5 分钟

  • 启动延迟,特别是应用不活跃或者突发流量的情况下延迟尤为明显

  • 平台依赖,比如服务发现、监控、调试、API Gateway 等都依赖于 serverless 平台提供的功能

 

《Kubernetes 权威指南》

难得一见的好书

 

TBD

 

 

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐