高性能

发布时间 2023-07-10 13:51:31作者: 张家豪

高性能

存储高性能

关系数据库

读写分离

  • 主从模式
    • 存在的问题
      • 从节点同步主节点数据可能存在延迟,导致读不到。
    • 解决方法
      • 先读从节点,无数据再读主节点,关键数据可直接读取主节点

分库分表

  • 使用场景
    • 数据量达到千万以上
    • 即使有索引索引也会很慢
    • 文件很大,备份和恢复时间过长
    • 文件过大,丢失数据量大的风险高
  • 业务分表
    • join 问题
    • 事务问题
    • 成本问题
  • 分表
    • 垂直分表
      • 例如:婚恋网站人物列表只需要有 name,age等属性即可,无需过的属性导致查询度过慢
    • 水平分表:会引入更多的复杂度
      • 路由
        • 范围路由
        • hash 路由
        • 配置路由
      • join
        • 只能多次 join 解决
      • count
        • 多次 count
        • 记录数表,新增表进行处理
      • order by
        • 多次 order by 进行聚合

实现方法

  • 程序代码封装
    • 特点
    • 实现简单,可根据业务进行定制
    • 开发工作量大
    • 故障问题不好处理
  • 开源方案
    • 淘宝的 TDDL
  • 中间件封装
    • 特点
      • 支持多种编程语言
      • 支持完整的数据库协议和 SQL 规范,内容丰富导致 bug 可能会较多
      • 所有的数据库操作都变成对中间件的操作,会影响性能
      • 主从切换无感知,有中间件解决
  • 方案
    • MySQL Proxy
    • MySQL Router
    • Atlas
    • ShardingSphere
  • 实现复杂度
    • 因为分表的 order by 等需要聚合还要识别 SQL 的关键字,所以实现比较困难

NoSQL

关系数据库的缺点

  • 1.行记录无法存储数据结构
  • 2.关系数据库的 schema 扩展不方便
  • 3.关系数据库大数据情况下 I/O较高
  • 4.关系数据库的文档搜索能力较弱
    • 全文搜索的条件可以随意排列组合,如果通过索引满足则会添加大量的索引
    • 模糊匹配的方式无法满足,只能用 like,like 是全表扫描速度较慢

分类

  • K-V 存储: Redis
  • 文档数据库: MongoDB
  • 列式数据库:Hbase
  • 全文搜索引擎:Elasticsearch

K-V存储

redis 目前问题:不支持完整的 ACID

文档数据库

  • 优势
    • 新增字段简单
    • 历史数据不会出错
    • 可以很容易存储复杂的数据结构

列式数据库

  • 优势
    • 业务同时读取多列效率较高,因为这些列式存储在一起的,一次磁盘读写就能把一数据的所有列都读取到内存中
    • 可以一次写多个列

全文搜索引擎

  • 原理是倒排序,即内容和文件建立关联关系

缓存

使用场景

  • 需要复杂的运算之后得到结果,存储系统也无能为力
  • 读多写少,存储系统有心无力

缓存穿透:缓存中没有数据导致去查询数据库

  • 存储数据不存在,可通过设置默认值解决
  • 缓存数据生成耗费大量时间,

缓存雪崩:缓存失效后导致系统性能的下降

  • 更新锁,只能一个线程去更新
  • 后台更新,缓存本身设置为永久有效,定时任务或消息通知去更新缓存数据

缓存热点:热点数据进行缓存

计算高性能

单服务器高性能

关键之一是网络编程模型

  • 服务器如何管理连接
  • 服务器如何处理请求
  • 解决方向
    • I/O 模型
    • 进程模型

PPC(Process per Connection )

  • 流程
    • 1.父进程接受连接
    • 2.父进程 fork 子进程
    • 3.子进程处理请求的读写
    • 4.子进程关闭连接
  • 弊端
    • fork 代价过高
    • 父子进程通信复杂
    • 进程数量增大后多操作系统压力过大

prefork

  • 进行连接时才 fork 会让用户感觉卡段,所以出现了预fork优化流程,但是也会出现“惊群”问题,即只会有一个子进程去连接,但是会唤起所有的子进程去尝试,浪费线程上下文切换
  • 也存在父子线程通信复杂问题;进程数量增大后导致操作系统压力过大

