高并发高可用学习笔记

高并发高可用学习笔记

高并发解决解决方案

系统层:将一个系统拆分成多系统

  • 将原来系统的模块,设计成新的子系统,单独部署,各个子系统之间,通过接口调用
  • Dubbo(待研究)

缓存层:遇到“读”瓶颈,使用缓存

为啥单线程的redis可以支撑高并发,效率比多线程的memcached还高?redis底层原理?

基础:socket网络通信原理
:redis和memcache区别:
	redis数据类型多,数据结构多
	memcached 原生不支持集群,自带集群模式
redis的单线程模型
	名词:file(文件) event(事件) handler(文件事件处理器)
	因为文件事件处理器,是单线程的,所以redis才叫单线程模型
	
	IO多路复用监听socket通信中产生的事件,并将事件放入到队列,
	文件事件分派器,根据socket通信内容,指派处理器
redis单线程模型能支撑高并发的原因:
	1:连接处理器,请求处理器,应答处理器,都是纯内存操作,快速处理
	2:文件事件处理器(IO多路复用程序),非阻塞(监听并不断插入队列)
	3:避免了多线程上下文切换

redis的数据类型,与对应的应用场景

  • 1:string kv 最简单的一种
  • 2:hash 对象,数组,改的时候,可以只改一个属性
  • 3:list 链表 可以模拟队列,分页 lrange
  • 4:set 程序部署在多台机器上,进行去重
  • 5:zset 有序集合,排行榜应用

redis的过期策略?

 定期删除(100ms随机抽取部分过期,并删除)
+惰性删除(查出过期,就删)
+ 配置一个内存淘汰机制(最近最少用)
1:缓存基于内存,不使用,会被热点数据挤掉
2:过期时间,需要加一定的随机性,防止雪崩
3:过期不代表,一定会删除,但是查是肯定查不到的

如何保证redis高并发高可用?

1高并发:集群(哨兵模式)几十万QPS
2高可用:持久化到磁盘
    如何重启恢复redis缓存数据    快照备份和日志备份
  • 主从复制的两种方式:
    1:将RDB快照文件写到磁盘,再传输到slave
    2:内存中快照文件,不存磁盘,直接传到slave
  • 主从加哨兵,什么时候会丢数据(master中最新数据没来得及复制到salve 就挂了)
  • 脑裂问题,如何减少数据丢失:主从之间断网 从自动选主,出现两个主 ,导致新主上,没有新数据 解决原理:min-slaves-to-write min-slaves-max-lag 控制slave延迟不能比master落后太多,会让master暂停写入,让client自己降级缓存,或者灌入kafka消息队列
  • 主观宕机 客观宕机 如何选举,如何自动修正其他slave配置
  • slave 不会自动过期可以 master过期key 会发删除命令到slave
  • backlog 是第一次做全量复制中断,后续做增量复制用的
  • 恢复备份时 会导致master run id 变化,触发slave会重新做 全量复制

缓存雪崩,穿透,击穿

  • 雪崩,大规模失效,如同时过期 ,某个缓存宕机
    事前,缓存必须高可用,redis多个slave 且多级缓存,系统内部有ehcache最热数据的缓存,大小约1G,然后是redis缓存,然后是MYSQL
    事中,本地ehcache缓存,加限流加降级 避免MYSQL被打死 限流2000QPS 其余3000QPS降级,返回友情提示,保证MYSQL不死,缓存恢复后,不再限流
    事后,redis 必须做持久化,后续可以快速恢复

  • 穿透,4/5请求(自己bug 或者黑客的假请求),缓存没有,库里面也没有 解决,库里面没查到,也将null写到缓存

  • 击穿,抗了很大并发,突然失效 ,解决:设置永不过期

缓存和数据库双写一致性问题:

  • 大并发写情况下,与一致性要求不高情况下的方案:先删缓存,然后写数据库
  • 大并发读写,且严格要求一致性,串行化读写,将相同商品ID的读写,哈希到同一服务器的同一内存队列中,并合并队列中的相同读操作,根据实际情况增加机器,保证相应时间

redis并发竞争问题 redis的CAS方案

白话:多个客户端,写同一个KEY,如何解决并发?  解决:分布式锁   且数据本身从MYSQL查出来的时候,要带时间戳,把时间戳,当成版本,对比,决定是否写入缓存

