2023业务总结笔记

一、线程的七个参数?
1.核心线程数 CUP密集型:cpu核心数加1,io密集型:2*cpu核心数
2.最大线程数
3.线程工厂
4.线程三大队列:LinkedBlockingDeque(链表同步阻塞队列)、ArrayBlockingQueue(数组同步阻塞队列)、SynchronousQueue(同步阻塞队列)
5.拒绝四大策略: DiscardPolicy 默认忽略,抛出异常AbortPolicy ,DiscardOldestPolicy 丢弃最老的任务剩下任务给线程处理,
CallerRunsPolicy调用线程中的execute方法执行,异步变成同步.

二、在CSC中的实际的应用场景:商品版本管控刷新,
在接口自定义:
@Async(value = “commonExecutor”)
定义注解加上 @Configuration,@EnableAsync
核心线程数设置为8,cpu核心数是4,
最大线程数设置为 10
线程存活时间60s,
线程工厂:LinkedBlockingDeque(链表同步阻塞队列)小于线程池大小+队列部分放入runnable立刻执行,剩下放入runnable阻塞队列当中,大于的话则直接抛异常
拒绝策略是 DiscardPolicy忽略

(CPU密集型:核心线程数 = CPU核数 + 1
IO密集型:核心线程数 = CPU核数 * 2)

三、.ThreadLocal 的内存泄漏问题是什么?如何解决?
ThreadLoal用到 是map数据结构存储,key线程对象,是弱引用,而value是对应值是强引用,弱引用在触发GC后会被回收,
那么可能会出现Map的key为null,value有值,出现内存泄漏,
所以因此应该在ThreadLocal在GET或zet之后调用remove方法,或者把threadLocal设置为 private static类型、

四、线程调用start和run的区别是什么?
线程的状态: 新建-就绪-阻塞-运行-死亡
start是让线程处于就绪状态相当于排队,并没有运行,当得到cup的时间片,就开始执行run方法,具有异步执行的效果,
而run方法是是thread类中的一个方法,相当于线程的任务处理逻辑的入口方法,它是一个线程体具有同步执行的效果,

五、实际工作中是如何使用多线程的?
在service实现的接口上加注解:
用注解 : @Async(value = “commonExecutor”)
使用 CompletableFuture.supplyAsync()来实现运行多线程,
用 CompletableFuture.allOf().join()来阻塞线程

六.实际工作中你是如何改动jvm调优的?
设置java虚拟机堆区内存初始内存分配的大小 -Xms X m x : − 6 g , j a v a 虚拟机堆区内存可被分配的最大上限 − X m x {Xmx:-6g}, java虚拟机堆区内存可被分配的最大上限 -Xmx Xmx:6g,java虚拟机堆区内存可被分配的最大上限Xmx{Xms:-6g},删除 JAVA_OPTS_CMS定义
JAVA_OPTS_MEM=“-XX:+UseG1GC -Xmx X m s : − 6 g − X m s {Xms:-6g} -Xms Xms:6gXms{Xmx:-6g} -XX:ThreadStackSize=128k -XX:+UseStringDeduplication -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=256m "
JAVA_OPTS_GC=”-XX:+PrintGCDetails -XX:+PrintGCDateStamps -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=100 -XX:GCLogFileSize=10M -Xloggc:logs/gc-$SRV_NAME-%t.log -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=logs/heapdump.hprof "

七.为什么使用G1垃圾回收器?

首先我们的CSC系统的生产环境是JDK8,内存是8g。
基于一下三点考虑用G1回收器
生产环境是JDK8。内存是8g。所以用G1垃圾回收器,如果内存是4G的生产环境则用CMS垃圾回收器,
1.G1调优参数比较少,使用很少的参数可以达到不错的GC吞吐量和AVG停顿时间。
G1触发YongGc的频率会大于CMS而,缺点是时间耗时会长一点,
2.G1的新时代大小不是固定不变的,会根据应用动态伸缩。这样好处是我们不需要根据是批量导入导出,还是ocp应用配置多套JVM参数
3.JAVA9及以后将废除CMS垃圾回收算法,使用CMS不利于未来JDK升级。

