web项目 day07(一)

分布式存储及 Web 服务器性能评估

  • 高可用

    • 通过设计,减少系统不能提供服务的时间
      • 服务常年可用,无中断。可用性为 100%
      • 以 100 为时间单位,有 1 个时间单位无法提供服务,可用性为 99 %
      • 4 个 9 的可用性服务,可用性为 99.99 %,一年中大概有 8.76 个小时无法提供服务
  • 高并发

    • 通过设计,保证系统能够同时并行处理很多请求

    常见互联网项目分层架构

    分层架构下的高可用及高并发

数据库瓶颈

  1. IO 瓶颈
    1. 磁盘读 IO 瓶颈,热点数据太多,数据库缓存放不下,每次查询时会产生大量的 IO,降低查询速度 -> 分库和垂直分表。
    2. 网络 IO 瓶颈,请求的数据太多,网络带宽不够 -> 分库。
  2. CPU 瓶颈
    1. SQL 问题,如 SQL 中包含 join,group by,order by,非索引字段条件查询等,增加 CPU 运算的操作 -> SQL 优化,建立合适的索引;在业务层进行业务计算代替 SQL 中复杂查询。
    2. 单表数据量太大,查询时扫描的行太多,SQL 效率低,CPU 出现瓶颈 -> 水平分表。
  3. 解决思路:核心思想 - 分而治之

分布式数据库

数据量不大时,单库单表即可支撑整个系统。当数据量达到一定规模后,则需通过分布式数据库支持。
同时,单点数据库无法保证服务高可用,一旦出现宕机整个服务便 “停摆” 了