线上缓存实例情况

redis cluster  10台机器,其中5台机器部署了master ,且各挂载一个slave
5个节点	对外进行读写服务 每台机器5万QPS  共25万QPS
8核CPU +32G内存  1T磁盘  分配给redis的,是10G  共计50G
任何主实例宕机   salve自动切换为master
如果每条数据10Kb  10W条数据1G    可以存500万数据   常驻200W条
总redis内存 占用20G  不到50%

队列层:遇到“写”瓶颈,使用队列

队列的主要作用:削峰,异步,解耦

  • 削峰案例:将高于平时的大量数据,“储存”到队列中,慢慢处理;
  • 异步案例:写入延时过高,或者写并发过高,异步处理
  • 解耦案例:A子系统发布数据,各个子系统,按需订阅
如何保证消息队列高可用
rabbitMQ 高可用
  • 普通镜像模式:非高可用模式,单台宕机后,丢失消息(类似一致性hash实现的memcache,宕机一台,丢失缓存)
  • 镜像集群模式:普通模式的升级,每台机器的队列,都有完整备份,宕机后,备份机顶上,非分布式,但是高可用
kafka高可用
  • 本身的分布式高可用架构,多个partition(leader),每个partition都有至少一个副本(fellow),leader宕机,fellow顶上
如何保证消息的幂等性
  • 队列消息体中,单一业务消息,包含唯一消息ID,发送方生成,消费方判重
如何保证队列中消息不丢失
可能的丢失原因:
  • 1:写到队列时候的网络原因
  • 2:消息到了队列,队列内部出错,没保存下来
  • 3:队列保存好后,消费者没来得及消费,队列自己挂了
  • 4:消费者,拿到了消息,但是没有来得及消费,就挂了,队列以为已经处理完了
rabbitMQ解决方案
  • 发送失败
1:基于rabbitMQ的发送消息事务(类似MYSQL事务提交回滚),保证发送成功(缺点,阻塞,降低队列吞吐)
2:生产者调成confirm模式(回调机制,优化了上一种方式),生产者提供回调函数
  • 队列本身丢失消息:将队列的信息持久化到磁盘:
2.1(持久化Q)将队列设置为持久化,
2.2(持久化M)将消息的delivery Mode 设置为持久化,
这种情况下,还有风险,放到内存就挂掉,没来得及持久化,但是概率已经很低了。
  • 消费者丢失数据:原因:消费者打开了autoACK,处理:关闭自动应答,自己写代码应答(类似kafka应答)
kafka解决方案
  • kafka的leader和follower类似redis的哨兵模式的故障切换
  • 若leader倒下(消息到leader就倒下,没到follower),自动选举一个follower,导致的数据丢失
1:kafka服务端min.insync.replicas参数,大于1,每个partition至少两个副本
2:min.insync.replicas参数,大于1,要求每个leader至少感知一个follower存在
3:生产端设置acks=all这个是要求每条数据,都写入了leader和follower才认为写入成功
4:生产端设置retries=MAX  设置无限次重发送
		以上设置,可以实现,宕掉leader后,若leader还保有一个follower是可以正常工作的。即可保证kafka本身不会丢数据
	按照以上设置kafka生产者不会丢失数据
怎么保证从消息队列中拿到的数据按顺序执行
  • rabbitMQ
    问题场景:需要保证顺序消费的数据,被不同消费者消费
    解决:需要保证顺序性的数据,放置到同一个Queue,让同一个消费者消费
  • kafka
    生产者指定相同KEY,相同Key的数据,进行hash分发,会被按顺序放到同一个partition,kafka默认就是一个消费者,对应一个partition,若单线程,吞吐量不够,可以多线程消费
    若消费者是多线程并发处理,就会出问题
    此时,需要保证顺序的那几条消息,加入内存队列,给相同一个线程消费,类似rabbitMQ,才能进行多线程并发,加大吞吐量
几百万消息在消息队列积压了几个小时怎么办
原因:一般是消费者挂掉了
解决1:先修复消费者
	2:问题转变为如何快速消费所有数据
	2.1新申请一批机器,将原来消费者程序,改成新的生产者,新机器改为消费者,加速消费

	2.2 坑:MQ被设置自动过期,解决:写程序,想办法重现原来生产者发送的数据
	2.3 坑:MQ磁盘快爆了。类似2.1方式解决   ,或者消费者,消费完就扔掉,后续写程序结合2.2查漏补缺,实现快速消费

