架构设计是一系列相关的抽象模式,是人们对一个结构内的元素及元素间关系的一种主观映射的产物。
一、计算机网络基础
OSI
Open System Interconnection,简称OSI模型或七层模型。
开放系统互连参考模型,是国际标准化组织(ISO)和国际电报电话咨询委员会(CCITT)联合制定的开放系统互连参考模型,为开放式互连信息系统提供了一种功能结构的框架。
OSI模型从低到高分别是:(1)物理层 (2)数据链路层 (3)网络层 (4)传输层 (5)会话层 (6)表示层 (7)应用层
1. 物理层
建立、维护、断开物理连接。
由底层网络定义协议。
2. 数据链路层
建立逻辑连接、进行硬件地址寻址、差错校验等功能。
将比特组合成字节进而组合成帧,用MAC地址访问介质,错误发现但不能纠正。
由底层网络定义协议。
3. 网络层
进行逻辑地址寻址,实现不同网络之间的路径选择。
主要协议有:ICMP / IGMP / IP(IPV4, IPV6)。
ICMP
Internet Control Message Protocol,Internet控制报文协议,面向无连接的协议。
用于在IP主机、路由器之间传递控制信息(控制信息是指网络通不通、主机是否可达、路由是否可用等网络本身的消息)。
IGMP
Internet Group Management Protocol,互联网组管理协议。
是TCP/IP协议族中负责IP组播成员管理的协议。
用来在IP主机和与其直接相邻的组播路由器之间建立、维护组播组成员关系。
IP
Internet Protocol,网际互连协议,根据端到端的设计原则。
IP只为主机提供一种无连接的、不可靠的、尽力而为的数据报传输服务。
4. 传输层
定义传输数据的协议端口号,以及流控和差错校验。
主要协议有:TCP / UDP。
TCP
Transmission Control Protocol,传输控制协议。
是一种面向连接的、可靠的、基于字节流的传输层通信协议。
UDP
User Datagram Protocol,用户数据报协议。
是一种无序建立连接就可以发送封装的IP数据包的方法。
5. 会话层
建立、管理、终止会话。
对应主机进程,指本地主机与远程主机正在进行的会话。
6. 表示层
数据的表示、安全、压缩。
主要格式有:JPEG / ASCII / EBCDIC / 加密格式。
JPEG
Joint Photographic Experts Group,联合图像专家组。
是用于连续色调静态图像压缩的一种标准,文件后缀名为 .jpg 或 .jpeg。
ASCII
American Standard Code for Information Interchange,美国信息交换标准代码。
是基于拉丁字母的一套电脑编码系统,主要用于显示现代英语和其它西欧语言。
7. 应用层
网络服务与最终用户的一个接口
主要协议有:HTTP / FTP / TFTP / SMTP / SNMP / DNS / TELNET / HTTPS / POP3 / DHCP。
HTTP
HyperText Transfer Protocol,超文本传输协议,是因特网上应用最广泛的一种网络传输协议。
所有的WWW文件都必须遵守这个标准。
HTTP是一个基于TCP/IP通信协议来传递数据(HTML文件、图片文件、查询结果等)。
HTTP工作原理:
HTTP协议工作于 客户端~服务端 架构上,浏览器作为HTTP客户端通过URL向HTTP服务端(即WEB服务器)发送请求。
WEB服务器根据接收到请求后,向客户端发送响应信息。
HTTP默认端口号为80,但是也可以改为8080或者其它端口。
FTP
File Transfer Protocol,文件传输协议,是TCP/IP协议族中的协议之一。
FTP协议包括两个组成部分,(1)FTP服务器 (2)FTP客户端。
其中FTP服务器用来存储文件。
用户可以使用FTP客户端通过FTP协议访问位于FTP服务器上的资源。
TFTP
Trivial File Transfer Protocol,简单文件传输协议。
是TCP/IP协议族中的一个用来在客户机与服务器之间进行简单文件传输的协议。
提供不复杂、开销不大的文件传输服务,端口号为69。
SMTP
Simple Mail Transfer Protocol,简单邮件传输协议,是一种提供可靠且有效的电子邮件传输的协议。
SNMP
简单网络管理协议,是专门设计用于在IP网络管理网络节点(服务器、工作站、路由器、交换机等)。
DNS
Domain Name System,域名系统(服务)协议,是一种分布式网络目录服务。
主要用于域名与IP地址的相互转换,以及控制因特网的电子邮件的发生。
TELNET
Telnet协议是TCP/IP协议族中的一员,是Internet远程登录服务的标准协议和主要方式。
它为用户提供了在本地计算机上完成远程主机工作的能力。
HTTPS
Hyper Text Transfer Protocol over SecureSocket Layer,超文本传输安全协议。
是在HTTP的基础上通过传输加密和身份认证保证了传输过程的安全性。
它被广泛用于万维网上安全敏感的通讯(例如:交易支付等)。
POP3
Post Office Protocol – Version 3,邮局协议版本3,是TCP/IP协议族中的一员。
主要用于支持使用客户端远程管理在服务器上的电子邮件。
DHCP
Dynamic Host Configuration Protocol,动态主机配置协议,是一个局域网的网络协议。
指的是由服务器控制一段IP地址范围。
客户机登录服务器时就可以自动获得服务器分配的IP地址和子网掩码。
B. TCP / IP 模型
TCP/IP 是一个四层协议系统。
TCP/IP模型从低到高分别是:(1)数据链路层 (2)网络层 (3)传输层 (4)应用层。
1. 数据链路层
对应OSI模型的物理层与数据链路层。
数据链路层实现了网卡接口的网络驱动程序,以处理数据在物理媒介上的传输。
主要协议有:ARP / RARP。
ARP/RARP主要实现IP地址和机器物理地址(通常是MAC地址)之间的相互转换。
ARP
Address Resolve Protocol,地址解析协议,是根据IP地址获取物理地址的一个TCP/IP协议。
RARP
ReverseAddress Resolve Protocol,反地址解析协议。
允许局域网的物理机器从网关服务器的ARP表或者缓存上请求其IP地址。
2. 网络层
对应OSI模型的网路层。
网络层实现数据包的选路和转发。
网络层的任务就是选择路由器,以确定两台主机之间的通信路径。
网路层最核心的协议是IP协议。
3. 传输层
对应OSI模型的传输层。
传输层为两台主机上的应用程序提供端到端(end to end)的通信。
传输层只关心通信的起始端和目的端,而不在乎数据包的中转过程。
主要协议有:TCP / UDP。
4. 应用层
对应OSI模型的会话层、表示层、应用层。
应用层负责处理应用程序的逻辑。
1. 局域网(Local Area Network(LAN))
局域网是指在某一区域内由多台计算机互联组成的计算机组。
局域网可以由一个办公室的两台计算机组成,也可以由一个公司内的几千台计算机组成。
局域网可以实现文件管理、应用软件共享、打印机共享、电子邮件、传真等功能。
2. 路由器(Router)
是连接两个或多个网络的硬件设备,在网络间起网关的作用。
路由器读取每一个数据包中的地址然后决定如何传送的专用智能型的网络设备。
路由器会根据信道的情况自动选择和设定路由、以最佳路径、按前后顺序发送信号。
3. 广播
主机之间“一对所有”的通讯模式。
网络对其中每一台主机发出的信号都进行无条件复制并转发,所有主机都可以接收到所有信息(无论是否需要)。
例:有限电视网就是典型的广播型网络。
4. mac地址
指网卡的地址,每块网卡出厂时都被烧制上一个世界唯一的mac地址,长度为48位的二进制。
通常由12位16进制数表示(前6位是厂商编号,后6位是流水线号)。
5. IP地址 与 IP协议
规定网络地址的协议叫IP协议。
IP协议的作用主要有两个,一个是为每台计算机分配IP地址,另一个是确定哪些地址在同一个子网络。
IP协议定义的地址称之为IP地址,广泛采用的是ipv4,由32位二进制表示。范围0.0.0.0 ~ 255.255.255.255。
6. 端口
一台拥有IP地址的主机所对应的不同服务。
通过不同的IP地址可以获取不同主机,通过“IP地址 + 端口号”来区分不同的服务。
例:WEB服务、FTP服务、SMTP服务,这些服务可以由一个IP地址来实现,但不同的服务则对应不同的端口。
7. 子网掩码
表示子网络特征的一个参数。
子网掩码不能单独存在,它必须结合IP地址一起使用。
子网掩码只有一个作用,就是将某个IP地址划分成网络地址和主机地址两部分。
A. 分布式系统
系统中的多个模块在不同服务器上的部署。
一组独立的计算机展现给用户的是一个统一的整体。
例:Tomcat与数据库分布部署在不同的服务器上。
B. 系统集群
一个特定领域的软件部署在多台服务器上并作为一个整体提供一类服务。
在集群中,多台服务器内容、工作过程等完全一样,客户端可以连接任意一个节点获得服务。
并且当集群中一个节点掉线时,其它节点可以自动的接替它继续提供服务。
C. 系统高可用性
通常来描述一个系统经过特殊的设计,从而减少停工时间,而保持其服务的高度可用性。
系统中部分服务器掉线时,其它服务器能够接替它继续提供服务,则可认为系统具有高可用性。
D. 负载均衡
将负载(工作任务)进行平衡、分摊到多个操作单元上进行运行。
当客户端请求发送到系统时,通过某种算法把请求分发到多个可用的服务器上。
使系统中每个服务器都能够均匀的处理请求。
E. 代理
当客户端无法直接跟服务端发起请求的时候,就需要代理服务。代理分为:(1)正向代理 (2)反向代理
1. 正向代理
正向代理 是一台 位于客户端和目标服务器之间的 代理服务器。
当客户端需要获取目标服务器中的数据时、先向代理服务器发送请求并指定目标服务器。
由代理服务器向目标服务器发送请求获取数据、并将获取到的数据返回给客户端。
正向代理的作用
访问客户端不能访问的资源。
对客户端访问进行授权、认证。
可以做缓存,加速访问资源。
记录用户访问记录,对外隐藏用户信息。
2. 反向代理
反向代理 也是一台位于客户端和服务器之间的代理服务器。
但是客户端并不知道目标服务器,当客户端需要获取目标服务器中的数据时、先向代理服务器发送请求。
由代理服务器将请求转发给内部网络上的服务器,并将从目标服务器上获取到的数据返回给客户端。
反向代理的作用
保证内网的安全,阻止web攻击。
负载均衡,通过反向代理服务器优化网站的负载。
A. Tomcat
是一个免费的开源代码的web应用服务器,属于轻量级应用服务器。
在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP程序的首选。
B. Nginx
engine x,是一款自由的、开源的、高性能的HTTP和反向代理web服务器。
同时也提供了IMAP/POP3/SMTP服务。
C. LVS
Linux Virtual Server,即Linux虚拟服务器,是一个虚拟的服务器集群系统。
使用集群技术和Linux操作系统实现一个高性能、高可用的服务器。
D. F5
F5负载均衡服务器(硬件)。
F5 BIG_IP提供12种灵活的算法将所有流量均衡的分配到各个服务器。
优点
能够直接通过智能交换机实现,处理能力更强,而且与系统无关,负载性能强,适用于大访问量、简单的应用。
缺点
成本高,配置冗余。
E. Docker
Docker是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的镜像中。
然后发布到任何流行的Linux或Windows机器上。
也可以实现虚拟化,容器是完全使用沙箱机制,相互之间不会有任何接口。
F. NoSQL
非关系型数据库。
NoSQL也称Not Only SQL的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称。
NoSQL适用于超大规模数据的存储,这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展。
NoSQL满足CAP定理(CAP定理见分布式章节),而非ACID属性。
1. NoSQL优点
高可扩展性。
分布式计算。
低成本。
架构的灵活性,半结构化数据。
没有复杂的关系。
2. NoSQL缺点
没有标准化。
有限的查询功能。
3. NoSQL的数据库分类
(key, value)键值对存储
可以通过key快速查询到其value,一般来说,存储不管value的格式。
如:Redis,Oracle BDB。
列存储
按列存储数据,方便存储结构化和半结构化,方便做数据压缩。
如:HBase,Cassandra。
文档存储
一般用类似json的格式存储,存储的内容是文档型的。
如:MongoDB,CouchDB。
图像存储
图形关系的最佳存储。
如:Neo4J,FlockDB。
对象存储
通过类似面向对象语言的语法操作数据库,通过对象的方式存取数据。
如:db4o, Versant。
Xml数据库
高效的存储XML数据,并支持XML的内部查询语法。
如:Berkeley DB XML, BaseX。
G. Redis
Redis是完全开源免费的,遵守BSD协议,是一个高性能的(key - value)数据库。
Redis是一个开源的使用ANSI C语言编写,提供多种语言的API。
Redis通常被称为数据结构服务器。
1. Redis特点
Redis支持数据的持久化,可以将内存中的数据保存在磁盘上,重启的时候可以再次加载进行使用。
Redis不仅仅支持简单的(key - value)类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
Redis支持数据的备份,即master-slave模式的数据备份。
Redis性能极高,读的速度是 110000次/s,写的速度是81000次/s。
Redis的所有操作都是原子性的。
2. Redis支持五种数据类型
(1)String(字符串)。
(2)hash(哈希)。
(3)list(列表)。
(4)set(集合)。
(5)zset(sorted set:有序集合)。
String(字符串)
String是redis最基本的类型,一个key对应一个value。
String类型是二进制安全的,也就是string可以包含任何数据。
String类型的值最大能存储512MB。
例:
DEL key :删除key。
SET key value :存储数据。
GET key :根据key获取数据。
Hash(哈希)
Redis hash是一个键值(key=>value)对集合。
Redis hash是一个String类型的field和value的映射表,hash特别适合用于存储对象。
例:
HDEL key field :删除一个field字段。
HMSET key field1 value1 field2 value2 :存储数据
HGET key field1 :根据key获取对象field1的值
HGET key field2 :根据key获取对象field2的值
List(列表)
Redis列表是简单的字符串列表,按照插入顺序排序,也可以添加一个元素到列表的头部或者尾部。
列表最多可存储2^32 – 1个元素(4294967295, 每个列表可存储40多亿个元素)。
例:
LPOP key :移出并获取到列表的第一个元素。
LPUSH key values :添加一个元素到key对应的list列表中。
LRANGE key begin end :获取list列表指定范围内的元素。
LREM key count value :移除列表元素。
Set(集合)
Redis的Set是String类型的无序集合。
集合是通过哈希表实现的,所以添加、删除、查找的复杂度都是O(1)。
集合最多可存储2^32 – 1个元素(4294967295, 每个集合可存储40多亿个元素)。
例:
SPOP key :移除并返回集合中的一个随机元素。
SADD key member :添加一个元素到key对应的set集合中,成功返回1,如果元素已存在返回0。
SMEMBERS key :获取集合中的所有成员。
zset(sorted set:有序集合)
和set一样,也是String类型元素的集合,且不允许重复的成员。
zset为每个元素都关联一个double类型的分数,redis通过分数来为集合中的成员进行从小到大的排序。
zset的成员是唯一的,但分数(score)却可以重复。
例:
ZREM key member :移除有序集合中的一个成员。
zadd key score member :添加元素到集合,元素在集合中存在则更新对应的score。
ZRANGEBYSCORE key min max :通过分数返回有序集合指定区间内的成员。
3. Redis事务
Redis事务可以一次执行多个命令,并且带有三个重要的保证:
批量操作在发送EXEC命令前被放入队列缓存。
收到EXEC命令后进入事务执行,事务中任意命令执行失败,其余的命令依然被执行。
在事务执行过程中,其它客户端提交的命令请求不会插入到事务执行命令序列中。
一个事务从开始到执行经历三个阶段
开始事务
命令入队
执行事务
事务函数
MULTI :开始事务
EXEC :执行事务
DISCARD :取消事务
WATCH key[key …] :监视一个(或多个)key。
如果在事务执行之前这个(或这些)key被其它命令所改动,那么事务将被打断。
UNWATCH :取消WATCH命令对所有key的监视。
H. ElasticSearch
ElasticSearch是一个基于Lucene的搜索服务器。
它提供了一个分布式多用户能力的全文搜索引擎。
ElasticSearch基于RESTful web接口,用Java语言开发,是一种流行的企业级搜索引擎。
ElasticSearch底层采用了分段的存储模式,使它在读写时几乎完全避免了锁的出现,大大提升了读写性能。
实现原理
首先用户将数据提交到ElasticSearch数据库中。
再通过分词控制器将对应的语句分词,将其权重和分词结果一并存入数据。
当用户搜索数据的时候,再根据权重将结果排名、打分,最后返回结果呈现给用户。
I. HDFS
Hadoop Distributed File System,是指适合运行在通用硬件上的分布式文件系统。
HDFS是分布式计算中数据存储管理的基础,是基于流数据模式访问和处理超大文件的需求而开发的。
1. HDFS特点
高容错性、可构建在廉价机器上。
适合批处理。
适合大数据处理。
流式文件访问。
2. HDFS局限
不支持低延迟访问。
不适合小文件存储。
不支持并发写入。
不支持修改。
3. HDFS底层架构
HDFS是一个主/从(Mater/Slave)体系结构,HDFS集群拥有一个NameNode和一些DataNode。
NameNode管理文件系统的元数据,DataNode存储实际的数据。
HDFS Client
客户端,提供一些命令来管理、访问HDFS,比如启动或者关闭HDFS。
与DataNode交互,读取或者写入数据。
读取时,要与NameNode交互,获取文件的位置信息。
写入HDFS的时候,Client将文件切分成一个一个的Block,然后进行存储。
NameNode
即Master,管理HDFS的名称空间。
管理数据块(Block)映射信息。
配置副本策略。
处理客户端读写请求。
DataNode
即Slave,NameNode下达命令,DataNode执行实际的操作。
存储实际的数据块。
执行数据块的读/写操作。
Secondary NameNode
并非NameNode的热备,当NameNode挂掉的时候,它并不能马上替换NameNode并提供服务。
辅助NameNode,分担其工作量。
定期合并fsimage和fsedits,并推送给NameNode。
在紧急情况下,可辅助恢复NameNode。
J. zookeeper
zookeeper是一个分布式的,开放源码的分布式应用程序协调服务。
zookeeper主要是用来解决分布式应用中经常遇到的一些数据管理问题。
提供的功能包括:配置维护,域名服务,分布式同步,组服务等。
zookeeper功能非常强大,可以实现诸如分布式应用配置管理、统一命名服务、状态同步服务、集群管理等功能。
例:
假设我们的程序是分布式部署在多台机器上,如果我们要改变程序的配置文件。
需要逐台机器去修改,非常麻烦。
现在把这些配置全部放到zookeeper上去,保存在zookeeper的某个目录节点中。
然后所有相关应用程序对这个目录节点进行监听。
一旦配置信息发生变化,每个应用程序就会收到zookeeper的通知。
然后从zookeeper获取新的配置信息应用到系统中。
1. zookeeper数据结构
zookeeper与标准的文件系统非常相似,也是用“/”表示上下层级关系。
zookeeper的数据存储结构就像一颗树,这颗树由节点(zNode)组成。
zookeeper分为服务端和客户端,由客户端来操作节点。
zookeeper的每个节点都可以做ACL(Access Controller List)权限控制。
权限分为:CREAT,READ,WRITE,DELETE,ADMIN,ALL。
2. zNode节点
每个zNode节点都能存储数据,每个zNode默认存1M的数据,可以用配置最大存4M数据。
zookeeper有4种节点类型
持久节点(PERSISTENT)
默认的节点类型,创建节点的客户端与zookeeper断开连接后,该节点依然存在。
持久排序节点(PERSISTENT_SEQUENTIAL)
所谓排序节点,就是在创建节点的同时,zookeeper根据创建的时间顺序给该节点名称进行编号。
临时节点(EPHEMERAL)
和持久节点相反,当创建节点的客户端与zookeeper断开连接后,临时节点也会被删除。
临时排序节点(EPHEMERAL_SEQUENTIAL)
在创建节点时,zookeeper根据创建的时间顺序给该节点名称进行编号。
当创建节点的客户端与zookeeper断开连接后,临时节点也会被删除。
K. MQ
全称Message Queue,消息队列。
消息队列中间件是分布式系统中重要的组件。
消息队列主要解决应用耦合、异步消息、流量削锋、日志处理等问题。
实现高性能、高可用、可伸缩和最终一致性架构,是大型分布式系统不可缺少的中间件。
消息队列也可简单理解为在消息的传输过程中保存消息的容器。
消息队列的主要目的是提供路由并保证消息的传递。
如果发送消息时接收者不可用,消息队列会保留消息,直到可以成功地传递它。
1. 消息队列使用案例
如下图所示:使用消息队列应用于日志的技术架构体系。
日志采集客户端
负责日志数据采集,定时写入消息队列(Kafka)中。
消息队列(Kafka)
负责日志数据的接收,存储和转发。
Logstash
日志解析,统一成JSON输出给Elasticsearch。
Elasticsearch
实时日志分析服务的核心技术,一个schemaless,实时的数据存储服务,通过index组织数据,兼具强大的搜索和统计功能。
Kibana
基于Elasticsearch的数据可视化组件,提供超强的数据可视化能力。
2. JMS消息服务
JMS(Java Message Service),Java消息服务,是一个消息服务的标准规范。
允许应用程序组件基于JavaEE平台创建、发送、接收和读取消息。
它使分布式通信耦合度更低,消息服务更加可靠以及异步性。
JMS标准中,有两种消息模型:(1)P2P(Point to Point); (2)Publish / Subscribe(Pub/Sub)。
P2P(Point to Point)
每个消息都被发送到一个特定的队列中,接收者从队列中获取消息。
队列保留着消息,直到它们被消费或超时。
P2P特点:
每个消费只有一个消费者(Consumer),一旦被消费,消息就不再保留在消息队列中。
发送者和接收者之间没有时间上的依赖性。
接收者在成功接收消息之后需向队列应答成功。
Pub/Sub模式
多个发布将消息发送到Topic,系统将这些消息传递给多个订阅者。
Pub/Sub特点:
每个消息可以有多个消费者。
发布者和订阅者之间有时间上的依赖性。
为了消费消息,订阅者必须保持运行的状态。
JMS中可以通过两种方式来消费消息:
同步
订阅者或接收者通过receive()方法接收消息。
receive()方法在接收到消息之前(或超时之前)将一直阻塞。
异步
订阅者或接收者可以注册为一个消息监听器。
当消息到达之后,系统自动调用监听器的onMessage()方法。
3. JMS编程模型
ConnectionFactory
创建Connection对象的工厂,针对两种不同的JMS消息模型。
分别有QueueConnectionFactory和TopicConnectionFactory两种。
Destination
Destination的意思是消息生产者的消息发送目标或者说消息消费者的消息来源。
Connection
Connection表示在客户端和JMS系统之间建立的连接(对TCP/IP Socket的包装)。
Connection可以产生一个或多个Session。
Connection也有两种类型:QueueConnection和TopicConnection。
Session
Session是操作消息的接口,可以通过session创建生产者、消费者、消息等。
Session提供了事务的功能,当需要使用session发送/接收多个消息时。
可以将这些发送/接收动作放到一个事务中。
同样也有两种类型:QueueSession和TopicSession。
消息生产者
消息生产者由Session创建,并用于将消息发送到Destination。
也有两种类型:QueueSender和TopicPublisher。
消息消费者
消息消费者由Session创建,用于接收被发送到Destination的消息。
也有两种类型:QueueReceiver和TopicSubscriber。
可分别通过session的createReceiver(Queue)或createSubscriber(Topic)创建。
MessageListener
消息监听器。
如果注册了消息监听器,一旦消息到达,将自动调用监听器的onMessage()方法。
4. 常用消息队列
ActiveMQ
ActiveMQ是Apache出品的,是最流行、能力最强劲的开源消息总线。
ActiveMQ特性:
多种语言和协议编写客户端。
完全支持JMS1.1和J2EE1.4规范(持久化,XA消息,事务)。
对Spring的支持。
支持多种传送协议:TCP,UDP,SSL。
支持通过JDBC和journal提供高速的消息持久化。
从设计上保证了高性能的集群,客户端-服务器,点对点。
支持Ajax,支持与Axis的整合。
RabbitMQ
RabbitMQ是流行的开源消息队列系统。
支持Ajax、持久化,用于在分布式系统中存储转发消息。
ZeroMQ
号称史上最快的消息队列,ZeroMQ是一个简单好用的传输层。
像框架一样的一个socket library,它使得socket编程更加简单、简洁和性能更高。
特点:
高性能、非持久化,可单独部署或集成到应用中使用,可作为socket通信库使用。
Kafka
Kafka是一种高吞吐量的分布式发布订阅消息系统。
它可以处理消费者规模的网站中的所有动作流数据。
A. CAP原则
CAP原则又称CAP定理,在一个分布式系统中,CAP原则指的是以下三条要素最多只能同时实现两条、不可能三者兼顾。
1. 一致性(Consistency)
在分布式系统中的所有数据备份,在同一时刻是否是同样的值。
也就是说分布式系统中的所有节点访问同一份最新的数据副本。
2. 可用性(Availability)
在分布式系统中部分节点故障后,系统整体是否还能响应客户端的读写请求 ?
在分布式系统中,提供的服务要一直保持可用,并且是正常的响应时间。
3. 分区容错性(Partition tolerance)
在分布式系统中,遇到某节点或网络分区故障的时候,仍然能够对外提供满足一致性或可用性的服务。
B. 分布式通信技术
进程间通信(IPC)是在多任务操作系统或联网的计算机之间运行的程序和进程所用的通信技术。
两种类型的进程间通信(IPC)
本地过程调用:共享内存空间、使任务同步和互相发送信息。
远程过程调用:通过网络进行传输(RPC)。
1. JAVA NIO
全称Java non-blocking IO,提供缓存支持的数据容器,Java NIO可以提供非阻塞式的高伸缩性网络。
JAVA NIO有三大核心:(1)Channel(通道); (2)Buffer(缓存区); (3)Selector。
Channel
也称“通道”,Channel是双向的,即可以用来进行读操作,也可以用来进行写操作。
Channel有点类似IO流,不同点是IO流是单向的,Channel是双向的。
JAVA NIO的Channel主要实现有:
FileChannel:从文件中读写数据。
DatagramChannel:通过UDP读写网络中的数据。
SocketChannel:通过TCP读写网络中的数据。
ServerSocketChannel:监听新进来的TCP连接,对每一个新进来的连接都会创建一个SocketChannel。
Buffer(缓存区)
JAVA NIO中的Buffer主要实现有:
ByteBuffer。
CharBuffer。
DoubleBuffer。
FloatBuffer。
IntBuffer。
LongBuffer。
ShortBuffer。
写入数据到Buffer。
调用flip()方法。
从Buffer中读取数据。
调用clear()方法或者compact()方法。
Selector
Selector运行单线程处理多个Channel。
JAVA NIO 的特点
即可以从通道中读取数据,也可以写数据到通道中。
通道可以异步读写。
通道中的数据总是要先读到一个Buffer,或者总是要从一个Buffer中写入。
2. TCP与UDP
TCP协议
全称Transmission Control Protocol,即传输控制协议。
TCP是一种面向连接的、可靠的、基于字节流的通信协议。
面向连接:先连接,再通信。
可靠的:相对于UDP连接,TCP传输更可靠。
TCP通过一序列的机制(面向连接机制、发送应答机制)来保障传输的可靠性。
UDP协议
User Datagram Protocol,用户数据报协议。
UDP是一种无连接的传输协议,UDP为应用程序提供了一种无需建立连接就可以发送封装的IP数据报的方法。
TCP与UDP不同点
TCP基于字节流的方式收发数据,UDP基于数据报通信的方式收发数据。
TCP是面向连接的(先建立连接、再进行通信),UDP是面向无连接的。
TCP提供可靠的服务,UDP不保证可靠性。
应用场景
TCP适合通信质量要求较高的场景。
例:HTTP传输,文件传输,SMTP传输,目前大部分的传输都是基于TCP协议进行传输。
UDP相对于TCP传输速度更快,实时性更好,消耗资源更少,但稳定性、可靠性比TCP差。
适合对网络通讯质量要求不高,速度要求尽量快,更实时的场景,例:QQ语音,QQ视频。
TCP的三次握手
第一次握手:客户端A向服务端B发送连接请求(客户端服务端)。
第二次握手:服务端B向客户端A发送确认连接,同时向客户端A发送连接请求(服务端客户端)。
第三次握手:客户端A收到服务端的确认信息,正确无误后,再向客户端发送确认连接信息(客户端服务端)。
3. RPC 通信
全称Remote Procedure Call,即远程过程调用。
它是一种通过网络从远程计算机程序上请求服务,而不需要了解底层网络技术的协议。
RPC 实现原理
若客户端想要调用服务器端提供的函数/方法,由于不在同一个内存空间,因此无法直接调用。
需要通过网络来表达调用的语义和传达调用的数据。
一个基本的RPC架构里面应该至少包含以下4个组件:
1)客户端(Client):服务调用方(服务消费者),通过本地调用的方式调用服务。
2)客户端存根(Client stub):存放服务端地址信息,将客户端的请求参数数据信息打包成网络信息(序列化、反序列化),再通过网络传输发送给服务端。
3)服务端存根(Server stub):接收客户端发送过来的请求消息并进行解包(序列化、反序列化),然后再调用本地服务进行处理。
4)服务端(Server):服务的真正提供者。
如下图所示
整个调用过程如下:
1) 建立通信
主要是通过在客户端和服务器之间建立TCP连接,远程过程调用的所有交换的数据都在这个连接里传输。
连接可以是按需连接,调用结束后就断掉,也可以是长连接,多个远程过程调用共享同一个连接。
2) 服务寻址
客户端和服务器之间建立TCP连接后,就要解决寻址问题。
也就是客户端如何获取服务器端的地址呢(如主机名或IP地址、端口)?
可靠的寻址方式是RPC的实现基石(比如可以采用Redis或者zookeeper来注册服务等等)。
如下图所示
从服务提供者的角度看
当提供者服务启动时,需要自动向注册中心注册服务。
当提供者服务停止时,需要向注册中心注销服务。
提供者需要定时向注册中心发送服务请求。
一段时间注册中心未收到来自提供者的服务请求时,认为提供者已停止服务。
从注册中心上摘掉对应的服务。
从调用者角度看
调用者启动时订阅注册中心的消息并从注册中心获取提供者的地址。
当有提供者上线或者下线时,注册中心会告知到调用者。
调用者下线时,取消订阅。
3) 网络传输
序列化
当客户端机器上的应用发起一个RPC调用时。
调用方法和其入参等信息需要通过底层的网络协议进行传输(如TCP)。
由于网络协议是基于二进制的,那就需要将所有需要传输的参数数据都先进行序列化(Serialize)或者编组(marshal)成二进制的形式才能在网络中进行传输。
然后通过寻址操作和网络传输协议将序列化或编组之后的二进制数据发送给服务器端机器上。
反序列化
当服务器端机器接收到客户端机器的应用发来的请求之后。
需要对接收到的参数等信息进行反序列化操作(序列化的逆操作)。
即将二进制信息恢复为内存中的表达方式。
然后再找到对应的方法进行本地调用(一般是通过生成代理Proxy去调用),之后得到调用的返回值。
4) 服务调用
服务器端机器进行本地调用(通过代理Proxy)之后得到了返回值进行计算处理。
此时还需要再把计算结果再发送回客户端机器,同样也需要经过序列化操作。
然后再经过网络传输将二进制数据发送回客户端机器。
而客户端机器接收到这些返回值后,则再次进行反序列化操作,恢复内存中的表达方式。
最后再交给客户端机器上的具体应用进行相关处理。
如下图所示
C. 分布式锁
分布式锁是一种分布式协调技术来实现多个进程之间的协调运行。
Synchronized、 ReentranLock
只能使用在多线程之间调用共享内存的场景。
不能使用在多进程中(多个JVM)。
在多进程中每个进程对应的都是不同的内存空间。
分布式锁的特征
在分布式系统环境下使用,同一个方法在同一时间只能被一个进程的其中一个线程执行。
分布式锁具备可重入特性,具备锁实现机制,防止死锁。
分布式锁还必须具备非阻塞特性,即没有获取到锁将直接返回获取锁失败。
1. Redis锁
基于redis分布式锁实现的三个核心要素:(1)加锁; (2)解锁; (3)锁超时。
加锁
setnx(key, value)
key是锁的唯一标识,可以根据业务来命名;value是一个随机生成的UUID。
setnx(key, 1)。
加锁原理:
当一个线程执行setnx返回1时,说明key不存在,该线程获取锁成功。
当一个线程执行setnx返回0时,说明key已经存在,该线程获取锁失败。
解锁
del(key)
当得到锁的线程执行完任务,需要释放锁,以便其它线程可以进入。
释放锁之后,其它线程就可以继续执行setnx命令来获得锁。
锁超时
如果一个得到锁的线程在执行任务的过程中断开,还未来得及显示地释放锁。
那么已经被锁住的资源将会永远被锁住,其它线程也无法进来。
expire(key, 30):30是超时时间(单位second),
一个简单的加锁、释放锁、设置超时时间的伪代码
if (setnx(key, 1) == 1){
expire(key, 30);
try{
……
}finally{
del(key);
}
}
setnx和expire的非原子性
极端情况1举例:
当线程在setnx 与 expire之间突然断开.
这个时候setnx成功获取到锁,但expire还没有执行到也就不会有超时时间.
那么这个时候,那么已经被锁住的资源还是永远会被锁住,无法释放。
避免这种情况可以使用:set命令, set(key, 1, 30, NX);
极端情况2举例:
当线程1执行完setnx与expire时,假如加锁expire设置30秒超时时间。
但是此处代码逻辑过于复杂,超过30秒还未执行到del释放锁命令。
这时线程1的锁超时自动释放。
此时线程2获取到同一把锁。
随后线程1终于执行完了代码开始执行del命令释放锁。
此时实际上线程1释放的是线程2的锁。
避免这种情况的两种方案:
执行del之前可以先通过锁的value值UUID进行判断,若是自己加的锁则执行del进行锁释放。
给获得锁的线程开启一个守护线程,用来给快要过期的锁“续航”。
2. zookeeper锁
zookeeper分布式锁应用了zookeeper节点中的临时排序节点的原理。
zookeeper第三方库Curator客户端中封装了一个可重入的锁服务。
获取锁
首先在zookeeper当中,创建一个持久节点ParentLock。
当线程1想要获取锁的时候,需要在这个ParentLock节点下面创建一个临时排序节点Lock。
之后线程1查找ParentLock下面所有的临时顺序节点。
首先判断自己创建的节点Lock是否是第一个节点。
如果是则成功获取锁。
如果不是,则获取锁失败,向位于它的前一个节点注册Watcher,进入等待状态。
这种模式跟多线程锁中的ReentrantLock中使用的AQS队列差不多。
释放锁
当已经获取到锁的线程任务完成,会显示地调用删除节点的指令。
如果此结点存在Watcher,则它后面必然有正在等待锁资源的节点存在。
同时它后面第一个等待锁资源的节点就会收到通知、获取到锁。
3. zookeeper锁与redis锁区别
zookeeper锁有封装好的框架,容易实现,有等待锁的队列,大大提升抢锁效率。
zookeeper添加和删除节点性能较低。
Redis锁中使用set和del指令的性能较高。
Redis锁实现复杂,需要考虑超时、原子性、误删等情况。
Redis锁没有等待锁的队列,只能在客户端自旋来等锁,效率低下。
1. 事务
事务是由一组操作构成的可靠的独立的工作单元,事务具备ACID的特性,即原子性、一致性、隔离性、持久性。
2. 分布式事务
是指事务的参与者、资源管理器、事务管理器分别位于不同的服务器上。
例:
在微服务系统当中,有两个服务(1)库存服务,对应数据库1; (2)订单服务,对应数据库2。
正常情况下,两个数据库同时更新成功,两边的数据才能保持一致性。
非正常情况下,数据库1更新成功,数据库2更新失败,两边的数据失去了应有的一致性。
这种情况下,就需要使用分布式事务进行(commit、rollback)进行管理。
由全局事务管理器来管理和协调多个资源管理器之间的一致性。
3. 名词解释
资源管理器
可以是一个DBMS、或者是一个消息服务器管理系统,资源管理器负责控制和管理实际的资源。
事务管理器
负责协调和管理事务,事务管理器控制着全局事务,管理事务的生命周期,并且协调资源。
本地事务
当事务由资源管理器本地管理时被称作本地事务,优点是具备ACID的特性,高效、可靠、实现简单。
全局事务
当事务由全局事务管理器进行全局管理时被称作全局事务。
事务管理器负责管理全局的事务状态和参与的资源,协同资源的一致提交和回滚。
4. 几种常用的实现分布式事务的技术
XA分布式事务协议
XA分布式事务协议(分布式事务规范),是全局事务管理器与资源管理器的接口。
该规范主要定义了全局事务管理器和局部资源管理器之间的接口(主流的数据库产品都实现了XA接口)。
XA协议包含2PC(两阶段提交)和3PC(三阶段提交)
2PC
第一阶段:
全局事务管理节点首先向所有的参与事务的节点发送Prepare请求。
参与事务的节点在接到Prepare请求后,每一个参与者节点会各自执行与事务有关的数据更新。
并同时写入Undo Log和Redo Log日志中(Undo Log与Redo Log的详解见数据库一章)。
如果参与者执行成功,暂时不提交任务,而是向全局事务管理节点返回Done(完成)消息。
当全局事务管理节点接到了所有参与者的返回消息后,整个分布式事务将会进入第二个阶段。
第二阶段:
如果全局事务管理节点收到的所有参与者的返回消息都是Done(完成)。
那么它将会向所有事务参与者发出Commit请求。
参与事务的节点接到Commit请求之后。
事务参与者节点会各自进行本地事务的提交,并释放资源。
当本地事务完成提交后,将会向全局事务管理节点返回ACK(完成)信息。
当全局事务管理节点接收到所有事务参与者的ACK(完成)反馈之后,整个分布式事务成功完成。
若在XA的第一阶段,如果某个事务参与者反馈失败信息。
说明该节点的本地事务执行不成功,需要回滚(rollback)。
在第二阶段,全局事务管理节点向所有的事务参与者发送Abort请求。
接收到Abort请求之后,各个事务参与者节点需要在本地进行事务的回滚操作。
回滚操作依照Undo Log进行。
XA两阶段的缺点:
性能问题:
XA协议遵循强一致性,在事务执行过程中,各个节点占用着数据库资源。
只有当所有节点准备完毕,全局事务管理节点才会通知提交,参与者提交后释放资源
这样的过程有着非常明显的性能问题。
可以使用MQ消息中间件解决性能问题(异步处理)。
单点故障问题:
全局管理节点是整个XA模型的核心。
如果其宕机,事务参与者将一直处于中间状态无法完成事务,可以使用3PC进行解决。
数据不一致问题:
在XA协议的第二个阶段,如果发生局部网络问题。
若一部分事务参与者收到了提交信息,另一部分事务参与者没收到提交信息。
那么就导致了节点之间数据的不一致。
3PC
XA三阶段提交在两阶段提交的基础上增加了CanCommit阶段,并且引入了超时机制。
一旦事务参与者迟迟没有接收到全局事务管理节点的commit请求,会自动进行本地commit。
这样可以解决单点故障问题,但还是无法解决性能与数据不一致问题。
TCC补偿事务
TCC事务是Try、Commit、Cancel三种指令的缩写。
其逻辑模式类似于XA两阶段提交,但是实现方式是在代码层面人为实现。
例:A转账给B,有一个本地方法,里面依次调用:
Try阶段:
首先在Try阶段,要先调用远程接口把A和B的钱冻结。
Confirm阶段:
执行远程调用的转账操作,转账成功进行解冻处理。
只要Try阶段成功,默认Confirm阶段是不会出错的。
Cancel阶段:
如果第二步执行成功,那么转账成功。
如果第二步执行失败,则将A和B的钱做解冻处理,转账失败。
本地消息表(异步处理)
本地消息表与业务数据表处于同一个数据库中。
这样就能利用本地事务来保证在对这两个表的操作满足事务特性,并且使用了消息队列来最终一致性。
例:A转账100元给B
A对应的本地数据库中的账户减少100(更新成功)。
之后A向本地消息表发送一个消息,本地事务能保证这个消息一定会被写入本地消息表中。
之后A将本地消息表中的消息转发到消息队列中(Kafka等)。
如果转发成功则将消息从本地消息表中删除,否则继续重新转发。
之后B从消息队列中读取消息,并执行消息中的操作,B对应的本地数据库中的账户加100。
转账成功。
重要的事情说三遍:
架构设计的复杂度一定要根据实际业务场景进行分析。
架构设计的复杂度一定要根据实际业务场景进行分析。
架构设计的复杂度一定要根据实际业务场景进行分析。
对于一般类产品,架构设计到能够满足系统的性能指标要求就足够了。
对于电商类产品,应设计到能满足下一阶段用户量和性能指标要求的程度,并根据业务的增长不断的迭代升级架构,以支持更高的并发和更丰富的业务。
A. 软件架构模型
此架构模型适用小型软件项目。
软件架构设计一般将整个业务应用分为三层架构模型:(1)UI表示层 (2)DLL业务逻辑层 (3)DAL数据访问层。
1. UI表示层
提供交互式的界面,用于直接和用户交互,也称为交互层,通常是网页、UI等。
2. DLL业务逻辑层
负责数据的传递与处理。
例:用户录入的信息要经过业务逻辑层的处理后,才能展现给用户。
3. DAL数据访问层
用于操作数据库,对数据的保存、读取和更新。
B. 单体架构
单体架构是指由一台或多台计算机组成中心节点,将数据集中存储在这个中心节点中。
并且整个系统的所有业务功能也均在此集中处理。
一个典型的单体应用就是将所有的业务场景的UI表示层、DLL业务逻辑层和DAL数据访问层放在一个工程中。
最终经过编译、打包,部署在一台服务器上。
例:
典型的J2EE工程。
它是将表示层的JSP、业务逻辑层的Service、Controller和数据访问层的Dao,打包成war包。
部署在Tomcat、Jetty或者其它Servlet容器中运行。
1. 单体架构的缺陷
复杂性高
所有业务都集中处理。
所有计算都集中处理。
所有的相关数据都统一存储、集中访问。
模块的边界模糊,依赖关系不清晰,代码质量不能得到有效保证。
可靠性差,若发生某个应用的BUG,可能会波及整个系统的使用,造成全局性的影响。
维护困难
单体架构一般不存在业务系统间的互相调用。
代码冗余性很高,随着时间推移、需求变更和人员更迭,会形成应用程序的技术债务逐渐上升。
随着业务的发展和功能膨胀,这种架构很容易发生腐化现象。
扩展性差
单体架构只能作为一个整体进行扩展,无法结合业务模块的特点按需扩展。
单体架构一般使用统一的技术平台或方案解决所有问题,团队的每个成员都必须使用相同的开发语言和架构,想要引入新的框架或技术平台非常困难。
C. 集群架构
集群是一组相互独立的、通过高速网络互连的计算机,它们构成了一个组,并以单一系统的模式加以管理。
集群主要是简单加机器解决问题,对于问题本身不做任何分解。
集群架构一样存在单体架构的缺陷。
集群优势
提高性能、降低成本、提高可扩展性、增强可靠性。
集群也可以简单理解为
把单体架构复制几份,这样就构成了一个集群。
集群中的每台应用服务器称为一个节点,每个节点都提供相同的服务。
这样系统的处理能力就相当于提升了好几倍(具体取决于有多少节点就提升多少倍)。
集群架构图
D. 分布式架构
1. 分布式架构简介
分布式架构简单可以理解为(分工 + 协作)。
分布式系统是一组独立的计算机展现给用户的是一个统一的整体。
系统拥有多种通用的物理和逻辑资源,可以动态分配任务,分散的物理和逻辑资源通过计算机网络实现信息交换。
系统中存在一个以全局的方式管理计算机资源的分布式操作系统。
在操作系统之上有一层软件中间件负责实现这个模型。
例:万维网就是典型的分布式系统的例子。
2. 分布式系统的特征
分布性
分布式系统由多台计算机组成,它们在地域上是分散的。
可以散布在一个单位、一个城市、一个国家,甚至全球范围内。
自治性
分布式系统中的各个节点都包含自己的处理机和内存,各自具有独立的处理数据的功能。
并行性
一个大的任务可以划分为若干个子任务,分别在不同的主机上执行。
全局性
分布式系统中必须存在一个单一的、全局的进程通信机制。
使得任何一个进程都能与其它进程通信,并且不区分本地通信与远程通信。
3. 分布式系统的优点
资源共享。
加快计算速度。
可靠性高。
通信方便、快捷。
4. 常见分布式架构
1)应用层实现分布式(单元化架构),每个单元都有自己的数据,可以绑定应用资源。
2)业务进行分库分表,事务一致性设计,通过数据库中间件负责连接管理和路由。
3)分布式事务数据库(理论上对应用透明,复杂SQL支持完备度)。
5. 分布式架构图(此处以某金融平台核心系统为例)
1. SOA
全称Service Oriented Architecture,即面向服务的架构。
SOA是一个组件模型,它将应用程序的不同功能单元(称为服务)进行拆分。
并通过这些服务之间定义良好的接口和协议联系起来。
在SOA模型中,所有的功能都定义成了独立的服务。
服务之间通过交互和协调完成业务的整体逻辑。
所有的服务通过服务总线或流程管理器来连接,最终提供一系列完整的功能。
各个服务通常以独立的形式部署运行,服务之间通过网络进行调用。
2. ESB
全称 Enterprise Service Bus,即企业服务总线。
提供了网络中最基本的连接中枢,是构筑企业神经系统的必要元素。
简单来说ESB就是一根管道,用来连接各个服务节点。
ESB的存在是为了集成基于不同协议的不同服务。
ESB做了消息的转化、解释以及路由的工作,以此来让不同的服务互联互通。
ESB的核心内容
服务元数据管理:包括服务注册、生命周期等。
协议适配:支持各种集成和通信协议,支持各种消息传输和业务集成方式。
中介服务:支持各种集成场景,支持各种消息处理与转换模式。
治理与监控:服务调用与消息处理的日志及统计分析,服务质量、服务降级、流控等等。
安全性:传输通信安全性,数据安全性,服务调用安全性,身份验证等等。
其它还有事务管理、高性能、高可用、高可靠性、高稳定性等等。
3. 微服务
微服务不再强调传统SOA架构里面比较重的ESB企业服务总线,同时以SOA的思想进入到单个业务系统内部实现真正的组件化。
微服务架构和SOA架构非常类似,微服务架构更强调的是“业务需要彻底的组件化及服务化”。
原单个业务系统会被拆分为多个可以独立开发、设计、部署运行的小应用。
这些小应用间通过服务化完成交互和集成。
微服务的特征
通过服务实现组件化。
按业务能力来划分服务和开发团队。
去中心化。
基础设施自动化。
微服务架构需要关注的几个点
微服务颗粒度拆分策略、服务边界定义,同时要从功能和性能方面综合考虑。
职责单一化、运行隔离化,理论上支持单一微服务独立发布、独立部署、独立运行。
支持并行开发,降低构建及部署耗时,提高开发效率,同时降低系统影响范围,通过集成DevOps体系,提高生产版本发布频率。
分布式事务支持,微服务应用设计要完全满足分布式架构平台事务规范要求。
4. 云计算的三个层次
假设有一家不需要其它任何公司提供服务的大牛公司。
那这家公司就必需拥有:(1)基础设施; (2)平台; (3)软件。
基础设施:包括服务器、网络设备、存储设备等。
平台则包括:操作系统、中间件、运行库等。
软件包括:应用程序、数据等。
了解了这些,其实IaaS / PaaS / SaaS就是云计算的三种服务:
IaaS
Infrastructure-as-a-Service:基础设施即服务。
IaaS公司会提供场外服务器、存储和网络硬件(也可以选择租用),节省维护成本和办公场地。
公司可以在任何时候利用这些硬件来运行其应用。
特点:
费用因消费而异。
服务高度可扩展。
通常在单个硬件上包括多个用户。
为组织提供对基础架构的完全控制。
动态灵活。
PaaS
Platform-as-a-Service:平台即服务。
PaaS公司可以提供各种开发和分发应用的解决方案,比如虚拟服务器和操作系统等。
特点:
资源可轻松扩展或缩小。
提供各种服务以协助开发,测试和部署应用程序。
许多用户可以访问相同的开发应用程序。
SaaS
Software-as-a-Service:软件即服务。
也是目前普通用户接触最多的层面,在网络上任意一个远程服务器上的应用都属于SaaS。
特点:
统一的管理。
可通过互联网访问。
用户不负责硬件或软件更新。
托管在远程服务器上。
5. 微服务架构图(此处以某金融平台核心系统为例)