常见的分布式数据库实现方式有 “分库” 和 “分表”, 也被称作 “数据分片”

  1. 数据分片

    • 单表查询能力上限: 约为 500 万 左右
    • 方式: 分库、分表
  2. 垂直拆分

    单表字段太多的时候会进行垂直拆分, 不是为了分布式存储,而是为了提升单表性能

    按照业务拆分成库,如:支付业务,订单业务,用户中心等

                                垂直分表
                                   |
    user                           | ext_info
                                   |
    | id  name  sex  age  location | uid aa  bb  cc  dd  ee  ff |
    | ---------------------------- | -------------------------- |
    | 1   xxx   f    11   beijing  | 1  x   x   x   x   x   x   |
    | 2   xxx   f    11   beijing  | 2  x   x   x   x   x   x   |
    | 3   xxx   f    11   beijing  | 3  x   x   x   x   x   x   |
    | 4   xxx   f    11   beijing  | 4  x   x   x   x   x   x   |
    | 5   xxx   f    11   beijing  | 5  x   x   x   x   x   x   |
    | 6   xxx   f    11   beijing  | 6  x   x   x   x   x   x   |
    | 7   xxx   f    11   beijing  | 7  x   x   x   x   x   x   |
    | 8   xxx   f    11   beijing  | 8  x   x   x   x   x   x   |
    | 9   xxx   f    11   beijing  | 9  x   x   x   x   x   x   |
    
  3. 水平拆分

    水平拆分既可以用在 “分表” 处理,也可用在 “分库” 处理

    user
    id  name  sex  age  location  aa  bb  cc  dd  ee  ff
    ------------------------------------------------------ user_1
    1   xxx   f    11   beijing   x   x   x   x   x   x
    2   xxx   f    11   beijing   x   x   x   x   x   x
    3   xxx   f    11   beijing   x   x   x   x   x   x
    ------------------------------------------------------ user_2
    4   xxx   f    11   beijing   x   x   x   x   x   x
    5   xxx   f    11   beijing   x   x   x   x   x   x
    6   xxx   f    11   beijing   x   x   x   x   x   x
    ------------------------------------------------------ user_3
    7   xxx   f    11   beijing   x   x   x   x   x   x
    8   xxx   f    11   beijing   x   x   x   x   x   x
    9   xxx   f    11   beijing   x   x   x   x   x   x
    
    • 按范围拆分

      • 优点: 构建简单, 扩容极其方便.

      • 缺点: 不能随运营发展均衡分配资源(热点数据分布不均匀,历史数冷当前数据热)

      • 分库示例

        Database-1       1 -  500W   <- uid: 3120482
        Database-2    500W - 1000W
        Database-3   1000W - 1500W   <- post_id: 10278327
        Database-4   1500W - 2000W
        
    • 按余数(hash)拆分

      • 优点: 能够随着运营发展均匀分配负载

      • 缺点: 扩容不方便(数据库数量为偶数,方便未来扩容)

      • 示例

        uid = 3120483
        mod = uid % len(Databases) -> 3
        db_name = 'Database-3'
        
        mod = uid % len(Tables) -> 3
        table_name = 'users_3'
        
        Database-0      10  20  30   ...  3120480
        Database-1   1  11  21  31   ...  3120481
        Database-2   2  12  22  32   ...  3120482
        Database-3   3  13  23  33   ...  3120483
        		users_0
        		users_1
        		users_2
        		users_3  <- 3120483
        Database-4   4  14  24  34   ...  3120484
        Database-5   5  15  25  35   ...  3120485
        Database-6   6  16  26  36   ...  3120486
        Database-7   7  17  27  37   ...  3120487
        Database-8   8  18  28  38   ...  3120488
        Database-9   9  19  29  39   ...  3120489
        
  4. 分布式数据库的 ID

    • 必须保证全服多机上产生的 ID 唯一
    • 常见全局唯一 ID 生成策略
      1. 基于存储的自增 ID
        • 可在 Redis 中为每一个表记录当前最新 ID 是多少, 获取下一个 ID 时进行自增
        • 优点: 思路简单, ID 连续
        • 缺点: 有存储依赖, 一旦 Redis 出现问题, 则会影响全部数据库存储
      2. 基于算法确保唯一
        • 常见算法有 UUID、COMB、Snowflake、ObjectID 等
        • 优点: 快速、无存储依赖
        • 缺点: 一般产生的 ID 数值都比较大, 某些算法的 ID 并非是增序
  5. 水平分表分库下,用户如何登录?如何根据用户名查询?

    1. account_user_mapping
      1. id, username, phone, email, password, uid
      2. 通过缓存加速访问
    2. 为每种登录方式创建映射表(可进行分库分表)
      1. (usernane, password, uid),(email, password, uid), (phone, uid)
      2. md5(username) -> 32bit -> 前 16bit 确定库,后 16bit 确定表
      3. md5(phone) -> 32bit -> 倒数第二位 确定库,倒数第一位 确定表
      4. 对 account 进行分表
  6. 大众点评订单系统分库分表实践

数据库集群

  • 通过增加冗余的数据库服务器可构建数据库集群

  • 同一集群中的多台数据库保存的数据必须完全一致(最终一致性)

  • 集群中一台服务器宕机,其他服务器可以继续提供服务

  • 常见结构:一主多从,主从之间通过 binlog 进行数据同步

  • 读写分离

    • 主机用来做数据写入;从机用来数据读取
  • 通过 binlog 实现主从同步

  • 程序自身实现读写分离

在这里插入图片描述

  • 使用第三方代理实现读写分离(mycat)

在这里插入图片描述

服务高可用

  1. 对软硬件的冗余, 以消除单点故障. 任何系统都会有一个或多个冗余系统做备份
  2. 对故障的检测和恢复. 检测故障以及用备份的结点接管故障点, 也就是 “故障转移”
    1. keepalived
    2. zookeeper
  3. 需要很可靠的交汇点 (CrossOver). 这是一些不容易冗余的结点, 比如域名解析(存在缓存问题)等.

