消息队列问题
MQ 的问题任何技术都会有利有弊,MQ 给整体系统架构带来很多好处,但也会付出一定的代价。
MQ 主要引入了以下问题:
系统可用性降低:引入了 MQ 后,通信需要基于 MQ 完成,如果 MQ 宕机,则服务不可用。
系统复杂度提高
使用 MQ,需要关注一些新的问题:
如何保证消息没有 重复消费?
如何处理 消息丢失 的问题?
如何保证传递 消息的顺序性?
如何处理大量 消息积压 的问题?
一致性问题:假设系统 A 处理完直接返回成功的结果给用户,用户认为请求成功。但如果此时,系统 BCD 中只要有任意一个写库失败,那么数据就不一致了。这种情况如何处理?
下面,我们针对以上问题来一一分析。
1. 重复消费如何保证消息不被重复消费 和 如何保证消息消费的幂等性 是同一个问题。
必须先明确产生重复消费的原因,才能对症下药。
重复消费问题原因重复消费问题通常不是 MQ 来处理,而是由开发来处理的。
以 Kafka 举例,Kafka 每个 Partition 都是一个有序的、不可变的记录序列,不断追加到结构化的提交日志中。Partition 中为每条记录分配一个连续的 id 号,称为 ...
Skip List--跳表
Skip List–跳表跳表是一种神奇的数据结构,因为几乎所有版本的大学本科教材上都没有跳表这种数据结构,而且神书《算法导论》、《算法第四版》这两本书中也没有介绍跳表。但是跳表插入、删除、查找元素的时间复杂度跟红黑树都是一样量级的,时间复杂度都是O(logn),而且跳表有一个特性是红黑树无法匹敌的(具体什么特性后面会提到)。所以在工业中,跳表也会经常被用到。废话不多说了,开始今天的跳表学习。
通过本文,你能 get 到以下知识:
什么是跳表?
跳表的查找、插入、删除元素的流程
跳表查找、插入、删除元素的时间复杂度
跳表插入元素时,如何动态维护索引?
为什么Redis选择使用跳表而不是红黑树来实现有序集合?
工业上其他使用跳表的场景
友情提示:下文在跳表插入数据时,会讲述如何动态维护索引,实现比较简单,逻辑比较绕,不要放弃,加油!!!如果一遍看不懂没关系,可以选择暂时性的跳过,毕竟这块偏向于源码。但是读者必须知道跳表的查找、插入、删除的时间复杂度都是 O(logn),而且可以按照范围区间查找元素,当工作中遇到某些场景时,需要想到可以使用跳表解决问题即可。毕竟 ...
10.分库分表
1. 为什么要拆分数据库?单体项目在构建之初,数据库的负载和数据量都不大,所以不需要对数据库做拆分,小型财务系统、文书系统、ERP系统、OA系统,用一个MySQL数据库实例基本就够用了。
就像《淘宝技术这十年》里面说到的,电商业务的数据量增长飞快,所以最开始的PHP+MySQL的架构已经不能满足实际要求了,于是淘宝想到的第一个办法就是把MySQL替换成Oracle。但是没过了多久,在08年前后,单节点的Oracle数据库也不好用了,于是淘宝终于告别了单节点数据库,开始拆分数据库。从一个节点,变成多个节点。
拆分数据库是有讲究的,比如说拆分方法有两种:垂直切分和水平切分。那你是先水平切分还是垂直切分呢?顺序无所谓?不,顺序有所为,次序绝对不能错:先水平切分,然后垂直切分。
2. 什么是垂直切分?垂直切分是根据业务来拆分数据库,同一类业务的数据表拆分到一个独立的数据库,另一类的数据表拆分到其他数据库。
比如说一个新零售的电商数据库,我们可以把跟商品相关的数据表拆分成一个数据库,然后在这些数据表的基础之上,构建出商品系统。比如用JAVA或者PHP语言,创建出一个商城系统。然后把跟进销存相关的 ...
13.线程安全
4种解决线程安全问题的方式前言线程安全问题,在做高并发的系统的时候,是程序员经常需要考虑的地方。怎么有效的防止线程安全问题,保证数据的准确性?怎么合理的最大化的利用系统资源等,这些问题都需要充分的理解并运行线程。当然关于多线程的问题在面试的时候也是出现频率比较高的。下面就来学习一下吧!
线程先来看看什么是进程和线程?
进程是资源(CPU、内存等)分配的基本单位,它是程序执行时的一个实例。程序运行时系统就会创建一个进程,并为它分配资源,然后把该进程放入进程就绪队列,进程调度器选中它的时候就会为它分配CPU时间,程序开始真正运行。就比如说,我们开发的一个单体项目,运行它,就会产生一个进程。
线程是程序执行时的最小单位,它是进程的一个执行流,是CPU调度和分派的基本单位,一个进程可以由很多个线程组成,线程间共享进程的所有资源,每个线程有自己的堆栈和局部变量。线程由CPU独立调度执行,在多CPU环境下就允许多个线程同时运行。同样多线程也可以实现并发操作,每个请求分配一个线程来处理。在这里强调一点就是:计算机中的线程和应用程序中的线程不是同一个概念。
总之一句话描述就是:进程是资源分配的最小单位 ...
7.CPU密集型和IO密集型
在看《Java并发编程的艺术》线程池这一块时,提到了要合理地配置线程池,要分析任务特性。任务的性质:CPU密集型、IO密集型和混合型。
CPU密集型和IO密集型CPU密集型也是指计算密集型,大部分时间用来做计算逻辑判断等CPU动作的程序称为CPU密集型任务。该类型的任务需要进行大量的计算,主要消耗CPU资源。这种计算密集型任务虽然也可以用多任务完成,但是任务越多,花在任务切换的时间就越多,CPU执行任务的效率就越低,所以,要最高效地利用CPU,计算密集型任务同时进行的数量应当等于CPU的核心数。
IO密集型任务指任务需要执行大量的IO操作,涉及到网络、磁盘IO操作,对CPU消耗较少。
和线程池配置的关系CPU密集型任务应配置尽可能小的线程,如配置CPU数目+1个线程的线程池。由于IO密集型任务线程并不是一直在执行任务,则应配置尽可能多的线程,如2*CPU数目。
区别和使用:IO密集型:大量网络,文件操作 CPU 密集型:大量计算,cpu 占用越接近 100%, 耗费多个核或多台机器
业务要具体分析,假如CPU现在是10%,数据量增大一点点,CPU狂飙,那也可能CPU密集型。
如何确定线 ...
代理
Java 反射和动态代理简介什么是反射反射(Reflection)是 Java 程序开发语言的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性。
通过反射机制,可以在运行时访问 Java 对象的属性,方法,构造方法等。
反射的应用场景反射的主要应用场景有:
开发通用框架 - 反射最重要的用途就是开发各种通用框架。很多框架(比如 Spring)都是配置化的(比如通过 XML 文件配置 JavaBean、Filter 等),为了保证框架的通用性,它们可能需要根据配置文件加载不同的对象或类,调用不同的方法,这个时候就必须用到反射——运行时动态加载需要加载的对象。
动态代理 - 在切面编程(AOP)中,需要拦截特定的方法,通常,会选择动态代理方式。这时,就需要反射技术来实现了。
注解 - 注解本身仅仅是起到标记作用,它需要利用反射机制,根据注解标记去调用注解解释器,执行行为。如果没有反射机制,注解并不比注释更有用。
可扩展性功能 - 应用程序可以通过使用完全限定名称创建可扩展性对象实例来使用外部的用户定义类。
反射的缺点
性能开销 ...
20.双亲委派
Java双亲委派模型一、前言平时做业务开发比较少接触类加载器,但是如果想深入学习Tomcat、Spring等开源项目,或者从事底层架构的开发,了解甚至熟悉类加载的原理是必不可少的。
java的类加载器有哪些?什么是双亲委派?为什么要双亲委派?如何打破它?多多少少对这些概念了解一些,甚至因为应付面试背过这些知识点,但是再深入一些细节,却知之甚少。
二、类加载器类加载器,顾名思义就是一个可以将Java字节码加载为java.lang.Class实例的工具。这个过程包括,读取字节数组、验证、解析、初始化等。另外,它也可以加载资源,包括图像文件和配置文件。
类加载器的特点:
动态加载,无需在程序一开始运行的时候加载,而是在程序运行的过程中,动态按需加载,字节码的来源也很多,压缩包jar、war中,网络中,本地文件等。类加载器动态加载的特点为热部署,热加载做了有力支持。
全盘负责,当一个类加载器加载一个类时,这个类所依赖的、引用的其他所有类都由这个类加载器加载,除非在程序中显式地指定另外一个类加载器加载。所以破坏双亲委派不能破坏扩展类加载器以上的顺序。
一个类的唯一性由加载它的类加载器 ...
5.操作系统-进程调度算法
进程调度算法先来先服务调度算法先来先服务(FCFS)调度算法是一种最简单的调度算法,该算法既可用于作业调度,也可用于进程调度。当在作业调度中采用该算法时,每次调度都是从后备作业队列中选择一个或多个最先进入该队列的作业,将它们调入内存,为它们分配资源、创建进程,然后放入就绪队列。在进程调度中采用FCFS算法时,则每次调度是从就绪队列中选择一个最先进入该队列的进程,为之分配处理机,使之投入运行。该进程一直运行到完成或发生某事件而阻塞后才放弃处理机。
短作业(进程)优先调度算法短作业(进程)优先调度算法,是指对短作业或短进程优先调度的算法。它们可以分别用于作业调度和进程调度。短作业优先(SJF)的调度算法是从后备队列中选择一个或若干个估计运行时间最短的作业,将它们调入内存运行。而短进程优先(SPF)调度算法则是从就绪队列中选出一个估计运行时间最短的进程,将处理机分配给它,使它立即执行并一直执行到完成,或发生某事件而被阻塞放弃处理机时再重新调度。
时间片轮转法在早期的时间片轮转法中,系统将所有的就绪进程按先来先服务的原则排成一个队列,每次调度时,把CPU分配给队首进程,并令其执行一个时间片。时 ...
6.死锁的概念
死锁概念,死锁产生的四个必要条件,如何避免和预防死锁一、死锁概念死锁是指两个或多个进程在执行的过程中,因为竞争资源而造成互相等待的现象,若无外力作用,它们都无法推进下去。-1.在等待对方时占有不可抢占的资源-举个例子,假设有P1,P2两个进程,都需要A和B两个资源,两个都等待另一个资源而不肯释放资源,就这样无限等待中,这就形成死锁。这只是死锁的一种情况,就是在等待对方时占有不可抢占的资源。-2.竞争可消耗资源引起死锁-有P1,P2,P3三个进程,P1向P2发送消息并接受P3消息,P2向P3发送消息并接受P2消息,P3向P1发送消息并接受P2消息,如果设置是先接到消息后发送消息,则所有的消息都不能发送,也造成了死锁。-3.进程推进顺序不当引起死锁-有进程P1,P2,都需要资源A,B,本来可以P1运行A,P1运行B,P2运行B,P2运行A,P2运行B,但顺序换了,P1运行A时P2运行B,容易引发死锁,属于第一种的资源抢占问题。
二、产生死锁的四个必要条件1.互斥条件-一个资源每次只能被一个进程使用,即在一段时间内某资源仅为一个进程所使用。此时如果有其他进程请求该资源,则请求进程只能等待。- ...
4.操作系统-页面置换算法
页面置换算法地址映射过程中,若在页面中发现所要访问的页面不在内存中,则产生缺页中断。当发生缺页中断时操作系统必须在内存选择一个页面将其移除内存,以便为即将调入的页面让出空间。而用来选择淘汰那一页的规则叫做页面置换算法。
最佳置换算法(OPT)(理想置换算法)这是一种理想情况下的页面置换算法,但实际上是不可能实现的。该算法的基本思想是:发生缺页时,有些页面在内存中,其中有一页将很快被访问(也包含紧接着的下一条指令的那页),而其他页面则可能要到10、100或者1000条指令后才会被访问,每个页面都可以用在该页面首次被访问前所要执行的指令数进行标记。最佳页面置换算法只是简单地规定:标记最大的页应该被置换。这个算法唯一的一个问题就是它无法实现。当缺页发生时,操作系统无法知道各个页面下一次是在什么时候被访问。虽然这个算法不可能实现,但是最佳页面置换算法可以用于对可实现算法的性能进行衡量比较。
先进先出置换算法(FIFO)最简单的页面置换算法是先入先出(FIFO)法。这种算法的实质是,总是选择在主存中停留时间最长(即最老)的一页置换,即先进入内存的页,先退出内存。理由是:最早调入内存的页,其不再被 ...