有界队列特点,aqs为啥使用双向队列,completableFuture特点,cpu高和oom问题排查实战,聚集非聚集索引再次理解,阿里开发手册理解,qps\并发\tps实战,mysql全文索引

1 有界队列的阻塞特点,满元素时 怎么阻塞生产者,空元素时怎么阻塞消费者

特点:

  • 当队列满时,生产者线程会被阻塞,直到队列有空位 
  • 当队列空时,消费者线程会被阻塞,调用直到有新元素加入

队列满时,调用await()方法释放锁并阻塞生产者

消费者消费完一条数据,调用signal() 唤醒一个生产者。

2. aqs为啥使用双向队列  既然双向队列这么好,那还要单向队列干嘛

双向队列查询和修改的是时间复杂度都是o(1),很适合效率要求很高的线程切换场景

但是为啥还要单向队列呢?首先双向队列肯定继承了单向队列的功能,并且需要更多的指针记录前后节点信息,需要耗费更多的内容,并且较复杂,对使用者不友好。只能想到这点区别了。

3. completableFuture的特点

因为future会阻塞主线程 ,知道异步线程返回。而completableFuture很好的解决了这个问题

4.concurrenthashmap为啥不允许空元素 key和value都不允许为空

防止歧义,get(key)时,是元素本身就不存在,还是value是null

待补充 线程安全问题。要仔细理解...

5.怎么排查线上cpu飙高问题

刚好排查过这类问题,巡检时发现机器top超100%,用如下方法定位到具体的报错日志。

发现有一个seg自然语言的二方包,在循环调用内部的oa系统接口,不通。然后日志中也在不断输入报错信息。

这个就等吧,等他们接口回复了,重启下服务就正常了。

这一般是代码问题,日志上肯定是有反应的。所以第一目的还是找日志。但是一台机器上有很多

服务怎么定位具体是哪个呢?

步骤如下 top 查看是哪个进程cpu占用率高。如果持续超过100% 那么必然有问题。

然后pwdx pid 就能看到是哪个服务的问题了(此时进入到这个服务的日志中,可以简单排查)。然后打印堆栈信息,能给直接给出报错的问题代码。

命令如下:先找出进程中占用率高的线程,top -Hp pid。 

然后在java中用Integer.toHexString(线程id) 把10进制的线程id转成16进制。

然后再打印这个线程的堆栈信息:jstack pid |grep -A 20  线程di

打印的日志可以直接定位报错的代码行  很好用。

我这里的问题是三方包调用接口不同,然后一直再重复调用。修复接口就行了。不过一般都要再重启服务才能生效。

6.怎么排查oom问题,或者内存占用率高的问题。

首先可以使用free -g 查看机器内存使用率。

再者 如果出现oom 一般系统就崩溃了,属于很严重的问题。这种问题在系统日志中会有体现的。

所以看下崩溃的服务日志,然后属于下面哪种异常

    • Java heap space:堆内存不足
    • Metaspace:元空间溢出(JDK 8+)
    • Direct buffer memory:堆外内存耗尽
    • Unable to create new native thread:线程数超限

如果是堆内存不足,那就是可能存在大对象,比如数据库没有分页查询的数据量太大,年轻代放不下 直接放到老年代了。还有内存泄露(缓存未设置过期时间,就一直存在)

如果是元空间溢出,我们要先思考元空间是放类文件的,还有常量池的内容。那就有可能是动态加载的类太多了。可以考虑检查下代码中的动态代理或者类加载器的相关代码,或者再扩大下元空间的大小。当然了 1.8后的版本去除了元空间,放磁盘了。不会出现这种问题了。

还有其他两个不说了 没见过,

此外还有可以获取dump信息,进一步排查大对象信息。命令如下:

jmap -dump:live,format=b,file=heap.hprof <PID>

但是这种方法不太现实 打印的东西太多太乱,最好能够调用出 jconsole 可以直接查看对象信息。大对象是放到最前面的。

7.G1 垃圾收集的特点,为什么低延迟

这种问题 很复杂很深层次的问题 我们只要记住使用场景就行了。

G1是1.9后默认的垃圾回收,起始于1.74u。低延迟的原因有,多分区,并发处理,标记-整理清除算法,局部复制清除算法,可设置stopworld时间,适合大型服务 大内存场景。

8,幸存一区和幸存二区 来回回收超过15次 就被放到老年代了,为啥是15次。

因为存放这个值的类型是4个bit,也就是最大值也就是1111,8+4+2+1=15,所以不但默认是15,而且最大也只能是15.

9,再说equals 

单就对象而言,如果重写 ,那么比较的是值,不重写比较的是地址,等同于==

10,list是1.5倍扩容,map是2倍扩容。

此外 如果已知数据量大小,可创建时就设置集合大小,防止扩容带来的消耗。 list是1.5倍是因为 避免额外空间浪费,map 2倍扩容是因为可很大程度上避免重写计算哈希,并降低冲突。

11,聚集索引 非聚集索引

再次理解这俩个概念,以前理解的都是错的。。。

本质区别,前者索引叶子节点存放实际数据,后者只存指针。所以后者要做回表查询。

再者innodb中,除了主键索引是聚集索引,其他索引都是非聚集索引。所以二者在一个表中是共存的状态。而且通过主键索引查询的速度特别快。

还有就是myisam中都是非聚集索引,因为是表级锁,纯读场景无冲突,所以适合大量的查询操作,并且支持全文索引,倒排索引,内存开销低

12. 不适合建索引的情况

更新多,体量小,散列程度第,函数操作多

14.索引是可以设置长度的,要是必要的,尤其是对文本类型的,长度过程,很占内存。