服务高并发(并发与性能)

  • 概念

    • 理解 I/O 的概念
    • 理解 “同步/异步”、“阻塞/非阻塞”
    • 异步模型并不会消灭阻塞,而是在发生 I/O 阻塞时切换到其他任务,从而达到异步非阻塞
  • 计算密集型

    • CPU 长时间满负荷运行, 如图像处理、大数据运算、科学运算等
    • 计算密集型: 用 C 语言或 Cython 补充
  • I/O 密集型

    • 网络 IO, 文件 IO, 设备 IO 等
    • Unix: 一切皆文件
  • 多任务处理

    • 进程、线程、协程调度的过程叫做上下文切换
    • 进程、线程、协程对比
    名称资源占用数据通信上下文切换 (Context)
    进程不方便 (网络、共享内存、管道等)操作系统按时间片切换, 不够灵活, 慢
    线程非常方便按时间片切换, 不够灵活, 快
    协程非常小非常方便根据I/O事件切换, 更加有效的利用 CPU
  • 全局解释器锁 ( GIL )

在这里插入图片描述

  • 它确保任何时候一个进程中都只有一个 Python 线程能进入 CPU 执行。

  • 全局解释器锁造成单个进程无法使用多个 CPU 核心

  • 通过多进程来利用多个 CPU 核心,一般进程数与CPU核心数相等,或者CPU核心数两倍

  • 协程

    • Python 下协程的发展:

      • stackless / greenlet / gevent
      • tornado 通过纯 Python 代码实现了协程处理 (底层使用 yield)
      • asyncio: Python 官方实现的协程
    • asyncio 实现协程

      import asyncio
      
      async def foo(n):
          for i in range(10):
              print('wait %s s' % n)
              await asyncio.sleep(n)
          return i
      
      task1 = foo(1)
      task2 = foo(1.5)
      tasks = [asyncio.ensure_future(task1),
              asyncio.ensure_future(task2)]
      
      loop = asyncio.get_event_loop()  # 事件循环,协程调度器
      loop.run_until_complete( asyncio.wait(tasks) )
      
  • 结论:通常使用多进程 + 多协程达到最大并发性能

    • 因为 GIL 的原因, Python 需要通过多进程来利用多个CPU内核
    • 线程切换效率低, 而且应对 I/O 不够灵活
    • 协程更轻量级,完全没有协程切换的消耗,而且可以由程序自身统一调度和切换
    • HTTP Server 中,每一个请求都由独立的协程来处理
  • 单台服务器最大连接数

    • 文件描述符: 限制文件打开数量 (一切皆文件)
    • 内核限制: net.core.somaxconn
    • 内存限制
    • 修改文件描述符: ulimit -n 100000
  • 使用 Gunicorn 驱动 Django

  • 分清几个概念(面试题)

    • WSGI:
      全称是 WebServerGatewayInterface, 它是 Python 官方定义的一种描述 HTTP 服务器 (如nginx)与 Web 应用程序 (如 Django、Flask) 通信的规范。全文定义在 PEP3333
    • uwsgi:
      与 WSGI 类似, 是 uWSGI 服务器自定义的通信协议, 用于定义传输信息的类型(type of information)。每一个 uwsgi packet 前 4byte 为传输信息类型的描述, 与 WSGI 协议是两种东西, 该协议性能远好于早期的 Fast-CGI 协议。
    • uWSGI:
      uWSGI 是一个全功能的 HTTP 服务器, 实现了WSGI协议、uwsgi 协议、http 协议等。它要做的就是把 HTTP协议转化成编程语言支持的网络协议。比如把 HTTP 协议转化成 WSGI 协议, 让 Python 可以直接使用。
    HTTP Server  => 负责 1. 接受、断开客户端请求; 2. 接收、发送网络数据
        ^
        |
        v
      WSGI       => 负责 在 HTTPServer 和 WebApp 之间进行数据转换
        ^
        |
        v
    Web App      => 负责 Web 应用的业务逻辑
    

压力测试

  • 常用工具
  • Web 系统性能关键指标: RPS (Requests per second) 每秒处理的请求数
  • 其他指标:
    • 响应时间
    • 吞吐量
    • QPS (每秒响应请求数,在互联网领域,这个指标和吞吐量区分的没有那么明显)
    • 并发用户数
    • TPS (每秒处理事务数, 数据库指标)
  • Ubuntu 下安装 ab: apt-get install apache2-utils
  • 压测: ab -k -n 1000 -c 300 http://127.0.0.1:9000/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值