46 Matching Annotations
  1. Aug 2022
    1. 如果希望 Value 以 JSON 保存并带上类型信息,更简单的方式是,直接使用 RedisSerializer.json() 快捷方法来获取序列化器。
    1. 尽量将业务逻辑写在业务代码中,让数据库只做“读写数据”的事情。因此,这类方法的应用还是比较广泛的
    1. 使用 addSuppressed 方法把 finally 中的异常附加到主异常上
    2. 把原始异常作为转换后新异常的 cause,原始异常信息同样不会丢
    3. 我不建议在框架层面进行异常的自动、统一处理,尤其不要随意捕获异常。但,框架可以做兜底工作
    4. 不在业务代码层面考虑异常处理,仅在框架层面粗犷捕获和处理异常
    5. Controller 层往往会给予用户友好提示,或是根据每一个 API 的异常表返回指定的异常类型,同样无法对所有异常一视同仁
    6. 如果使用 Java8 以上版本可以使用 Arrays.stream 方法来转换,否则可以把 int 数组声明为包装类型 Integer 数组:
    1. 这就最大程度地减少了事务之间的锁等待,提升了并发度
    2. 最可能造成锁冲突、最可能影响并发度的锁的申请时机尽量往后放
    1. 把innodb_flush_neighbors的值设置成0。因为这时候IOPS往往不是瓶颈,而“只刷自己”,就能更快地执行完必要的刷脏页操作,减少SQL语句响应时间
    1. 普通索引和change buffer的配合使用,对于数据量大的表的更新优化还是很明显的
    2. 对于写多读少的业务来说,页面在写完以后马上被访问到的概率比较小,此时change buffer的使用效果最好。这种业务模型常见的就是账单类、日志类的系统
    1. 由于线程池在工作队列满了无法入队的情况下会扩容线程池,那么我们是否可以重写队列的 offer 方法,造成这个队列已满的假象呢?

      默认情况下,先塞满队列,再扩容线程池。

      线程池不满时,queue直接拒绝,这样就可以让线程池扩容

      https://github.com/apache/tomcat/blob/a801409b37294c3f3dd5590453fb9580d7e33af2/java/org/apache/tomcat/util/threads/TaskQueue.java

    2. 对于执行比较慢、数量不大的 IO 任务,或许要考虑更多的线程数,而不需要太大的队列。
    3. 由于线程池在工作队列满了无法入队的情况下会扩容线程池,那么我们是否可以重写队列的 offer 方法,造成这个队列已满的假象呢?
      1. 默认情况下,先塞满队列,再扩容线程池。
      2. 线程池不满时,queue直接拒绝,这样就可以让线程池扩容

      https://github.com/apache/tomcat/blob/a801409b37294c3f3dd5590453fb9580d7e33af2/java/org/apache/tomcat/util/threads/TaskQueue.java

    4. 由于我们 Hack 了队列,在达到了最大线程后势必会触发拒绝策略,那么能否实现一个自定义的拒绝策略处理程序,这个时候再把任务真正插入队列呢
    5. 队列来做缓冲。

      类似消息队列

    6. 对于执行比较慢、数量不大的 IO 任务,或许要考虑更多的线程数,而不需要太大的队列。
    7. 禁止使用这些方法来创建线程池,而应该手动 new ThreadPoolExecutor 来创建线程池
    8. tem.lock.tryLock(10, TimeUnit.SECONDS)

      这里避免了长时间死锁

    1. 因为无需默认构造函数就可以反射生成对象,这个属性在很多的序列框架可以使用,比如 xml 转换成 bean
    1. 比较理想的机制是,在alter table语句里面设定等待时间,如果在这个指定的等待时间里面能够拿到MDL写锁最好,拿不到也不要阻塞后面的业务语句,先放弃

      等待

    2. 使用参数–single-transaction的时候,导数据之前就会启动一个事务,来确保拿到一致性视图。而由于MVCC的支持,这个过程中数据是可以正常更新的。
    1. alter table T engine=InnoDB
    2. 第一原则是,如果通过调整顺序,可以少维护一个索引,那么这个顺序往往就是需要优先考虑采用的
    1. RabbitMQ版可用于单体应用被拆解为微服务后不同微服务间的通信
      1. 接受券核销、购买信息(异步解耦、削峰填谷)
      2. 用户注册信息(异步解耦)
      3. 推送数据给ES(缓存同步)
      4. 分销活动,用户购买订单号+券id的最终一致性
      5. 延时队列,异步(取消订单)
    1. retry只能在自动ack模式下使用。如果一定要在手动ack模式下使用retry功能,需保证消息能在有限次重试过程中可以重试成功,否则超过重试次数,又没办法执行ack或者nack,消息就会一直处于unack,并不会转发到死信队列

      manul模式下重试可能还有bug:

      recover与manual模式也有关系(是否是bug、按理manul不能被自动ack/reject

      重试机制下: 1. 默认情况,manual模式的消息会最终处于unack状态; 1. ImmediateRequeueMessageRecoverer,manual消息会被重新requeue; 1. RejectAndDontRequeueRecoverer,manual模式的消息会最终处于unack状态;

    1. 建议消费者在 visibilityTimeout 时间内消费成功后需要调用(batch)DeleteMessage 接口删除该消息,否则该消息将会重新变成为 active 状态,此消息又可被消费者重新消费,保证消息至少消费一次,但是不能保证幂等性, 业务侧需要有去重逻辑。

      消费者需要delete,不然可能会出现重新消费

    1. 您可以将消费过的去重 key 缓存(如 KV 等),然后每次消费时检查去重 key 是否已消费过。去重 key 缓存可以根据消息最大有效时间来淘汰。CMQ 提供了队列当前最小未消费消息的时间(min_msg_time),您可以使用该时间和业务生产消息最大重试时间来确定缓存淘汰时间。存在多个消费者时,去重 key 缓存就需要是分布式的

      分布式缓存的最佳实践

    2. 去重 key

      correlatedata

    1. AmqpRejectAndDontRequeueException 异常的时候,则消息会被拒绝,且 requeue = false(不重新入队列)

      auto模式下,可以用这个异常来控制消息进入死信队列

    1. 在需要使用消息的return机制时候,mandatory参数必须设置为true
      • //常用的三个配置如下
      • //1---设置手动应答(acknowledge-mode: manual)
      • // 2---设置生产者消息发送的确认回调机制 ( #这个配置是保证提供者确保消息推送到交换机中,不管成不成功,都会回调

      // publisher-confirm-type: correlated

      // #保证交换机能把消息推送到队列中

      // publisher-returns: true

      // template:

      // #以下是rabbitmqTemplate配置

      // mandatory: true) * // 3---设置重试

    1. see that the utilisation increases with the prefetch limit until we reach a limit of about 30. After that the network bandwidth limitation starts to dominate and increasing the limit has no further benefit
  2. Apr 2020
  3. redux.js.org redux.js.org
    1. functions should be relatively short and ideally only do one specific thing

      函数最好是单一职责