八.什么是jdk8的元空间?为什么要用它?

jvm内存区域分为五大块,分别是 方法区,java虚拟机栈(进程),本地方法栈,堆(线程),程序计数器,

在java堆里面jdk1.8之前是分为新生代1:老年代3,而新生代里面的又又S0:S1:E区(1:1:2) ,垃圾回收方式用的是复制回收方法【标记清楚,标记整理,复制回收,分代回收】,
其中,方法区(永久代)和老年代捆绑无论谁满了都会触发GC,内存变化导致OOM场景过多,
为了解决这个问题那么,jdk1.7就做过优化把字符串常量池,静态变量移出了永久代,放入到堆中。
而到来1.8,则把永久代还剩余的内容移到了一个新的地方,那就是元空间(基本数据类型,类信息)。
这样可以避免经常OOM的场景,

九.为什么-Xms设置初始Java堆大小6g,而-Xmx设置最大Java堆大小6g
生产环境的物理内存是8G,本应该设置4g的堆大小,但是由于实际环境,会有非堆内存或者本地内存占用空间,
则应该把堆大小设置为6G

十.高并发处理什么业务场景?你是如何解决的?
对于多个人提交审批单据,可能出现网络延迟,用户多点两下,就会出现重复单子,
增加redis锁,本质是StringRedisTemplate redisTemplate;对redis加key和设置默认失效时间

十一.Redis+lua实现业务和事务的逻辑开发原理?重点执行的是什么?

十二.切面编程涉及哪些?
日志切面主要是涉及对特定的价格模块发送操作日志,

定义切点【@Pointcut 扫描类路径】->
横切逻辑【@Around指定执行pointcut方法象】->
织入 【用 ProceedingJoinPoint 类对获取执行方法前后的 getArgs 方法获取入参出参,执行方法内容用proceed,
其中对于加了注解的方法 用切点对象的getAnnotation方法获取】
在织入中拿到注解描述的类型,新增,删除,修改 还有拿入参出参对操作日志的发送。

我做的是写一个自定义的接口,
用@interface 定义一个注解接口RepordOperate

再用@Pointcut方法定义扫描的路径,然后用@Around指定执行pointcut方法,在切点
并且在写一个

十三.设计模式涉及哪些?

十四.代码的简洁之道几大原则?
单一,开闭原则,
里氏替换,依赖倒置,
接口隔离原则 ,迪米特法则

十五.多线程的应用场景?
使用商品版本管控刷新

CompletableFuture.supplyAsync(())
CompletableFuture.allOf(futures.toArray(new CompletableFuture[futures.size()])).join()

异步功能使用多线程?

十六.HashMap的扩容机制和原理?

十七.工厂模式:基于类的继承,和接口的多实现 一个方法解决一个复杂问题,复杂简单化,如对数据输出的模板化拼接

十八.策略模式: 类的继承,和接口的多实现 , 一个方法可以解决多个问题 。如消除多个if判断,判断输入是数字,英文,汉子等情况

十九.适配器模式: 是通过继承类实现接口完成适配,如220v电压转成5v电压

解释Explain得到的结果

  1. type 反应查询语句的性能
    我们主需要注意一个最重要的的 type 的信息很明显地体现出是否用到了索引:

type 结果值从好到坏依次是:

system > const > eq_ref > ref > fulltext > ref_or_null > index_merge > unique_subquery > index_subquery > range > index > ALL