15.时刻关注阿里开发手册

像包名要小写,用单数,一个单词;接口方法 不显示声明public abstract;枚举类的值要大些;方法命名,查询单个数据用getxxx,查询集合用listxxx,计数用countxxx;实体类用xxxDo于表字段对应,service层用xxxDTO。long型要用 大写L。浮点型数据判断不能用==或equals,要用math或者bigDecimal。养成习惯,在pojo类中都重写toString()方法用于日志打印。Java序列化是用来把对象写到文件中的,当然了也可先用JSON转成字符串再写进去。使用多个锁时,一定要保证锁的顺序性,防止死锁。switch必须要有default,即使啥都不写。要习惯用大于小于判断数字,而不是用等于。优先使用spring的BeanUtils做浅拷贝 效率还行。pattern正则实例化的时候 要放到方法体外,做预编译,提高效率,可作为静态变量或成员变量。业务错误码分单个大类,A00开头表示用户错误,B00开头表示系统错误,C00开头表示第三方错误。http错误码可由500内部异常代为处理。打印日志不要使用json.tojsonstring,而是重写对象的tostring方法。单元测试间保持独立,不要互相调用。数据库小数类型都用decimal.对于过长的大字段建议独立出一张表来关联,避免影响其他字段的索引效率。表数据超过500万行或2g,才考虑分库分表。字段无符号表示字段值>=0,并且舍弃了小数部分,扩大了数据范围。尽量建唯一索引,即使是组合出来的唯一索引,这样不仅是为了提高查询速度,也能避免脏数据。虽然加索引会影响插入速度,但是可以忽略不计。在varchar上建索引必须指点索引长度。严禁使用左模糊查询,可以考虑用反转数据(新字段)+右模糊实现。全文索引具有分词功能 mysql具有此能力。

ALTER TABLE articles ADD FULLTEXT ft_index (content);  -- 全文单列索引创建

禁止使用外键,由业务来控制。修改操作,必须要先查询再修改,保持目标数据存在。多表查询必须使用别名,就用t1,t2...表示。mysql utf8编码 一个中文字符占三个字节。

16.禁止使用大POJO类,造成字段yao不要怕麻烦 多建类。

 17.业务异常码是补充http状态码不足的问题。

但是http状态码也不能扩展,所以如果内部异常了要体现在http状态码上可以统一返回一个500内部异常,然后在响应体中具体给出详细的自定义业务异常码。

18. java调用三方接口时,接收的数据格式可以都用string字符串接收,再转成json对象,再转成pojo实体类。

19,单例模式 不要用双重检查锁,慢而且有延迟风险,可以用volatile关键字修饰创建的对象变量,然后加一层锁就行,并且再锁内部再判一次null.

20,tps qps 并发

tps:一秒钟处理的完整事务数,可能包含多个接口。根据统计的角度不同而有所变化,可能是加载一个页面的所有接口算作一个tps,也可能是一个业务流程。

qps:一秒钟处理一个接口的次数,所以一个tps可能包含多个qps.

21, (22有修正)项目的tps, 是这样的 我的项目中计算 tps的结果是100。没有使用jmeter这样的工具,而是使用批量数据处理,得出的结果。计算的业务是银行的贷款审批流程。需要处理批量业务,要求半小时内处理完,总数据量大概20万。处理单个业务大概需要1s,最大支持40个并发,3台机器。所以40*3*60*30=216000 刚好能处理完20万业务请求.

其实最大能限制处理性能的是数据库的处理能力,并不是有多个机器,多大的并发。因为这里是流程较长 需要处理调用的外部接口多,瓶颈不在数据库,可以单独的累加。

22,怎么理解并发?(修正实际业务系统处理能力数据) 

并发数是指同时处理的请求数。个人感觉是可以理解成机器能处理的线程数,即逻辑线程数。

(1)那么,qps=并发/0.5=64=逻辑线程数/0.5  因为是一个接口也就是tps=qps.

如果我们机器的逻辑线程数32,从日志中得出的贷款审批流程需要0.5秒。另外压测得出20万条数据在10分钟内处理完,有3台机器。

(2)从而反向推理出200000/3/10/60=qps=tps=100(单个机器的处理能力)

可以看出1,2得出的结果不一样,实际的处理能力更强,也就是并发更高,并发=55.比逻辑线程数要大。

这是因为 系统是io密集型的。 所以单台机器的并发是55,tps(吞吐量)=100, 平均用时0.5s

所以由于线程的切换,程序的并发能力是变换的,并发数也就不等于线程数。 

总之要根据压测结果去推并发数,然后再调整程序中的线程池,内存去优化结果。不能根据tomcat的并发数、线程数 ,连接数(10000)来判断。 要实事求是。

23,redis缓存和mysql数据一致性问题

先删除缓存再更新数据库,就可以了。但是极端情况下,由于这俩操作不在一个事务中,所以还是要做最终一致性处理,就是把更新失败的操纵记录到队列中,重试就行。

24,为什么java使用lua脚本操作redis   因为保证了查询和删除在一个事务中。

25,springboot 自动装配

这也是spring 与springboot之间的最大的区别。

所谓自动装配,是声明了@EnableAutoConfiguration 后 项目启动后采用spi机制。会加载jar包中meta-info目录下下的spring.factories文件,读取其中的bean类,装载到容器中。

26 ,redis哨兵和redis cluster集群的区别

首先两个都是多节点 主从结构,并且支持故障自动转移,读写分离。 哨兵就是做监听和故障转移的。但是redis cluster支持多主多从和自动扩容,不过也太麻烦了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老马识途2.0

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值