一、从代码层面考虑
1.考虑线程安全问题,非原子代码都是线程不安全的代码
非原子的代码包括但不限于:(计算:对成员变量计算)
2.如何解决线程不安全的代码
3.锁的概念
3.1 悲观锁
3.1.1 JDK锁
synchronized
a:作用-->加到方法上,该方法就变成同步方法
b:原理->当第一个线程进入该方法时,在该线程外打上自己线程标识,执行完会删除标识,其他线程看到标识会等待上一个线程执行完,才会执行方法
lock
lock是一个接口只要有两个实现类
重入锁:ReetranLock
读写锁:(I/O)
3.1.2 分布式锁
a:为什么用分布式锁
在集群部署/分布式部署,JDK锁时锁不住的,只能加分布式锁
b:如何实现分布式锁
用redis来实现分布式锁
用redis实现分布式锁的原理-->利用redis中setnx指令实现的
用redis实现分布式锁的缺点-->
1.锁的时间不宜指定
2.删除锁的不是原子性操作
c:redisson框架实现分布式锁
lock.tryLock():锁的时间默认30s,有个watch dog机制
lock.tryLock(20,1,TimeUnit.SECONDS):
参数一:锁的时间,参数二,三:线程获取锁的时间
3.2 乐观锁
原理:CAS
比较并交换(在该数据之前,判断当前的数据是否等于提前读取出来的数据),如果条件不成立则证明该数据被其他线程修改了
使用场景:竞争(并发量)不高,可以考虑用乐观锁代替悲观锁
出现问题:ABA,只看开始与结果,中间被改变再改回来就无法察觉
如何解决:给变量加一个版本的字段
(update set num =30 where oldnum = num and oldversion = version)
二、接口性能问题
1.接口的数据一定要提前缓存起来
1.1 如何做缓存?
redis做缓存
1.2 用redis如何做缓存
a:查redis中有没有数据
b:查数据库
c:放入redis,要给有效时间(TTL->time to live)
1.3 用redis做缓存带来的问题
a:数据一致性问题。解决:采用延时双删(延迟的时间 200ms)
b:击穿:热点key失效。 解决:把查数据,和放缓存代码锁起来
雪崩:同一段时间内,大量key失效。 解决:缓存时间不一样
穿透:数据库,缓存都没有数据。 解决:1:缓存空对象。 2:布隆过滤器
2.后端服务器,集群部署
nginx:反向代理服务器 / 静态资源服务器(图片,前端的代码)
负载均衡:轮询,权重,ip Hash