学习问题记录

分布式ID生成

  1. UUID
    UUID是16字节128位长的数字,通常以36字节的字符串表示,示例如下:
    3F2504E0-4F89-11D3-9A0C-0305E82C3301
    UUID的生成基于多项客观因素,如时间等,所以可以保证全局唯一性。
    缺点:无法保证ID自增。而且因为随机生成,mysql的B+树索引,在入库的时候会有很多节点分裂的相关操作,降低性能。

  2. 数据库自增
    基于数据库的Auto_increament机制,可以获得全局唯一id,并且id自增。
    缺点:这种分布式id严重依赖于数据库,数据库出现问题的时候会导致雪崩。而且但数据库的情况高并发时,性能不高,多数据库分库时又很难进行扩展,例如A库,1、3、5、7,B库,2、4、6、8。

  3. SnowFlake算法
    生成的id共64位
    第一位为0,无实际意义
    第二位开始,41位为时间戳,精确到毫秒级
    第42位开始,10位机器位,包括5位数据中心位和5位工作机器节点位
    最后12位,同一毫秒内id自增
    即不依赖数据库,又保证id自增,性能也很nice

缓存淘汰策略

  • FIFO
    先进先出
    双向链表实现
    可用map保存key的位置,来提高性能
  • LRU
    最近最久被使用
    双向链表实现,被使用的key转到链表头部,每次淘汰时删除最后链尾元素
  • LFU
    最近最少被使用
    队列实现,每次插入数据放入队列尾,每次使用数据对队列重新排序,队满时删除队头元素

分布式锁

分布式锁实现方式一般有三种:基于数据库,基于zookeeper临时有序节点,基于redis的nx、ex参数
基于redis的分布式锁设计:
加锁:加上NX、EX参数(在把NX、EX作为参数写在同一条语句中,能保证操作的原子性),NX在没有key的时候才创建key并加入缓存,EX设置缓存超时时间,设置超时时间可以防止死锁等情况。

阻塞锁:加锁时多线程竞争,阻塞,循环等待,在循环时可使线程sleep一定时间,防止一直拿不到锁而一直循环请求消耗CPU资源。也可以自定义阻塞时间,每次循环sleep时阻塞时间减去sleep时间,当为0时,等待时间过长未获取锁,返回错误。

解锁:在redis中把key删除就表示解锁。但是会有情况,有线程A,set了一个过期时间10s的锁,但是执行了20秒,在后10s里,另一个线程B,set了这个锁并执行完释放,导致B释放了A的锁。对这种问题,在加锁的时候每个线程设置一个自身独有的key,删除缓存释放锁的时候判断是不是自身的锁就ok。

注:redis中的原子操作也可以用lua脚本实现,暂时还不会,>.>

缓存

本地缓存:Guava Cache,Encache
分布式缓存:Redis,Memcached

Guava

google开发的java核心增强库,其中包含:
基本工具
快速失败拒绝null
前置条件
object常用方法
强大的排序工具
异常和错误
集合
不可变集合
新集合
集合扩展工具类
缓存
本地缓存,支持多种淘汰策略
并发
回调
服务维持
字符串处理
多种工具,分割、连接等等
原生类型
对java原生类型的扩展
区间
可比较类型的区间(不太懂)
I/O
简化I/O操作,尤其是文件流操作
散列
比hashcode更复杂的散列实现
布隆过滤器
事件总线
发布订阅模式组件通信
数学工具类
反射

秒杀系统

乐观锁更新 + 分布式限流 + Redis 缓存 + Kafka 异步

sql优化

  • 字段的默认值不设置为null
    设置为null的值可能会带来和预期不一致的查询结果
  • 在数据区分不明显的情况下不使用索引
    数据区分不明显的情况下,使用索引并不会加快查询速度,反而会额外花费时间来维护索引树从而降低性能
  • 严格按照数据格式写sql
    如果写的sql中数据类型和数据库中的数据类型不一致,sql会做强制数据转换,耗费大量时间
  • 需要join的两表字段类型相同
  • 明确知道有几条数据时
    指明查询数据条数,停止游标移动加快查询速度
select name from user where username='zhangsan' limit 1
  • 避免索引失效
  1. 在字段上进行计算不会使用索引
select name from user where FROM_UNIXTIME(create_time) < CURDATE();

应该修改为:

select name from user where create_time < FROM_UNIXTIME(CURDATE());
  1. 负向查询不会使用索引
    例如:
select name from user where id not in (1,3);

可以的情况下改写成

select name from user where id in (2,4);
  1. 前缀匹配不会使用索引
    例如:
select name from user where name like '%zhangsan'

频繁使用的前缀匹配可以替换为全文检索
4. 注意最左前缀匹配情况
如果给 user 表中的 username pwd 字段创建了复合索引那么使用以下SQL 都可以命中索引:

select username from user where username='zhangsan' and pwd ='123'
select username from user where pwd ='123' and username='zhangsan'
select username from user where username='zhangsan'

但是使用

select username from user where pwd ='123'

不会使用索引

算法

  • 链表排序
    归并法
  • 数组右移k位
    在不借用额外存储空间的情况下,保证时间复杂度最低。
    将数组翻转,再对前k位翻转,后n-k位翻转即可,时间复杂度为n

进程、线程通信方式

进程间通信方式:管道,消息队列,信号量(semaphore),共享内存
线程通信方式:全局变量,wait、notify、notifyall

JDK监控和故障处理

命令

  • jps -l
    jps命令可以查看java进程启动类的相关信息
  • jstat -[options] [vmid]
    通过输入参数可以查看各种状态信息,vmid是进程id,可以用jps命令查看
    jstat -class vmid :显示 ClassLoader 的相关信息;
    jstat -compiler vmid :显示 JIT 编译的相关信息;
    jstat -gc vmid :显示与 GC 相关的堆信息;
    jstat -gccapacity vmid :显示各个代的容量及使用情况;
    jstat -gcnew vmid :显示新生代信息;
    jstat -gcnewcapcacity vmid :显示新生代大小与使用情况;
    jstat -gcold vmid :显示老年代和永久代的信息;
    jstat -gcoldcapacity vmid :显示老年代的大小;
    jstat -gcpermcapacity vmid :显示永久代大小;
    jstat -gcutil vmid :显示垃圾收集信息;
  • jinfo [vmid]
    可以查看虚拟机各项参数
  • jmap
    生成堆转储快照
  • jhat
    用于分析 heapdump 文件,它会建立一个 HTTP/HTML 服务器,让用户可以在浏览器上查看分析结果
  • jstack
    命令用于生成虚拟机当前时刻的线程快照。线程快照就是当前虚拟机内每一条线程正在执行的方法堆栈的集合

监控工具

  • JConsole
    JConsole 是基于 JMX 的可视化监视、管理工具。可以很方便的监视本地及远程服务器的 java 进程的内存使用情况。可以在控制台输出console命令启动或者在 JDK 目录下的 bin 目录找到jconsole.exe然后双击启动。
  • Visual VM
    可以监控Java 虚拟机 上运行的 Java 应用程序的详细信息。在 VisualVM 的图形用户界面中,您可以方便、快捷地查看多个 Java 应用程序的相关信息。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值