KANG's BLOG

Let's have some fun

分布式的核心问题:复制和分区

前言 互联网时代的用户爆发式增长,为了提供系统的可靠性、可扩展性、高性能等特点,分布式的架构方式应运而生。 想提供7x24的业务可用性,就必须让同一份数据存储在不同机器上用作备份。 为了解决并发高的问题,单一机器无法满足要求,就需要水平增加更多的机器来提升性能。 这就是分布式下的两个核心问题:复制和分区。 复制 1 为什么要复制 高可用性 当一个数据节点出现问题不能响应请求时,系统仍可以通过将请求打到其他数据节点上来保证系统的整体可用性。

clickhouse基础概念

Clickhouse特点 Clickhouse(后面简称ck)主要用于在线分析处理查询,得益于优秀的设计,成为OLAP领域的佼佼者。 下面就来看看它具体采用了哪些设计来达到高性能的实时分析能力。 对于数据库来说,高性能的核心问题就是并行处理和减少磁盘IO,所以ck采用了MPP架构,底层数据基于列式存储。 MPP 大规模并行处理架构,是share nothing类型的,特点是每个计算单元内所有的资源完全独立,包括CPU、内存、硬盘、甚至操作系统,节点间数据完全隔离,仅靠网络进行通信。 计算时各个节点单独计算,最后汇总后进行整理。所以上层用户使用时,MPP架构可以被视作整体。 share nothing的流行,也是因为随着时代发展,硬件层级能够带来万兆带宽和RDMA技术的支撑。

高效团队建设

高效团队的七条准则 把团队人数控制在10人以下 小型团队具有较低的沟通成本。 过多人参与同一个目标的话,每个人的责任感会变低。 团队需要充分的心理安全环境 一线员工作为企业的直接生产力,应该有充分的心理安全环境,这更利于他们主动表达、敢于创新、勇于承担。 如何使团队成员获得心理安全,放弃印象管理,应当是团队建设的第一要务。 复盘十分重要 越是项目型团队应该越频繁的进行高质量的复盘,复盘能够让团队成员清晰看到目标和现实的差距,并找到实现目标的路径。 公司中90%的工作是通过协作和不断及时复盘来完成的。

JVM中方法调用原理

1 引言 多态是Java语言极为重要的一个特性,可以说是Java语言动态性的根本,那么线程执行一个方法时到底在内存中经历了什么,JVM又是如何确定方法执行版本的呢? 2 栈帧 JVM中由栈帧存储方法的局部变量表、操作数栈、动态连接和方法返回地址等信息。每一个方法的调用就是从入栈到出栈到过程。 2.1 局部变量表 局部变量表由变量槽组成,《Java虚拟机规范》指出:“每个变量槽都应该能存放一个boolean、byte、char、short、int、float、reference或returnAddress类型的数据”。 这八种数据类型都可以使用32位或更小的物理内存来存储,如果是64位虚拟机环境下,虚拟机需要通过对齐填充来使变量槽与在32位虚拟机环境下外观一致。

现代JDK中亚毫秒级停顿的处理器:Shenandoah和ZGC

Shenandoah一词来自于印第安语,十九世纪四十年代有一首著名的航海歌曲在水手中广为流传,讲述一位年轻富商爱上印第安酋长Shenandoah的女儿的故事。后来美国有一条位于Virginia州西部的小河以此命名,所以Shenandoah的中文译名为“情人渡”...

一种适用于简单业务的微服务分层架构

前言 从强调内外隔离的六边形架构,逐渐发展衍生出的层层递进、注重领域模型的洋葱架构,再到和DDD完美契合的整洁架构。架构风格的不断演进,其实就是为了适应软件需求越来越复杂的特点。 可以看到,越现代的架构风格越倾向于清晰的职责定位,且让领域模型成为架构的核心。 基于这些架构风格,在软件架构设计过程中又有非常多的架构分层模型。 三层架构 传统服务通常使用三层架构: 门面层 作为服务暴露的入口,处理所有的外部请求。部分情况下,门面层甚至不需要单独定义对象而是直接使用服务层的实体定义。 服务层 作为核心业务层,包含所有业务逻辑。并对基础层能力进行简单组合提供一定的能力复用。

JVM经典垃圾回收器的运行机制和原理

1 JVM运行时内存划分 1.1 运行时数据区域 方法区 属于共享内存区域,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。 运行时常量池,属于方法区的一部分,用于存放编译期生成的各种字面量和符号引用。 JDK1.8之前,Hotspot虚拟机对方法区的实现叫做永久代,1.8之后改为元空间。二者区别主要在于永久代是在JVM虚拟机中分配内存,而元空间则是在本地内存中分配的。很多类是在运行期间加载的,它们所占用的空间完全不可控,所以改为使用本地内存,避免对JVM内存的影响。 根据《Java虚拟机规范》的规定,如果方法区无法满足新的内存分配需求时,将抛出OutOfMemoryError异常。 堆 线程共享,主要是存放对象实例和数组。

Java类加载原理

类加载的时机 类的完整生命周期分为如下步骤: flowchart LR load(加载)-->verification(验证)-->preperation(准备)-->resolution(解析)-->initialization(初始化)-->using(使用)-->unloading(卸载) classDef circle1 fill:#3e93ef, stroke:#3e93ef, color: #fff; classDef circle2 fill:#ff8a00, stroke:#ff8a00, color: #fff; load:::circle1 verification:::circle1 preperation:::circle1 initialization:::circle1 unloading:::circle1 resolution:::circle2 using:::circle2 其中加载、验证、准备、初始化和卸载这五个阶段的顺序是确定的,而Java为了支持“动态绑定”,解析有可能在初始化之后。

统一管理jar包版本的工具: Maven BOM

BOM是什么 BOM全称Bill Of Materials,中文是材料清单。POM自身只支持单继承,BOM的作用就行进行统一的包版本管理。尤其适合解决对于微服务架构下,需要统一多个服务jar包版本的诉求。 开源的RPC组件Dubbo就提供了这样一份BOM:dubbo-dependencies-bom BOM有什么 BOM并不是特殊的技术或者组件,其仅仅是一份pom文件,核心是在<dependencyManagement/>节点中添加不同jar包的maven坐标。其他项目使用bom后,再引用bom中包含的jar时,就不需要显示的指定jar包版本了。 <project...> <modelVersion>4.0.0</modelVersion> <groupId>com.jd.open</groupId> <artifactId>open-bom</artifactId> <version>1.

栈上分配和TLAB的区别

栈上分配 JVM中,栈上空间为线程私有,堆上空间为全局共享。所以大部分对象存在于堆上,线程通过栈上的引用指向堆上对象的内存地址。堆上没有任何引用关系的对象会被JVM标记后GC掉。 很多对象不存在逃逸现象,即线程专有,那么从栈到堆的寻址过程就显得有些多余了,而且还需要等到GC时才能清理该对象,不如直接将该对象创建在线程自身的栈帧中,随着线程销毁直接清除,这就叫栈上分配。JDK7之后,栈上分配的对象会被JVM打散成一个一个的原始类型,这些原始类型就叫做“标量”,这个行为叫做标量替换。每个标量可以被单独的分析和优化,这样就无需再创建原始对象了,即节省了创建对象的成本,又避免了对象清理带来的GC。栈上分配和标量替换都是JIT的优化机制,更多可见:JIT编译器的优化方式 举个例子,通过语文和英语考试分数相加计算总分: class Score { int chinese; int english; } public int calculateTotalScore() { Score score = new Score(1, 2); return score.