队列下的数据库写瓶颈:分库分表

分库分表(常用是水平拆分) 对订单ID,进行hash分发,分布式数据库,到不同库,解决库写不过来的情况

数据库分库分表中间件

sharding-jdbc (分布式事务,分库分表,读写分离,都支持,client___缺点耦合,维护成本低,升级成本高)  
mycat(代理____维护成本高,升级成本低)
cobar(代理)  TDDL(client) atlas(代理)

如何不停机将数据库迁移到分库分表

低级方案:公告,停机运维  ,停机,重新分发   中途没搞定,回滚到原来数据,第二天继续
高级方案:不停机双写方案

如何设计可以动态扩容的分库分表方案

低级:停机,重新迁移    上亿数据,维护时间超级长
刚开始做分库分表,规划三五年内够用
扩容原因:数据量太大的扩容,写并发太大的扩容
扩容方式:8台机器原来8个库,每个库8张表    将其中4个库4个表,迁移到新的8台机   相当于扩容两倍,但是库数量和表的总数没变,若使用 取模方法  获取库的位置,很方便迁移

分库分表以后,全局ID主键如何处理?

1:给一个表,专门插入一下,可以得到唯一自增ID,后续手动将ID设置为得到的ID  
	 缺点:单表成为性能瓶颈   适合并发低,但是数据量大的情况
2:redis 分布式锁  自增
3:snowflake算法

读写分离的原理,主从同步的延时怎么处理?

主从同步,为了支撑更多读写
	经验:   主库1000/S 写   几ms延迟     主库  2000/s  会有几十毫秒延迟   主库并发越高,延迟越久
	5.6版本以后,从库relay日志  可以多线程,速度稍快
半同步复制:semi-sync复制  主库写入数据,且至少一个从库获取到binlog日志,才算写入成功  这样保证不丢失数据
  • 原因:延迟问题:没读到,后续更新,代码以为读到,出现bug
  • 解决方案
      1:拆库,降低写入并发,降低延迟(所以这里是有效方案)
      2:并行复制,有点作用,但是不大
      3:写代码时,需要慎重,需要考虑,有主从延时。(这里是源头解决)
      4:若后续有更新操作,不要读了再更新,直接更新
      5:要求高的,直接读一下主库(不推荐)
    

缓存下的数据库读瓶颈:读写分离

搜索: 单机lucene,集群ES

其他问题

分布式Session

存redis

分布式事务

  • 方案一:两阶段提交方案(XA方案----此方案low,交叉访问了服务)
    第一阶段:先和各个子系统确认,是否正常 (团建前确认)
    第二阶段:完成事务 (执行团建)
  • 方案二:TCC方案(各个系统有自己的数据库,A系统,联系BC银行) 实现方案较复杂,维护成本高
    Try阶段:通过接口让B银行检查,前够不够,并冻住,让C银行检查,账户是否存在
    confirm阶段:A系统在自己数据库插入记录,调用B接口,扣款,调用C接口,转账
    cancel阶段:如果上面出问题,回滚,自己写代码,实现回滚
  • 方案三:本地消息表方案
    各自有自己的消息表,并且都有状态,然后自己检查状态,重发消息,
    消息处理好,通知别人,让别人改状态
  • 方案四:可靠消息最终一致性方案 3.2.6版本RocketMQ
    上个方案中,插入表以前,发prepare消息,插入成功后,发confirm消息,表的待确定,改为rocketMQ消息的待确定,待确定太久,rocketMQ会自动扫描,调用A系统回调,重发MQ,A系统,不断重发,总可以发成功,最终B也执行成功,整个系统需要保证幂等性
  • 方案五:最大努力通知方案 一定程度,允许分布式事务失败
    多次通知,通知多次后,即使失败,也不管了 如日志
分布式事务,会导致代码复杂十倍,平衡方案
平衡方案:监控代码,记录完整日志,事后人工修复,只有事务要求极高的地方采用这个分布式事务

订单,资金  这种做分布式事务
积分,订单信息,这种做监控,写日志

感谢–中华石杉—老师,给我进行扫盲

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值