关单操作?
- 优先考虑定时任务、Redisson+redis、RocketMQ延迟消息实现(订单量特别大的时候,不建议使用MQ)
- 每个订单都有一个消息会增加资源消耗
- 可靠性问题(丢失)
- 大量的无效消息
- 不是所有消息队列都支持
- 一般通过定时任务实现,像阿里内部就是超时中心(TOC)
- 定时任务:Timer、定时任务线程池、XXL-JOB这种
- 时间不精确
- 无法处理大量订单
- 扫描数据库造成压力大
- 分库分表后需要全表扫描
- Redisson+redis
- Redisson定义了分布式延迟队列RDelayedQueue,在zset的基础上增加了一个基于内存的延迟队列
- 当添加一个元素到延迟队列的时候,将数据和超时时间放进zset中,启动一个延时任务,当任务到期的时候,就将zset中的数据取出来,返回给客户端使用。
每天100w次登录请求,4核8G机器如何做JVM调优?
- 首先确定有没有流量高峰?假设存在某一段时间有峰值,比如30min,那么QPS就是600左右,应该做怎样的优化?
- 将堆内存设置为操作系统的一半。初始和最大设置成一样的,避免扩容收缩操作,提高稳定性。
- 垃圾收集器选择:
- 考虑STW和吞吐量的问题
- serial排除,parnew和parallel scavange更关注吞吐量,4G可以使用G1
- 通过-XX:MaxGCPauseMills=100~200之间
- 然后调节G1的一些配置,比如并行线程数,并发线程数
- 添加日志,动态调整
如果QPS提高了一百倍,应该怎么办?
- DDOS攻击
- 设计一个支持高并发的系统:
- 架构、性能优化、容错、可伸缩性等等
- 分布式架构:降低单点故障的风险,提高可伸缩性和性能
- 集群部署:负载均衡,提高可用性和性能
- 缓存
- 异步处理:消息队列等降低请求响应时间和提高吞吐量
- 预加载:预先加载需要的资源,减少等待时间
- 代码优化和调优:避免长事务、减小锁的粒度等,提高性能
- 数据库优化:索引设计、分库分表、读写分离
- 熔断降级限流:防止雪崩
- 压力测试
- 容错和监控
不使用redis分布式锁,如何防止用户重复点击?
- 滑动窗口限流
- token,判断token有没有被消费过,在数据库判断
- 前端按钮
- 一般redis使用不了一般是降级成直接使用数据库。
购物车功能?
- 不需要把商品的所有信息保存下来,只需要保存SKUID加上数量时间等,至于其他的到时候反查数据库就可以。
- 未登录用户存在cookie和LocalStorage里面
- 登陆的要么存数据库,要么存redis
- 数据库和redis各有好处,可靠性,性能权衡,mysql有事务机制。
秒杀系统?
- 高并发瞬时流量
- 架构方面做逐层的流量过滤,经过客户端、CDN、WEB、缓存、数据库
- 客户端做一些随机请求的过滤
- Nginx做一些流量的过滤,IP限流等等
- 服务器sentinel限流
- 查询操作写操作用缓存抗一下,缓存上本地缓存性能要高于分布式缓存
- 热点数据:
- 拆分+缓存
- 缓存就是做一些预热,不仅redis做预热,本地缓存也做预热,防止热点key问题
- 数据量大:
- 分库分表
- 库存正确扣减:
- 如何避免超卖少卖
- 从redis中取出当前库存,lua脚本执行达到原子性+有序性,redisson的信号量
- redis中先扣减,发一个MQ消息,之后再做真正的数据库扣减操作
- 导致少卖:
- 引入对账机制,比如用zset添加流水记录,定时拉取一段时间内的所有记录,然后数据库比对,发现不一致就进行补偿处理
- 如果商家在过程中补货了?
- 增加一个全局标志位,在补货过程中不允许扣减库存,补货的数量相应的去redis里更新,这样会导致用户停滞
- 订阅binlog,补了多少就去redis修改多少。
- 业务手段:
- 预约
- 预售
- 前端弄些验证码
Zset实现点赞和排行榜?
- 朋友圈点赞:
- 首先分析朋友圈点赞是什么功能
- 被点赞人的微信号
- 点赞人的微信号
- 点赞时间
- 通过zset实现
- key被点赞人的这篇朋友圈的ID
- value表示点赞人的微信号
- score表示点赞的时间
- 点赞就更新score,jedis.zadd(key,cow,userId)
- 取消点赞就移除,jedis.zrem(key,userId)
- 查询就通过ZREVRANGEBYSCORE命令逆序返回点赞人的微信号
- 首先分析朋友圈点赞是什么功能
- 排行榜
- 在score相同时,会按照value排序
- 那么score设置为分数+(1-时间戳小数)
查找附近的人的功能?
- 通过Redis的GEOADD将用户的经纬度存在一个指定的键值中,然后通过redis的GEORADIUS命令查询指定经纬度附近一定范围的用户。
消息队列推好还是拉好?
- 推模式就是在消费端和消息中间件建立TCP长连接或者注册一个回调,有数据就通过长连接或者回调将数据推送
- 拉就是消费者轮询,通过不断轮询检查有没有数据。
- 拉可以自己掌握消息数量和速度,但是轮询有对中间件有一定的压力
- 推消息是实时的,缺点就是如果生产速度大于消费速度消费者会产生堆积,容易压垮。
- 看消费者和消息中间件是不是双向通信。
- 使用长轮询:发起一个长轮询请求,有消息就返回,没有就等一会儿,等到有新消息到达。还没有就等下一次长轮询。
如何进行SQL调优的?
- 首先定位到慢sql的地方
- 接下来分析
- 索引失效:查询执行计划是否执行了索引
- 多表join:嵌套循环,外循环的每条记录都要和内循环的记录做比较,n张表就O(N^n)的复杂度。Mysql8中增加了Hash join,驱动表的数据会构建一张hash表,然后被驱动表的去进行匹配,最后聚合,但是有内存限制,此时就可以通过基于磁盘的hash joi,分批加载,到达O(N)的复杂度。
- 索引离散度低:
- 查询字段太多:避免冗余查询
- 表数据量太大:建立索引不一定能解决了,通过数据归档,比如只保留半年内的数据,或者说是分库分表、分区。
- 数据库连接不够:业务量大就分库,慢SQL、长事务,并发大的情况下存在排队,就可以像上迷案的秒杀服务那样解决。还有一个改造Mysql,比如阿里的Inventory-Hint。
- 表结构不合理:做一些反范式化,冗余字段,避免join。
- 数据库参数不合理,增加事务文件大小,缓冲池大小,read线程数
- 参数调优
不用synchronized实现线程安全单例?
饿汉可以,静态内部类、枚举也可以,还能用CAS实现,但是其实loadclass就是synchronized修饰的。
private static final AtomicReference<Lazy> INSTANCE=new AtomicReference<>();
//CAS实现
//原子性可见性有序性都保证了,但是会造成CPU开销
public static Lazy casInstance(){
while (true){
Lazy singleton = INSTANCE.get();
if (null!=singleton){
return singleton;
}
Lazy ans = new Lazy();
if (INSTANCE.compareAndSet(null,ans)){
return singleton;
}
}
}
本地缓存和分布式缓存有什么区别?
- 两种不同的缓存架构,主要区别在于数据的存储和管理方式
- 本地缓存是指将数据存储在单个应用程序中,提高性能,减少数据库访问次数,但是在集群环境中,多个本地缓存中数据可能不一致。Caffeine,异步化比较好
- 分布式缓存的优点在于共享数据,提高系统的可伸缩性和可用性,但是有数据一致性、故障恢复,管理和维护成本。
多级缓存是怎么应用的?
- 客户端缓存、CDN缓存、Nginx这两个放静态资源,然后本地、分布式缓存
Innodb用跳表,redis用B+数可以吗?
-
关系型数据库以表的形式存储,非关系型以key-value的形式存储
-
B+磁盘友好(顺序性,以及磁盘预读,页分裂时就读取或者修改一页),跳表内存友好(多级索引结构,磁盘IO性能低)
接口很慢如何定位问题?
- 阿里的arthas定位,比如是哪个商品相关的,然后分析SQL,进行SQL调优
如何保证REDIS中的数据都是热点数据?
- 数据预热,先将热的数据先加进去
- 热点数据更新:热key检测
- 过期策略:LRU或者LFU
- 缓存淘汰策略
用了一锁二查三更新,为什么还有重复数据?
- 存在锁已经释放了,但是事务还没提交,然后后面进来的接着操作。
- 主要就是因为事务的粒度大于锁的粒度
- 声明式事务@Transactional改为编程式事务
一个接口QPS3000,接口RT为200ms,需要几台机器?
- 那么就是单线程一秒处理5个请求,假设tomcat有200个线程,那么吞吐量就是1000个/s
- 实际需要做压测,然后预估2-3倍数,大概6-9台机器。
商城系统如何设计一个数据一致性方案?
- 比如下单的时候需要有订单系统、库存系统、积分系统、邮件系统、外部机构这些组成
- 像完整的分布式事务的话:
- 订单系统和库存系统就考虑强一致性
- 积分系统考虑最终一致性
- 邮件考虑最大努力通知
- 像外部的话,很多因素影响,一般是在协议上约定:
- 风控通过,投保一定成功
- 先资金流理赔,再补齐信息流
- 每天异步同步一次就可以了
如何实现缓存预热?
- 启动预热:
- 定时任务:类似于秒杀活动,开始前一天先把相关数据放进redis里面
- 用时加载
- 缓存加载器:比如caffeine就有,定义一些机制
应用占用内存持续升高,堆内存、元空间都没变化,可能原因?
- bytebuffer使用直接内存,未回收
- 线程栈
- JNI或者本地代码