一般来说,得保证查询至少达到 range 级别,最好能达到 ref 级别,否则就可能出现性能问题。

  1. possible_keys: SQL查询时用到的索引。
    可以看到,没加索引时,possible_keys 的值为 NULL,加了索引后的值为 address,即用到了索引address(索引默认为(column_list)中的第一个列的名字).

  2. key 显示SQL实际决定查询结果使用的键(索引)。如果没有使用索引,值为NULL
    可以看到,没加索引时,key 的值为 NULL,加了索引后的值为 address,即决定查询结果用到了索引address

  3. rows 显示MySQL认为它执行查询时必须检查的行数
    可以看到,没加索引时,rows 的值为17,即数据表student中所有数据,说明没加索引时的SQL查询是全表扫描;

加了索引后,rows 的值为6,数据库表中address以“北京市”开头的一共也就6条,SQL在执行查询操作时,一共也检查了6行,不必进行全表扫描查询,可以很容易得出结论:加索引的SQL查询性能远高于不加索引的情况

二十、spring是如何解决循环依赖的?
bean的生命周期是 实例化,属性复制,初始化,销毁
spring创建bean会有三个对象,一个是singleObjects 单例对象,一级缓存存放的是单例对象,已经完全初始化好的对象,
还有earySingleObjects 二级缓存对象存放原始bean未填充属性,singleFactory,单例工厂三级缓存放的就是最开始实例化对象入单例工厂当中,
以此解决循环依赖的问题

18.7-19.7-20.7-21.7-22.7-23.7
18年.7月-20年.3月,深圳安达研创公司做物流系统,负责海关清关模块开发,对货物的分组,商品描述的翻译,报文xml文件解析,还有相关pdf证书的导出功能,
20年.4月-21年.11月 深圳长亮科技做大总账银行管理系统,
21年.12月-23年.3月 南昌叶子科技,

CSC全球渠道管理系统,开发打造标准统一的,全球化的、多组织的交易平台,支撑CRM领域欧加集团的交易务,
并通过提供标准开放API以满足各国家、代理的灵活需求
渠道供应链平台核心能力为订单流(合同流),物流,资金流,信息流,发票流,政策流。平台按照全球化,多组织设计

主要是全球销售管理系统价格模块的主体开发负责人,此系统主要针对的是工厂对一代的代理商发货相关管理,
其中对商品手机/IOT的需要对国内外不同区域,设置不同的价格给客户去定价格,
设置临时价作为参考价,基线价作为销服的基准价格,出货价作为正式价,提供了调价功能可以可以修改正式价

二十一、MVVC是什么?
他是mysql在并发场景下,通过隐藏字段比如undolog,readview部分组成,主要还是在行数据加上版本号,
MVCC是MySQL在并发场景下,为了避免读写冲突的一种实现机制。其有隐藏字段、undolog、readview几部分组成。核心是在每一行的数据上添加一个版本号,以达到并发控制

二十二、MQ如何保证消息不被重复消费?

二十三、发生OOM,什么命令查看线程,进程这些?

二十四、dubbo如何保证异步同步?
首先dubbo底层是用netty的NIO的异步通讯机制,
基于此dubbo有下面几个调用的方法?
同步调用和异步调用:
Consumer 配置:
<dubbo:reference id=“asyncService” interface=“com.alibaba.dubbo.samples.async.api.AsyncService”>
<dubbo:method name=“goodbye” async=“true” return=“false”/>
</dubbo:reference>
用dubbo标签配置 return=“false”,实现异步调用,不写默认是同步调用
参数回调:
Dubbo Consumer 端发起调用后,同时通过RpcContext.getContext().getFuture()获取跟返回结果关联的Future对象,然后就可以开始处理其他任务;当需要这次异步调用的结果时,可以在任意时刻通过future.get(timeout)来获取。

sent=“true” 等待消息发出,消息发送失败将抛出异常;
sent=“false” 不等待消息发出,将消息放入 IO 队列,即刻返回。
事件通知:

二十五、设计一个双十一的抢茅台的系统你如何设计?考虑哪些点?url是如何设计?(假设qps是10w)