TPC(Thread per Connection)

  • 流程
    • 1.父进程接受连接
    • 2.父进程创建子线程
    • 3.子线程处理请求的读写
    • 4.子线程关闭连接
  • 虽然解决了线程通信复杂和fork 代价过高问题,但是也引入的新的问题
    • 高并发情况下依然存在性能问题
    • 虽无需进程间通信了,但线程间的互斥和共享又引入了新的复杂度,可能一不小心出现死锁问题
      • 可能出现某个线程异常导致整个进程的结束
    • 还是存在 CPU 线程调度和切换代价问题

PreThread

  • 流程
    • 1.主线程accept,然后将连接交给某个线程处理
      1. 子线程都尝试去accept,最终只有一个子线程accept成功

Reactor

  • 要解决的问题
    • 为了解决PPC多次创建进程问题,可以通过进行池化,实现资源的节约,但是引入后出现了新的问题
      • 进程如何高效的处理多个连接:一个连接一个进程时可以通过阻塞进行读取,但是一个进程连接多个连接时就不能阻塞到某个进程上,解决这个问题的方法就是将read改为非阻塞的,进行不断的轮询多个连接,但是解决方式并不优雅,轮询也是小号CPU的,如果一个进程的连接数过多,轮询的效率也不高,为了解决这个问题想到了只有连接上有数据的时候进程采取处理,这就是I/O多路复用技术的来源
    • 两个关键实现点
      • 当多条连接共用一个阻塞对象后,进程只需要在一个阻塞对象上等待,而无需再轮询所有的连接
      • 当某条连接有新的数据可以处理时,操作系统会通知进程,进程从阻塞状态返回,开始进行业务处理
  • 模式的核心
    • reactor:监听和分配时间
    • 处理资源线程池:负责处理时间
  • 实现方案
    • 单Reactor 单进程/单线程
      • Reactor对象通过select监控连接事件,收到事件通知后通过dispatch进行分发
      • 如果是连接建立的事件,则由Acceptor处理,Acceptor通过accept接受连接,并创建一个Handler来处理连接后续的各种事件
      • 如果不是连接建立事件,则Reactor会调用连接对象的Handler(第2步中创建的hadnler)进行响应
      • Handler会完成read-->业务处理-->send的完整业务流程
      • 优点:简单,没有进程间通信,没有进程竞争,全部都在同一个进程中完成
      • 缺点
        • 只有一个进程,无法发挥多核CPU的性能
        • 只能部署多个系统来利用多核CPU,这样会带来运维复杂度
        • handler在处理某个连接的业务时,整个进程无法处理其他连接的事件,很容易导致性能瓶颈
      • 适用场景
        • 业务处理速度非常快的,例如: Redis
    • 单Reactor 多线程
      • 1.主线程中,Reactor对象通过select监听连接事件,收到事件后通过dispatch进行分发
    • 多Reactor 多进程/线程

Proactor

集群高性能

负载均衡器的分类

  • DNS负载均衡:不同地区的用户访问同一个域名返回不同的ip
    • 优点
      • 简单、成本低
      • 就近访问,提升访问速度
    • 缺点
      • 更新不及时
      • 扩展性差
      • 分配策略比较简单
  • 硬件负载均衡:F5和A10
    • 优点
      • 功能强大
      • 性能强大
      • 稳定性高
      • 支持安全防护
    • 缺点
      • 价格昂贵
      • 扩展能力差
  • 软件负载均衡
    • 分类
      • nginx:7层负载均衡
      • LVS:是linux内核的4层负载均衡
    • 优点
      • 简单
      • 便宜
      • 灵活
    • 缺点
      • 性能一般
      • 功能没有硬件负载均衡那么强大
      • 一般不具备防火墙和防DDOS攻击等安全功能

负载均衡器架构

    1. DNS负载均衡实现地理级别的负载均衡
    1. F5实现集群级别的负载均衡
    1. 软件负载均衡实现机器级别的负载均衡

负载均衡器算法

  • 任务平分类:可以决定平均分配到各个服务器上,也可以是按照比例或者权重
  • 负载均衡类:根据服务器的负载来进行分配,这里的负载不一定是CPU负载,而是系统当前压力,可以是CPU负载来衡量,也可以是连接数、I/O使用率、网卡吞吐量等来衡量系统的压力
  • 性能最优类:根据服务器的响应时间来进行任务分配,优先分配给响应最快的服务器
  • Hash类:根据某些信息进行Hash运算,分配到指定服务器上。常见的有源地址Hash、目标地址Hash、session id hash、用户id Hash等