微布开发-热点动态缓存击穿
业务场景:热点动态中的某一条说说因为过期且当时大量用户请求查看动态详情,出现数据库查询压力骤增的情况,从而导致某一热点动态的缓存击穿的情况。
想法:1、 互斥锁:在热点数据的缓存失效时,可以尝试使用分布式锁来避免多个请求同时访问数据库。在获取锁的情况下,只有一个请求去加载数据并更新缓存,其他请求等待,从而减轻数据库的压力。
获取互斥锁: 当缓存失效时,多个请求会尝试获取一个互斥锁。如果只有一个请求能够成功获取锁,那么它将负责加载数据并更新缓存。
获取锁成功: 如果某个请求成功获取了互斥锁,它可以开始加载数据。在加载数据时,需要判断缓存是否已经被其他请求加载(可能在当前请求获取锁的过程中被其他请求加载了),避免重复加载数据。
更新缓存: 获取锁成功的请求负责加载数据并更新缓存。在更新缓存之后,释放互斥锁,让其他等待锁的请求有机会获取锁并使用更新后的缓存。
获取锁失败: 如果请求获取锁失败,意味着其他请求已经在加载数据和更新缓存了。这些失败的请求可以等待一段时间后再次尝试,或者直接返回默认值,以避免多次同时访问数据库。
伪代码如下:123456789101112131415161718 ...
Spring-DesignPattern
控制反转和依赖注入工厂模式单例模式代理模式模版方法观察者模式适配器模式装饰者模式
Spring-AOP
AOP(面向切面编程):就是把公共逻辑抽出来,让开发者更好的专注于业务逻辑的开发,AOP是OOP的补充,OOP是面向类和对象的,但是AOP是面向不同切面的,一个切面可以横跨多个类和对象去操作,极大提高开发效率。
例如一个订单的创建,可能需要下列四个步骤
1、权限校验
2、事务管理
3、创建订单
4、日志打印
如果使用AOP的思想,其实就可以把四个步骤抽象成四个切面,让开发者专注于第3个切面,其他的切面都用基础通用的逻辑(就是抽象出来的公共逻辑),统计交给AOP封装管理。
实现原理:通过代理模式实现,实现方式有两种,一种事基于Java原生的动态代理,一种是基于cglib的动态代理。
Spring AOP默认使用JDK的原生代理,可以代理任何接口,但是不能代理没有接口的类,所以使用cglib来实现动态代理没有接口的类。
AOP的业务场景:1、参数校验
当使用AOP思想实现参数校验功能时,你可以创建一个AOP切面来拦截需要校验的方法,并从HttpServletRequest中获取JWT参数进行校验。以下是一个基本示例:
...
Spring-IOC
什么是IOC所谓的IOC就是Inversion Of Control,也就是控制反转,其实就是对于某个对象A,原来的控制权在B手上,B想用就能用,想不用就不用,但是现在把控制权交还给了A,只有A给了别人权限才能用,这就是控制反转。
没有IOC的时候,举例如下:
1234567class A{}class B{ private A a = new A();//此时就是我们所说的控制权在B手上,也就是控制(不是控制反转) public void use(){ System.out.println(a);//此时B对A控制使用 }}
有了IOC时使用如下:
1234567891011@Component class A{}class B{ //此时控制权在A自己手上,可以直接使用,当然如果对象A没有注入到容器之中的话,B就不能使用。 @Resource private A a; private void use(){ ...
leetcode-k个一组翻转链表
题目描述:给你链表的头节点 head ,每 k 个节点一组进行翻转,请你返回修改后的链表。
k 是一个正整数,它的值小于或等于链表的长度。如果节点总数不是 k 的整数倍,那么请将最后剩余的节点保持原有顺序。
你不能只是单纯的改变节点内部的值,而是需要实际进行节点交换。
12输入:head = [1,2,3,4,5], k = 2输出:[2,1,4,3,5]
12输入:head = [1,2,3,4,5], k = 3输出:[3,2,1,4,5]
思路关键点:
局部翻转
k > 剩余局部链表长度时,这部分链表无需翻转
步骤:
初始化
ListNode dummy = new ListNode(0,head);
设置指针实现局部翻转
ListNode pre = dummy,end = dummy
end.next != null 则遍历链表
根据k确定第一组局部链表的尾部指针
for(int i = 0; i < k && end != null; i++) end = end.next;
此时end == null时,说明剩余的局部链表长 ...
面经-借钱包交易平台Java开发实习
如果对于jdk版本升级,对于jvm的一些参数修改有哪些?
-Xmx 和 -Xms:这些参数用于设置 JVM 的最大堆内存和初始堆内存大小。在 JDK 版本升级后,由于可能存在新的特性或改进,建议重新评估应用程序的内存需求,并相应地调整这些参数。
-XX:NewRatio 和 -XX:SurvivorRatio:这些参数用于调整新生代(Young Generation)和老年代(Old Generation)的比例和新生代中 Eden 区和 Survivor 区的比例。在 JDK 版本升级后,新的默认比例可能会有所变化,可能需要重新设置这些参数以优化垃圾回收性能。
-XX:+UseConcMarkSweepGC 和 -XX:+UseG1GC 等:这些参数用于选择不同的垃圾回收器。随着 JDK 版本的升级,可能会引入新的垃圾回收器或对现有的回收器进行优化,因此需要根据应用程序的特性和需求选择合适的垃圾回收器和相应的参数。
-XX:MaxMetaspaceSize:在 JDK 8 及之前的版本中,用于设置永久代(Permanent Generation)的最大大小。但从 JDK 8 开始,永 ...
微布开发-实现说说审核发布机制(暂未完成)
业务场景:调用微信三方接口进行图片/视频安全校验,由于微信的视频/图片校验结果是异步返回到服务端的接口,所以需要将附有照片或者视频的说说审核通过之后再将说说发布到论坛中。
问题分析:1、如何标识所有图片/视频审核完成之后再发布呢?
因为每次向微信的接口发送请求的时候,会对每张照片的审核都会有一个任务id(trace_id),根据这个traceid映射对应的is_valid(标识是否校验通过)和talkbid(说说的主键id)字段来标识
单独拉一张表出来存储图片url和trace_id的关系,然后用一个is_valid字段根据微信接口异步返回的结果标识判断是否校验通过,如果校验通过is_valid就变成1,还在校验过程中或者校验未通过就标识0。
使用Redis通过设置超时时间来使标识自动淘汰,释放内存空间
在说说表添加一个trace_id字段,存储每张照片的trace_id,并用逗号分隔开,每次微信异步返回结果之后如果审核通过就把trace_id和返回过来的trace_id部分删除,否则就不删除,同时判断此时trace_id字段是否为空,如果等于空值了,那么就说明全部校验通过了、然后将 ...
微布开发-优化UGC消息拉取响应速度
业务场景:小程序端消息通知tab页中点赞通知列表、新粉丝通知列表、评论通知列表等UGC消息接口响应速度高达7s左右,经排查问题优化之后响应时间从7s优化至200ms以内,效果展示图如下:
问题分析及排查:
索引问题?
刚开始以为是数据量太大且没有添加索引导致查询速度很慢从而导致接口反映速度很慢,但是一看数据量也不是很大,而且也有通过添加索引(是通过receiverBid(接受者的主键id)创建)的手段,并且通过explain语句分析我所写的语句走了索引,因此排除索引问题。
业务逻辑代码问题?
后面去查看业务代码、发现业务代码中除了分页查询UGC消息列表、还有一个同步的修改UGC消息读取状态的操作,也就是当用户拉取了UGC消息之后,将未读的记录转变成已读状态,一看到这里发现是两个同步操作,就赶紧通过打日志的方式判断查询操作和修改操作所耗时间,来进一步确定究竟是哪里出了问题,查看日志发现真的是因为修改操作耗时太多(为什么MySQL写操作比读操作慢?)导致的,我当时就想到了两个思路:
1、通过一个事务来进行批量的修改操作,不过还是采取同步,但是我感觉这样如果批量同步修改的 ...
微布开发-将说说记录的图片url单独提出来用一个表存储的设计
这样的目的是为了后续方便说说附带的图片进行修改以及调用三方接口校验图片是否违规。
大概表设计如下:
怎么转移说说表的pics字段的****url 到新的y_talk_images字段呢?
12345678910111213141516INSERT INTO y_talk_images (talk_bid, images_url, user_bid, trace_id, is_valid, is_delete, create_time)SELECT bid, SUBSTRING_INDEX(SUBSTRING_INDEX(pics, ',', numbers.n), ',', -1) AS images_url, y_talk.user_bid, NULL AS trace_id, 1 AS is_valid, 0 AS is_delete, y_talk.create_time -- 使用此图片对应的说说创建时间作为创建时间FROM (SELECT 1 n UNION ALL SELECT 2 U ...