首先这是要应对个高并发的场景。会采用分布式的系统进行设计
拆分为商品主数据,订单服务,库存服务,支付模块服务
部署到,K8S容器平台的支持自动扩容,
扩容,限流,缓存三大方向
扩容方向而言现在基本都是K8S容器化自动部署,因此可以让服务自动扩容,
限流方面而言:对于刷子或者恶意的黑客攻击这种无效的流量这是可以用ngix或者spring cloud gatway进行限流10W限制到1w
对于有效的10w的qps的请求,则会进入到redis集群当中,对于单个redis的集群吞吐量是2w的。一般设计10主10从的集群部署,
应对10w的并发,如何并发的热点key相同这要用本地缓存。如caffine缓存框架使用了 w-tinylfu 策略是要缓存命中率会高很多,
在这里插入图片描述
发问一级缓存caffeine ,如果 没有找到,再访问 二级缓存 redis 集群

缓存放的数据一般是爆款商品的skuId,店铺id,仓库id等这些和sku相关维度的信息。
目前的redis换成加+本地缓存还是存在问题:
1.HotKey占用大量的Redis CPU时间,使其性能变差并影响其它请求;
2.在抢购、秒杀活动中,由于商品对应库存Key的请求量过大,超出Redis处理能力造成超卖
3.HotKey的请求压力数量超出Redis的承受能力造成缓存击穿,此时大量强求将直接指向后端存储,将后端存储打挂并影响到其它业务;

难点其实在于对于HotKey的探测探索并将HotKey放到本地内存的问题,如果,hotkey找的好那么放到内存缓存中效率会大大提升
这边可以用一个级缓存实现方案TMC:
TMC的优点是引入了一个Hermes-SDK它有自己的,独立线程池+有界队列,保证事件上报&监听的I/O操作与业务执行线程隔离,即使出现非预期性异常也不会影响基本业务功能;
进来一个key会先发往 Hermes询问是否为热点key是的话则直接内存缓存中取,不是的话则是从缓存集群中取,key变更或者失效都会进行广播保证集群的最终一致性。
TMC 热点发现流程分为四步:
数据收集:收集 Hermes-SDK 上报的 key 访问事件;
热度滑窗:对 App 的每个 Key,维护一个时间轮,记录基于当前时刻滑窗的访问热度;
热度汇聚:对 App 的所有 Key,以 的形式进行 热度排序汇总;
热点探测:对 App,从 热 Key 排序汇总 结果中选出 TopN 的热点 Key ,推送给 Hermes-SDK;

然后进入到商品服务,通过fegin远程调用调用订单服务,库存服务,下单扣减库存,余额等。
对于下单,扣减库存情况要加上redis分布式锁,
对库存更新,用update set stock = stock-1 where id=1 and version=1
对应插入操作和更新操作,先执行插入,再执行更新,这样锁住的数据库的范围会更小。

对应分布式事务问题可以用两阶段提交或者三阶段提交
主要的角色是有一个事务协调者对事务进行控制最终是否提交或者回滚,角色是两个CanCommit,和DoCommit,比如参与者A,参与者B事务发起请求,都要经过协调者收到提交成功的信息返回给参与者,才能再进行提交成功。

TCC是一种两阶段提交的变种,try尝试阶段把订单状态设置为支付中,设置,可用库存数量=库存数量-1,
try成功这执行commit,库存数量=可用库存数量,
try失败的话则执行cancle 可用库存数量=库存数量
,这样可以保证数据最终一致性也就是base理论

缺点也很明显就是参与者需要等协调者返回可以提交的信息才能提交成功,网络延迟或者服务器done机都可能导致资源同步阻塞那,一个事务一直在准备阶段没有提交,因此出现了三阶段提交3PC,那就是预提交阶段,PreCommit,参与者无法及时接收到来自协调者的提交或者中断事务请求时,在等待超时之后,会继续进行事务提交

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值