57 Matching Annotations
  1. Dec 2022
  2. 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. 任何时候,都应该为自定义线程池指定有意义的名称,以方便排查问题
    8. 禁止使用这些方法来创建线程池,而应该手动 new ThreadPoolExecutor 来创建线程池
    9. 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

    3. 采取 Pull 的方式问题就简单了许多,由于 Consumer 是主动到服务端拉取数据,此时只需要降低自己访问频率即可。举例:如前端是 flume 等日志收集业务,不断向 CMQ 生产消息,CMQ 向后端投递,后端业务如数据分析等业务,效率可能低于生产者。

      pull适用于日志分析等实时性不高的、吞吐量大的场景

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

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

    1. 如果channel.basicNack(8, false, false);表示deliveryTag=8的消息处理失败且将该消息直接丢弃。

      basicNack的requeue为false情况下,数据会被直接丢弃

    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
    1. 分散治理(Decentralized Governance)

      有时候也需要有个控制层来撮合业务

    2. 基础设施自动化,如 CI/CD 的长足发展,大大降低了构建、发布、运维工作的复杂性。

      为了职责,而做了职责分离,所以只是半自动化的

    3. 另外,尽管在分布式中,我们要想处理好一致性的问题也很困难,很多时候都没法使用传统的事务处理来保证不出现一致性问题。但是两害相权取其轻,一致性问题这些必要的代价是值得付出的。

      分布式事务没有

    4. 在单体服务中,通常一个系统的各个功能模块会使用同一个数据库,虽然这种中心化的存储确实天生就更容易避免一致性的问题,但是,同一个数据实体在不同服务的视角里,它的抽象形态往往也是不同的。

      营销甚至想访问券库

    5. 避免把软件研发看作是要去完成某种功能,而要把它当做是一种持续改进、提升的过程

      营销服务就没有当成产品来搞,为业务而业务

    6. 这一点在真正实践的时候,其实多少都会留点儿宽松的处理余地。因为大多数的公司都不会在某一个服务用 Java,另一个用 Python,下一个用 Golang,而是通常都会统一主流语言,甚至会有统一的技术栈或专有的技术平台。

      大数据那边可能有

    7. 如果本应该归属同一个产品内的功能,被划分在了不同的团队当中,那就必然会产生大量的跨团队沟通协作,而跨越团队边界,无论是在管理、沟通,还是在工作安排上,都会产生更高的成本。高效的团队,自然会针对这个情况进行改进,而当团队和产品磨合调节稳定了之后,就会拥有一致的结构

      我们的问题应该是相反的:折上折前期电商、券微服务区分度不够。

  3. Apr 2020
  4. redux.js.org redux.js.org
    1. functions should be relatively short and ideally only do one specific thing

      函数最好是单一职责