公众号笔记: 2019年

1、多路复用

  作用:一个通讯连接的基础上,可以同时进行多个请求响应处理。

  由于上层应用协议的制定问题,很多传统服务不能支持多路复用,例如:http1.1,sqlserver 和 redis 等。有些服务提供批量处理,但是这些处理都是基于一个RPS(每秒请求数)下。

  单路存在的问题:每个请求响应独占一个连接,独占连接网络读写,导致连接大量时间被闲置,无法更好的利用网络资源。

  独占读写IO,这样导致 RPS 处理量必须由 IO 承担,IO 操作起来比较损耗性能,所以再高 RPS 处理就会出现性能问题。

  多路复用在一个连接上同时处理多个请求响应,大大减少连接的数量,并提高了网络的处理能力。

  共享连接,不同请求响应数据包可以合并到一个 IO 上处理,降低 IO 的处理量,性能更好。

  NIO 和 Netty 就用到了多路复用的技术

2、StringBuilder 为什么线程不安全

  StringBuilder 都是通过一个 char 数据存储字符串的,并且数组是可变的。

  StringBuilder 有两个成员变量(继承的父类里):char[] value 和 int count。并且 StringBuilder 的 append() 方法调用父类 AbstractStringBuilder 的 append() 方法。其中有一行:count+= len ,这个操作不是一个原子操作。

  当多线程都执行到该行代码时,都拿到的count值,两个线程做完 count+=len 操作后,值是 count = count + len 而不是 count = count + 2*len。所以线程不安全。(count += len 就是线程不安全)

3、分布式数据库表ID生成器

  解决方案:唯一识别码 UUID、雪花算法、自增 ID、对 ID 进行缓存。

  雪花算法开源的分布式 ID 生成算法,结果是一个 long 型的 id。整个结构是64位,用 long 来存储。41位时间戳(当前时间-开始时间),10位工作机器 id,12位序列号,最后1位0。

  优点:整体上按照时间自增排序,并且整个分布式系统内不会产生 ID 碰撞(由数据中心 ID 和机器 ID 作区分),效率极高。大概每秒产生26W个 ID。

  生成ID也不依赖于DB,完全在内存生成,高性能高可用。并且 ID 呈递增,后续 ID 的插入对索引树比较友好。

  缺点:依赖系统时针的一致性。如果时针回拔,则可能造成 ID 冲突,或者 ID 乱序。

4、高并发下的幂等性

  1、可以用唯一索引来保证幂等性。当新增多次的时候,唯一索引就保证了只有1条数据的插入。

  2、乐观锁。可以通过版本号控制、通过条件控制。

  3、分布式锁。主要是多线程并发锁的思路来实现。

5、高频次下的点赞和取消点赞的实现思路

  如果每次点赞和取消点赞都操作数据库,那么压力会很大。所以用 redis 来做缓存,并且定时任务在一个时间段,从 redis 同步数据到数据库。

  至于 redis 中存什么数据格式,键值对怎么存,以及定时任务的间隔时间,就考虑实际情况。

6、优雅处理 Java 中的空值

  Service 层的接口,返回逻辑处理后的集合/对象(不要返回web层返回给前端的对象),集合不要返回 null,而是返回一个空集合

  如果返回是对象,可以用 Optional.ofNullable(dao 层方法),有两个含义,存在 or 缺省。

7、如果遇到一种很慢的 sql 语句

  如果用到了创建时间拉查询范围时间内的数据,sql 语句查询时间很长,并且各种优化都不行。

  主要是看下是否用到了 create_time 的索引(范围索引很重要!!!),如果没应用到,那就强制让 sql 语句使用索引。在 where 字段前,使用 FORCE INDEX('cre_tim_idx')。

8、简单说说 BIO 和 NIO

  BIO 会产生两次阻塞,第一次是等待连接时的阻塞,第二次是等待数据时阻塞。

  单线程情况下,BIO 是无法处理多个请求的。所以在多核的情况下,一个请求就开启一个线程来处理。但是多线程情况的 BIO 也有问题,空请求也会创建一个单独的线程,当不活跃的线程过多时,连接数一多时就会对服务器端产生很大的压力。

  NIO 使用了操作系统底层的轮询系统调度。同步非阻塞,服务器实现模式为一个请求一个线程,即客户端发送的连接请求都会注册到多路复用器上,多路复用器轮询到连接有I/O请求时才启动一个线程进行处理。

9、获取当前时间(Java8)

  Java 8获取时间和设置时间格式,用 LocalDate、LocalTime、LocalDateTime。

  不用Date,因为打印出来的时间不是格式化,可读性差。

  使用 SimpleDateFormat 对时间进行格式化(format),是线程不安全的。

  LocalDate.now() 获取当前年月日,再根据 getYear() 等方法可以获取到年月日、星期几。也可以构造指定的年月日:localDate.of(2019,9,10)。                 LocalTime.now() 只会获取几点几分几秒。

  LocalDateTime = LocalDate + LocalTime,可以根据 localDateTime.toLocalDate() 获取 LocalDate.

  获取秒数、毫秒数:System.currentTimeMillis().也可以格式化时间。

  多操作就会对该 Java8 的新写法熟悉。

10、分页 Limit 1000000,10 怎么优化

  例如 order by id字段,可以拿到上一页的 id 最大值当做参数,作为查询条件,再 limit 10 就可以。

  能条件下推的尽量下推。例如在一个子查询条件里,和最外层的条件里,如果能写到最外层,就写到最外层。

posted @ 2019-12-10 10:24  几近虚年  阅读(142)  评论(0编辑  收藏  举报