JAVA基础
JVM
设计模式
技术栈
Redis(Remote Dictionary Server(远程数据服务))缓存
Redis是基于内存的高速缓存key-value数据库(C语言开发)
优点:
1.基于内存读写速度快,可以支持高性能的业务场景
2.支持丰富的数据结构(String,hash,set,list,sort)
3.QPS可以达10万+
缺点:
- 数据不一致
- 缓存雪崩
- 缓存穿透
- 缓存并发
- 数据库容量受到物理内存的限制,不能用作海量数据的高性能读写
数据不一致问题(mysql+redis)
业界方案:监听mysql的binlog日志,异步淘汰缓存
缓存雪崩(大量缓存同时失效,导致直接查DB,导致DB压力太大奔溃)
业界方案:将热点数据设置不同的过期时间,以防止同时查询热点数据给数据库带来压力
缓存穿透(针对用户恶意攻击)
在查询缓存没有值,再查询mysql也没有值时,会将此key的value设置为null,并添加六十秒过期时间
业界方案:布隆过滤器(存在误算率,随着存入的元素数量增加,误算率也随着增加)
布隆过滤器的思想:核心是实现了一个超大的位数组和几个哈希函数,每一个元素,都调用这几个哈希函数算出哈希值,并落到这个数组中,随着元素的增加,哈希值的相似度就会升高,误判率就会出现
Redis热点key的寻找方案
redis于4.0.3版本开始正式支持基于LFU的热点key发现机制。
Least Frequently Used——简称LFU,意为最不经常使用,是redis4.0新增的一类内存逐出策略,从LFU的字面意思我们很容易联想到key的访问频率,并对访问频率进行了统计
可以对概率因子和衰减因子进行配置,推荐使用redis的默认值即可:
lfu-log-factor 10
lfu-decay-time 1
要注意需要先把内存逐出策略设置为allkeys-lfu或者volatile-lfu,否则会返回错误
redis 4.0.3同时也提供了redis-cli的热点key发现功能,执行redis-cli时加上–hotkeys选项即可,示例如下:$./redis-cli –hotkeys 排在前面就是热点key
Redis和Memcache对比
|
Redis |
Memcache |
数据结构 |
多种数据结构:String,hash,set,list,sort |
Key-value |
集群模式 |
Redis自带(redis cluster) |
客户端自己实现 |
线程模式 |
单线程(小数据量性能好,可以持久化) |
多线程(大数据量100M性能好,不能持久化) |
MQ(Message Queue)消息队列
MQ:是一种应用程序对应用程序传递消息的中间件,是通过读写出入队列来通信。
三种通讯模式 1.点对点,2.多点广播,3.发布和订阅(一般用这个)
优点:
1.异步:执行失败重试,提高接口的性能(失效策略;数据回补)
2.解耦:利用MQ降低系统的耦合性(系统重构)
3.削峰:将一些无需及时返回且耗时的操作提取出来,进行异步处理,从而节省服务器的响应时间来提高系统的吞吐量(秒杀,公司的活动:抢金币)
缺点:
1.MQ一旦挂了,整个系统就奔溃了(高可用)
2.系统的复杂度提高(消息堆积)
3.数据不一致(消息重复,消息顺序,消息丢了)
如何选型:RabbitMQ,RocketMQ,Kafka
Kafka是主要用于配合大数据类的系统来进行实时数据计算、日志采集等场景(主要支持简单的MQ功能)
我们一般在RabbitMQ和RocketMQ中间来选择
选择RocketMQ的理由(阿里出品):
1.topic可以达到几百,几千个的级别,吞吐量会有较小幅度的下降(RabbitMQ会大幅下降)
2.分布式集群,每个部分都可以水平扩展(RabbitMQ主从集群)
3.java开发(RabbitMQ用erlang语言开发)
4.吞吐量是10万级(RabbitMQ是万级)
缺点:
1.延时毫秒级(RabbitMQ是微秒级)
2.社区活跃度一般(RabbitMQ比较好版本迭代特别快)
MQ的高可用
RabbitMQ是镜像集群模式(主从)
Kafka是分布式集群(副本集,HA),每个节点都有一个replicate备份。读写都在leader节点
RocketMQ是分布式集群如下
Name Server:主要提供轻量级查找和路由服务(保存了其它三部分的信息)(各个节点之间不通信)
Broker Cluster:轻量的topic和queue机制(消息的存储,支持push和pull)
Product Cluster:分布式的producers通过负载均衡模型向broker发送消息
Consumer Cluster:支持push,pull,支持集群消费与消息广播同时提供实时订阅
MQ的消息幂等性(不重复)
造成的原因:1.系统重启 2.网络异常 3.消费失败
解决方案
- 消息的唯一标识存入redis中并进行判断
- 数据库的存储判断
MQ丢消息
- producter:发送消息状态超时或者失败,则会触发默认的2次重试(支持日志的索引查找)
- broker:是一主多从的节点,同时支持同步和异步刷盘的策略,保证消息落到本地内存中,消息也支持持久化到commitlog里面,即使宕机,未消费的消息也可以加载出来
- consumer:确保拉取到的消息成功消费,consumer自身维护了一个持久化的offset,消费成功后才会更新自己的offset,offset会持久化到本地,即使consumer挂掉重启之后可以继续拉取offset之前的消息到本地
MQ消息的积压
策略:超出了buffer,也可以丢弃,然后再从CommitLog中补数据
打开rocketmq的控制台查看是历史消费记录,如果是消息写入速度大于消息的消费速度,调整业务代码或对消费者进行扩容
Consumer消费消息出现问题,只能操作临时紧急扩容了,具体操作步骤和思路如下:
1)先修复consumer的问题,确保其恢复消费速度,然后将现有cnosumer都停掉
2)新建一个topic,partition是原来的10倍,临时建立好原先10倍或者20倍的queue数量
3)然后写一个临时的分发数据的consumer程序,这个程序部署上去消费积压的数据,消费之后不做耗时的处理,直接均匀轮询写入临时建立好的10倍数量的queue
4)接着临时征用10倍的机器来部署consumer,每一批consumer消费一个临时queue的数据
5)这种做法相当于是临时将queue资源和consumer资源扩大10倍,以正常的10倍速度来消费数据
6)等快速消费完积压数据之后,得恢复原先部署架构,重新用原先的consumer机器来消费消息
MQ消息的顺序
避开这种使用场景
数据库
Mysql事务默认(可重复读)
事务隔离级别 |
脏读 |
不可重复读 |
幻读 |
读未提交(read-uncommitted) |
是 |
是 |
是 |
不可重复读(read-committed) |
否 |
是 |
是 |
可重复读(repeatable-read) |
否 |
否 |
是 |
串行化(serializable) |
否 |
否 |
否 |
脏读:一个事务读到另一个事务未提交的更新数据
幻读:已提交的插入数据
mysql默认的事务隔离级别为repeatable-read
网络
URL解析统一资源定位符 (Uniform Resource Locator, URL)
调用链路
http://www.baidu.com(scheme:通信协议, host:主机, port:端口号)
DNS解析(DNS缓存)
TCP连接
发送http请求
服务器处理请求并返回http报文
浏览器解析渲染页面
连接结束
思考
秒杀设计思路
用户量不大的策略
队列+redis全局计数器即可
用户量大的策略(柔性服务策略)
- 前端处理95%的请求直接返回已经售光(前端随机数,矩阵,离散等概率算法)
- 全局计数处理
- 降级跳过非关键逻辑
- 中间错误异步修复
- 业务流程上可以通过:抢购预约码
有损服务的策略(列表页)
第一种策略
列表页分为三块,同时发起三个异步请求后端进行处理
第二种策略
A:搜索筛选项时,比如搜索海淀-知春路的帖子,只出海淀的帖子(维度高一些)
B:第三块是广告页可以选择不展示
C:列表页中的数据可以继续简化(简化埋点,日志,广告等业务数据)
D:筛选项可以进行15分钟一次的缓存刷新