销售提成合并滚动明细逻辑
销售提成合并滚动明细逻辑滚动明细回款金额暂未发完的账单,会滚动到下一个工资月继续发放
同步底表增量同步BI底表数据,系统自动给本次拉取的数据打上“工资月份”的标识,BPO(T+2),HRO(T+1)。
合并明细合并时注意需保留用户编辑后的数据,部分字段需延用(自动带出)上个账单月的数值。
常用的缓存组件Redis是如何运行的
Redis简介Redis 是一款基于 ANSI C 语言编写的,BSD 许可的,日志型 key-value 存储组件,它的所有数据结构都存在内存中,可以用作缓存、数据库和消息中间件。
Redis 是 Remote dictionary server 即远程字典服务的缩写,一个 Redis 实例可以有多个存储数据的字典,客户端可以通过 select 来选择字典即 DB 进行数据存储。
Redis核心数据类型同为 key-value 存储组件,Memcached 只能支持二进制字节块这一种数据类型。而 Redis 的数据类型却丰富的多,它具有 8 种核心数据类型,每种数据类型都有一系列操作指令对应。
首先,来看一下 Redis 的核心数据类型。Redis 有 8 种核心数据类型,分别是 :
string 字符串类型;
list 列表类型;
set 集合类型;
sorted set 有序集合类型;
hash 类型;
bitmap 位图类型;
geo 地理位置类型;
HyperLogLog 基数统计类型。
string 字符串string 是 Redis 的最基本数据类型。可以把它理解为 ...
缓存的基本思想
缓存的基本思想空间换时间。
缓存中的数据通常存储于内存中,因此访问速度非常快。为了避免内存中的数据在重启或者宕机之后丢失,很多缓存中间件会利用磁盘做持久化。
缓存相比较于我们常用的关系型数据库来说访问速度要快非常多,为了避免用户请求数据库中的数据速度过于缓慢,我们可以在数据库之上增加一层缓存。
除了能提高访问速度之外,缓存支持的并发量也要大。有了缓存后,数据库的压力也会随之变小。
缓存的分类本地缓存本地缓存的方案
JDK 自带的 HashMap 和 ConcurrentHashMap
ConcurrentHashMap 是线程安全版本的 HashMap,大部分场景不会使用这两者做缓存,因为只提供了缓存的功能,并没有提供其他诸如过期时间之类的功能。
Ehcache、Guava Cache、Spring Cache 比较常用的本地缓存框架
Ehcache 比其他两者更重量。Ehcache 可以嵌入到 Hibernate 和 MyBatis 作为多级缓存,并且可以将缓存的数据持久化到本地磁盘中
Guava Cache 和 Spring Cache 两者比较像。Guava 使用更 ...
Java业务开发常见问题
Spring 框架:IoC 和 AOP 是扩展的核心
当 Bean 产生循环依赖时,比如 BeanA 的构造方法依赖 BeanB 作为成员需要注入,BeanB 也依赖 BeanA,你觉得会出现什么问题呢?又有哪些解决方式呢?
答:Bean 产生循环依赖,主要包括两种情况:一种是注入属性或字段涉及循环依赖,另一种是构造方法注入涉及循环依赖。接下来,我分别和你讲一讲。
第一种,注入属性或字段涉及循环依赖,比如 TestA 和 TestB 相互依赖:
1234567891011121314151617181920212223@Componentpublic class TestA { @Autowired @Getter private TestB testB;}@Componentpublic class TestB { @Autowired @Getter private TestA testA;}
针对这个问题,Spring 内部通过三个 Map 的方式解决了这个问题,不会出错。基本原理是,因为循环依赖,所 ...
Java程序从虚拟机迁移到Kubernetes的一些坑
在大多数的公司中,Kubernetes 集群由运维来搭建,而程序的发布一般也是由 CI/CD 平台完成。从虚拟机到 Kubernetes 的整个迁移过程,基本不需要修改任何代码,可能只是重新发布一次而已。所以,我们 Java 开发人员可能对迁移这个事情本身感知不强烈,认为 Kubernetes 只是运维需要知道的事情。但是程序一旦部署到了 Kubernetes 集群中,在容器环境中运行,总是会出现各种各样之前没有的奇怪的问题。
Pod IP 不固定带来的坑Pod 是 Kubernetes 中能够创建和部署应用的最小单元,我们可以通过 Pod IP 来访问到某一个应用实例,但需要注意的是,如果没有经过特殊配置,Pod IP 并不是固定不变的,会在 Pod 重启后会发生变化。
不过好在,通常我们的 Java 微服务都是没有状态的,我们并不需要通过 Pod IP 来访问到某一个特定的 Java 服务实例。通常来说,要访问到部署在 Kubernetes 中的微服务集群,有两种服务发现和访问的方式:
通过 Kubernetes 来实现。也就是通过 Service 进行内部服务的互访,通 ...
漫谈RocketMQ消息发送
topic路由机制消息发送者向某一个topic发送消息时,需要查询topic的路由信息。初次发送时会根据topic的名称向NameServer集群查询topic的路由信息,然后将其缓存在本地内存中,并且每隔30s依次遍历缓存中的topic,向NameServer查询最新的路由信息。如果成功查询到路由信息,会将这些信息更新到本地缓存,实现topic路由信息的动态感知。
RocketMQ提供了自动创建主题的机制,消息发送者向一个不存在的主题发送消息时,向NameServer查询该主题的路由信息会先返回空,如果开启了自动创建主题机制,会使用一个默认的主题名再次从NameServer查询路由信息,然后消息发送者会使用默认主题的路由信息进行负载均衡,但不会直接使用默认路由信息为新主题创建对应的路由信息。
生产环境中,为何不建议自动创建topic原因分析因为生产环境一般是集群部署多台broker服务器,autoCreateTopicEnable设置为true,表示开启topic自动创建,但新创建的topic的路由信息只包含在其中一台broker服务器上。
期望回答:为了消息发送的高可用,希望新创 ...
线程安全小妙招
TreadLocal的正确打开方式我们知道,ThreadLocal 适用于变量在线程间隔离,而在方法或类间共享的场景。如果用户信息的获取比较昂贵(比如从数据库查询用户信息),那么在 ThreadLocal 中缓存数据是比较合适的做法。
但是如果错误地使用了ThreadLocal,可能会导致有时获取到的用户信息是别人的。为什么会出现用户信息错乱的 Bug 呢?
我们来复现一下这个场景。
使用 Spring Boot 创建一个 Web 应用程序,使用 ThreadLocal 存放一个 Integer 的值,来暂且代表需要在线程中保存的用户信息,这个值初始是 null。在业务逻辑中,我先从 ThreadLocal 获取一次值,然后把外部传入的参数设置到 ThreadLocal 中,来模拟从当前上下文获取到用户信息的逻辑,随后再获取一次值,最后输出两次获得的值和线程名称。
12345678910111213141516private static final ThreadLocal<Integer> currentUser = ThreadLocal.withInitial(() ...
RocketMQ集群性能调优及运维
系统参数调优在解压 RocketMQ 安装包后,在 bin 目录中有个 os.sh 的文件,该文件由 RocketMQ 官方推荐系统参数配置。通常这些参数可以满足系统需求,也可以根据情况进行调整。
最大文件数设置用户的打开的最多文件数:
123456vim /etc/security/limits.conf# End of filebaseuser soft nofile 655360baseuser hard nofile 655360* soft nofile 655360* hard nofile 655360
系统参数设置系统参数的调整以官方给出的为主,下面对各个参数做个说明。设置时可以直接执行 sh os.sh 完成系统参数设定,也可以编辑 vim /etc/sysctl.conf 文件手动添加如下内容,添加后执行 sysctl -p 让其生效。
123456789vm.overcommit_memory=1vm.drop_caches=1vm.zone_reclaim_mode=0vm.max_map_count=655360vm.dirty_background_rat ...
RocketMQ消息消费原理及实战
DefaultMQPushConsumer 核心参数与工作原理Push模型消息拉取机制
其核心关键点如下:
经过队列负载机制后,会分配给当前消费者一些队列,注意一个消费组可以订阅多个主题,正如上面 pullRequestQueue 中所示,topic_test、topic_test1 这两个主题都分配了一个队列。
轮流从 pullRequestQueue 中取出一个 PullRequest 对象,根据该对象中的拉取偏移量向 Broker 发起拉取请求,默认拉取 32 条,可通过上文中提到的 pullBatchSize 参数进行改变,该方法不仅会返回消息列表,还会返更改 PullRequest 对象中的下一次拉取的偏移量。
接收到 Broker 返回的消息后,会首先放入 ProccessQueue(处理队列),该队列的内部结构为 TreeMap,key 存放的是消息在消息消费队列(consumequeue)中的偏移量,而 value 为具体的消息对象。
然后将拉取到的消息提交到消费组内部的线程池,并立即返回,并将 PullRequest 对象放入到 pullRequestQueue 中 ...
JVM调优实战——解决内存占用高问题
JVM启动后一段时间内内存占用飙升如下,是我们一服务重启后运行快2天的内存占用情况,可以发现内存一直从45%涨到了62%,8G的容器,上涨内存大小为1.36G!
但我们这个服务其实没有内存泄露问题,因为JVM为堆申请的内存是虚拟内存,如4.8G,但在启动后JVM一开始可能实际只使用了3G内存,导致Linux实际只分配了3G。
然后在gc时,由于会复制存活对象到堆的空闲部分,如果正好复制到了以前未使用过的区域,就又会触发Linux进行内存分配,故一段时间内内存占用会越来越多,直到堆的所有区域都被touch到。
而通过添加JVM参数-XX:+AlwaysPreTouch,可以让JVM为堆申请虚拟内存后,立即把堆全部touch一遍,使得堆区域全都被分配物理内存,而由于Java进程主要活动在堆内,故后续内存就不会有很大变化了,我们另一服务添加了此参数,内存表现如下:
可以看到,内存上涨幅度不到2%,无此参数可以提高内存利用度,加此参数则会使应用运行得更稳定。
如我们之前一服务一周内会有1到2次GC耗时超过2s,当我添加此参数后,再未出现过此情况。这是因为当无此参数时,若GC访问到了未读写 ...