一、CDN
1、什么是CDN
- CDN 就是将静态资源分发到多个不同的地方以实现就近访问,进而加快静态资源的访问速度,减轻服务器以及带宽的负担.(可看作是一层特殊缓存服务,用来处理静态资源的请求)
2、CDN工作原理
- 静态资源是如何被缓存到 CDN 节点
-
可通过预热的方式将源站的资源同步到 CDN 的节点中。用户首次请求资源可直接从 CDN 节点中取,无需回源。可降低源站压力,提升用户体验。若不预热,访问的资源可能不在 CDN 节点中,这时CDN 节点将请求源站获取资,即为回源。
- 回源:当 CDN 节点上没有用户请求的资源或该资源的缓存已经过期时,CDN 节点需要从原始服务器获取最新的资源内容,这个过程就是回源。当用户请求发生回源的话,会导致该请求的响应速度比未使用 CDN 还慢,因为相比于未使用 CDN 还多了一层 CDN 的调用流程。
- 预热:预热是指在 CDN 上提前将内容缓存到 CDN 节点上。这样当用户在请求这些资源时,能够快速地从最近的 CDN 节点获取到而不需要回源,进而减少了对源站的访问压力,提高了访问速度。
- 若资源更新,可对其刷新 ,删除 CDN 节点上缓存的旧资源,并强制 CDN 节点回源站获取最新资源。
-
- 如何找到最合适的 CDN 节点
-
GSLB (Global Server Load Balance,全局负载均衡)是 CDN 的大脑,负责多个 CDN 节点之间相互协作,最常用的是基于 DNS 的 GSLB。CDN 会通过 GSLB 找到最合适的 CDN 节点
-
浏览器向 DNS 服务器发送域名请求;
- DNS 服务器向根据 CNAME( Canonical Name ) 别名记录向 GSLB 发送请求;
- GSLB 返回性能最好(通常距离请求地址最近)的 CDN 节点(边缘服务器,真正缓存内容的地方)的地址给浏览器;
- 浏览器直接访问指定的 CDN 节点。
-
-
GSLB 会根据请求的 IP 地址、CDN 节点状态(比如负载情况、性能、响应时间、带宽)等指标来综合判断具体返回哪一个 CDN 节点的地址。
-
- 如何防止静态资源被盗用
-
设置 Referer 防盗链,具体来说就是根据 HTTP 请求的头信息里面的 Referer 字段对请求进行限制。我们可以通过 Referer 字段获取到当前请求页面的来源页面的网站地址,这样我们就能确定请求是否来自合法的网站。CDN 服务提供商几乎都提供了这种比较基础的防盗链机制。
-
时间戳防盗链机制
-
二、负载均衡
1、什么是负载均衡
- 指的是将用户请求分摊到不同的服务器上处理,以提高系统整体的并发处理能力以及可靠性。负载均衡服务可以有由专门的软件或者硬件来完成,硬件的性能更好,软件的价格更便宜.
- 负载均衡是一种比较常用且实施起来较为简单的提高系统并发能力和可靠性的手段
2、负载均衡的分类
- 服务端负载均衡
- 主要应用在 系统外部请求 和 网关层 之间,可以使用 软件(Nginx) 或者 硬件(F5) 实现。
- 硬件负载均衡的优势是性能很强且稳定,缺点就是太贵
- 软件负载均衡
- 四层负载均衡(LVS):工作在 OSI 模型第四层,也就是传输层,主要协议是 TCP/UDP,负载均衡器在这一层能够看到数据包里的源端口地址以及目的端口地址,会基于这些信息通过一定的负载均衡算法将数据包转发到后端真实服务器。也就是说,四层负载均衡的核心就是 IP+端口层面的负载均衡,不涉及具体的报文内容。
- 七层负载均衡(Nginx):工作在 OSI 模型第七层,也就是应用层,主要协议是 HTTP 。这一层的负载均衡比四层负载均衡路由网络请求的方式更加复杂,它会读取报文的数据部分(如HTTP 部分的报文),然后根据读取到的数据内容(如 URL、Cookie)做出负载均衡决策。七层负载均衡器的核心是报文内容层面的负载均衡,执行第七层负载均衡的设备通常被称为 反向代理服务器 。
-
七层负载均衡比四层负载均衡会消耗更多的性能,不过,也相对更加灵活,能够更加智能地路由网络请求,如可根据请求的内容进行优化如缓存、压缩、加密。
- 主要应用在 系统外部请求 和 网关层 之间,可以使用 软件(Nginx) 或者 硬件(F5) 实现。
- 客户端负载均衡
-
客户端负载均衡 主要应用于系统内部的不同的服务之间,可以使用现成的负载均衡组件来实现。在客户端负载均衡中,客户端会自己维护一份服务器的地址列表,发送请求之前,客户端会根据对应的负载均衡算法来选择具体某一台服务器处理请求。客户端负载均衡器和服务运行在同一个进程或者说 Java 程序里,不存在额外的网络开销。不过,客户端负载均衡的实现会受到编程语言的限制,比如说 Spring Cloud Load Balancer 就只能用于 Java 语言。Java 领域主流的微服务框架 Dubbo、Spring Cloud 等都内置了开箱即用的客户端负载均衡实现。Dubbo 属于是默认自带了负载均衡功能,Spring Cloud 是通过组件的形式实现的负载均衡,属于可选项,比较常用的是 Spring Cloud Load Balancer(官方,推荐) 和 Ribbon(Netflix,已被弃用)。
-
3、负载均衡的算法
- 随机法
- 轮训法:挨个轮询服务器处理,也可以设置权重
- 两次随机法:在随机法的基础上多增加了一次随机,多选出一个服务器。随后再根据两台服务器的负载等情况,从其中选择出一个最合适的服务器。
- 哈希法:将请求参数信息通过哈希函数转换成一个哈希值,然后根据哈希值来决定
- 最小连接法:当有新的请求出现时,遍历服务器节点列表并选取其中连接数最小的一台服务器来响应当前请求。相同连接的情况下,可以进行加权随机。最少连接数基于一个服务器连接数越多,负载就越高这一理想假设。然而, 实际情况是连接数并不能代表服务器的实际负载,有些连接耗费系统资源更多,有些连接不怎么耗费系统资源。
- 最少活跃法:以活动连接数为标准,活动连接数可以理解为当前正在处理的请求数。活跃数越低,说明处理能力越强,这样就可以使处理能力强的服务器处理更多请求。相同活跃数的情况下,可以进行加权随机。
- 最快响应时间法:以响应时间为标准来选择具体是哪一台服务器处理。客户端会维持每个服务器的响应时间,每次请求挑选响应时间最短的。相同响应时间的情况下,可以进行加权随机。这种算法可以使得请求被更快处理,但可能会造成流量过于集中于高性能服务器的问题。
4、七层负载均衡
- DNS解析:DNS 解析实现负载均衡的原理:在 DNS 服务器中为同一个主机记录配置多个 IP 地址,这些 IP 地址对应不同的服务器。当用户请求域名的时候,DNS 服务器采用轮询算法返回 IP 地址,这样就实现了轮询版负载均衡。(可支持IP地址权重配置)
- 反向代理:客户端将请求发送到反向代理服务器,由反向代理服务器去选择目标服务器,获取数据后再返回给客户端。对外暴露的是反向代理服务器地址,隐藏了真实服务器 IP 地址。反向代理“代理”的是目标服务器,这一个过程对于客户端而言是透明的。Nginx 就是最常用的反向代理服务器,它可以将接收到的客户端请求以一定的规则(负载均衡策略)均匀地分配到这个服务器集群中所有的服务器上。
5、客户端负载均衡怎么做
- 可使用现成的负载均衡组件来实现
- Netflix Ribbon
- Spring Cloud Load Balancer:随机/轮训
- dubbo:加权随机、加权轮训、最少活跃数、一致性hash
三、数据库优化
1、读写分离
- 读写分离主要是为了将对数据库的读写操作分散到不同的数据库节点上。 能够小幅提升写性能,大幅提升读性能。
-
一般情况下,我们都会选择一主多从,也就是一台主数据库负责写,其他的从数据库负责读。主库和从库之间会进行数据同步,以保证从库中数据的准确性。这样的架构实现起来比较简单,并且也符合系统的写少读多的特点。
-
实现
- 部署多台数据库,选择其中的一台作为主数据库,其他的一台或者多台作为从数据库。
- 保证主数据库和从数据库之间数据实时同步,这个过程也就是我们常说的主从复制。
- 系统将写请求交给主数据库处理,读请求交给从数据库处理。
- 具体实现
- 代理方式:在应用和数据中间加了一个代理层。应用程序所有的数据请求都交给代理层处理,代理层负责分离读写请求,将它们路由到对应的数据库中。提供类似功能的中间件有 MySQL Router(官方, MySQL Proxy 的替代方案)、Atlas(基于 MySQL Proxy)、MaxScale、MyCat。
- 组件方式:引入第三方组件,如sharding-jdbc
- 主从复制原理:binlog记录mysql数据库中数据的所有变化(DDL和DML语句)
- 主库将数据库中数据的变化写入到 binlog
- 从库连接主库,从库会创建一个 I/O 线程向主库请求更新的 binlog
- 主库会创建一个 binlog dump 线程来发送 binlog ,从库中的 I/O 线程负责接收
- 从库的 I/O 线程将接收的 binlog 写入到 relay log 中
- 从库的 SQL 线程读取 relay log 同步数据到本地(也就是再执行一遍 SQL )
-
避免主从延迟
-
强制将读请求路由到主库处理
-
延迟读取
-
-
延迟原因:
- 从库 I/O 线程接收 binlog 的速度跟不上主库写入 binlog 的速度,导致从库 relay log 的数据滞后于主库 binlog 的数据;
- 从库 SQL 线程执行 relay log 的速度跟不上从库 I/O 线程接收 binlog 的速度,导致从库的数据滞后于从库 relay log 的数据。
- 从库机器性能比主库差
- 从库处理请求过多
- 从库太多
- 网络延迟
2、分库分表
- 分库
- 垂直分库:单一数据库按照业务进行划分,不同的业务使用不同的数据库,进而将一个数据库的压力分担到多个数据库。
- 水平分库:把同一个表按一定规则拆分到不同的数据库中,每个库可以位于不同的服务器上,这样就实现了水平扩展,解决了单表的存储和性能瓶颈的问题。
- 分表
- 垂直分表:对数据表列的拆分,把一张列比较多的表拆分为多张表。
- 水平分表:对数据表行的拆分,把一张行比较多的表拆分为多张表,可以解决单一表数据量过大的问题。
- 什么时候需要分库分表
- 单表的数据达到千万级别以上,数据库读写速度比较缓慢
- 数据库中的数据占用的空间越来越大,备份时间越来越长。
- 应用的并发量太大(应该优先考虑其他性能优化方法,而非分库分表)。
- 缺点:成本高,非必要尽量不采用
3、数据冷热分离
-
数据冷热分离是指根据数据的访问频率和业务重要性,将数据分为冷数据和热数据,冷数据一般存储在存储在低成本、低性能的介质中,热数据高性能存储介质中。
-
冷数据和热数据:热数据是指经常被访问和修改且需要快速访问的数据,冷数据是指不经常访问,对当前项目价值较低,但需要长期保存的数据
- 时间维度区分:按照数据的创建时间、更新时间、过期时间等,将一定时间段内的数据视为热数据,超过该时间段的数据视为冷数据。
- 访问频率区分:将高频访问的数据视为热数据,低频访问的数据视为冷数据。
- 思想:对数据进行分类,然后分开存储
- 优缺点
- 优点:热数据的查询性能得到优化(用户的绝大部分操作体验会更好)、节约成本(可以冷热数据的不同存储需求,选择对应的数据库类型和硬件配置,比如将热数据放在 SSD 上,将冷数据放在 HDD 上)
- 缺点:系统复杂性和风险增加(需要分离冷热数据,数据错误的风险增加)、统计效率低(统计的时候可能需要用到冷库的数据)。
- 冷数据迁移:
- 业务层代码实现:当有对数据进行写操作时,触发冷热分离的逻辑,判断数据是冷数据还是热数据,冷数据就入冷库,热数据就入热库。这种方案会影响性能且冷热数据的判断逻辑不太好确定,还需要修改业务层代码,因此一般不会使用。
- 任务调度:可以利用 xxl-job 或者其他分布式任务调度平台定时去扫描数据库,找出满足冷数据条件的数据,然后批量地将其复制到冷库中,并从热库中删除。这种方法修改的代码非常少,非常适合按照时间区分冷热数据的场景。
- 监听数据库的变更日志 binlog :将满足冷数据条件的数据从 binlog 中提取出来,然后复制到冷库中,并从热库中删除。这种方法可以不用修改代码,但不适合按照时间维度区分冷热数据的场景。
-
如果你的公司有 DBA 的话,也可以让 DBA 进行冷数据的人工迁移,一次迁移完成冷数据到冷库。
-
冷数据存储
-
冷数据的存储要求主要是容量大,成本低,可靠性高,访问速度可以适当牺牲。
-
冷数据存储方案:
- 中小厂:直接使用 MySQL/PostgreSQL 即可(不改变数据库选型和项目当前使用的数据库保持一致),比如新增一张表来存储某个业务的冷数据或者使用单独的冷库来存放冷数据(涉及跨库查询,增加了系统复杂性和维护难度)
- 大厂:Hbase(常用)、RocksDB、Doris、Cassandra
-
四、消息队列
见消息队列文章