• 架构设计优化


    假设有这样一个需求:
    建设一个类似51.com的社交网站,大概能承载亿级用户,每天大概有百万级活跃用户访问。一期至少主要包括用户注册、认证,用户间相互添加好友关系,
    可以建立朋友圈/分组功能。此外,还提供站内信功能,可以分享短篇文字,展示照片,可以对朋友的照片点赞等功能。分享的时候,可以设定可见朋友圈
    对象,哪些朋友(分组)可见,哪些朋友(分组)不可见。

    用户总量1亿
    月均活跃用户量 3000万
    日活跃用户峰值100万
    数据库QPS约2万
    100万人同时在线,峰值每用户触发2000次数据库request, 1000000*2000/86400 = 23148
    数据表至少10个,库总量约1T
      通行证
        • 用户资料,行均1K,100G
        • 认证,行均100字节,10G
      用户关系
        • 好友,行均100字节,10G
        • 分组,行均100字节,10G
        • 黑名单,行均100字节,10G
      消息中心
        • 收发消息,正反向2个表,行均1K,100G
        • 点赞,行均50字节,5G
      个人空间
        • 图片,行均100字节,10G
        • 微博短消息,行均1K,100G
      历史操作日志
        • 保守估计每天产生各种操作记录至少1000万,行均100字节,每天新增1G
    方案选择关键点
      • 单机 vs 多机
      • 单实例 vs 多实例
      • 单表 vs 多表
      • 单节点 vs 高可用
    上面这个业务,技术方案的难点
      • 单实例负载高,发生宕机时,若备用节点数据未预热,引发雪崩效应;
      • 高并发时,简单的SQL(count + 1,或者更新标记位),都可能引发负载飙升,大量锁等待;
      • 主库压力太大,从库无法及时跟上主库,发生故障时,无法直接快速切换;
      • 数据量大,不适合在主库上实时备份;
      • 数据量大,不适合在线实施DDL变更;

    为什么要拆分
      • 单实例/单库/单表上并发大
      • 单实例/单库/单表物理文件大
      • 单表大,在线DDL无法容忍
      • 出现性能瓶颈
      • 单节点出现抖动不稳定现象,影响全局
      • 充分利用机器的资源(MySQL利用CPU多核的特点决定)

    垂直拆分的原则
    1、 根据业务规划,区分不同功能模块;
    2、 按不同功能划分数据库/表,必要时,可进行拆分和冗余;
    3、 同时,也可能不完全纯粹垂直拆分,可以把几个功能中压力不均的库表放在同一个实例中,提高资源利用率。后期数据库出现性能瓶颈时,再将这些功能模块数据库表再次垂直拆分出去。
    垂直拆分的优点
      • 分而治之,精细化开发,程序&业务模块解耦
      • 应用程序模块清晰,容易定位
      • 数据库的拆分简单,容易理解
      • 个别功能模块出现问题时,不容易影响全局
    垂直拆分的缺点
      • 多个功能之间不能进行join,需要靠程序/中间件完成
      • 需要考虑在每个功能DB前引入数据访问层,基于API对外提供服务,这样以后每个功能的DB拆分也可以做到对外透明
      • 事务控制需要借助于消息队列进行控制(程序层减依赖)
      • 对于功能中特别大的表还有可能存在性能瓶颈
      • 过渡拆分会造成管理复杂

    水平拆分的原则
    (垂直拆分完毕后,或者未拆分时)单表读写压力还是太大,或者单表数据量太大,不利于日常管理和业务扩展,这时候就需要考虑进行水平拆分了。
    水平拆分优点
      • 同一个功能内的关连,事务操作都可以进行
      • 不会存在超大规模的表
      • 应用程序端改动比较小
      • 拆分规则设计的好的情况,较难触到性能瓶颈,也比较易扩展
    水平拆分的缺点
      • 数据分散,group by ,order by , sum, count等排序,聚集函数不能支持,如果一定需要,需要某一个地方存全量冗余数据/统计数据
      • 分片过多,会造成维护难度增加,比较定位(要求分区尽可能的简单)
      • 后期迁移、扩容、增加节点较复杂
      • 分表的方式需要比较综合权衡考虑,避免对后期再次扩展的影响

    user_id%16--(00-15)
    group_id hash(user_id)
    msg_id range

    分布式数据库设计方案介绍
    类似用户类数据,可以对user_id按hash或是range进行拆分
    拆分的路由规策,可以只细分到库级别,也可细分到表级别,或者同时细分到库和表
    例如:根据分区键 user_id 拆分,计划拆分为16个子节点
    - 只细分到库级别,例如根据user_id%16=N,对应到N个分库上
    - 只细分到表级别,例如根据user_id%100=N,对应到N个分表上
    - 如果需要同时分库分表,例如先分10个库,每个库再分10个表,共100个分表,可以先根据 user_id&get;&get;1%10=N分成N个库再根据user_id%10=N分成N个表。
    例如,user_id = 12345,则最终定位到上user_DB_02.user_table_05
    (12345&get;&get;1)%10 =&get; 2 --位移运算
    12345%10 =&get; 5

    • 有些情况下,可以基于时间维度进行拆分,例如日志归档类数据,或者冷热数据分离
    • 在处理中可以考虑分为,每天一表,每10天一表,月度表,季度表,半年表,年表,历史归档表

    redis相比memcached
    优点
    1、redis具有持久化机制,可以定期将内存中的数据持久化到硬盘上。
    2、redis具备类似binlog功能,可以将所有操作写入日志,当redis出现故障,可依照binlog进行数据恢复
    3、redis原生支持的数据类型更多,使用的想象空间更大。
    总体来讲,TPS方面redis要高于mongodb
    mongodb支持丰富的数据表达,索引,最类似关系型数据库,支持的查询语言非常丰富

    适合redis、memcached的场景
    1、频繁重复的简单,数据变更很少的SQL
    2、计数器类统计,每次++;
    3、缓存一些不经常变化的数据;
    4、频繁数据库查询结果缓存;
    5、业务端临时处理结果,汇总后批量回写;
    6、空结果缓存,避免数据库雪崩;

    利用Redis为MySQL减压
    - string类型,计数器 count incr 1,快速计数,缓解update压力
    - hash类型,K-V数据缓存,user_N-&get;{id:1,name:yejr,age:25},缓解读压力
    - list类型,pop/push,可作为消息队列,或者取最新TOP N数据,缓解读压力
    - set类型,无需唯一集合,去重操作,缓解读压力
    - sort set类型,有序唯一集合,可以作为排行榜用途,缓解分组统计读压力

    利用mongodb为MySQL减压
    - 非严格schema场景下,甚至可以取代MySQL,例如一些小游戏
    - 长记录cache,例如用户数据
    - 大尺寸、低价值数据写入、分析,例如操作日志
    - 需要快速扩展计算节点
    - 分布式运算任务

  • 相关阅读:
    jq-demo-阻止冒泡,阻止默认行为
    jq-demo-轮播图
    jq-demo-点击选择(英雄联盟)
    jq-demo-tab切换
    jq-demo-拖拽
    hdu 4031 Attack 线段树
    codeforces 633C. Spy Syndrome 2 hash
    sublime模式下开启vim并修改esc
    codevs 1256 打鼹鼠 LIS
    codevs 1455 路径 计算m^n%p
  • 原文地址:https://www.cnblogs.com/yhq1314/p/10684992.html
Copyright © 2020-2023  润新知