Mq
    mq事务消息
    image.png
    在rocketMq的中核心4组件为namesrv、broker、consumer、producer。

    broker:消息存储中心,多个主/从组成Broker集群,message的数据都写入master节点,Slave节点从master节点同步数据

    nameserver:注册中心,保存broker节点的路由信息,提供接口给producer和consumer访问,broker心跳检测

    producer:消息生产者,通过namesrv获取broker的地址并发送消息。

    consumer:消息消费者,通过nameserver获取broker的地址并消费消息。

    Consumer端消费失败,会把消息存到重试队列,重试次数越多投递延时就越大,默认16次,超过次数后会把消息存到死信队列,需要人工干预

    RocketMQ的消息存储由CommitLog和ConsumeQueue两部分组成,其中CommitLog用于存储原始的消息,最大是1个G,写满会创建下一个,而ConsumeQueue表示一个topic的一个queue,用于存储投递到某一个queue中的消息的位置信息,消息消费后只是当前Consumer的消费进度(CommitLog的offset)更新了,默认48小时后会删除不再使用的CommitLog文件

    为什么要主动拉取消息?

    如果broker主动推送消息的话有可能push速度快,消费速度慢的情况,那么就会造成消息在consumer端堆积过多,同时又不能被其他consumer消费的情况。而pull的方式可以根据当前自身情况来pull,不会造成过多的压力而造成瓶颈。所以采取了pull的方式。

    https://www.cnblogs.com/ynyhl/p/11320797.html
    kafka和rocketMq
    kafka每个partition独占一个目录,每个partition均有各自的数据文件.log;而rocketmq是每个topic共享一个数据文件commitlog因为kafka的topic一般有多个partition,所以kafka的数据写入熟读比rocketmq高出一个量级。但超过一定数量的文件同时写入,会导致原先的顺序写转为随机写,性能急剧下降,所以kafka的分区数量是有限制的。

    同步刷盘
    在返回写成功状态时,消息已经被写入磁盘。具体流程是,消息写入内存的PAGECACHE后,立刻通知刷盘线程刷盘,然后等待刷盘完成,刷盘线程执行完成后唤醒等待的线程,返回消息写成功的状态。
    异步刷盘
    在返回写成功状态时,消息可能只是被写入了内存的PAGECACHE,写操作的返回快,吞吐量大;当内存里的消息量积累到一定程度时,统一触发写磁盘操作,快速写入。

    线程池
    newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程(60s),若无可回收,则新建线程。
    newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
    newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
    newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

    3、Runnable和Callable的区别

    (1) Callable规定(重写)的方法是call(),Runnable规定(重写)的方法是run()。

    (2) Callable的任务执行后可返回值,而Runnable的任务是不能返回值的。

    (3) call方法可以抛出异常,run方法不可以。

    (4) 运行Callable任务可以拿到一个Future对象,表示异步计算的结果。它提供了检查计算是否完成的方法,以等待计算的完成,并检索计算的结果。通过Future对象可以了解任务执行情况,可取消任务的执行,还可获取执行结果。

    Runnable多实现 Thread实现了Runnable

    终断线程
    1. 使用标志位终止线程
    2. 使用 stop() 终止线程
    释放锁,数据一致性
    资源未清理
    3. 使用 interrupt() 中断线程
    中断状态是线程固有的一个标识位,可以通过此标识位安全的终止线程。比如,你想终止
    一个线程 thread 的时候,可以调用 thread.interrupt()方法,在线程的 run 方法内部可以
    根据 thread.isInterrupted()的值来优雅的终止线程

    https://www.cnblogs.com/liyutian/p/10196044.html

    Springboot
    https://www.cnblogs.com/niechen/p/9027804.html
    SpringBoot启动的时候会通过@EnableAutoConfiguration注解找到META-INF/spring.factories配置文件中的所有自动配置类,并对其进行加载,而这些自动配置类都是以AutoConfiguration结尾来命名的,它实际上就是一个JavaConfig形式的Spring容器配置类,它能通过以Properties结尾命名的类中取得在全局配置文件中配置的属性如:server.port,而XxxxProperties类是通过@ConfigurationProperties注解与全局配置文件中对应的属性进行绑定的。

    公平锁:每个线程在获取锁时会先查看此锁维护的等待队列,如果为空,或者当前线程是等待队列的第一个,就占有锁,否则就会加入到等待队列中,以后会按照先进先出的规则从队列中取到自己
    非公平锁
    非公平锁比较粗鲁,上来就直接尝试占有锁,如果尝试失败,就再采用类似公平锁那种方式。

    乐观锁
    乐观锁是一种乐观思想,即认为读多写少,遇到并发写的可能性低,每次去拿数据的时候都认为
    别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数
    据,采取在写时先读出当前版本号,然后加锁操作(比较跟上一次的版本号,如果一样则更新),
    如果失败则要重复读-比较-写的操作。
    java 中的乐观锁基本都是通过 CAS 操作实现的, CAS 是一种更新的原子操作, 比较当前值跟传入
    值是否一样,一样则更新,否则失败。

    悲观锁
    悲观锁是就是悲观思想,即认为写多,遇到并发写的可能性高,每次去拿数据的时候都认为别人
    会修改,所以每次在读写数据的时候都会上锁,这样别人想读写这个数据就会 block 直到拿到锁。
    java中的悲观锁就是Synchronized,AQS框架下的锁则是先尝试cas乐观锁去获取锁,获取不到,
    才会转换为悲观锁,如 RetreenLock。

    调优
    cpu高 jstack 定位代码
    jstat 命令可以查看堆内存各部分的使用量,以及加载类的数量。
    jmap 它可以生成 java 程序的 dump 文件, 也可以查看堆内对象示例的统计信息、查看 ClassLoader 的信息以及 finalizer 队列。

    1, jps 查看java进程pid
    image.png
    2, top -Hp pid 找出该进程内最耗费CPU的线程
    image.png
    3, printf “%x\n” 1787 得到十六进制值为6fb
    image.png
    4, jstack pid > file.log 通过jstack 把该进程的所有线程堆栈打印到file.log中
    5, vi file.log 打开文件搜索 6fb 找到具体出问题的代码.

    jmap
    命令:jmap pid
    描述:对象的起始地址、映射大小以及共享对象文件的路径全称

    命令:jmap -heap pid
    描述:显示Java堆详细信息

    命令:jmap -histo:live pid
    描述:显示堆中对象的统计信息

    命令:jmap -dump:format=b,file=heapdump.phrof pid
    描述:生成堆转储快照dump文件。

    -Xms 堆初始值
    -Xmx 堆最大可用值
    -Xmn 新生代堆最大可用值
    -XX:SurvivorRatio 用来设置新生代中eden空间和from/to空间的比例.
    含以-XX:SurvivorRatio=eden/from=den/to
    总结:在实际工作中,我们可以直接将初始的堆大小与最大堆大小相等,
    这样的好处是可以减少程序运行时垃圾回收次数,从而提高效率。

    公平锁和非公平锁
    在使用公平锁时,某线程想要获取锁,不仅需要判断当前表示状态的变量的值是否为0,还要判断队列里是否还有其他线程,若队列中还有线程则说明当前线程需要排队,进行入列操作,并将自身阻塞;若队列为空,才能尝试去获取锁。而对于非公平锁,当表示状态的变量的值是为0,就可以尝试获取锁,不必理会队列是否为空,这样就实现了插队获取锁的特点。通常来说非公平锁的吞吐率比公平锁要高,我们一般常用非公平锁。

    //创建令牌桶实例[每秒在令牌桶中放行10个请求]
    private RateLimiter rateLimiter = RateLimiter.create(10);

    boolean tryAcquire = rateLimiter.tryAcquire(5, TimeUnit.SECONDS);

    浅析 Spring 事务
    1、 Spring事务的使用
    Spring 中的事务有以下几种使用方式

    • 编程式事务;
    • 使用XML配置声明式事务;
    • 使用注解配置声明式事务。

    随着注解的流行,一般使用注解配置声明式事务@Transactional
    2、Spring事务的七种传播机制

    1. @Transactional(propagation = Propagation.REQUIRED)

    若当前存在事务,则加入该事务,若不存在事务,则新建一个事务

    1. @Transactional(propagation = Propagation.REQUIRE_NEW)

    若当前没有事务,则新建一个事务。若当前存在事务,则新建一个事务

    1. @Transactional(propagation = Propagation.NESTED)

    如果当前存在事务,则嵌套在当前事务中执行。如果当前没有事务,则新建一个事务

    1. @Transactional(propagation = Propagation.SUPPORTS)

    支持当前事务,若当前不存在事务,以非事务的方式执行

    1. @Transactional(propagation = Propagation.NOT_SUPPORTED)

    以非事务的方式执行,若当前存在事务,则把当前事务挂起

    1. @Transactional(propagation = Propagation.MANDATORY)

    强制事务执行,若当前不存在事务,则抛出异常

    1. @Transactional(propagation = Propagation.NEVER)

    以非事务的方式执行,如果当前存在事务,则抛出异常
    3、使用事务可能导致不生效的一些坑
    3.1、private的方法中使用声明式事务
    Idea会提示错误,但是仍可以运行。Spring 默认通过动态代理的方式实现 AOP,对目标方法进行增强,private方法无法被代理,Spring 自然也无法动态增强事务处理逻辑
    3.2、抛出的异常不是继承于RuntimeException
    Spring 事务默认是对RuntimeException进行回滚,而不继承RuntimeException的不回滚。可以添加 @Transactional(rollbackFor = Exception.class) 来表示所有的Exception都回滚。
    3.3、没有被 Spring 管理
    没有加 @Service注解,也就不受Spring管理
    3.4、不支持事务
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    表示不以事务运行,当前若存在事务则挂起
    3.5、异常被捕获
    在代码处捕获了异常,且没有继续向上抛出,Spring 事务会失效
    3.6、Mysql 引擎是MyISAM
    MyISAM不支持事务,可以改成InnoDB引擎
    3.7、自身使用错误
    最常见的错误使用是,同一个Service里面的两个方法A和B,A方法没有标注声明式事务@Transactional,B方法开启了事务。A调用了B,B运行过程中报错,此时,事务不会生效。
    未使用声明事务的方法调用其他方法,会使用原始对象而不是代理对象调用其他方法,Spring只有在代理对象调用的时候事务才生效。
    解决办法

    1. 获取代理对象

    在类上加上@EnableAspectJAutoProxy(exposeProxy = true)
    获取代理对象 Object proxyObj = (Object) AopContext.currentProxy();
    通过proxyObj调用B方法

    1. 注入自身对象

    @Resource private Object object;
    通过object调用B方法

    1. A方法添加声明式事务注解@Transactional

    用例测试结果对照
    4、总结
    Spring 事务失效的情况有很多种,需要多加测试防止场景失效。还需要注意甄别不同场景使用的不同事务传播机制的应用。商城事务的问题很重要,大家一定要引起注意。