diff --git a/Docker.md b/Docker.md new file mode 100644 index 0000000..61f0298 --- /dev/null +++ b/Docker.md @@ -0,0 +1,172 @@ +### Docker + +* [1.什么Docker](#1什么docker) +* [2.Docker与虚拟机有何不同](#2docker与虚拟机有何不同) +* [3.什么是Docker镜像](#3什么是docker镜像) +* [4.什么是Docker容器](#4什么是docker容器) +* [5.Docker容器有几种状态](#5docker容器有几种状态) +* [6.DockerFile中最常见的指定是什么?](#6dockerfile中最常见的指定是什么) +* [7.DockerFile中的命令COPY和ADD命令有什么区别?](#7dockerfile中的命令copy和add命令有什么区别) +* [8.Docker的常用命令?](#8docker的常用命令) +* [9.容器与主机之间的数据拷贝命令?](#9容器与主机之间的数据拷贝命令) +* [10.启动nginx容器(随机端口映射),并挂载本地文件目录到容器html的命令?](#10启动nginx容器随机端口映射并挂载本地文件目录到容器html的命令) +* [11.如何使用 Docker 技术创建与环境无关的容器系统?](#11如何使用-docker-技术创建与环境无关的容器系统) +* [12.有什么方法确定一个 Docker 容器运行状态](#12有什么方法确定一个-docker-容器运行状态) +* [13. Docker Image 和 Docker Layer (层) 有什么不同](#13-docker-image-和-docker-layer-层-有什么不同) +* [14.如何停止所有正在运行的容器?](#14如何停止所有正在运行的容器) +* [15.如何清理批量后台停止的容器?](#15如何清理批量后台停止的容器) +* [16.如何临时退出一个正在交互的容器的终端,而不终止它?](#16如何临时退出一个正在交互的容器的终端而不终止它) +* [17.Docker 群(Swarm)是什么](#17docker-群swarm是什么) +* [18.在使用 Docker 技术的产品中如何监控其运行](#18在使用-docker-技术的产品中如何监控其运行) +* [19.什么是孤儿卷及如何删除它?](#19什么是孤儿卷及如何删除它) +* [20.在 Windows 系统上可以运行原生的 Docker 容器吗?](#20在-windows-系统上可以运行原生的-docker-容器吗) +* [21.在 非 Linux 操作系统平台上如何运行 Docker ?](#21在-非-linux-操作系统平台上如何运行-docker-) +* [参考链接](#参考链接) + +#### 1.什么Docker + +Docker是一个容器化平台,它以容器的形式将您的应用程序及其所有依赖项打包在一起,以确保您的应用程序在任何环境中无缝运行。 + +#### 2.Docker与虚拟机有何不同 + +Docker不是虚拟化方法。它依赖于实际实现基于容器的虚拟化或操作系统级虚拟化的其他工具。为此,Docker最初使用LXC驱动程序,然后移动到libcontainer现在重命名为runc。Docker主要专注于在应用程序容器内自动部署应用程序。应用程序容器旨在打包和运行单个服务,而系统容器则设计为运行多个进程,如虚拟机。因此,Docker被视为容器化系统上的容器管理或应用程序部署工具。 +A 容器不需要引导操作系统内核,因此可以在不到一秒的时间内创建容器。此功能使基于容器的虚拟化比其他虚拟化方法更加独特和可取。 +B 由于基于容器的虚拟化为主机增加了很少或没有开销,因此基于容器的虚拟化具有接近本机的性能。 +C 对于基于容器的虚拟化,与其他虚拟化不同,不需要其他软件。 +D 主机上的所有容器共享主机的调度程序,从而节省了额外资源的需求。 +E 与虚拟机映像相比,容器状态(Docker或LXC映像)的大小很小,因此容器映像很容易分发。 +F 容器中的资源管理是通过cgroup实现的。Cgroups不允许容器消耗比分配给它们更多的资源。虽然主机的所有资源都在虚拟机中可见,但无法使用。这可以通过在容器和主机上同时运行top或htop来实现。所有环境的输出看起来都很相似。 + +#### 3.什么是Docker镜像 + +Docker镜像是Docker容器的源代码,Docker镜像用于创建容器。使用build命令创建镜像。 + +#### 4.什么是Docker容器 + +Docker容器包括应用程序及其所有依赖项,作为操作系统的独立进程运行。 + +#### 5.Docker容器有几种状态 + +四种状态:运行、已暂停、重新启动、已退出。 + +#### 6.DockerFile中最常见的指定是什么? + +| 指令 | 备注 | +| ----- | ---------------------- | +| FROM | 指定基础镜像 | +| LABEL | 功能为镜像指定标签 | +| RUN | 运行指定命令 | +| CMD | 容器启动时要运行的命令 | + +#### 7、DockerFile中的命令COPY和ADD命令有什么区别? + +COPY和ADD的区别时COPY的SRC只能是本地文件,其他用法一致。 + +#### 8.Docker的常用命令? + +| 命令 | 备注 | +| ------------- | -------------------- | +| docker pull | 拉去或更新指定的镜像 | +| docker push | 将镜像推送到远程仓库 | +| docker rm | 删除容器 | +| docker rmi | 删除镜像 | +| docker images | 列出所有镜像 | +| docker ps | 列出所有容器 | + +#### 9.容器与主机之间的数据拷贝命令? + +Docker cp命令用于穷奇与主机之间的数据拷贝 + +- 主机到哦容器:docker cp /www 96f7f14e99ab:/www/ +- 容器到主机:docker cp 96f7f14e99ab:/www /tmp + +#### 10.启动nginx容器(随机端口映射),并挂载本地文件目录到容器html的命令? + +``` +Docker run -d -p --name nginx2 -v /home/nginx:/usr/share/nginx/html nginx +``` + +#### 11.如何使用 Docker 技术创建与环境无关的容器系统? + +Docker 技术有三中主要的技术途径辅助完成此需求: + +- 存储卷(Volumes) +- 环境变量(Environment variable)注入 +- 只读(Read-only)文件系统 + +#### 12.有什么方法确定一个 Docker 容器运行状态 + +使用如下命令行命令确定一个 Docker 容器的运行状态 + +``` +$ docker ps –a +``` + +这将列表形式输出运行在主机上的所有 Docker 容器及其运行状态。从这个列表中很容易找到想要的容器及其运行状态。 + +#### 13. Docker Image 和 Docker Layer (层) 有什么不同 + +Image :一个 Docker Image 是由一系列 Docker 只读层(read-only Layer) 创建出来的。 +Layer: 在 Dockerfile 配置文件中完成的一条配置指令,即表示一个 Docker 层(Layer)。 +如下 Dockerfile 文件包含 4 条指令,每条指令创建一个层(Layer)。 + +``` +FROM ubuntu:15.04 +COPY . /app +RUN make /app +CMD python /app/app.py +``` + +重点,每层只对其前一层进行一(某)些进化。 + +#### 14.如何停止所有正在运行的容器? + +使用docker kill $(sudo docker ps -q) + +#### 15.如何清理批量后台停止的容器? + +使用docker rm $(sudo docker ps -a -q) + +#### 16.如何临时退出一个正在交互的容器的终端,而不终止它? + +按Ctrl+p,后按Ctrl+q,如果按Ctrl+c会使容器内的应用进程终止,进而会使容器终止。 + +#### 17.Docker 群(Swarm)是什么 + +Docker Swarm -- Docker 群 -- 是原生的 Docker 集群服务工具。它将一群 Docker 主机集成为单一一个虚拟 Docker 主机。利用一个 Docker 守护进程,通过标准的 Docker API 和任何完善的通讯工具,Docker Swarm 提供透明地将 Docker 主机扩散到多台主机上的服务。 + +#### 18.在使用 Docker 技术的产品中如何监控其运行 + +Docker 在产品中提供如 运行统计和 Docker 事件的工具。可以通过这些工具命令获取 Docker 运行状况的统计信息或报告。 + +Docker stats : 通过指定的容器 id 获取其运行统计信息,可获得容器对 CPU,内存使用情况等的统计信息,类似 Linux 系统中的 top 命令。 +Docker events :Docker 事件是一个命令,用于观察显示运行中的 Docker 一系列的行为活动。 +一般的 Docker 事件有:attach(关联),commit(提交),die(僵死),detach(取消关联),rename(改名),destory(销毁)等。也可使用多个选项对事件记录筛选找到想要的事件信息。 + +#### 19.什么是孤儿卷及如何删除它? + +孤儿卷是未与任何容器关联的卷。在 Docker v。1.9 之前的版本中,删除这些孤儿卷存在很大问题。 + +#### 20.在 Windows 系统上可以运行原生的 Docker 容器吗? + +在 'Windows Server 2016' 系统上, 你可以运行 Windows 的原生容器, 微软推出其映像是 'Windows Nano Server' , 一个轻量级的运行在容器中的 Windows 原生系统。 您可以在其中布署基于 .NET 的应用。 + +译注: 结合 Docker 的基本技术原理,参考后面的 问题 26 和 问题 27, 可推测, 微软在系统内核上开发了对 Docker 的支持, 支持其闭源系统的容器化虚拟技术。但译者认为, Windows 系统本就是闭源紧耦合的系统, 好像你在本机上不装 .NET 组件,各应用能很好运行似的。何必再弄个容器,浪费资源。这只是译者自己之孔见,想喷就喷! 另: Windows Server 2016 版本之后的都可支持这种原生 Docker 技术,如 Windows Server 2018 版。 + +#### 21.在 非 Linux 操作系统平台上如何运行 Docker ? + +容器化虚拟技术概念可能来源于,在 Linux 内核版本 2.6.24 上加入的对 命名空间( namespace) 的技术支持特性。 容器化进程加入其进程 ID 到其创建的每个进程上并且对每个进程中的系统级调用进行访问控制及审查。 其本身是由系统级调用 clone () 克隆出来的进程, 允许其创建属于自己命名空间的进程实例,而区别于之前的,归属与整个本机系统的进程实例。 + +如果上述在 Linux 系统内核上的技术实现成为可能, 那么明显的问题是如何在 非 Linux 系统上运行容器化的 Docker 。过去, Mac 和 Windows 系统上运行 Docker 容器都使用 Linux 虚拟机(VMs) 技术, Docker 工具箱使用的容器运行在 Virtual Box 虚拟机上。 现在,最新的情况是, Windows 平台上使用的是 Hyper-V 产品技术,Mac 平台上使用的是 Hypervisor.framework (框架)产品技术。 + +#### 参考链接 + +https://www.cnblogs.com/xiaoyangjia/p/11388806.html + +https://www.wkcto.com/article/detail/662 + +https://blog.csdn.net/qq_43286578/article/details/105160725 + +https://learnku.com/server/t/42179 + +https://www.jianshu.com/p/f11077d7b301 diff --git a/Dubbo.md b/Dubbo.md new file mode 100644 index 0000000..361cb32 --- /dev/null +++ b/Dubbo.md @@ -0,0 +1,173 @@ +## Dubbo + +* [1.Dubbo是什么?](#1dubbo是什么) +* [2.为什么要用Dubbo?](#2为什么要用dubbo) +* [3.Dubbo 和 Dubbox 有什么区别?](#3dubbo-和-dubbox-有什么区别) +* [4.dubbo都支持什么协议,推荐用哪种?](#4dubbo都支持什么协议推荐用哪种) +* [5.Dubbo需要 Web 容器吗?](#5dubbo需要-web-容器吗) +* [6.Dubbo内置了哪几种服务容器?](#6dubbo内置了哪几种服务容器) +* [7.Dubbo默认使用什么注册中心,还有别的选择吗?](#7dubbo默认使用什么注册中心还有别的选择吗) +* [8.Dubbo有哪几种配置方式?](#8dubbo有哪几种配置方式) +* [9.在 Provider 上可以配置的 Consumer 端的属性有哪些?](#9在-provider-上可以配置的-consumer-端的属性有哪些) +* [10.Dubbo启动时如果依赖的服务不可用会怎样?](#10dubbo启动时如果依赖的服务不可用会怎样) +* [11.Dubbo推荐使用什么序列化框架,你知道的还有哪些?](#11dubbo推荐使用什么序列化框架你知道的还有哪些) +* [12.Dubbo默认使用的是什么通信框架,还有别的选择吗?](#12dubbo默认使用的是什么通信框架还有别的选择吗) +* [13.注册了多个同一样的服务,如果测试指定的某一个服务呢?](#13注册了多个同一样的服务如果测试指定的某一个服务呢) +* [14.Dubbo支持服务多协议吗?](#14dubbo支持服务多协议吗) +* [15.当一个服务接口有多种实现时怎么做?](#15当一个服务接口有多种实现时怎么做) +* [16.服务上线怎么兼容旧版本?](#16服务上线怎么兼容旧版本) +* [17.Dubbo可以对结果进行缓存吗?](#17dubbo可以对结果进行缓存吗) +* [18.Dubbo服务之间的调用是阻塞的吗?](#18dubbo服务之间的调用是阻塞的吗) +* [19.Dubbo支持分布式事务吗?](#19dubbo支持分布式事务吗) +* [20.Dubbo支持服务降级吗?](#20dubbo支持服务降级吗) +* [21.Dubbo如何优雅停机?](#21dubbo如何优雅停机) +* [22.服务提供者能实现失效踢出是什么原理?](#22服务提供者能实现失效踢出是什么原理) +* [23.如何解决服务调用链过长的问题?](#23如何解决服务调用链过长的问题) +* [24.服务读写推荐的容错策略是怎样的?](#24服务读写推荐的容错策略是怎样的) +* [25.Dubbo必须依赖的包有哪些?](#25dubbo必须依赖的包有哪些) +* [26.Dubbo的管理控制台能做什么?](#26dubbo的管理控制台能做什么) +* [27.说说 Dubbo 服务暴露的过程。](#27说说-dubbo-服务暴露的过程) + +#### 1.Dubbo是什么? + +Dubbo是阿里巴巴开源的基于 Java 的高性能 RPC 分布式服务框架,现已成为 Apache 基金会孵化项目。 + +#### 2.为什么要用Dubbo? + +因为是阿里开源项目,国内很多互联网公司都在用,已经经过很多线上考验。内部使用了 Netty、Zookeeper,保证了高性能高可用性。 + +使用 Dubbo 可以将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,可用于提高业务复用灵活扩展,使前端应用能更快速的响应多变的市场需求。 + +#### 3.Dubbo 和 Dubbox 有什么区别? + +Dubbox 是继 Dubbo 停止维护后,当当网基于 Dubbo 做的一个扩展项目,如加了服务可 Restful 调用,更新了开源组件等。 + +#### 4.dubbo都支持什么协议,推荐用哪种? + +dubbo://(推荐) + +rmi:// + +hessian:// + +http:// + +webservice:// + +thrift:// + +memcached:// + +redis:// + +rest:// + +#### 5.Dubbo需要 Web 容器吗? + +不需要,如果硬要用 Web 容器,只会增加复杂性,也浪费资源。 + +#### 6.Dubbo内置了哪几种服务容器? + +Spring Container + +Jetty Container + +Log4j Container + +#### 7.Dubbo默认使用什么注册中心,还有别的选择吗? + +推荐使用 Zookeeper 作为注册中心,还有 Redis、Multicast、Simple 注册中心,但不推荐。 + +#### 8.Dubbo有哪几种配置方式? + +1)Spring 配置方式 +2)Java API 配置方式 + +#### 9.在 Provider 上可以配置的 Consumer 端的属性有哪些? + +1)timeout:方法调用超时 +2)retries:失败重试次数,默认重试 2 次 +3)loadbalance:负载均衡算法,默认随机 +4)actives 消费者端,最大并发调用限制 + +#### 10.Dubbo启动时如果依赖的服务不可用会怎样? + +Dubbo 缺省会在启动时检查依赖的服务是否可用,不可用时会抛出异常,阻止 Spring 初始化完成,默认 check="true",可以通过 check="false" 关闭检查。 + +#### 11.Dubbo推荐使用什么序列化框架,你知道的还有哪些? + +推荐使用Hessian序列化,还有Duddo、FastJson、Java自带序列化。 + +#### 12.Dubbo默认使用的是什么通信框架,还有别的选择吗? + +Dubbo 默认使用 Netty 框架,也是推荐的选择,另外内容还集成有Mina、Grizzly。 + +#### 13.注册了多个同一样的服务,如果测试指定的某一个服务呢? + +可以配置环境点对点直连,绕过注册中心,将以服务接口为单位,忽略注册中心的提供者列表。 + +#### 14.Dubbo支持服务多协议吗? + +Dubbo 允许配置多协议,在不同服务上支持不同协议或者同一服务上同时支持多种协议。 + +#### 15.当一个服务接口有多种实现时怎么做? + +当一个接口有多种实现时,可以用 group 属性来分组,服务提供方和消费方都指定同一个 group 即可。 + +#### 16.服务上线怎么兼容旧版本? + +可以用版本号(version)过渡,多个不同版本的服务注册到注册中心,版本号不同的服务相互间不引用。这个和服务分组的概念有一点类似。 + +#### 17.Dubbo可以对结果进行缓存吗? + +可以,Dubbo 提供了声明式缓存,用于加速热门数据的访问速度,以减少用户加缓存的工作量。 + +#### 18.Dubbo服务之间的调用是阻塞的吗? + +默认是同步等待结果阻塞的,支持异步调用。 + +Dubbo 是基于 NIO 的非阻塞实现并行调用,客户端不需要启动多线程即可完成并行调用多个远程服务,相对多线程开销较小,异步调用会返回一个 Future 对象。 + +#### 19.Dubbo支持分布式事务吗? + +目前暂时不支持,后续可能采用基于 JTA/XA 规范实现。 + +#### 20.Dubbo支持服务降级吗? + +Dubbo 2.2.0 以上版本支持。 + +#### 21.Dubbo如何优雅停机? + +Dubbo 是通过 JDK 的 ShutdownHook 来完成优雅停机的,所以如果使用 kill -9 PID 等强制关闭指令,是不会执行优雅停机的,只有通过 kill PID 时,才会执行。 + +#### 22.服务提供者能实现失效踢出是什么原理? + +服务失效踢出基于 Zookeeper 的临时节点原理。 + +#### 23.如何解决服务调用链过长的问题? + +Dubbo 可以使用 Pinpoint 和 Apache Skywalking(Incubator) 实现分布式服务追踪,当然还有其他很多方案。 + +#### 24.服务读写推荐的容错策略是怎样的? + +读操作建议使用 Failover 失败自动切换,默认重试两次其他服务器。 + +写操作建议使用 Failfast 快速失败,发一次调用失败就立即报错。 + +#### 25.Dubbo必须依赖的包有哪些? + +Dubbo 必须依赖 JDK,其他为可选。 + +#### 26.Dubbo的管理控制台能做什么? + +管理控制台主要包含:路由规则,动态配置,服务降级,访问控制,权重调整,负载均衡,等管理功能。 + +#### 27.说说 Dubbo 服务暴露的过程。 + +Dubbo 会在 Spring 实例化完 bean 之后,在刷新容器最后一步发布 ContextRefreshEvent 事件的时候,通知实现了 ApplicationListener 的 ServiceBean 类进行回调 onApplicationEvent 事件方法,Dubbo 会在这个方法中调用 ServiceBean 父类 ServiceConfig 的 export 方法,而该方法真正实现了服务的(异步或者非异步)发布。 + + +#### 参考资料 + +https://blog.csdn.net/moakun/article/details/82919804 + diff --git a/Elasticsearch.md b/Elasticsearch.md new file mode 100644 index 0000000..0f9bfc4 --- /dev/null +++ b/Elasticsearch.md @@ -0,0 +1,182 @@ +## Elasticsearch + +* [1.为什么要使用Elasticsearch?](#1为什么要使用elasticsearch) +* [2.Elasticsearch是如何实现Master选举的?](#2elasticsearch是如何实现master选举的) +* [3.Elasticsearch中的节点(比如共20个),其中的10个选了一个master,另外10个选了另一个master,怎么办?](#3elasticsearch中的节点比如共20个其中的10个选了一个master另外10个选了另一个master怎么办) +* [4.详细描述一下Elasticsearch索引文档的过程。](#4详细描述一下elasticsearch索引文档的过程) +* [5.详细描述一下Elasticsearch更新和删除文档的过程](#5详细描述一下elasticsearch更新和删除文档的过程) +* [6.详细描述一下Elasticsearch搜索的过程](#6详细描述一下elasticsearch搜索的过程) +* [7.Elasticsearch对于大数据量(上亿量级)的聚合如何实现?](#7elasticsearch对于大数据量上亿量级的聚合如何实现) +* [8.在并发情况下,Elasticsearch如果保证读写一致?](#8在并发情况下elasticsearch如果保证读写一致) +* [9.ElasticSearch中的集群、节点、索引、文档、类型是什么?](#9elasticsearch中的集群节点索引文档类型是什么) +* [10.ElasticSearch中的分片是什么?](#10elasticsearch中的分片是什么) +* [11.什么是ElasticSearch?](#11什么是elasticsearch) +* [12.Elasticsearch中的倒排索引是什么?](#12elasticsearch中的倒排索引是什么) +* [13.Elasticsearch中的分析器是什么?](#13elasticsearch中的分析器是什么) +* [14.说说Elasticsearch常用的调优手段?](#14说说elasticsearch常用的调优手段) +* [15.Elasticsearch 在部署时,对 Linux 的设置有哪些优化方法?](#15elasticsearch-在部署时对-linux-的设置有哪些优化方法) +* [16.客户端在和集群连接时,如何选择特定的节点执行请求?](#16客户端在和集群连接时如何选择特定的节点执行请求) +* [17.在 Elasticsearch 中,是怎么根据一个词找到对应的倒排索引的?](#17在-elasticsearch-中是怎么根据一个词找到对应的倒排索引的) +* [18.对于 GC 方面,在使用 Elasticsearch 时要注意什么?](#18对于-gc-方面在使用-elasticsearch-时要注意什么) +* [19.在并发情况下,Elasticsearch 如果保证读写一致?](#19在并发情况下elasticsearch-如果保证读写一致) +* [20.如何监控 Elasticsearch 集群状态?](#20如何监控-elasticsearch-集群状态) + + + +#### 1.为什么要使用Elasticsearch? + +因为在我们的数据,将来会非常多,所以采用以往的模糊查询,模糊查询前置配置,会放弃索引,导致商品查询是全表扫面,在百万级别的数据库中,效率非常低下,而我们使用ES做一个全文索引,我们将经常查询的商品的某些字段,比如说商品名,描述、价格还有id这些字段我们放入我们索引库里,可以提高查询速度。 + +#### 2.Elasticsearch是如何实现Master选举的? + +Elasticsearch的选主是ZenDiscovery模块负责的,主要包含Ping(节点之间通过这个RPC来发现彼此)和Unicast(单播模块包含一个主机列表以控制哪些节点需要ping通)这两部分; +对所有可以成为master的节点(node.master: true)根据nodeId字典排序,每次选举每个节点都把自己所知道节点排一次序,然后选出第一个(第0位)节点,暂且认为它是master节点。 +如果对某个节点的投票数达到一定的值(可以成为master节点数n/2+1)并且该节点自己也选举自己,那这个节点就是master。否则重新选举一直到满足上述条件。 +补充:master节点的职责主要包括集群、节点和索引的管理,不负责文档级别的管理;data节点可以关闭http功能。 + +#### 3.Elasticsearch中的节点(比如共20个),其中的10个选了一个master,另外10个选了另一个master,怎么办? + +当集群master候选数量不小于3个时,可以通过设置最少投票通过数量(discovery.zen.minimum_master_nodes)超过所有候选节点一半以上来解决脑裂问题; +当候选数量为两个时,只能修改为唯一的一个master候选,其他作为data节点,避免脑裂问题。 + +#### 4.详细描述一下Elasticsearch索引文档的过程。 + +协调节点默认使用文档ID参与计算(也支持通过routing),以便为路由提供合适的分片。 +shard = hash(document_id) % (num_of_primary_shards) +当分片所在的节点接收到来自协调节点的请求后,会将请求写入到Memory Buffer,然后定时(默认是每隔1秒)写入到Filesystem Cache,这个从Momery Buffer到Filesystem   Cache的过程就叫做refresh; +当然在某些情况下,存在Momery Buffer和Filesystem Cache的数据可能会丢失,ES是通过translog的机制来保证数据的可靠性的。其实现机制是接收到请求后,同时也会写入到translog中,当Filesystem cache中的数据写入到磁盘中时,才会清除掉,这个过程叫做flush; +在flush过程中,内存中的缓冲将被清除,内容被写入一个新段,段的fsync将创建一个新的提交点,并将内容刷新到磁盘,旧的translog将被删除并开始一个新的translog。 +flush触发的时机是定时触发(默认30分钟)或者translog变得太大(默认为512M)时; + +#### 5.详细描述一下Elasticsearch更新和删除文档的过程 + +删除和更新也都是写操作,但是Elasticsearch中的文档是不可变的,因此不能被删除或者改动以展示其变更; +磁盘上的每个段都有一个相应的.del文件。当删除请求发送后,文档并没有真的被删除,而是在.del文件中被标记为删除。该文档依然能匹配查询,但是会在结果中被过滤掉。当段合并时,在.del文件中被标记为删除的文档将不会被写入新段。 +在新的文档被创建时,Elasticsearch会为该文档指定一个版本号,当执行更新时,旧版本的文档在.del文件中被标记为删除,新版本的文档被索引到一个新段。旧版本的文档依然能匹配查询,但是会在结果中被过滤掉。 + +#### 6.详细描述一下Elasticsearch搜索的过程 + +搜索被执行成一个两阶段过程,我们称之为 Query Then Fetch; +在初始查询阶段时,查询会广播到索引中每一个分片拷贝(主分片或者副本分片)。 每个分片在本地执行搜索并构建一个匹配文档的大小为 from + size 的优先队列。PS:在搜索的时候是会查询Filesystem Cache的,但是有部分数据还在Memory Buffer,所以搜索是近实时的。 +每个分片返回各自优先队列中 所有文档的 ID 和排序值 给协调节点,它合并这些值到自己的优先队列中来产生一个全局排序后的结果列表。 +接下来就是 取回阶段,协调节点辨别出哪些文档需要被取回并向相关的分片提交多个 GET 请求。每个分片加载并 丰富 文档,如果有需要的话,接着返回文档给协调节点。一旦所有的文档都被取回了,协调节点返回结果给客户端。 +补充:Query Then Fetch的搜索类型在文档相关性打分的时候参考的是本分片的数据,这样在文档数量较少的时候可能不够准确,DFS Query Then Fetch增加了一个预查询的处理,询问Term和Document frequency,这个评分更准确,但是性能会变差。 + +#### 7.Elasticsearch对于大数据量(上亿量级)的聚合如何实现? + +Elasticsearch 提供的首个近似聚合是cardinality 度量。它提供一个字段的基数,即该字段的distinct或者unique值的数目。它是基于HLL算法的。HLL 会先对我们的输入作哈希运算,然后根据哈希运算的结果中的 bits 做概率估算从而得到基数。其特点是:可配置的精度,用来控制内存的使用(更精确 = 更多内存);小的数据集精度是非常高的;我们可以通过配置参数,来设置去重需要的固定内存使用量。无论数千还是数十亿的唯一值,内存使用量只与你配置的精确度相关 。 + +#### 8.在并发情况下,Elasticsearch如果保证读写一致? + +可以通过版本号使用乐观并发控制,以确保新版本不会被旧版本覆盖,由应用层来处理具体的冲突; +另外对于写操作,一致性级别支持quorum/one/all,默认为quorum,即只有当大多数分片可用时才允许写操作。但即使大多数可用,也可能存在因为网络等原因导致写入副本失败,这样该副本被认为故障,分片将会在一个不同的节点上重建。 +对于读操作,可以设置replication为sync(默认),这使得操作在主分片和副本分片都完成后才会返回;如果设置replication为async时,也可以通过设置搜索请求参数_preference为primary来查询主分片,确保文档是最新版本。 + +#### 9.ElasticSearch中的集群、节点、索引、文档、类型是什么? + +群集是一个或多个节点(服务器)的集合,它们共同保存您的整个数据,并提供跨所有节点的联合索引和搜索功能。群集由唯一名称标识,默认情况下为“elasticsearch”。此名称很重要,因为如果节点设置为按名称加入群集,则该节点只能是群集的一部分。 +节点是属于集群一部分的单个服务器。它存储数据并参与群集索引和搜索功能。 +索引就像关系数据库中的“数据库”。它有一个定义多种类型的映射。索引是逻辑名称空间,映射到一个或多个主分片,并且可以有零个或多个副本分片。 MySQL =>数据库,ElasticSearch =>索引。 +文档类似于关系数据库中的一行。不同之处在于索引中的每个文档可以具有不同的结构(字段),但是对于通用字段应该具有相同的数据类型。 MySQL => Databases =>Tables => Columns / Rows, ElasticSearch => Indices => Types =>具有属性的文档。 +类型是索引的逻辑类别/分区,其语义完全取决于用户。 + +#### 10.ElasticSearch中的分片是什么? + +在大多数环境中,每个节点都在单独的盒子或虚拟机上运行。 +索引 - 在Elasticsearch中,索引是文档的集合。 +分片 -因为Elasticsearch是一个分布式搜索引擎,所以索引通常被分割成分布在多个节点上的被称为分片的元素。 + +#### 11.什么是ElasticSearch? + +Elasticsearch是一个基于Lucene的搜索引擎。它提供了具有HTTP Web界面和无架构JSON文档的分布式,多租户能力的全文搜索引擎。Elasticsearch是用Java开发的,根据Apache许可条款作为开源发布。 + +#### 12.Elasticsearch中的倒排索引是什么? + +倒排索引是搜索引擎的核心。搜索引擎的主要目标是在查找发生搜索条件的文档时提供快速搜索。倒排索引是一种像数据结构一样的散列图,可将用户从单词导向文档或网页。它是搜索引擎的核心。其主要目标是快速搜索从数百万文件中查找数据。 + +#### 13.Elasticsearch中的分析器是什么? + +在ElasticSearch中索引数据时,数据由为索引定义的Analyzer在内部进行转换。 分析器由一个Tokenizer和零个或多个TokenFilter组成。编译器可以在一个或多个CharFilter之前。分析模块允许您在逻辑名称下注册分析器,然后可以在映射定义或某些API中引用它们。 + +Elasticsearch附带了许多可以随时使用的预建分析器。或者,您可以组合内置的字符过滤器,编译器和过滤器器来创建自定义分析器。 + +#### 14.说说Elasticsearch常用的调优手段? + +设计阶段调优 +(1)根据业务增量需求,采取基于日期模板创建索引,通过 roll over API 滚动索引; +(2)使用别名进行索引管理; +(3)每天凌晨定时对索引做 force_merge 操作,以释放空间; +(4)采取冷热分离机制,热数据存储到 SSD,提高检索效率;冷数据定期进行 shrink操作,以缩减存储; +(5)采取 curator 进行索引的生命周期管理; +(6)仅针对需要分词的字段,合理的设置分词器; +(7)Mapping 阶段充分结合各个字段的属性,是否需要检索、是否需要存储等。…….. + +写入调优 +(1)写入前副本数设置为 0; +(2)写入前关闭 refresh_interval 设置为-1,禁用刷新机制; +(3)写入过程中:采取 bulk 批量写入; +(4)写入后恢复副本数和刷新间隔; +(5)尽量使用自动生成的 id。 + +查询调优 +(1)禁用 wildcard; +(2)禁用批量 terms(成百上千的场景); +(3)充分利用倒排索引机制,能 keyword 类型尽量 keyword; +(4)数据量大时候,可以先基于时间敲定索引再检索; +(5)设置合理的路由机制。 + +其他调优 +部署调优,业务调优等。 +上面的提及一部分,面试者就基本对你之前的实践或者运维经验有所评估了。 + + +#### 15.Elasticsearch 在部署时,对 Linux 的设置有哪些优化方法? + +(1)64 GB 内存的机器是非常理想的, 但是 32 GB 和 16 GB 机器也是很常见的。少于 8 GB 会适得其反。 +(2)如果你要在更快的 CPUs 和更多的核心之间选择,选择更多的核心更好。多个内核提供的额外并发远胜过稍微快一点点的时钟频率。 +(3)如果你负担得起 SSD,它将远远超出任何旋转介质。 基于 SSD 的节点,查询和索引性能都有提升。如果你负担得起,SSD 是一个好的选择。 +(4)即使数据中心们近在咫尺,也要避免集群跨越多个数据中心。绝对要避免集群跨越大的地理距离。 +(5)请确保运行你应用程序的 JVM 和服务器的 JVM 是完全一样的。 在Elasticsearch 的几个地方,使用 Java 的本地序列化。 +(6)通过设置 gateway.recover_after_nodes、gateway.expected_nodes、gateway.recover_after_time 可以在集群重启的时候避免过多的分片交换,这可能会让数据恢复从数个小时缩短为几秒钟。 +(7)Elasticsearch 默认被配置为使用单播发现,以防止节点无意中加入集群。只有在同一台机器上运行的节点才会自动组成集群。最好使用单播代替组播。 +(8)不要随意修改垃圾回收器(CMS)和各个线程池的大小。 +(9)把你的内存的(少于)一半给 Lucene(但不要超过 32 GB!),通过ES_HEAP_SIZE 环境变量设置。 +(10)内存交换到磁盘对服务器性能来说是致命的。如果内存交换到磁盘上,一个100 微秒的操作可能变成 10 毫秒。 再想想那么多 10 微秒的操作时延累加起来。 不难看出 swapping 对于性能是多么可怕。 +(11)Lucene 使用了大 量 的文件。同时,Elasticsearch 在节点和 HTTP 客户端之间进行通信也使用了大量的套接字。 所有这一切都需要足够的文件描述符。你应该增加你的文件描述符,设置一个很大的值,如 64,000。 + + +#### 16.客户端在和集群连接时,如何选择特定的节点执行请求? + +TransportClient 利用 transport 模块远程连接一个 elasticsearch 集群。它并不加入到集群中,只是简单的获得一个或者多个初始化的 transport 地址,并以 轮询 的方式与这些地址进行通信。 + +#### 17.在 Elasticsearch 中,是怎么根据一个词找到对应的倒排索引的? + +(1)Lucene的索引过程,就是按照全文检索的基本过程,将倒排表写成此文件格式的过程。 +(2)Lucene的搜索过程,就是按照此文件格式将索引进去的信息读出来,然后计算每篇文档打分(score)的过程。 + +#### 18.对于 GC 方面,在使用 Elasticsearch 时要注意什么? + +(1)倒排词典的索引需要常驻内存,无法 GC,需要监控 data node 上 segmentmemory 增长趋势。 +(2)各类缓存,field cache, filter cache, indexing cache, bulk queue 等等,要设置合理的大小,并且要应该根据最坏的情况来看 heap 是否够用,也就是各类缓存全部占满的时候,还有 heap 空间可以分配给其他任务吗?避免采用 clear cache等“自欺欺人”的方式来释放内存。 +(3)避免返回大量结果集的搜索与聚合。确实需要大量拉取数据的场景,可以采用scan & scroll api 来实现。 +(4)cluster stats 驻留内存并无法水平扩展,超大规模集群可以考虑分拆成多个集群通过 tribe node 连接。 +(5)想知道 heap 够不够,必须结合实际应用场景,并对集群的 heap 使用情况做持续的监控。 +(6)根据监控数据理解内存需求,合理配置各类circuit breaker,将内存溢出风险降低到最低 + +#### 19.在并发情况下,Elasticsearch 如果保证读写一致? + +(1)可以通过版本号使用乐观并发控制,以确保新版本不会被旧版本覆盖,由应用层来处理具体的冲突; +(2)另外对于写操作,一致性级别支持 quorum/one/all,默认为 quorum,即只有当大多数分片可用时才允许写操作。但即使大多数可用,也可能存在因为网络等原因导致写入副本失败,这样该副本被认为故障,分片将会在一个不同的节点上重建。 +(3)对于读操作,可以设置 replication 为 sync(默认),这使得操作在主分片和副本分片都完成后才会返回;如果设置 replication 为 async 时,也可以通过设置搜索请求参数_preference 为 primary 来查询主分片,确保文档是最新版本。 + +#### 20.如何监控 Elasticsearch 集群状态? + +Marvel 让你可以很简单的通过 Kibana 监控 Elasticsearch。你可以实时查看你的集群健康状态和性能,也可以分析过去的集群、索引和节点指标。 + +#### + +#### 参考链接 + +https://www.cnblogs.com/heqiyoujing/p/11146178.html + +https://www.cnblogs.com/zhuifeng523/p/12103350.html diff --git a/JavaIO.md b/JavaIO.md new file mode 100644 index 0000000..d9d8cbe --- /dev/null +++ b/JavaIO.md @@ -0,0 +1,154 @@ +## Java IO + + +* [1.Java 中有几种类型的流?](#1java-中有几种类型的流) +* [2.什么是 java序列化?](#2什么是-java序列化) +* [3.如何实现 java 序列化?](#3如何实现-java-序列化) +* [4.字节流和字符流的区别?](#4字节流和字符流的区别) +* [5.PrintStream、BufferedWriter、PrintWriter的比较?](#5printstreambufferedwriterprintwriter的比较) +* [6.什么是节点流,什么是处理流,它们各有什么用处,处理流的创建有什么特征?](#6什么是节点流什么是处理流它们各有什么用处处理流的创建有什么特征) +* [7.流一般需要不需要关闭,如果关闭的话在用什么方法,一般要在那个代码块里面关闭比较好,处理流是怎么关闭的,如果有多个流互相调用传入是怎么关闭的?](#7流一般需要不需要关闭如果关闭的话在用什么方法一般要在那个代码块里面关闭比较好处理流是怎么关闭的如果有多个流互相调用传入是怎么关闭的) +* [8.什么是BIO](#8什么是bio) +* [9.什么是NIO](#9什么是nio) +* [10.什么是AIO](#10什么是aio) +* [11.同步与异步](#11同步与异步) +* [12.阻塞与非阻塞](#12阻塞与非阻塞) +* [13.同步、异步、阻塞、非堵塞](#13同步异步阻塞非堵塞) +* [14.通道是个什么意思?](#14通道是个什么意思) +* [15.缓冲区是什么意思?](#15缓冲区是什么意思) +* [16.IO多路复用的底层原理](#16io多路复用的底层原理) +* [参考链接](#参考链接) + + + + +#### 1.Java 中有几种类型的流? + +(1)按照流的方向:输入流(inputStream)和输出流(outputStream);(2)按照实现功能分:节点流(可以从或向一个特定的地方(节点)读写数据。如 FileReader)和处理流(是对一个已存在的流的连接和封装,通过所封装的流的功能调用实现数据读写。如 BufferedReader。处理流的构造方法总是要带一个其他的流对象做参数。一个流对象经过其他流的多次包装,称为流的链接);(3)按照处理数据的单位: 字节流和字符流。字节流继承于 InputStream 和 OutputStrea,字符流继承于InputStreamReader 和 OutputStreamWriter 。 + +#### 2.什么是 java序列化? + +序列化就是一种用来处理对象流的机制,所谓对象流也就是将对象的内容进行流化。可以对流化后的对象进行读写操作,也可将流化后的对象传输于网络之间。序列化是为了解决在对对象流进行读写操作时所引发的问题 + +#### 3.如何实现 java 序列化? + +序列化的实现,将需要被序列化的类实现Serializable 接口,该接口没有需要实现的方法,implements Serializable 只是为了标注该对象是可被序列化的,然后使用一个输出流(如:File Output Stream)来构造一个 Object Output Stream(对象流)对象,接着,使用 Object Output Stream 对象的 write Object(Object obj)方法就可以将参数为 obj 的对象写出(即保存其状态),要恢复的话则用输入流。 + +#### 4.字节流和字符流的区别? + +字节流读取的时候,读到一个字节就返回一个字节;字符流使用了字节流读到一个或多个字节(中文对应的字节数是两个,在 UTF-8 码表中是 3 个字节)时。先去查指定的编码表,将查到的字符返回。字节流可以处理所有类型数据,如:图片,MP3,AVI视频文件,而字符流只能处理字符数据。只要是处理纯文本数据,就要优先考虑使用字符流,除此之外都用字节流。字节流主要是操作 byte 类型数据,以 byte 数组为准,主要操作类就是 OutputStream、InputStream字符流处理的单元为 2 个字节的 Unicode 字符,分别操作字符、字符数组或字符串,而字节流处理单元为 1 个字节,操作字节和字节数组。所以字符流是由 Java 虚拟机将字节转化为 2 个字节的 Unicode 字符为单位的字符而成的,所以它对多国语言支持性比较好!如果是音频文件、图片、歌曲,就用字节流好点,如果是关系到中文(文本)的,用字符流好点。在程序中一个字符等于两个字节,java 提供了 Reader、Writer 两个专门操作字符流的类。 + +#### 5.PrintStream、BufferedWriter、PrintWriter的比较? + +1. PrintStream类的输出功能非常强大,通常如果需要输出文本内容,都应该将输出流包装成PrintStream后进行输出。它还提供其他两项功能。与其他输出流不同,PrintStream 永远不会抛出 IOException;而是,异常情况仅设置可通过 checkError 方法测试的内部标志。另外,为了自动刷新,可以创建一个 PrintStream +2. BufferedWriter:将文本写入字符输出流,缓冲各个字符从而提供单个字符,数组和字符串的高效写入。通过write()方法可以将获取到的字符输出,然后通过newLine()进行换行操作。BufferedWriter中的字符流必须通过调用flush方法才能将其刷出去。并且BufferedWriter只能对字符流进行操作。如果要对字节流操作,则使用BufferedInputStream +3. PrintWriter的println方法自动添加换行,不会抛异常,若关心异常,需要调用checkError方法看是否有异常发生,PrintWriter构造方法可指定参数,实现自动刷新缓存(autoflush) + +#### 6.什么是节点流,什么是处理流,它们各有什么用处,处理流的创建有什么特征? + +1. 节点流 直接与数据源相连,用于输入或者输出 +2. 处理流:在节点流的基础上对之进行加工,进行一些功能的扩展 +3. 处理流的构造器必须要 传入节点流的子类 + +#### 7.流一般需要不需要关闭,如果关闭的话在用什么方法,一般要在那个代码块里面关闭比较好,处理流是怎么关闭的,如果有多个流互相调用传入是怎么关闭的? + +1. 流一旦打开就必须关闭,使用close方法 +2. 放入finally语句块中(finally 语句一定会执行) +3. 调用的处理流就关闭处理流 +4. 多个流互相调用只关闭最外层的流 + +#### 8.什么是BIO + +BIO 就是传统的 [java.io](http://java.io/) 包,它是基于流模型实现的,交互的方式是同步、阻塞方式,也就是说在读入输入流或者输出流时,在读写动作完成之前,线程会一直阻塞在那里,它们之间的调用时可靠的线性顺序。它的有点就是代码比较简单、直观;缺点就是 IO 的效率和扩展性很低,容易成为应用性能瓶颈。 + +#### 9.什么是NIO + +是 Java 1.4 引入的 java.nio 包,提供了 Channel、Selector、Buffer 等新的抽象,可以构建多路复用的、同步非阻塞 IO 程序,同时提供了更接近操作系统底层高性能的数据操作方式。 + +#### 10.什么是AIO + +AIO 是 Java 1.7 之后引入的包,是 NIO 的升级版本,提供了异步非堵塞的 IO 操作方式,所以人们叫它 AIO(Asynchronous IO),异步 IO 是基于事件和回调机制实现的,也就是应用操作之后会直接返回,不会堵塞在那里,当后台处理完成,操作系统会通知相应的线程进行后续的操作 + +#### 11.同步与异步 + +同步就是一个任务的完成需要依赖另外一个任务时,只有等待被依赖的任务完成后,依赖的任务才能算完成,这是一种可靠的任务序列。要么成功都成功,失败都失败,两个任务的状态可以保持一致。而异步是不需要等待被依赖的任务完成,只是通知被依赖的任务要完成什么工作,依赖的任务也立即执行,只要自己完成了整个任务就算完成了。至于被依赖的任务最终是否真正完成,依赖它的任务无法确定,所以它是不可靠的任务序列。我们可以用打电话和发短信来很好的比喻同步与异步操作。 + +#### 12.阻塞与非阻塞 + +阻塞与非阻塞主要是从 CPU 的消耗上来说的,阻塞就是 CPU 停下来等待一个慢的操作完成 CPU 才接着完成其它的事。非阻塞就是在这个慢的操作在执行时 CPU 去干其它别的事,等这个慢的操作完成时,CPU 再接着完成后续的操作。虽然表面上看非阻塞的方式可以明显的提高 CPU 的利用率,但是也带了另外一种后果就是系统的线程切换增加。增加的 CPU 使用时间能不能补偿系统的切换成本需要好好评估。 + +#### 13.同步、异步、阻塞、非堵塞 + +同/异、阻/非堵塞的组合,有四种类型,如下表: + +| 组合方式 | 性能分析 | +| ---------- | ------------------------------------------------------------ | +| 同步阻塞 | 最常用的一种用法,使用也是最简单的,但是 I/O 性能一般很差,CPU 大部分在空闲状态。 | +| 同步非阻塞 | 提升 I/O 性能的常用手段,就是将 I/O 的阻塞改成非阻塞方式,尤其在网络 I/O 是长连接,同时传输数据也不是很多的情况下,提升性能非常有效。 这种方式通常能提升 I/O 性能,但是会增加CPU 消耗,要考虑增加的 I/O 性能能不能补偿 CPU 的消耗,也就是系统的瓶颈是在 I/O 还是在 CPU 上。 | +| 异步阻塞 | 这种方式在分布式数据库中经常用到,例如在网一个分布式数据库中写一条记录,通常会有一份是同步阻塞的记录,而还有两至三份是备份记录会写到其它机器上,这些备份记录通常都是采用异步阻塞的方式写 I/O。异步阻塞对网络 I/O 能够提升效率,尤其像上面这种同时写多份相同数据的情况。 | +| 异步非阻塞 | 这种组合方式用起来比较复杂,只有在一些非常复杂的分布式情况下使用,像集群之间的消息同步机制一般用这种 I/O 组合方式。如 Cassandra 的 Gossip 通信机制就是采用异步非阻塞的方式。它适合同时要传多份相同的数据到集群中不同的机器,同时数据的传输量虽然不大,但是却非常频繁。这种网络 I/O 用这个方式性能能达到最高。 | + +#### 14.通道是个什么意思? + +- 通道是对原 I/O 包中的流的模拟。到任何目的地(或来自任何地方)的所有数据都必须通过一个 Channel 对象(通道)。一个 Buffer 实质上是一个容器对象。发送给一个通道的所有对象都必须首先放到缓冲区中;同样地,从通道中读取的任何数据都要读到缓冲区中。Channel是一个对象,可以通过它读取和写入数据。拿 NIO 与原来的 I/O 做个比较,通道就像是流。 +- 正如前面提到的,所有数据都通过 Buffer 对象来处理。您永远不会将字节直接写入通道中,相反,您是将数据写入包含一个或者多个字节的缓冲区。同样,您不会直接从通道中读取字节,而是将数据从通道读入缓冲区,再从缓冲区获取这个字节。 + +#### 15.缓冲区是什么意思? + +- Buffer 是一个对象, 它包含一些要写入或者刚读出的数据。在 NIO 中加入 Buffer 对象,体现了新库与原 I/O 的一个重要区别。在面向流的 I/O 中,您将数据直接写入或者将数据直接读到 Stream 对象中 +- 在 NIO 库中,所有数据都是用缓冲区处理的。在读取数据时,它是直接读到缓冲区中的。在写入数据时,它是写入到缓冲区中的。任何时候访问 NIO 中的数据,您都是将它放到缓冲区中。 +- 缓冲区实质上是一个数组。通常它是一个字节数组,但是也可以使用其他种类的数组。但是一个缓冲区不 仅仅 是一个数组。缓冲区提供了对数据的结构化访问,而且还可以跟踪系统的读/写进程 + +ByteBuffer +CharBuffer +ShortBuffer +IntBuffer +LongBuffer +FloatBuffer +DoubleBuffer + +#### 16.IO多路复用的底层原理 + +IO多路复用使用两个系统调用(select/poll/epoll和recvfrom),blocking IO只调用了recvfrom;select/poll/epoll 核心是可以同时处理多个connection,而不是更快,所以连接数不高的话,性能不一定比多线程+阻塞IO好,多路复用模型中,每一个socket,设置为non-blocking,阻塞是被select这个函数block,而不是被socket阻塞的。 + +1)select机制 + +客户端操作服务器时就会产生这三种文件描述符(简称fd):writefds(写)、readfds(读)、和exceptfds(异常)。select会阻塞住监视3类文件描述符,等有数据、可读、可写、出异常 或超时、就会返回;返回后通过遍历fdset整个数组来找到就绪的描述符fd,然后进行对应的IO操作。 + +优点: +  几乎在所有的平台上支持,跨平台支持性好 +缺点: +  由于是采用轮询方式全盘扫描,会随着文件描述符FD数量增多而性能下降。 +  每次调用 select(),需要把 fd 集合从用户态拷贝到内核态,并进行遍历(消息传递都是从内核到用户空间) +  默认单个进程打开的FD有限制是1024个,可修改宏定义,但是效率仍然慢。 + +2)poll机制 + +基本原理与select一致,只是没有最大文件描述符限制,因为采用的是链表存储fd。 + +3)epoll机制 + +epoll之所以高性能是得益于它的三个函数 +  1)epoll_create()系统启动时,在Linux内核里面申请一个B+树结构文件系统,返回epoll对象,也是一个fd +  2)epoll_ctl() 每新建一个连接,都通过该函数操作epoll对象,在这个对象里面修改添加删除对应的链接fd, 绑定一个callback函数。 +  3)epoll_wait() 轮训所有的callback集合,并完成对应的IO操作 + +优点: +  没fd这个限制,所支持的FD上限是操作系统的最大文件句柄数,1G内存大概支持10万个句柄 +  效率提高,使用回调通知而不是轮询的方式,不会随着FD数目的增加效率下降 +  内核和用户空间mmap同一块内存实现 + + +### 参考链接 + +https://zhuanlan.zhihu.com/p/124230020 + +https://blog.csdn.net/chengyuqiang/article/details/79183748 + +https://www.wkcto.com/article/detail/259 + +https://www.cnblogs.com/lanqingzhou/p/13609317.html + +https://www.imooc.com/article/265871 + +https://blog.csdn.net/chenwiehuang/article/details/105296691 diff --git "a/Java\345\237\272\347\241\200.md" "b/Java\345\237\272\347\241\200.md" new file mode 100644 index 0000000..94766a8 --- /dev/null +++ "b/Java\345\237\272\347\241\200.md" @@ -0,0 +1,552 @@ +## Java基础 + + +* [1.说下面向对象四大特性](#1说下面向对象四大特性) +* [2.Java语言有哪些特点](#2java语言有哪些特点) +* [3.什么是Java程序的主类?应用程序和小程序的主类有何不同?](#3什么是java程序的主类应用程序和小程序的主类有何不同) +* [4.访问修饰符public,private,protected,以及不写(默认)时的区别?](#4访问修饰符publicprivateprotected以及不写默认时的区别) +* [5.float f=3.4;是否正确?](#5float-f34是否正确) +* [6.Java有没有goto?](#6java有没有goto) +* [7.&和&&的区别?](#7和的区别) +* [8.Math.round(11.5) 等于多少?Math.round(-11.5)等于多少?](#8mathround115-等于多少mathround-115等于多少) +* [9.用最有效率的方法计算2乘以8?](#9用最有效率的方法计算2乘以8) +* [10.什么是Java注释](#10什么是java注释) +* [11.Java有哪些数据类型](#11java有哪些数据类型) +* [12.final 有什么用?](#12final-有什么用) +* [13.final finally finalize的区别](#13final-finally-finalize的区别) +* [14.String str = "i" 和String str = new String("1")一样吗?](#14string-str--i-和string-str--new-string1一样吗) +* [15.Java 中操作字符串都有哪些类?它们之间有什么区别?](#15java-中操作字符串都有哪些类它们之间有什么区别) +* [16.Java中为什么要用 clone?](#16java中为什么要用-clone) +* [17.深克隆和浅克隆?](#17深克隆和浅克隆) +* [18.new一个对象的过程和clone一个对象的区别?](#18new一个对象的过程和clone一个对象的区别) +* [19.Java中实现多态的机制是什么?](#19java中实现多态的机制是什么) +* [20.谈谈你对多态的理解?](#20谈谈你对多态的理解) +* [21.构造器(constructor)是否可被重写(override)?](#21构造器constructor是否可被重写override) +* [22.两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?](#22两个对象值相同xequalsy--true但却可有不同的hash-code这句话对不对) +* [23.是否可以继承String类?](#23是否可以继承string类) +* [24.String类的常用方法有哪些?](#24string类的常用方法有哪些) +* [25.char型变量中能否能不能存储一个中文汉字,为什么?](#25char型变量中能否能不能存储一个中文汉字为什么) +* [26.this关键字的用法](#26this关键字的用法) +* [27.super关键字的用法](#27super关键字的用法) +* [28.this与super的区别](#28this与super的区别) +* [29.static存在的主要意义](#29static存在的主要意义) +* [30.static的独特之处](#30static的独特之处) +* [31.static应用场景](#31static应用场景) +* [32.static注意事项](#32static注意事项) +* [33.break ,continue ,return 的区别及作用](#33break-continue-return-的区别及作用) +* [34.在Java中定义一个不做事且没有参数的构造方法的作用](#34在java中定义一个不做事且没有参数的构造方法的作用) +* [35.构造方法有哪些特性?](#35构造方法有哪些特性) +* [36.静态变量和实例变量区别](#36静态变量和实例变量区别) +* [37.静态方法和实例方法有何不同?](#37静态方法和实例方法有何不同) +* [38.什么是方法的返回值?返回值的作用是什么?](#38什么是方法的返回值返回值的作用是什么) +* [39.什么是内部类?](#39什么是内部类) +* [40.内部类的分类有哪些](#40内部类的分类有哪些) +* [41.Java中异常分为哪些种类?](#41java中异常分为哪些种类) +* [42.hashCode 与 equals (重要)](#42hashcode-与-equals-重要) +* [43.hashCode()介绍](#43hashcode介绍) +* [44.为什么要有 hashCode](#44为什么要有-hashcode) +* [45.抽象类和接口(Java7)的区别](#45抽象类和接口java7的区别) +* [46.Java 8的接口新增了哪些特性?](#46java-8的接口新增了哪些特性) +* [47.重写和重载的区别](#47重写和重载的区别) +* [48.ArrayList和LinkedList有什么区别?](#48arraylist和linkedlist有什么区别) +* [49.HashMap是怎么实现的?](#49hashmap是怎么实现的) +* [50.HashMap在Java7和Java8中的实现有什么不同?](#50hashmap在java7和java8中的实现有什么不同) +* [51.HashMap有时候会死循环,你知道是什么原因吗?](#51hashmap有时候会死循环你知道是什么原因吗) +* [52.ConcurrentHashMap是怎么实现的?](#52concurrenthashmap是怎么实现的) +* [53.静态代理和动态代理的区别](#53静态代理和动态代理的区别) +* [54.JDK动态代理和CGLIB动态代理的区别](#54jdk动态代理和cglib动态代理的区别) +* [参考链接](#参考链接) + + + + + +## Java基础 + +#### 1.说下面向对象四大特性 + +封装、继承、多态、抽象。 + +#### 2.Java语言有哪些特点 + +简单易学(Java语言的语法与C语言和C++语言很接近) + +面向对象(封装,继承,多态) + +平台无关性(Java虚拟机实现平台无关性) + +支持网络编程并且很方便(Java语言诞生本身就是为简化网络编程设计的) + +支持多线程(多线程机制使应用程序在同一时间并行执行多项任) + +健壮性(Java语言的强类型机制、异常处理、垃圾的自动收集等) + +安全性 + +#### 3.什么是Java程序的主类?应用程序和小程序的主类有何不同? + +一个程序中可以有多个类,但只能有一个类是主类。在Java应用程序中,这个主类是指包含main()方法的类。而在Java小程序中,这个主类是一个继承自系统类JApplet或Applet的子类。应用程序的主类不一定要求是public类,但小程序的主类要求必须是public类。主类是Java程序执行的入口点。 + +#### 4.访问修饰符public,private,protected,以及不写(默认)时的区别? + +| 修饰符 | 当前类 | 同 包 | 子 类 | 其他包 | +| --------- | ------ | ----- | ----- | ------ | +| public | √ | √ | √ | √ | +| protected | √ | √ | √ | × | +| default | √ | √ | × | × | +| private | √ | × | × | × | + +类的成员不写访问修饰时默认为default。默认对于同一个包中的其他类相当于公开(public),对于不是同一个包中的其他类相当于私有(private)。受保护(protected)对子类相当于公开,对不是同一包中的没有父子关系的类相当于私有。Java中,外部类的修饰符只能是public或默认,类的成员(包括内部类)的修饰符可以是以上四种。 + +#### 5.float f=3.4;是否正确? + +不正确。3.4是双精度数,将双精度型(double)赋值给浮点型(float)属于下转型(down-casting,也称为窄化)会造成精度损失,因此需要强制类型转换float f =(float)3.4; 或者写成float f =3.4F;。 + +#### 6.Java有没有goto? + +goto 是Java中的保留字,在目前版本的Java中没有使用。(根据James Gosling(Java之父)编写的《The Java Programming Language》一书的附录中给出了一个Java关键字列表,其中有goto和const,但是这两个是目前无法使用的关键字,因此有些地方将其称之为保留字,其实保留字这个词应该有更广泛的意义,因为熟悉C语言的程序员都知道,在系统类库中使用过的有特殊意义的单词或单词的组合都被视为保留字) + +#### 7.&和&&的区别? + +&运算符有两种用法:(1)按位与;(2)逻辑与。 + +&&运算符是短路与运算。 + +逻辑与跟短路与的差别是非常巨大的,虽然二者都要求运算符左右两端的布尔值都是true整个表达式的值才是true。&&之所以称为短路运算是因为,如果&&左边的表达式的值是false,右边的表达式会被直接短路掉,不会进行运算。很多时候我们可能都需要用&&而不是&,例如在验证用户登录时判定用户名不是null而且不是空字符串,应当写为:username != null &&!username.equals(""),二者的顺序不能交换,更不能用&运算符,因为第一个条件如果不成立,根本不能进行字符串的equals比较,否则会产生NullPointerException异常。注意:逻辑或运算符(|)和短路或运算符(||)的差别也是如此。 + +#### 8.Math.round(11.5) 等于多少?Math.round(-11.5)等于多少? + +Math.round(11.5)的返回值是12,Math.round(-11.5)的返回值是-11。四舍五入的原理是在参数上加0.5然后进行下取整。 + +#### 9.用最有效率的方法计算2乘以8? + +2 << 3 + +#### 10.什么是Java注释 + +定义:用于解释说明程序的文字 + +Java注释的分类 +- 单行注释 + 格式: // 注释文字 +- 多行注释 + 格式: /* 注释文字 */ +- 文档注释 + 格式:/** 注释文字 */ + +Java注释的作用 +在程序中,尤其是复杂的程序中,适当地加入注释可以增加程序的可读性,有利于程序的修改、调试和交流。注释的内容在程序编译的时候会被忽视,不会产生目标代码,注释的部分不会对程序的执行结果产生任何影响。 + +注意事项:多行和文档注释都不能嵌套使用。 + +#### 11.Java有哪些数据类型 + +定义:Java语言是强类型语言,对于每一种数据都定义了明确的具体的数据类型,在内存中分配了不同大小的内存空间。 + +- 基本数据类型 + - 数值型 + - 整数类型(byte,short,int,long) + - 浮点类型(float,double) + - 字符型(char) + - 布尔型(boolean) +- 引用数据类型 + - 类(class) + - 接口(interface) + - 数组([]) + +#### 12.final 有什么用? + +用于修饰类、属性和方法; + +- 被final修饰的类不可以被继承 +- 被final修饰的方法不可以被重写 +- 被final修饰的变量不可以被改变,被final修饰不可变的是变量的引用,而不是引用指向的内容,引用指向的内容是可以改变的 + +#### 13.final finally finalize的区别 + +- final可以修饰类、变量、方法,修饰类表示该类不能被继承、修饰方法表示该方法不能被重写、修饰变量表 + 示该变量是一个常量不能被重新赋值。 +- finally一般作用在try-catch代码块中,在处理异常的时候,通常我们将一定要执行的代码方法finally代码块 + 中,表示不管是否出现异常,该代码块都会执行,一般用来存放一些关闭资源的代码。 +- finalize是一个方法,属于Object类的一个方法,而Object类是所有类的父类,该方法一般由垃圾回收器来调 + 用,当我们调用System.gc() 方法的时候,由垃圾回收器调用finalize(),回收垃圾,一个对象是否可回收的 + 最后判断。 + +#### 14.String str = "i" 和String str = new String("1")一样吗? + +不一样,因为内存的分配方式不一样。String str = "i"的方式JVM会将其分配到常量池中,而String str = new String("i")JVM会将其分配到堆内存中。 + +#### 15.Java 中操作字符串都有哪些类?它们之间有什么区别? + +操作字符串的类有:String、StringBuffer、StringBuilder。 +String 和 StringBuffer、StringBuilder 的区别在于 String 声明的是不可变的对象,每次操作都会生成新的 String 对象,再将指针指向新的 String 对象,而 StringBuffer 、 StringBuilder 可以在原有对象的基础上进行操作,所以在经常改变字符串内容的情况下最好不要使用 String。 +StringBuffer 和 StringBuilder 最大的区别在于,StringBuffer 是线程安全的,而 StringBuilder 是非线程安全的,但 StringBuilder 的性能却高于 StringBuffer,所以在单线程环境下推荐使用 StringBuilder,多线程环境下推荐使用 StringBuffer。 + +#### 16.Java中为什么要用 clone? + +在实际编程过程中,我们常常要遇到这种情况:有一个对象 A,在某一时刻 A 中已经包含了一些有效值,此时可能会需要一个和 A 完全相同新对象 B,并且此后对 B 任何改动都不会影响到 A 中的值,也就是说,A 与 B 是两个独立的对象,但 B 的初始值是由 A 对象确定的。在 Java 语言中,用简单的赋值语句是不能满足这种需求的。要满足这种需求虽然有很多途径,但clone()方法是其中最简单,也是最高效的手段。 + +#### 17.深克隆和浅克隆? + +浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。 + + +深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。 + +#### 18.new一个对象的过程和clone一个对象的区别? + +new 操作符的本意是分配内存。程序执行到 new 操作符时,首先去看 new 操作符后面的类型,因为知道了类型,才能知道要分配多大的内存空间。分配完内存之后,再调用构造函数,填充对象的各个域,这一步叫做对象的初始化,构造方法返回后,一个对象创建完毕,可以把他的引用(地址)发布到外部,在外部就可以使用这个引用操纵这个对象。 + +clone 在第一步是和 new 相似的,都是分配内存,调用 clone 方法时,分配的内存和原对象(即调用 clone 方法的对象)相同,然后再使用原对象中对应的各个域,填充新对象的域,填充完成之后,clone方法返回,一个新的相同的对象被创建,同样可以把这个新对象的引用发布到外部。 + +#### 19.Java中实现多态的机制是什么? + +Java中的多态靠的是父类或接口定义的引用变量可以指向子类或具体实现类的实例对象,而程序调用的方法在运行期才动态绑定,就是引用变量所指向的具体实例对象的方法,也就是内存里正在运行的那个对象的方法,而不是引用变量的类型中定义的方法。 + +#### 20.谈谈你对多态的理解? + +多态就是指程序中定义的引用变量所指向的具体类型和通过该引用变量发出的方法调用在编程时并不确定,而是在程序运行期间才确定,即一个引用变量到底会指向哪个类的实例对象,该引用变量发出的方法调用到底是哪个类中实现的方法,必须在程序运行期间才能决定。因为在程序运行时才确定具体的类,这样,不用修改源代码,就可以让引用变量绑定到各种不同的对象上,从而导致该引用调用的具体方法随之改变,即不修改程序代码就可以改变程序运行时所绑定的具体代码,让程序可以选择多个运行状态,这就是多态性。 + +#### 21.构造器(constructor)是否可被重写(override)? + +答:构造器不能被继承,因此不能被重写,但可以被重载。 + +#### 22.两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对? + +不对,如果两个对象x和y满足x.equals(y) == true,它们的哈希码(hash code)应当相同。 + +Java对于eqauls方法和hashCode方法是这样规定的: + +(1)如果两个对象相同(equals方法返回true),那么它们的hashCode值一定要相同; + +(2)如果两个对象的hashCode相同,它们并不一定相同。 + +当然,你未必要按照要求去做,但是如果你违背了上述原则就会发现在使用容器时,相同的对象可以出现在Set集合中,同时增加新元素的效率会大大下降(对于使用哈希存储的系统,如果哈希码频繁的冲突将会造成存取性能急剧下降)。 + +#### 23.是否可以继承String类? + +String 类是final类,不可以被继承。 + +补充:继承String本身就是一个错误的行为,对String类型最好的重用方式是关联关系(Has-A)和依赖关系(Use-A)而不是继承关系(Is-A)。 + +#### 24.String类的常用方法有哪些? + +•indexof();返回指定字符的的索引。 + +•charAt();返回指定索引处的字符。 + +•replace();字符串替换。 + +•trim();去除字符串两端空格。 + +•splt();字符串分割,返回分割后的字符串数组。 + +•getBytes();返回字符串byte类型数组。 + +•length();返回字符串长度。 + +•toLowerCase();将字符串转换为小写字母。 + +•toUpperCase();将字符串转换为大写字母。 + +•substring();字符串截取。 + +•equals();比较字符串是否相等。 + +#### 25.char型变量中能否能不能存储一个中文汉字,为什么? + +char可以存储一个中文汉字,因为Java中使用的编码是Unicode(不选择任何特定的编码,直接使用字符在字符集中的编号,这是统一的唯一方法),一个char 类型占2个字节(16 比特),所以放一个中文是没问题的。 + +#### 26.this关键字的用法 + +this是自身的一个对象,代表对象本身,可以理解为:指向对象本身的一个指针。 + +this的用法在java中大体可以分为3种: + +1.普通的直接引用,this相当于是指向当前对象本身。 + +2.形参与成员名字重名,用this来区分: + +```java +public Person(String name, int age) { + this.name = name; + this.age = age; +} +``` + +3.引用本类的构造函数 + +```java +class Person{ + private String name; + private int age; + + public Person() { + } + + public Person(String name) { + this.name = name; + } + public Person(String name, int age) { + this(name); + this.age = age; + } +} +``` + +#### 27.super关键字的用法 + +super可以理解为是指向自己超(父)类对象的一个指针,而这个超类指的是离自己最近的一个父类。 + +super也有三种用法: + +1.普通的直接引用 + +与this类似,super相当于是指向当前对象的父类的引用,这样就可以用super.xxx来引用父类的成员。 + +2.子类中的成员变量或方法与父类中的成员变量或方法同名时,用super进行区分 + +```java +class Person{ + protected String name; + + public Person(String name) { + this.name = name; + } + +} + +class Student extends Person{ + private String name; + + public Student(String name, String name1) { + super(name); + this.name = name1; + } + + public void getInfo(){ + System.out.println(this.name); //Child + System.out.println(super.name); //Father + } + +} + +public class Test { + public static void main(String[] args) { + Student s1 = new Student("Father","Child"); + s1.getInfo(); + + } +} +``` + +3.引用父类构造函数 + +3、引用父类构造函数 + +- super(参数):调用父类中的某一个构造函数(应该为构造函数中的第一条语句)。 +- this(参数):调用本类中另一种形式的构造函数(应该为构造函数中的第一条语句)。 + +#### 28.this与super的区别 + +- super:它引用当前对象的直接父类中的成员(用来访问直接父类中被隐藏的父类中成员数据或函数,基类与派生类中有相同成员定义时如:super.变量名 super.成员函数据名(实参) +- this:它代表当前对象名(在程序中易产生二义性之处,应使用this来指明当前对象;如果函数的形参与类中的成员数据同名,这时需用this来指明成员变量名) +- super()和this()类似,区别是,super()在子类中调用父类的构造方法,this()在本类内调用本类的其它构造方法。 +- super()和this()均需放在构造方法内第一行。 +- 尽管可以用this调用一个构造器,但却不能调用两个。 +- this和super不能同时出现在一个构造函数里面,因为this必然会调用其它的构造函数,其它的构造函数必然也会有super语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。 +- this()和super()都指的是对象,所以,均不可以在static环境中使用。包括:static变量,static方法,static语句块。 +- 从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。 + +#### 29.static存在的主要意义 + +static的主要意义是在于创建独立于具体对象的域变量或者方法。 以致于即使没有创建对象,也能使用属性和调用方法 ! + +static关键字还有一个比较关键的作用就是 用来形成静态代码块以优化程序性能 。static块可以置于类中的任何地方,类中可以有多个static块。在类初次被加载的时候,会按照static块的顺序来执行每个static块,并且只会执行一次。 + +为什么说static块可以用来优化程序性能,是因为它的特性:只会在类加载的时候执行一次。因此,很多时候会将一些只需要进行一次的初始化操作都放在static代码块中进行。 + +#### 30.static的独特之处 + +1、被static修饰的变量或者方法是独立于该类的任何对象,也就是说,这些变量和方法 不属于任何一个实例对象,而是被类的实例对象所共享 。 + +怎么理解 “被类的实例对象所共享” 这句话呢?就是说,一个类的静态成员,它是属于大伙的【大伙指的是这个类的多个对象实例,我们都知道一个类可以创建多个实例!】,所有的类对象共享的,不像成员变量是自个的【自个指的是这个类的单个实例对象】…我觉得我已经讲的很通俗了,你明白了咩? + +2、在该类被第一次加载的时候,就会去加载被static修饰的部分,而且只在类第一次使用时加载并进行初始化,注意这是第一次用就要初始化,后面根据需要是可以再次赋值的。 + +3、static变量值在类加载的时候分配空间,以后创建类对象的时候不会重新分配。赋值的话,是可以任意赋值的! + +4、被static修饰的变量或者方法是优先于对象存在的,也就是说当一个类加载完毕之后,即便没有创建对象,也可以去访问。 + +#### 31.static应用场景 + +因为static是被类的实例对象所共享,因此如果 某个成员变量是被所有对象所共享的,那么这个成员变量就应该定义为静态变量 。 + +因此比较常见的static应用场景有: + +1、修饰成员变量 2、修饰成员方法 3、静态代码块 4、修饰类【只能修饰内部类也就是静态内部类】 5、静态导包 + +#### 32.static注意事项 + +1、静态只能访问静态。 2、非静态既可以访问非静态的,也可以访问静态的。 + +#### 33.break ,continue ,return 的区别及作用 + +break 跳出总上一层循环,不再执行循环(结束当前的循环体) + +continue 跳出本次循环,继续执行下次循环(结束正在执行的循环 进入下一个循环条件) + +return 程序返回,不再执行下面的代码(结束当前的方法 直接返回) + +#### 34.在Java中定义一个不做事且没有参数的构造方法的作用 + +Java程序在执行子类的构造方法之前,如果没有用super()来调用父类特定的构造方法,则会调用父类中“没有参数的构造方法”。因此,如果父类中只定义了有参数的构造方法,而在子类的构造方法中又没有用super()来调用父类中特定的构造方法,则编译时将发生错误,因为Java程序在父类中找不到没有参数的构造方法可供执行。解决办法是在父类里加上一个不做事且没有参数的构造方法。 + +#### 35.构造方法有哪些特性? + +名字与类名相同; + +没有返回值,但不能用void声明构造函数; + +生成类的对象时自动执行,无需调用。 + +#### 36.静态变量和实例变量区别 + +静态变量: 静态变量由于不属于任何实例对象,属于类的,所以在内存中只会有一份,在类的加载过程中,JVM只为静态变量分配一次内存空间。 + +实例变量: 每次创建对象,都会为每个对象分配成员变量内存空间,实例变量是属于实例对象的,在内存中,创建几次对象,就有几份成员变量。 + +#### 37.静态方法和实例方法有何不同? + +静态方法和实例方法的区别主要体现在两个方面: + +1. 在外部调用静态方法时,可以使用"类名.方法名"的方式,也可以使用"对象名.方法名"的方式。而实例方法只有后面这种方式。也就是说,调用静态方法可以无需创建对象。 +2. 静态方法在访问本类的成员时,只允许访问静态成员(即静态成员变量和静态方法),而不允许访问实例成员变量和实例方法;实例方法则无此限制 + +#### 38.什么是方法的返回值?返回值的作用是什么? + +方法的返回值是指我们获取到的某个方法体中的代码执行后产生的结果!(前提是该方法可能产生结果)。返回值的作用:接收出结果,使得它可以用于其他的操作! + +#### 39.什么是内部类? + +在Java中,可以将一个类的定义放在另外一个类的定义内部,这就是 内部类 。内部类本身就是类的一个属性,与其他属性定义方式一致。 + +#### 40.内部类的分类有哪些 + +内部类可以分为四种: 成员内部类、局部内部类、匿名内部类和静态内部类 。 + + #### 41.Java中异常分为哪些种类? + +按照异常需要处理的时机分为编译时异常(也叫受控异常)也叫 CheckedException 和运行时异常(也叫非受控异常)也叫 UnCheckedException。Java认为Checked异常都是可以被处理的异常,所以Java程序必须显式处理Checked异常。如果程序没有处理Checked 异常,该程序在编译时就会发生错误无法编译。这体现了Java 的设计哲学:没有完善错误处理的代码根本没有机会被执行。对Checked异常处理方法有两种: + +● 第一种:当前方法知道如何处理该异常,则用try...catch块来处理该异常。 + +● 第二种:当前方法不知道如何处理,则在定义该方法时声明抛出该异常。 + +运行时异常只有当代码在运行时才发行的异常,编译的时候不需要try…catch。Runtime如除数是0和数组下标越界等,其产生频繁,处理麻烦,若显示申明或者捕获将会对程序的可读性和运行效率影响很大。所以由系统自动检测并将它们交给缺省的异常处理程序。当然如果你有处理要求也可以显示捕获它们。 + +#### 42.hashCode 与 equals (重要) + +HashSet如何检查重复 + +两个对象的 hashCode() 相同,则 equals() 也一定为 true,对吗? + +hashCode和equals方法的关系 + +面试官可能会问你:“你重写过 hashcode 和 equals 么,为什么重写equals时必须重写hashCode方法?” + +#### 43.hashCode()介绍 + +hashCode() 的作用是获取哈希码,也称为散列码;它实际上是返回一个int整数。这个哈希码的作用是确定该对象在哈希表中的索引位置。hashCode() 定义在JDK的Object.java中,这就意味着Java中的任何类都包含有hashCode()函数。 + +散列表存储的是键值对(key-value),它的特点是:能根据“键”快速的检索出对应的“值”。这其中就利用到了散列码!(可以快速找到所需要的对象) + +#### 44.为什么要有 hashCode + +##### 我们以“HashSet 如何检查重复”为例子来说明为什么要有 hashCode: + +当你把对象加入 HashSet 时,HashSet 会先计算对象的 hashcode 值来判断对象加入的位置,同时也会与其他已经加入的对象的 hashcode 值作比较,如果没有相符的hashcode,HashSet会假设对象没有重复出现。但是如果发现有相同 hashcode 值的对象,这时会调用 equals()方法来检查 hashcode 相等的对象是否真的相同。如果两者相同,HashSet 就不会让其加入操作成功。如果不同的话,就会重新散列到其他位置。(摘自我的Java启蒙书《Head first java》第二版)。这样我们就大大减少了 equals 的次数,相应就大大提高了执行速度。 + +##### hashCode()与equals()的相关规定 + +如果两个对象相等,则hashcode一定也是相同的 + +两个对象相等,对两个对象分别调用equals方法都返回true + +两个对象有相同的hashcode值,它们也不一定是相等的 + +##### 因此,equals 方法被覆盖过,则 hashCode 方法也必须被覆盖 + +hashCode() 的默认行为是对堆上的对象产生独特值。如果没有重写 hashCode(),则该 class 的两个对象无论如何都不会相等(即使这两个对象指向相同的数据) + +##### 对象的相等与指向他们的引用相等,两者有什么不同? + +对象的相等 比的是内存中存放的内容是否相等而 引用相等 比较的是他们指向的内存地址是否相等。 + +#### 45.抽象类和接口(Java7)的区别 + +1. 抽象类可以提供成员方法的实现细节,而接口中只能存在public abstract 方法; +2. 抽象类中的成员变量可以是各种类型的,而接口中的成员变量只能是public static final类型的; +3. 接口中不能含有静态代码块以及静态方法,而抽象类可以有静态代码块和静态方法; +4. 一个类只能继承一个抽象类,而一个类却可以实现多个接口。 + +#### 46.Java 8的接口新增了哪些特性? + +增加了default方法和static方法,这2种方法可以有方法体。 + +#### 47.重写和重载的区别 + +重写是子类对父类的允许访问的方法的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写! +重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。 +重写方法不能抛出新的检查异常或者比被重写方法申明更加宽泛的异常。 + +重载(overloading) 是在一个类里面,方法名字相同,而参数不同。返回类型可以相同也可以不同。 +每个重载的方法(或者构造函数)都必须有一个独一无二的参数类型列表。 + + +#### 48.ArrayList和LinkedList有什么区别? + +1. ArrayList和LinkedList的差别主要来自于Array和LinkedList数据结构的不同。ArrayList是基于数组实现的,LinkedList是基于双链表实现的。另外LinkedList类不仅是List接口的实现类,可以根据索引来随机访问集合中的元素,除此之外,LinkedList还实现了Deque接口,Deque接口是Queue接口的子接口,它代表一个双向队列,因此LinkedList可以作为双向队列 ,栈(可以参见Deque提供的接口方法)和List集合使用,功能强大。 + +2. 因为Array是基于索引(index)的数据结构,它使用索引在数组中搜索和读取数据是很快的,可以直接返回数组中index位置的元素,因此在随机访问集合元素上有较好的性能。Array获取数据的时间复杂度是O(1),但是要插入、删除数据却是开销很大的,因为这需要移动数组中插入位置之后的的所有元素。 + +3. 相对于ArrayList,LinkedList的随机访问集合元素时性能较差,因为需要在双向列表中找到要index的位置,再返回;但在插入,删除操作是更快的。因为LinkedList不像ArrayList一样,不需要改变数组的大小,也不需要在数组装满的时候要将所有的数据重新装入一个新的数组,这是ArrayList最坏的一种情况,时间复杂度是O(n),而LinkedList中插入或删除的时间复杂度仅为O(1)。ArrayList在插入数据时还需要更新索引(除了插入数组的尾部)。 + +4. LinkedList需要更多的内存,因为ArrayList的每个索引的位置是实际的数据,而LinkedList中的每个节点中存储的是实际的数据和前后节点的位置。 + +#### 49.HashMap是怎么实现的? + +详见:https://blog.csdn.net/woshimaxiao1/article/details/83661464 + +#### 50.HashMap在Java7和Java8中的实现有什么不同? + +详见:https://blog.csdn.net/qq_36520235/article/details/82417949 + +#### 51.HashMap有时候会死循环,你知道是什么原因吗? + +详见:https://www.cnblogs.com/williamjie/p/11089522.html + +#### 52.ConcurrentHashMap是怎么实现的? + +详见:https://www.infoq.cn/article/ConcurrentHashMap/ + +#### 53.静态代理和动态代理的区别 + +静态代理中代理类在编译期就已经确定,而动态代理则是JVM运行时动态生成,静态代理的效率相对动态代理来说相对高一些,但是静态代理代码冗余大,一单需要修改接口,代理类和委托类都需要修改。 + +#### 54.JDK动态代理和CGLIB动态代理的区别 + +JDK动态代理只能对实现了接口的类生成代理,而不能针对类。 +CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法。因为是继承,所以该类或方法最好不要声明成final。 + + + +#### 参考链接 + +https://blog.csdn.net/jackfrued/article/details/44921941 + +https://www.cnblogs.com/Java-JJ/p/12625888.html + +http://www.mamicode.com/info-detail-3005972.html + + diff --git "a/Java\350\231\232\346\213\237\346\234\272.md" "b/Java\350\231\232\346\213\237\346\234\272.md" new file mode 100644 index 0000000..57b9567 --- /dev/null +++ "b/Java\350\231\232\346\213\237\346\234\272.md" @@ -0,0 +1,449 @@ +## Java虚拟机 + + +* [1.说一下JVM的内存结构?](#1说一下jvm的内存结构) +* [2.栈帧里面包含哪些东西?](#2栈帧里面包含哪些东西) +* [3.程序计数器有什么作用?](#3程序计数器有什么作用) +* [4.字符串常量存放在哪个区域?](#4字符串常量存放在哪个区域) +* [5.你熟悉哪些垃圾收集算法?](#5你熟悉哪些垃圾收集算法) +* [6.Java里有哪些引用类型?](#6java里有哪些引用类型) +* [7.JVM怎么判断一个对象是不是要回收?](#7jvm怎么判断一个对象是不是要回收) +* [8.GC Roots 有哪些?](#8gc-roots-有哪些) +* [9.你知道哪些GC类型?](#9你知道哪些gc类型) +* [10.对象都是优先分配在年轻代上的吗?](#10对象都是优先分配在年轻代上的吗) +* [11.你了解过哪些垃圾收集器?](#11你了解过哪些垃圾收集器) +* [12.说说CMS垃圾收集器的工作原理](#12说说cms垃圾收集器的工作原理) +* [13.说说G1垃圾收集器的工作原理](#13说说g1垃圾收集器的工作原理) +* [14.说说ZGC垃圾收集器的工作原理](#14说说zgc垃圾收集器的工作原理) +* [15.ZGC收集器中的染色指针有什么用?](#15zgc收集器中的染色指针有什么用) +* [16.说说类加载的过程](#16说说类加载的过程) +* [17.说下有哪些类加载器?](#17说下有哪些类加载器) +* [18.什么是双亲委派机制?](#18什么是双亲委派机制) +* [19.双亲委派机制可以被违背吗?请举例说明。](#19双亲委派机制可以被违背吗请举例说明) +* [20.Tomcat是怎么打破双亲委派机制的呢?](#20tomcat是怎么打破双亲委派机制的呢) +* [21.Java对象的布局了解过吗?](#21java对象的布局了解过吗) +* [22.什么情况下会发生栈内存溢出?](#22什么情况下会发生栈内存溢出) +* [23.JVM新生代中为什么要分为Eden和Survivor?](#23jvm新生代中为什么要分为eden和survivor) +* [24.JVM中一次完整的GC流程是怎样的,对象如何晋升到老年代?](#24jvm中一次完整的gc流程是怎样的对象如何晋升到老年代) +* [25.什么是指令重排序?](#25什么是指令重排序) +* [26.什么是内存屏障?](#26什么是内存屏障) +* [27.什么是happen-before原则?](#27什么是happen-before原则) +* [28.说说你知道的几种主要的JVM参数](#28说说你知道的几种主要的jvm参数) +* [29.怎么打出线程栈信息?](#29怎么打出线程栈信息) +* [30.为什么需要双亲委派模式?](#30为什么需要双亲委派模式) +* [31.怎么打破双亲委派模型?](#31怎么打破双亲委派模型) +* [32.说一下堆和栈的区别](#32说一下堆和栈的区别) +* [33.Java 8 为什么要将永久代(PermGen)替换为元空间(MetaSpace)呢?](#33java-8-为什么要将永久代permgen替换为元空间metaspace呢) +* [34.说一下Java对象的创建过程](#34说一下java对象的创建过程) +* [35.对象的访问定位有哪几种方式?](#35对象的访问定位有哪几种方式) +* [36.说一下堆内存中对象的分配的基本策略](#36说一下堆内存中对象的分配的基本策略) +* [37.Minor Gc和Full GC 有什么不同呢?](#37minor-gc和full-gc-有什么不同呢) +* [38.Java会存在内存泄漏吗?请简单描述。](#38java会存在内存泄漏吗请简单描述) +* [39.如何判断一个类是无用的类?](#39如何判断一个类是无用的类) +* [40.介绍一下类文件结构吧!](#40介绍一下类文件结构吧) +* [41.说一下 JVM 调优的工具?](#41说一下-jvm-调优的工具) +* [42.JVM调优命令有哪些?](#42jvm调优命令有哪些) +* [43.JRE、JDK、JVM 及 JIT 之间有什么不同?](#43jrejdkjvm-及-jit-之间有什么不同) +* [44.程序计数器为什么是私有的?](#44程序计数器为什么是私有的) +* [45.如何判断一个常量是废弃常量 ?](#45如何判断一个常量是废弃常量-) +* [参考资料](#参考资料) + + + +#### 1.说一下JVM的内存结构? + +详见:https://blog.csdn.net/rongtaoup/article/details/89142396 + +#### 2.栈帧里面包含哪些东西? + +局部变量表、操作数栈、动态连接、返回地址等 + +#### 3.程序计数器有什么作用? + +程序计数器是一块较小的内存空间,它的作用可以看作是当前线程所执行的字节码的行号指示器。这里面存的,就是当前线程执行的进度。 +程序计数器还存储了当前正在运行的流程,包括正在执行的指令、跳转、分支、循环、异常处理等。 + +#### 4.字符串常量存放在哪个区域? + +1. 字符串常量池,已经移动到堆上(jdk8之前是perm区),也就是执行intern方法后存的地方。 +2. 类文件常量池,constant_pool,是每个类每个接口所拥有的,这部分数据在方法区,也就是元数据区。而运行时常量池是在类加载后的一个内存区域,它们都在元空间。 + +#### 5.你熟悉哪些垃圾收集算法? + +标记清除(缺点是碎片化) +复制算法(缺点是浪费空间) +标记整理算法(效率比前两者差) +分代收集算法(老年代一般使用“标记-清除”、“标记-整理”算法,年轻代一般用复制算法) + +#### 6.Java里有哪些引用类型? + +强引用 +这种引用属于最普通最强硬的一种存在,只有在和 GC Roots 断绝关系时,才会被消灭掉。 + +软引用 +软引用用于维护一些可有可无的对象。在内存足够的时候,软引用对象不会被回收,只有在内存不足时,系统则会回收软引用对象,如果回收了软引用对象之后仍然没有足够的内存,才会抛出内存溢出异常。 +可以看到,这种特性非常适合用在缓存技术上。比如网页缓存、图片缓存等。 +软引用可以和一个引用队列(ReferenceQueue)联合使用,如果软引用所引用的对象被垃圾回收,Java 虚拟机就会把这个软引用加入到与之关联的引用队列中。 + +弱引用 +弱引用对象相比较软引用,要更加无用一些,它拥有更短的生命周期。当JVM进行垃圾回收时,无论内存是否充足,都会回收被弱引用关联的对象。弱引用拥有更短的生命周期,在 Java 中,用 java.lang.ref.WeakReference 类来表示。它的应用场景和软引用类似,可以在一些对内存更加敏感的系统里采用。 + +虚引用 +这是一种形同虚设的引用,在现实场景中用的不是很多。虚引用必须和引用队列(ReferenceQueue)联合使用。如果一个对象仅持有虚引用,那么它就和没有任何引用一样,在任何时候都可能被垃圾回收。实际上,虚引用的 get,总是返回 null。 + +#### 7.JVM怎么判断一个对象是不是要回收? + +引用计数法(缺点是对于相互引用的对象,无法进行清除) +可达性分析 + +#### 8.GC Roots 有哪些? + +GC Roots 是一组必须活跃的引用。用通俗的话来说,就是程序接下来通过直接引用或者间接引用,能够访问到的潜在被使用的对象。 + +GC Roots 包括: +Java 线程中,当前所有正在被调用的方法的引用类型参数、局部变量、临时值等。也就是与我们栈帧相关的各种引用。 +所有当前被加载的 Java 类。 +Java 类的引用类型静态变量。 +运行时常量池里的引用类型常量(String 或 Class 类型)。 +JVM 内部数据结构的一些引用,比如 sun.jvm.hotspot.memory.Universe 类。 +用于同步的监控对象,比如调用了对象的 wait() 方法。 +JNI handles,包括 global handles 和 local handles。 + +这些 GC Roots 大体可以分为三大类,下面这种说法更加好记一些: +活动线程相关的各种引用。 +类的静态变量的引用。 +JNI 引用。 + +有两个注意点: +我们这里说的是活跃的引用,而不是对象,对象是不能作为 GC Roots 的。 +GC 过程是找出所有活对象,并把其余空间认定为“无用”;而不是找出所有死掉的对象,并回收它们占用的空间。所以,哪怕 JVM 的堆非常的大,基于 tracing 的 GC 方式,回收速度也会非常快。 + +#### 9.你知道哪些GC类型? + +Minor GC:发生在年轻代的 GC。 +Major GC:发生在老年代的 GC。 +Full GC:全堆垃圾回收。比如 Metaspace 区引起年轻代和老年代的回收。 + +#### 10.对象都是优先分配在年轻代上的吗? + +不是。当新生代内存不够时,老年代分配担保。而大对象则是直接在老年代分配。 + +#### 11.你了解过哪些垃圾收集器? + +年轻代 +Serial 垃圾收集器(单线程,通常用在客户端应用上。因为客户端应用不会频繁创建很多对象,用户也不会感觉出明显的卡顿。相反,它使用的资源更少,也更轻量级。) +ParNew 垃圾收集器(多线程,追求降低用户停顿时间,适合交互式应用。) +Parallel Scavenge 垃圾收集器(追求 CPU 吞吐量,能够在较短时间内完成指定任务,适合没有交互的后台计算。) + +老年代 +Serial Old 垃圾收集器 +Parallel Old垃圾收集器 +CMS 垃圾收集器(以获取最短 GC 停顿时间为目标的收集器,它在垃圾收集时使得用户线程和 GC 线程能够并发执行,因此在垃圾收集过程中用户也不会感到明显的卡顿。) + +#### 12.说说CMS垃圾收集器的工作原理 + +Concurrent mark sweep(CMS)收集器是一种年老代垃圾收集器,其最主要目标是获取最短垃圾回收停顿时间, 和其他年老代使用标记-整理算法不同,它使用多线程的标记-清除算法。 +最短的垃圾收集停顿时间可以为交互比较高的程序提高用户体验。 +CMS 工作机制相比其他的垃圾收集器来说更复杂,整个过程分为以下 4 个阶段: +1)初始标记 +只是标记一下 GC Roots 能直接关联的对象,速度很快,仍然需要暂停所有的工作线程。 +2)并发标记 +进行 GC Roots 跟踪的过程,和用户线程一起工作,不需要暂停工作线程。 +3)重新标记 +为了修正在并发标记期间,因用户程序继续运行而导致标记产生变动的那一部分对象的标记记录,仍然需要暂停所有的工作线程。 +4)并发清除 +清除 GC Roots 不可达对象,和用户线程一起工作,不需要暂停工作线程。由于耗时最长的并发标记和并发清除过程中,垃圾收集线程可以和用户线程一起并发工作, 所以总体上来看CMS 收集器的内存回收和用户线程是一起并发地执行。 + +#### 13.说说G1垃圾收集器的工作原理 + +优点:指定最大停顿时间、分Region的内存布局、按收益动态确定回收集 + +G1开创的基于Region的堆内存布局是它能够实现这个目标的关键。虽然G1也仍是遵循分代收集理论设计的,但其堆内存的布局与其他收集器有非常明显的差异:G1不再坚持固定大小以及固定数量的分代区域划分,而是把连续的Java堆划分为多个大小相等的独立区域(Region),每一个Region都可以根据需要,扮演新生代的Eden空间、Survivor空间,或者老年代空间。收集器能够对扮演不同角色的Region采用不同的策略去处理,这样无论是新创建的对象还是已经存活了一段时间、熬过多次收集的旧对象都能获取很好的收集效果。 + +虽然G1仍然保留新生代和老年代的概念,但新生代和老年代不再是固定的了,它们都是一系列区域(不需要连续)的动态集合。G1收集器之所以能建立可预测的停顿时间模型,是因为它将Region作为单次回收的最小单元,即每次收集到的内存空间都是Region大小的整数倍,这样可以有计划地避免在整个Java堆中进行全区域的垃圾收集。更具体的处理思路是让G1收集器去跟踪各个Region里面的垃圾堆积的“价值”大小,价值即回收所获得的空间大小以及回收所需时间的经验值,然后在后台维护一个优先级列表,每次根据用户设定允许的收集停顿时间(使用参数-XX:MaxGCPauseMillis指定,默认值是200毫秒),优先处理回收价值收益最大的那些Region,这也就是“Garbage First”名字的由来。这种使用Region划分内存空间,以及具有优先级的区域回收方式,保证了G1收集器在有限的时间内获取尽可能高的收集效率。 + +G1收集器的运作过程大致可划分为以下四个步骤: +·初始标记 (Initial Marking):仅仅只是标记一下GC Roots能直接关联到的对象,并且修改TAMS指针的值,让下一阶段用户线程并发运行时,能正确地在可用的Region中分配新对象。这个阶段需要停顿线程,但耗时很短,而且是借用进行Minor GC的时候同步完成的,所以G1收集器在这个阶段实际并没有额外的停顿。 +·并发标记 (Concurrent Marking):从GC Root开始对堆中对象进行可达性分析,递归扫描整个堆里的对象图,找出要回收的对象,这阶段耗时较长,但可与用户程序并发执行。当对象图扫描完成以后,还要重新处理SATB记录下的在并发时有引用变动的对象。 +·最终标记 (Final Marking):对用户线程做另一个短暂的暂停,用于处理并发阶段结束后仍遗留下来的最后那少量的SATB记录。 +·筛选回收 (Live Data Counting and Evacuation):负责更新Region的统计数据,对各个Region的回收价值和成本进行排序,根据用户所期望的停顿时间来制定回收计划,可以自由选择任意多个Region构成回收集,然后把决定回收的那一部分Region的存活对象复制到空的Region中,再清理掉整个旧Region的全部空间。这里的操作涉及存活对象的移动,是必须暂停用户线程,由多条收集器线程并行完成的。 +从上述阶段的描述可以看出,G1收集器除了并发标记外,其余阶段也是要完全暂停用户线程的 。 + +#### 14.说说ZGC垃圾收集器的工作原理 + +1)内存布局 +·小型Region(Small Region):容量固定为2MB,用于放置小于256KB的小对象。 +·中型Region(Medium Region):容量固定为32MB,用于放置大于等于256KB但小于4MB的对象。 +·大型Region(Large Region):容量不固定,可以动态变化,但必须为2MB的整数倍,用于放置4MB或以上的大对象。每个大型Region中只会存放一个大对象,这也预示着虽然名字叫作“大型Region”,但它的实际容量完全有可能小于中型Region,最小容量可低至4MB。大型Region在ZGC的实现中是不会被重分配(重分配是ZGC的一种处理动作,用于复制对象的收集器阶段,稍后会介绍到)的,因为复制一个大对象的代价非常高昂。 + +2)染色指针 +染色指针是一种直接将少量额外的信息存储在指针上的技术,可是为什么指针本身也可以存储额外信息呢?在64位系统中,理论可以访问的内存高达16EB(2的64次幂)字节 [3] 。实际上,基于需求(用不到那么多内存)、性能(地址越宽在做地址转换时需要的页表级数越多)和成本(消耗更多晶体管)的考虑,在AMD64架构 [4] 中只支持到52位(4PB)的地址总线和48位(256TB)的虚拟地址空间,所以目前64位的硬件实际能够支持的最大内存只有256TB。此外,操作系统一侧也还会施加自己的约束,64位的Linux则分别支持47位(128TB)的进程虚拟地址空间和46位(64TB)的物理地址空间,64位的Windows系统甚至只支持44位(16TB)的物理地址空间。 +尽管Linux下64位指针的高18位不能用来寻址,但剩余的46位指针所能支持的64TB内存在今天仍然能够充分满足大型服务器的需要。鉴于此,ZGC的染色指针技术继续盯上了这剩下的46位指针宽度,将其高4位提取出来存储四个标志信息。通过这些标志位,虚拟机可以直接从指针中看到其引用对象的三色标记状态、是否进入了重分配集(即被移动过)、是否只能通过finalize()方法才能被访问到。当然,由于这些标志位进一步压缩了原本就只有46位的地址空间,也直接导致ZGC能够管理的内存不可以超过4TB(2的42次幂) 。 + +3)收集过程 +·并发标记 (Concurrent Mark):与G1、Shenandoah一样,并发标记是遍历对象图做可达性分析的阶段,前后也要经过类似于G1、Shenandoah的初始标记、最终标记(尽管ZGC中的名字不叫这些)的短暂停顿,而且这些停顿阶段所做的事情在目标上也是相类似的。与G1、Shenandoah不同的是,ZGC的标记是在指针上而不是在对象上进行的,标记阶段会更新染色指针中的Marked 0、Marked 1标志位。 +·并发预备重分配 (Concurrent Prepare for Relocate):这个阶段需要根据特定的查询条件统计得出本次收集过程要清理哪些Region,将这些Region组成重分配集(Relocation Set)。重分配集与G1收集器的回收集(Collection Set)还是有区别的,ZGC划分Region的目的并非为了像G1那样做收益优先的增量回收。相反,ZGC每次回收都会扫描所有的Region,用范围更大的扫描成本换取省去G1中记忆集的维护成本。因此,ZGC的重分配集只是决定了里面的存活对象会被重新复制到其他的Region中,里面的Region会被释放,而并不能说回收行为就只是针对这个集合里面的Region进行,因为标记过程是针对全堆的。此外,在JDK 12的ZGC中开始支持的类卸载以及弱引用的处理,也是在这个阶段中完成的。 +·并发重分配 (Concurrent Relocate):重分配是ZGC执行过程中的核心阶段,这个过程要把重分配集中的存活对象复制到新的Region上,并为重分配集中的每个Region维护一个转发表(Forward Table),记录从旧对象到新对象的转向关系。得益于染色指针的支持,ZGC收集器能仅从引用上就明确得知一个对象是否处于重分配集之中,如果用户线程此时并发访问了位于重分配集中的对象,这次访问将会被预置的内存屏障所截获,然后立即根据Region上的转发表记录将访问转发到新复制的对象上,并同时修正更新该引用的值,使其直接指向新对象,ZGC将这种行为称为指针的“自愈”(Self-Healing)能力。这样做的好处是只有第一次访问旧对象会陷入转发,也就是只慢一次,对比Shenandoah的Brooks转发指针,那是每次对象访问都必须付出的固定开销,简单地说就是每次都慢,因此ZGC对用户程序的运行时负载要比Shenandoah来得更低一些。还有另外一个直接的好处是由于染色指针的存在,一旦重分配集中某个Region的存活对象都复制完毕后,这个Region就可以立即释放用于新对象的分配(但是转发表还得留着不能释放掉),哪怕堆中还有很多指向这个对象的未更新指针也没有关系,这些旧指针一旦被使用,它们都是可以自愈的。 +·并发重映射 (Concurrent Remap):重映射所做的就是修正整个堆中指向重分配集中旧对象的所有引用,这一点从目标角度看是与Shenandoah并发引用更新阶段一样的,但是ZGC的并发重映射并不是一个必须要“迫切”去完成的任务,因为前面说过,即使是旧引用,它也是可以自愈的,最多只是第一次 +使用时多一次转发和修正操作。重映射清理这些旧引用的主要目的是为了不变慢(还有清理结束后可以释放转发表这样的附带收益),所以说这并不是很“迫切”。因此,ZGC很巧妙地把并发重映射阶段要做的工作,合并到了下一次垃圾收集循环中的并发标记阶段里去完成,反正它们都是要遍历所有对象的,这样合并就节省了一次遍历对象图 [9] 的开销。一旦所有指针都被修正之后,原来记录新旧对象关系的转发表就可以释放掉了。 + +#### 15.ZGC收集器中的染色指针有什么用? + +染色指针是一种直接将少量额外的信息存储在指针上的技术,可是为什么指针本身也可以存储额外信息呢?在64位系统中,理论可以访问的内存高达16EB(2的64次幂)字节 [3] 。实际上,基于需求(用不到那么多内存)、性能(地址越宽在做地址转换时需要的页表级数越多)和成本(消耗更多晶体管)的考虑,在AMD64架构 [4] 中只支持到52位(4PB)的地址总线和48位(256TB)的虚拟地址空间,所以目前64位的硬件实际能够支持的最大内存只有256TB。此外,操作系统一侧也还会施加自己的约束,64位的Linux则分别支持47位(128TB)的进程虚拟地址空间和46位(64TB)的物理地址空间,64位的Windows系统甚至只支持44位(16TB)的物理地址空间。 +尽管Linux下64位指针的高18位不能用来寻址,但剩余的46位指针所能支持的64TB内存在今天仍然能够充分满足大型服务器的需要。鉴于此,ZGC的染色指针技术继续盯上了这剩下的46位指针宽度,将其高4位提取出来存储四个标志信息。通过这些标志位,虚拟机可以直接从指针中看到其引用对象的三色标记状态、是否进入了重分配集(即被移动过)、是否只能通过finalize()方法才能被访问到。当然,由于这些标志位进一步压缩了原本就只有46位的地址空间,也直接导致ZGC能够管理的内存不可以超过4TB(2的42次幂) 。 + +#### 16.说说类加载的过程 + +加载 +验证 +准备(为一些类变量分配内存,并将其初始化为默认值) +解析(将符号引用替换为直接引用。类和接口、类方法、接口方法、字段等解析) +初始化 + +#### 17.说下有哪些类加载器? + +Bootstrap ClassLoader(启动类加载器) +Extention ClassLoader(扩展类加载器) +App ClassLoader(应用类加载器) + +#### 18.什么是双亲委派机制? + +双亲委派机制的意思是除了顶层的启动类加载器以外,其余的类加载器,在加载之前,都会委派给它的父加载器进行加载。这样一层层向上传递,直到祖先们都无法胜任,它才会真正的加载。 + +#### 19.双亲委派机制可以被违背吗?请举例说明。 + +可以被违背。 +打破双亲委派的例子:Tomcat + +对于一些需要加载的非基础类,会由一个叫作WebAppClassLoader的类加载器优先加载。等它加载不到的时候,再交给上层的ClassLoader进行加载。 +这个加载器用来隔绝不同应用的 .class 文件,比如你的两个应用,可能会依赖同一个第三方的不同版本,它们是相互没有影响的。 + +#### 20.Tomcat是怎么打破双亲委派机制的呢? + +是通过重写ClassLoader#loadClass和ClassLoader#findClass 实现的。可以看图中的WebAppClassLoader,它加载自己目录下的.class文件,并不会传递给父类的加载器。但是,它却可以使用 SharedClassLoader 所加载的类,实现了共享和分离的功能。 + +#### 21.Java对象的布局了解过吗? + +对象头区域此处存储的信息包括两部分: +1、对象自身的运行时数据( MarkWord ),占8字节 +存储 hashCode、GC 分代年龄、锁类型标记、偏向锁线程 ID 、 CAS 锁指向线程 LockRecord 的指针等, synconized 锁的机制与这个部分( markwork )密切相关,用 markword 中最低的三位代表锁的状态,其中一位是偏向锁位,另外两位是普通锁位。 +2、对象类型指针( Class Pointer ),占4字节 +对象指向它的类元数据的指针、 JVM 就是通过它来确定是哪个 Class 的实例。 + +实例数据区域 +此处存储的是对象真正有效的信息,比如对象中所有字段的内容 + +对齐填充区域 +JVM 的实现 HostSpot 规定对象的起始地址必须是 8 字节的整数倍,换句话来说,现在 64 位的 OS 往外读取数据的时候一次性读取 64bit 整数倍的数据,也就是 8 个字节,所以 HotSpot 为了高效读取对象,就做了"对齐",如果一个对象实际占的内存大小不是 8byte 的整数倍时,就"补位"到 8byte 的整数倍。所以对齐填充区域的大小不是固定的。 + +#### 22.什么情况下会发生栈内存溢出? + +栈是线程私有的,他的生命周期与线程相同,每个方法在执行的时候都会创建一个栈帧,用来存储局部变量表,操作数栈,动态链接,方法出口等信息。局部变量表又包含基本数据类型,对象引用类型。 +如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常,方法递归调用产生这种结果。 +如果Java虚拟机栈可以动态扩展,并且扩展的动作已经尝试过,但是无法申请到足够的内存去完成扩展,或者在新建立线程的时候没有足够的内存去创建对应的虚拟机栈,那么Java虚拟机将抛出一个OutOfMemory 异常。(线程启动过多)。 + +#### 23.JVM新生代中为什么要分为Eden和Survivor? + +如果没有Survivor,Eden区每进行一次Minor GC,存活的对象就会被送到老年代。老年代很快被填满,触发Major GC.老年代的内存空间远大于新生代,进行一次Full GC消耗的时间比Minor GC长得多,所以需要分为Eden和Survivor。 +Survivor的存在意义,就是减少被送到老年代的对象,进而减少Full GC的发生,Survivor的预筛选保证,只有经历16次Minor GC还能在新生代中存活的对象,才会被送到老年代。 +设置两个Survivor区最大的好处就是解决了碎片化,刚刚新建的对象在Eden中,经历一次Minor GC,Eden中的存活对象就会被移动到第一块survivor space S0,Eden被清空;等Eden区再满了,就再触发一次Minor GC,Eden和S0中的存活对象又会被复制送入第二块survivor space S1(这个过程非常重要,因为这种复制算法保证了S1中来自S0和Eden两部分的存活对象占用连续的内存空间,避免了碎片化的发生) + +#### 24.JVM中一次完整的GC流程是怎样的,对象如何晋升到老年代? + +当 Eden 区的空间满了, Java虚拟机会触发一次 Minor GC,以收集新生代的垃圾,存活下来的对象,则会转移到 Survivor区。 +大对象(需要大量连续内存空间的Java对象,如那种很长的字符串)直接进入老年态; +如果对象在Eden出生,并经过第一次Minor GC后仍然存活,并且被Survivor容纳的话,年龄设为1,每熬过一次Minor GC,年龄+1,若年龄超过一定限制(15),则被晋升到老年态。即长期存活的对象进入老年态。 +老年代满了而无法容纳更多的对象,Minor GC 之后通常就会进行Full GC,Full GC 清理整个内存堆 – 包括年轻代和年老代。 +Major GC 发生在老年代的GC,清理老年区,经常会伴随至少一次Minor GC,比Minor GC慢10倍以上。 + +#### 25.什么是指令重排序? + +在实际运行时,代码指令可能并不是严格按照代码语句顺序执行的。大多数现代微处理器都会采用将指令乱序执行(out-of-order execution,简称OoOE或OOE)的方法,在条件允许的情况下,直接运行当前有能力立即执行的后续指令,避开获取下一条指令所需数据时造成的等待。通过乱序执行的技术,处理器可以大大提高执行效率。而这就是指令重排。 + +#### 26.什么是内存屏障? + +内存屏障,也叫内存栅栏,是一种CPU指令,用于控制特定条件下的重排序和内存可见性问题。 +LoadLoad屏障:对于这样的语句Load1; LoadLoad; Load2,在Load2及后续读取操作要读取的数据被访问前,保证Load1要读取的数据被读取完毕。 +StoreStore屏障:对于这样的语句Store1; StoreStore; Store2,在Store2及后续写入操作执行前,保证Store1的写入操作对其它处理器可见。 +LoadStore屏障:对于这样的语句Load1; LoadStore; Store2,在Store2及后续写入操作被刷出前,保证Load1要读取的数据被读取完毕。 +StoreLoad屏障:对于这样的语句Store1; StoreLoad; Load2,在Load2及后续所有读取操作执行前,保证Store1的写入对所有处理器可见。它的开销是四种屏障中最大的。 在大多数处理器的实现中,这个屏障是个万能屏障,兼具其它三种内存屏障的功能。 + +#### 27.什么是happen-before原则? + +单线程happen-before原则:在同一个线程中,书写在前面的操作happen-before后面的操作。 锁的happen-before原则:同一个锁的unlock操作happen-before此锁的lock操作。 +volatile的happen-before原则:对一个volatile变量的写操作happen-before对此变量的任意操作(当然也包括写操作了)。 +happen-before的传递性原则:如果A操作 happen-before B操作,B操作happen-before C操作,那么A操作happen-before C操作。 +线程启动的happen-before原则:同一个线程的start方法happen-before此线程的其它方法。 +线程中断的happen-before原则 :对线程interrupt方法的调用happen-before被中断线程的检测到中断发送的代码。 +线程终结的happen-before原则: 线程中的所有操作都happen-before线程的终止检测。 +对象创建的happen-before原则: 一个对象的初始化完成先于他的finalize方法调用。 + +#### 28.说说你知道的几种主要的JVM参数 +1)堆栈配置相关 +-Xmx3550m: 最大堆大小为3550m。 +-Xms3550m: 设置初始堆大小为3550m。 +-Xmn2g: 设置年轻代大小为2g。 +-Xss128k: 每个线程的堆栈大小为128k。 +-XX:MaxPermSize: 设置持久代大小为16m +-XX:NewRatio=4: 设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。 +-XX:SurvivorRatio=4: 设置年轻代中Eden区与Survivor区的大小比值。设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6 +-XX:MaxTenuringThreshold=0: 设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。 + +2)垃圾收集器相关 +-XX:+UseParallelGC: 选择垃圾收集器为并行收集器。 +-XX:ParallelGCThreads=20: 配置并行收集器的线程数 +-XX:+UseConcMarkSweepGC: 设置年老代为并发收集。 +-XX:CMSFullGCsBeforeCompaction:由于并发收集器不对内存空间进行压缩、整理,所以运行一段时间以后会产生“碎片”,使得运行效率降低。此值设置运行多少次GC以后对内存空间进行压缩、整理。 +-XX:+UseCMSCompactAtFullCollection: 打开对年老代的压缩。可能会影响性能,但是可以消除碎片 + +3)辅助信息相关 +-XX:+PrintGC 输出形式: +[GC 118250K->113543K(130112K), 0.0094143 secs] [Full GC 121376K->10414K(130112K), 0.0650971 secs] + +-XX:+PrintGCDetails 输出形式: +[GC [DefNew: 8614K->781K(9088K), 0.0123035 secs] 118250K->113543K(130112K), 0.0124633 secs] [GC [DefNew: 8614K->8614K(9088K), 0.0000665 secs][Tenured: 112761K->10414K(121024K), 0.0433488 secs] 121376K->10414K(130112K), 0.0436268 secs + +#### 29.怎么打出线程栈信息? + +输入jps,获得进程号。 +top -Hp pid 获取本进程中所有线程的CPU耗时性能 +jstack pid命令查看当前java进程的堆栈状态 +或者 jstack -l > /tmp/output.txt 把堆栈信息打到一个txt文件。 +可以使用fastthread 堆栈定位(fastthread.io) + +#### 30.为什么需要双亲委派模式? + +在这里,先想一下,如果没有双亲委派,那么用户是不是可以自己定义一个java.lang.Object的同名类,java.lang.String的同名类,并把它放到ClassPath中,那么类之间的比较结果及类的唯一性将无法保证,因此,为什么需要双亲委派模型?防止内存中出现多份同样的字节码。 + +#### 31.怎么打破双亲委派模型? + +打破双亲委派机制则不仅要继承ClassLoader类,还要重写loadClass和findClass方法。 + +#### 32.说一下堆和栈的区别 + +1)物理地址 +堆的物理地址分配对对象是不连续的。因此性能慢些。在GC的时候也要考虑到不连续的分配,所以有各种算法。比如,标记-消除,复制,标记-压缩,分代(即新生代使用复制算法,老年代使用标记——压缩) +栈使用的是数据结构中的栈,先进后出的原则,物理地址分配是连续的。所以性能快。 + +2)内存分别 +堆因为是不连续的,所以分配的内存是在运行期确认的,因此大小不固定。一般堆大小远远大于栈。 +栈是连续的,所以分配的内存大小要在编译期就确认,大小是固定的。 + +3)存放的内容 +堆存放的是对象的实例和数组。因此该区更关注的是数据的存储 +栈存放:局部变量,操作数栈,返回结果。该区更关注的是程序方法的执行。 + +4)程序的可见度 +堆对于整个应用程序都是共享、可见的。 +栈只对于线程是可见的。所以也是线程私有。他的生命周期和线程相同。 + +#### 33.Java 8 为什么要将永久代(PermGen)替换为元空间(MetaSpace)呢? + +整个永久代有一个 JVM 本身设置固定大小上线,无法进行调整,而元空间使用的是直接内存,受本机可用内存的限制,并且永远不会出现java.lang.OutOfMemoryError。你可以使用 -XX:MaxMetaspaceSize 标志设置最大元空间大小,默认值为 unlimited,这意味着它只受系统内存的限制。-XX:MetaspaceSize 调整标志定义元空间的初始大小如果未指定此标志,则 Metaspace 将根据运行时的应用程序需求动态地重新调整大小。 + +#### 34.说一下Java对象的创建过程 + +1)类加载检查: 虚拟机遇到一条 new 指令时,首先将去检查这个指令的参数是否能在常量池中定位到这个类的符号引用,并且检查这个符号引用代表的类是否已被加载过、解析和初始化过。如果没有,那必须先执行相应的类加载过程。 +2)分配内存: 在类加载检查通过后,接下来虚拟机将为新生对象分配内存。对象所需的内存大小在类加载完成后便可确定,为对象分配空间的任务等同于把一块确定大小的内存从 Java 堆中划分出来。分配方式有 “指针碰撞” 和 “空闲列表” 两种,选择那种分配方式由 Java 堆是否规整决定,而Java堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定。 +选择以上2种方式中的哪一种,取决于 Java 堆内存是否规整。而 Java 堆内存是否规整,取决于 GC 收集器的算法是"标记-清除",还是"标记-整理"(也称作"标记-压缩"),值得注意的是,复制算法内存也是规整的。 + +在创建对象的时候有一个很重要的问题,就是线程安全,因为在实际开发过程中,创建对象是很频繁的事情,作为虚拟机来说,必须要保证线程是安全的,通常来讲,虚拟机采用两种方式来保证线程安全: +CAS+失败重试: CAS 是乐观锁的一种实现方式。所谓乐观锁就是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。虚拟机采用 CAS 配上失败重试的方式保证更新操作的原子性。 +TLAB: 为每一个线程预先在Eden区分配一块儿内存,JVM在给线程中的对象分配内存时,首先在TLAB分配,当对象大于TLAB中的剩余内存或TLAB的内存已用尽时,再采用上述的CAS进行内存分配 + +3)初始化零值: 内存分配完成后,虚拟机需要将分配到的内存空间都初始化为零值(不包括对象头),这一步操作保证了对象的实例字段在 Java 代码中可以不赋初始值就直接使用,程序能访问到这些字段的数据类型所对应的零值。 + +4)设置对象头: 初始化零值完成之后,虚拟机要对对象进行必要的设置,例如这个对象是那个类的实例、如何才能找到类的元数据信息、对象的哈希吗、对象的 GC 分代年龄等信息。 这些信息存放在对象头中。 另外,根据虚拟机当前运行状态的不同,如是否启用偏向锁等,对象头会有不同的设置方式。 + +5)执行 init 方法: 在上面工作都完成之后,从虚拟机的视角来看,一个新的对象已经产生了,但从 Java 程序的视角来看,对象创建才刚开始,init 方法还没有执行,所有的字段都还为零。所以一般来说,执行 new 指令之后会接着执行 init 方法,把对象按照程序员的意愿进行初始化,这样一个真正可用的对象才算完全产生出来。 + +#### 35.对象的访问定位有哪几种方式? + +建立对象就是为了使用对象,我们的Java程序通过栈上的 reference 数据来操作堆上的具体对象。对象的访问方式有虚拟机实现而定,目前主流的访问方式有使用句柄和直接指针2种: + +句柄: 如果使用句柄的话,那么Java堆中将会划分出一块内存来作为句柄池,reference 中存储的就是对象的句柄地址,而句柄中包含了对象实例数据与类型数据各自的具体地址信息。 + +直接指针: 如果使用直接指针访问,那么 Java 堆对象的布局中就必须考虑如何放置访问类型数据的相关信息,而reference 中存储的直接就是对象的地址。 + +这两种对象访问方式各有优势。使用句柄来访问的最大好处是 reference 中存储的是稳定的句柄地址,在对象被移动时只会改变句柄中的实例数据指针,而 reference 本身不需要修改。使用直接指针访问方式最大的好处就是速度快,它节省了一次指针定位的时间开销。 + +#### 36.说一下堆内存中对象的分配的基本策略 + +eden区、s0区、s1区都属于新生代,tentired 区属于老年代。大部分情况,对象都会首先在 Eden 区域分配,在一次新生代垃圾回收后,如果对象还存活,则会进入 s0 或者 s1,并且对象的年龄还会加 1(Eden区->Survivor 区后对象的初始年龄变为1),当它的年龄增加到一定程度(默认为15岁),就会被晋升到老年代中。对象晋升到老年代的年龄阈值,可以通过参数 -XX:MaxTenuringThreshold 来设置。 +另外,大对象和长期存活的对象会直接进入老年代。 + +#### 37.Minor Gc和Full GC 有什么不同呢? + +大多数情况下,对象在新生代中 eden 区分配。当 eden 区没有足够空间进行分配时,虚拟机将发起一次Minor GC。 +新生代GC(Minor GC):指发生新生代的的垃圾收集动作,Minor GC非常频繁,回收速度一般也比较快。 +老年代GC(Major GC/Full GC):指发生在老年代的GC,出现了Major GC经常会伴随至少一次的Minor GC(并非绝对),Major GC的速度一般会比Minor GC的慢10倍以上。 + +#### 38.Java会存在内存泄漏吗?请简单描述。 + +内存泄漏是指不再被使用的对象或者变量一直被占据在内存中。理论上来说,Java是有GC垃圾回收机制的,也就是说,不再被使用的对象,会被GC自动回收掉,自动从内存中清除 + +但是,即使这样,Java也还是存在着内存泄漏的情况,java导致内存泄露的原因很明确:长生命周期的对象持有短生命周期对象的引用就很可能发生内存泄露,尽管短生命周期对象已经不再需要,但是因为长生命周期对象持有它的引用而导致不能被回收,这就是java中内存泄露的发生场景。 + + +#### 39.如何判断一个类是无用的类? + +方法区主要回收的是无用的类,判定一个常量是否是“废弃常量”比较简单,而要判定一个类是否是“无用的类”的条件则相对苛刻许多。类需要同时满足下面3个条件才能算是 “无用的类” : +该类所有的实例都已经被回收,也就是 Java 堆中不存在该类的任何实例。 +加载该类的 ClassLoader 已经被回收。 +该类对应的 java.lang.Class 对象没有在任何地方被引用,无法在任何地方通过反射访问该类的方法。 + +虚拟机可以对满足上述3个条件的无用类进行回收,这里说的仅仅是“可以”,而并不是和对象一样不使用了就会必然被回收。 + +#### 40.介绍一下类文件结构吧! + +魔数: 确定这个文件是否为一个能被虚拟机接收的 Class 文件。 +Class 文件版本 :Class 文件的版本号,保证编译正常执行。 +常量池 :常量池主要存放两大常量:字面量和符号引用。 +访问标志 :标志用于识别一些类或者接口层次的访问信息,包括:这个 Class 是类还是接口,是否为 public 或者 abstract 类型,如果是类的话是否声明为 final 等等。 +当前类索引,父类索引 :类索引用于确定这个类的全限定名,父类索引用于确定这个类的父类的全限定名,由于 Java 语言的单继承,所以父类索引只有一个,除了 java.lang.Object 之外,所有的 java 类都有父类,因此除了 java.lang.Object 外,所有 Java 类的父类索引都不为 0。 +接口索引集合 :接口索引集合用来描述这个类实现了那些接口,这些被实现的接口将按implents(如果这个类本身是接口的话则是extends) 后的接口顺序从左到右排列在接口索引集合中。 +字段表集合 :描述接口或类中声明的变量。字段包括类级变量以及实例变量,但不包括在方法内部声明的局部变量。 +方法表集合 :类中的方法。 +属性表集合 : 在 Class 文件,字段表,方法表中都可以携带自己的属性表集合。 + +#### 41.说一下 JVM 调优的工具? + +常用调优工具分为两类,jdk自带监控工具:jconsole和jvisualvm,第三方有:MAT(Memory AnalyzerTool)、GChisto。 + +jconsole,Java Monitoring and Management Console是从java5开始,在JDK中自带的java监控和管理控制台,用于对JVM中内存, 线程和类等的监控。 +jvisualvm,jdk自带全能工具,可以分析内存快照、线程快照;监控内存变化、GC变化等。 +MAT,Memory Analyzer Tool,一个基于Eclipse的内存分析工具,是一个快速、功能丰富的Javaheap分析工具,它可以帮助我们查找内存泄漏和减少内存消耗。 +GChisto,一款专业分析gc日志的工具。 + +#### 42.JVM调优命令有哪些? + +jps,JVM Process Status Tool,显示指定系统内所有的HotSpot虚拟机进程。 +jstat,JVM statistics Monitoring是用于监视虚拟机运行时状态信息的命令,它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT编译等运行数据。 +jmap,JVM Memory Map命令用于生成heap dump文件 +jhat,JVM Heap Analysis Tool命令是与jmap搭配使用,用来分析jmap生成的dump,jhat内置了一个微型的HTTP/HTML服务器,生成dump的分析结果后,可以在浏览器中查看 +jstack,用于生成java虚拟机当前时刻的线程快照。 +jinfo,JVM Configuration info 这个命令作用是实时查看和调整虚拟机运行参数。 + +#### 43.JRE、JDK、JVM 及 JIT 之间有什么不同? + +JRE 代表 Java 运行时(Java run-time),是运行 Java 引用所必须的。JDK 代表 Java 开发工具(Java development kit),是 Java 程序的开发工具,如 Java编译器,它也包含 JRE。JVM 代表 Java 虚拟机(Java virtual machine),它的责任是运行 Java 应用。JIT 代表即时编译(Just In Time compilation),当代码执行的次数超过一定的阈值时,会将 Java 字节码转换为本地代码,如,主要的热点代码会被准换为本地代码,这样有利大幅度提高 Java 应用的性能。 + +#### 44.程序计数器为什么是私有的? + +程序计数器主要有下面两个作用: + +字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。 +在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。 +需要注意的是,如果执行的是 native 方法,那么程序计数器记录的是 undefined 地址,只有执行的是 Java 代码时程序计数器记录的才是下一条指令的地址。 + +所以,程序计数器私有主要是为了线程切换后能恢复到正确的执行位置。 + +#### 45.如何判断一个常量是废弃常量 ? + +运行时常量池主要回收的是废弃的常量。假如在常量池中存在字符串 "abc",如果当前没有任何 String 对象引用该字符串常量的话,就说明常量 "abc" 就是废弃常量,如果这时发生内存回收的话而且有必要的话,"abc" 就会被系统清理出常量池。 + + +### 参考资料 +https://blog.csdn.net/qq_41701956/article/details/100074023 +https://blog.csdn.net/cunily/article/details/106915944 +https://www.cnblogs.com/chengxuyuanxiaoyang/p/13692997.html diff --git "a/Java\351\233\206\345\220\210.md" "b/Java\351\233\206\345\220\210.md" new file mode 100644 index 0000000..4476fae --- /dev/null +++ "b/Java\351\233\206\345\220\210.md" @@ -0,0 +1,193 @@ +## Java集合 + +* [1.常见的集合有哪些?](#1常见的集合有哪些) +* [2.常见的集合底层实现](#2常见的集合底层实现) +* [3.HashMap与HashTable的区别?](#3hashmap与hashtable的区别) +* [4.ConcurrentHashMap和Hashtable的区别?](#4concurrenthashmap和hashtable的区别) +* [5.ConcurrentHashMap实现原理](#5concurrenthashmap实现原理) +* [6.ArrayList 和 Vector 的区别?](#6arraylist-和-vector-的区别) +* [7.ArrayList和LinkedList的区别?](#7arraylist和linkedlist的区别) +* [8.HashMap 默认的初始化长度是多少?](#8hashmap-默认的初始化长度是多少) +* [9.谈谈对HashMap 构造方法中初始容量、加载因子的理解](#9谈谈对hashmap-构造方法中初始容量加载因子的理解) +* [10.Java集合框架是什么?说出一些集合框架的优点?](#10java集合框架是什么说出一些集合框架的优点) +* [11.集合框架中的泛型有什么优点?](#11集合框架中的泛型有什么优点) +* [12.为何Collection不从Cloneable和Serializable接口继承?](#12为何collection不从cloneable和serializable接口继承) +* [13.为何Map接口不继承Collection接口?](#13为何map接口不继承collection接口) +* [14.Iterator是什么?](#14iterator是什么) +* [15.Enumeration和Iterator接口的区别?](#15enumeration和iterator接口的区别) +* [16.Iterater和ListIterator之间有什么区别?](#16iterater和listiterator之间有什么区别) +* [17.fail-fast与fail-safe有什么区别?](#17fail-fast与fail-safe有什么区别) +* [18.hashCode()和equals()方法有何重要性?](#18hashcode和equals方法有何重要性) +* [19.我们能否使用任何类作为Map的key?](#19我们能否使用任何类作为map的key) +* [20.如何决定选用HashMap还是TreeMap?](#20如何决定选用hashmap还是treemap) +* [21.哪些集合类提供对元素的随机访问?](#21哪些集合类提供对元素的随机访问) +* [22.BlockingQueue是什么?](#22blockingqueue是什么) +* [23.队列和栈是什么,列出它们的区别?](#23队列和栈是什么列出它们的区别) +* [24.Collections类是什么?](#24collections类是什么) +* [25.Comparable和Comparator接口有何区别?](#25comparable和comparator接口有何区别) + +#### 1.常见的集合有哪些? + +Collection接口的子接口包括:Set接口和List接口 +Map接口的实现类主要有:HashMap、TreeMap、Hashtable、ConcurrentHashMap以及Properties等 +Set接口的实现类主要有:HashSet、TreeSet、LinkedHashSet等 +List接口的实现类主要有:ArrayList、LinkedList、Stack以及Vector等 + +#### 2.常见的集合底层实现 + +ArrayList底层是数组。 +LinkedList底层是双向链表。 +HashMap底层与HashTable原理相同,Java 8版本以后如果同一位置哈希冲突大于8则链表变成红黑树。 +HashTable底层是链地址法组成的哈希表(即数组+单项链表组成)。 +HashSet底层是HashMap。 +LinkedHashMap底层修改自HashMap,包含一个维护插入顺序的双向链表。 +TreeMap底层是红黑树。 +LinkedHashSet底层是LinkedHashMap。 +TreeSet底层是TreeMap。 + +#### 3.HashMap与HashTable的区别? + +HashMap没有考虑同步,是线程不安全的;Hashtable使用了synchronized关键字,是线程安全的; +HashMap允许K/V都为null;后者K/V都不允许为null; + +#### 4.ConcurrentHashMap和Hashtable的区别? + +ConcurrentHashMap 结合了 HashMap 和 HashTable 二者的优势。HashMap 没有考虑同步,HashTable 考虑了同步的问题。但是 HashTable 在每次同步执行时都要锁住整个结构。 ConcurrentHashMap 锁的方式是稍微细粒度的。 + +#### 5.ConcurrentHashMap实现原理 + +JDK1.7 : 【数组(Segment) + 数组(HashEntry) + 链表(HashEntry节点)】 +ConcurrentHashMap(分段锁) 对整个桶数组进行了分割分段(Segment),每一把锁只锁容器其中一部分数据,多线程访问容器里不同数据段的数据,就不会存在锁竞争,提高并发访问率。 +Segment是一种可重入锁ReentrantLock,在ConcurrentHashMap里扮演锁的角色,HashEntry则用于存储键值对数据。 + +JDK1.8 : Node数组+链表 / 红黑树 +利用CAS+Synchronized来保证并发更新的安全,底层依然采用数组+链表+红黑树的存储结构。 + +#### 6.ArrayList 和 Vector 的区别? + +Vector 是线程安全的,ArrayList 是线程不安全的。 +Vector在数据满时增长为原来的两倍,而 ArrayList在数据量达到容量的一半时,增长为原容量的1.5倍。 + +#### 7.ArrayList和LinkedList的区别? + +LinkedList基于链表的数据结构;ArrayList基于动态数组的数据结构 +LinkedList 在插入和删除数据时效率更高,ArrayList 查询效率更高; + +#### 8.HashMap 默认的初始化长度是多少? + +在JDK中默认长度是16,并且默认长度和扩容后的长度都必须是 2 的幂。 + +#### 9.谈谈对HashMap 构造方法中初始容量、加载因子的理解 + +初始容量代表了哈希表中桶的初始数量,即 Entry< K,V>[] table 数组的初始长度。 +加载因子是哈希表在其容量自动增加之前可以达到多满的一种饱和度百分比,其衡量了一个散列表的空间的使用程度,负载因子越大表示散列表的装填程度越高,反之愈小。 + +#### 10.Java集合框架是什么?说出一些集合框架的优点? + +每种编程语言中都有集合,最初的Java版本包含几种集合类:Vector、Stack、HashTable和Array。随着集合的广泛使用,Java1.2提出了囊括所有集合接口、实现和算法的集合框架。在保证线程安全的情况下使用泛型和并发集合类,Java已经经历了很久。它还包括在Java并发包中,阻塞接口以及它们的实现。集合框架的部分优点如下: + +(1)使用核心集合类降低开发成本,而非实现我们自己的集合类。 + +(2)随着使用经过严格测试的集合框架类,代码质量会得到提高。 + +(3)通过使用JDK附带的集合类,可以降低代码维护成本。 + +(4)复用性和可操作性。 + +#### 11.集合框架中的泛型有什么优点? + +Java1.5引入了泛型,所有的集合接口和实现都大量地使用它。泛型允许我们为集合提供一个可以容纳的对象类型,因此,如果你添加其它类型的任何元素,它会在编译时报错。这避免了在运行时出现ClassCastException,因为你将会在编译时得到报错信息。泛型也使得代码整洁,我们不需要使用显式转换和instanceOf操作符。它也给运行时带来好处,因为不会产生类型检查的字节码指令。 + +#### 12.为何Collection不从Cloneable和Serializable接口继承? + +Collection接口指定一组对象,对象即为它的元素。如何维护这些元素由Collection的具体实现决定。例如,一些如List的Collection实现允许重复的元素,而其它的如Set就不允许。很多Collection实现有一个公有的clone方法。然而,把它放到集合的所有实现中也是没有意义的。这是因为Collection是一个抽象表现。重要的是实现。 + +当与具体实现打交道的时候,克隆或序列化的语义和含义才发挥作用。所以,具体实现应该决定如何对它进行克隆或序列化,或它是否可以被克隆或序列化。 + +在所有的实现中授权克隆和序列化,最终导致更少的灵活性和更多的限制。特定的实现应该决定它是否可以被克隆和序列化。 + +#### 13.为何Map接口不继承Collection接口? + +尽管Map接口和它的实现也是集合框架的一部分,但Map不是集合,集合也不是Map。因此,Map继承Collection毫无意义,反之亦然。 + +如果Map继承Collection接口,那么元素去哪儿?Map包含key-value对,它提供抽取key或value列表集合的方法,但是它不适合“一组对象”规范。 + +#### 14.Iterator是什么? + +Iterator接口提供遍历任何Collection的接口。我们可以从一个Collection中使用迭代器方法来获取迭代器实例。迭代器取代了Java集合框架中的Enumeration。迭代器允许调用者在迭代过程中移除元素。 + +#### 15.Enumeration和Iterator接口的区别? + +Enumeration的速度是Iterator的两倍,也使用更少的内存。Enumeration是非常基础的,也满足了基础的需要。但是,与Enumeration相比,Iterator更加安全,因为当一个集合正在被遍历的时候,它会阻止其它线程去修改集合。 + +迭代器取代了Java集合框架中的Enumeration。迭代器允许调用者从集合中移除元素,而Enumeration不能做到。为了使它的功能更加清晰,迭代器方法名已经经过改善。 + +#### 16.Iterater和ListIterator之间有什么区别? + +(1)我们可以使用Iterator来遍历Set和List集合,而ListIterator只能遍历List。 + +(2)Iterator只可以向前遍历,而LIstIterator可以双向遍历。 + +(3)ListIterator从Iterator接口继承,然后添加了一些额外的功能,比如添加一个元素、替换一个元素、获取前面或后面元素的索引位置。 + +#### 17.fail-fast与fail-safe有什么区别? + +Iterator的fail-fast属性与当前的集合共同起作用,因此它不会受到集合中任何改动的影响。Java.util包中的所有集合类都被设计为fail-fast的,而java.util.concurrent中的集合类都为fail-safe的。Fail-fast迭代器抛出ConcurrentModificationException,而fail-safe迭代器从不抛出ConcurrentModificationException。 + +#### 18.hashCode()和equals()方法有何重要性? + +HashMap使用Key对象的hashCode()和equals()方法去决定key-value对的索引。当我们试着从HashMap中获取值的时候,这些方法也会被用到。如果这些方法没有被正确地实现,在这种情况下,两个不同Key也许会产生相同的hashCode()和equals()输出,HashMap将会认为它们是相同的,然后覆盖它们,而非把它们存储到不同的地方。同样的,所有不允许存储重复数据的集合类都使用hashCode()和equals()去查找重复,所以正确实现它们非常重要。equals()和hashCode()的实现应该遵循以下规则: + +(1)如果o1.equals(o2),那么o1.hashCode() == o2.hashCode()总是为true的。 + +(2)如果o1.hashCode() == o2.hashCode(),并不意味着o1.equals(o2)会为true。 + + +#### 19.我们能否使用任何类作为Map的key? + +我们可以使用任何类作为Map的key,然而在使用它们之前,需要考虑以下几点: + +(1)如果类重写了equals()方法,它也应该重写hashCode()方法。 + +(2)类的所有实例需要遵循与equals()和hashCode()相关的规则。请参考之前提到的这些规则。 + +(3)如果一个类没有使用equals(),你不应该在hashCode()中使用它。 + +(4)用户自定义key类的最佳实践是使之为不可变的,这样,hashCode()值可以被缓存起来,拥有更好的性能。不可变的类也可以确保hashCode()和equals()在未来不会改变,这样就会解决与可变相关的问题了。 + +#### 20.如何决定选用HashMap还是TreeMap? + +对于在Map中插入、删除和定位元素这类操作,HashMap是最好的选择。然而,假如你需要对一个有序的key集合进行遍历,TreeMap是更好的选择。基于你的collection的大小,也许向HashMap中添加元素会更快,将map换为TreeMap进行有序key的遍历。 + +#### 21.哪些集合类提供对元素的随机访问? + + ArrayList、HashMap、TreeMap和HashTable类提供对元素的随机访问。 + +#### 22.BlockingQueue是什么? + +Java.util.concurrent.BlockingQueue是一个队列,在进行检索或移除一个元素的时候,它会等待队列变为非空;当在添加一个元素时,它会等待队列中的可用空间。BlockingQueue接口是Java集合框架的一部分,主要用于实现生产者-消费者模式。我们不需要担心等待生产者有可用的空间,或消费者有可用的对象,因为它都在BlockingQueue的实现类中被处理了。Java提供了集中BlockingQueue的实现,比如ArrayBlockingQueue、LinkedBlockingQueue、PriorityBlockingQueue,、SynchronousQueue等。 + +#### 23.队列和栈是什么,列出它们的区别? + +栈和队列两者都被用来预存储数据。java.util.Queue是一个接口,它的实现类在Java并发包中。队列允许先进先出(FIFO)检索元素,但并非总是这样。Deque接口允许从两端检索元素。 + +栈与队列很相似,但它允许对元素进行后进先出(LIFO)进行检索。 + +Stack是一个扩展自Vector的类,而Queue是一个接口。 + +#### 24.Collections类是什么? + +Java.util.Collections是一个工具类仅包含静态方法,它们操作或返回集合。它包含操作集合的多态算法,返回一个由指定集合支持的新集合和其它一些内容。这个类包含集合框架算法的方法,比如折半搜索、排序、混编和逆序等。 + +#### 25.Comparable和Comparator接口有何区别? + +Comparable和Comparator接口被用来对对象集合或者数组进行排序。Comparable接口被用来提供对象的自然排序,我们可以使用它来提供基于单个逻辑的排序。 + +Comparator接口被用来提供不同的排序算法,我们可以选择需要使用的Comparator来对给定的对象集合进行排序。 + + +#### 参考资料 + +https://blog.csdn.net/qq_36387471/article/details/105479208 + +https://blog.csdn.net/u010775025/article/details/79315361 diff --git "a/Java\351\253\230\345\271\266\345\217\221.md" "b/Java\351\253\230\345\271\266\345\217\221.md" new file mode 100644 index 0000000..a95f205 --- /dev/null +++ "b/Java\351\253\230\345\271\266\345\217\221.md" @@ -0,0 +1,252 @@ +## Java高并发 + +* [1.什么是进程](#1什么是进程) +* [2.什么是线程](#2什么是线程) +* [3.进程间如何通讯](#3进程间如何通讯) +* [4.线程间如何通讯](#4线程间如何通讯) +* [5.同步和异步有何不同,在什么情况下分别使用它们?举例说明](#5同步和异步有何不同在什么情况下分别使用它们举例说明) +* [6.进程调度算法](#6进程调度算法) +* [7.Java中Unsafe类详解](#7java中unsafe类详解) +* [8.如何测试并发量?](#8如何测试并发量) +* [9.有三个线程T1,T2,T3,怎么确保它们按顺序执行?](#9有三个线程t1t2t3怎么确保它们按顺序执行) +* [10.什么是线程调度器(Thread Scheduler)和时间分片(Time Slicing)?](#10什么是线程调度器thread-scheduler和时间分片time-slicing) +* [11.数据库死锁?](#11数据库死锁) +* [12.什么是锁顺序死锁?](#12什么是锁顺序死锁) +* [13.死锁的避免与诊断?](#13死锁的避免与诊断) +* [14.常见的并发容器?](#14常见的并发容器) +* [15.常见的同步工具类?](#15常见的同步工具类) +* [16.Nginx多进程模型是如何实现高并发的?](#16nginx多进程模型是如何实现高并发的) +* [17.CopyOnWriteArrayList](#17copyonwritearraylist) +* [18.AQS](#18aqs) +* [19.Java里的阻塞队列](#19java里的阻塞队列) +* [20.Fork/Join框架](#20forkjoin框架) + +#### 1.什么是进程 + +进程是指运行中的应用程序,每个进程都有自己独立的地址空间(内存空间)。 +比如用户点击桌面的IE浏览器,就启动了一个进程,操作系统就会为该进程分配独立的地址空间。当用户再次点击左边的IE浏览器,又启动了一个进程,操作系统将为新的进程分配新的独立的地址空间。目前操作系统都支持多进程。 + +#### 2.什么是线程 + +进程是表示自愿分配的基本单位。而线程则是进程中执行运算的最小单位,即执行处理机调度的基本单位。通俗来讲:一个程序有一个进程,而一个进程可以有多个线程。 + +#### 3.进程间如何通讯 + +管道(pipe) + +管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系 +有名管道(namedpipe) + +有名管道也是半双工的通信方式,但是它云溪无亲缘关系进程间的通信。 +信号量(semaphore) + +信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。 +消息队列(messagequeue) + +消息队列里有消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递消息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点 +信号(signal) + +信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生 +共享内存(shared memory) + +共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的IPC方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号量配合使用,来实现进程间的同步和通信。 +套接字(socket) + +套接口也是一种进程间通信机制,以其他通信机制不同的是,它可用于不同进程间的通信 + +#### 4.线程间如何通讯 + +锁机制:包括互斥锁、条件变量、读写锁 + +互斥锁提供了以排他方式防止数据结构被并发修改的方法 +读写锁允许多个线程同时读共享数据,而对写操作是互斥的 +条件变量可以以原子的方式阻塞进程,直到某个特定条件为真为止。对条件的测试是在互斥锁的保护下进行的。条件变量始终与互斥锁一起使用。 +信号量机制:包括无名线程信号量和命名线程信号量 + +信号机制:类似进程间的信号处理 +线程间的通信目的只要是用于新城同步,所以线程没有像进程通信中的用于数据交换的通信机制。 + +#### 5.同步和异步有何不同,在什么情况下分别使用它们?举例说明 + +如果数据将在线程间共享。例如:正在写的数据以后可能会被另一个线程读到,或者正在读的数据可能已经被另一个线程写过了,那么这些数据就是共享数据,必须进行同步存取 +当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步途径往往更有效。 +同步交互:指发送一个请求,需要等待返回,然后才能发送下一个请求,有个等待的过程 +异步交互:指发送一个请求,不需要等待返回,随时可以再发送下一个请求,即不需要等待。 +区别:一个需要等待,一个不需要等待 + +#### 6.进程调度算法 + +**实时系统**:FIFO(First Input First Output,先进先出算法),SJF(Shortest Job First,最短作业优先算法),SRTF(Shortest Remaining Time First,最短剩余时间优先算法)。 +**交互式系统**:RR(Round Robin,时间片轮转算法),HPF(Highest Priority First,最高优先级算法),多级队列,最短进程优先,保证调度,彩票调度,公平分享调度。 + +#### 7.Java中Unsafe类详解 + +1. 通过Unsafe类可以分配内存,可以释放内存;类中提供的3个本地方法allocateMemory、reallocateMemory、freeMemory分别用于分配内存,扩充内存和释放内存,与C语言中的3个方法对应。 +2. 可以定位对象某字段的内存位置,也可以修改对象的字段值,即使它是私有的; +3. 挂起与恢复:将一个线程进行挂起是通过park方法实现的,调用 park后,线程将一直阻塞直到超时或者中断等条件出现。unpark可以终止一个挂起的线程,使其恢复正常。整个并发框架中对线程的挂起操作被封装在 LockSupport类中,LockSupport类中有各种版本pack方法,但最终都调用了Unsafe.park()方法。 +4. cas + [Java中Unsafe类详解](http://blog.csdn.net/bluetjs/article/details/52758095) + +#### 8.如何测试并发量? + +可以使用apache提供的ab工具测试。 + +#### 9.有三个线程T1,T2,T3,怎么确保它们按顺序执行? + +在多线程中有多种方法让线程按特定顺序执行,你可以用线程类的join()方法在一个线程中启动另一个线程,另外一个线程完成该线程继续执行。为了确保三个线程的顺序你应该先启动最后一个(T3调用T2,T2调用T1),这样T1就会先完成而T3最后完成。 + +#### 10.什么是线程调度器(Thread Scheduler)和时间分片(Time Slicing)? + + 线程调度器是一个操作系统服务,它负责为Runnable状态的线程分配CPU时间。一旦我们创建一个线程并启动它,它的执行便依赖于线程调度器的实现。 + +  时间分片是指将可用的CPU时间分配给可用的Runnable线程的过程。分配CPU时间可以基于线程优先级或者线程等待的时间。线程调度并不受到Java虚拟机控制,所以由应用程序来控制它是更好的选择(即最好不要让你的程序依赖于线程的优先级)。 + +#### 11.数据库死锁? + +在执行一个事务时可能要获取多个锁,一直持有锁到事务提交,如果A事务需要获取的锁在另一个事务B中,且B事务也在等待A事务所持有的锁,那么两个事务之间就会发生死锁。但数据库死锁比较少见,数据库会加以干涉死锁问题,牺牲一个事务使得其他事务正常执行。 + +#### 12.什么是锁顺序死锁? + +两个线程试图以不同的顺序获得相同的锁,那么可能发发生死锁。比如转账问题,由from账户向to账户转账,假设每次我们先同步from对象,再同步to账户,然后执行转账操作,貌似没什么问题。如果这时候to账户同时向from账户转账,那么两个线程可能要永久等待了。 + +#### 13.死锁的避免与诊断? + + 如果一个线程最多只能获取一个锁,那么就不会发生锁顺序死锁了。如果确实需要获取多个锁,锁的顺序可以按照某种规约,比如两个资源的id值,程序按规约保证获取锁的顺序一致。或者可以使用显式的锁Lock,获取锁的时候设置超时时间,超时后可以重新发起,以避免发生死锁。 + +#### 14.常见的并发容器? + +ConcurrentHashMap:使用了分段锁,锁的粒度变得更小,多线程访问时,可能都不存在锁的竞争,所以大大提高了吞吐量。简单对比来看,就好比数据库上用行锁来取代表锁,行锁无疑带来更大的并发。 +CopyOnWriteArrayList:写入时复制,多线程访问时,彼此不会互相干扰或被修改的线程所干扰,当然copy时有开销的,尤其时列表元素庞大,且写入操作频繁时,所以仅当迭代操作远远大于修改操作时,才应该考虑使用。 +BlockingQueue:阻塞队列提供了可阻塞的put和take方法,当队列已经满了,那么put操作将阻塞到队列可用,当队列为空时,take操作会阻塞到队列里有数据。有界的队列是一种强大的资源管理器,可以在程序负荷过载时保护应用,可作为一种服务降级的策略。阻塞队列还提供offer操作,当数据无法加入队列时,返回失败状态,给应用主动处理负荷过载带来更多灵活性。 + +#### 15.常见的同步工具类? + + CountDownLatch:递减计数器闭锁,直到达到某个条件时才放行,多线程可以调用await方法一直阻塞,直到计数器递减为零。比如我们连接zookeeper,由于连接操作是异步的,所以可以使用countDownLatch创建一个计数器为1的锁,连接挂起,当异步连接成功时,调用countDown通知挂起线程;再比如5V5游戏竞技,只有房间人满了才可以开始游戏。 +FutureTask:带有计算结果的任务,在计算完成时才能获取结果,如果计算尚未完成,则阻塞 get +方法。FutureTask将计算结果从执行线程传递到获取这个结果的线程。 +Semaphore:信号量,用来控制同时访问某个特定资源的数量,只有获取到许可acquire,才能够正常执行,并在完成后释放许可,acquire会一致阻塞到有许可或中断超时。使用信号量可以轻松实现一个阻塞队列。 +CyclicBarrier:类似于闭锁,它可以阻塞一组线程,只有所有线程全部到达以后,才能够继续执行,so线程必须相互等待。这在并行计算中是很有用的,将一个问题拆分为多个独立的子问题,当线程到达栅栏时,调用await等待,一直阻塞到所有参与线程全部到达,再执行下一步任务。 + + + +#### 16.Nginx多进程模型是如何实现高并发的? + +进程数与并发数不存在很直接的关系。这取决取server采用的工作方式。如果一个server采用一个进程负责一个request的方式,那么进程数就是并发数。那么显而易见的,就是会有很多进程在等待中。等什么?最多的应该是等待网络传输。 + + + +Nginx的异步非阻塞工作方式正是利用了这点等待的时间。在需要等待的时候,这些进程就空闲出来待命了。因此表现为少数几个进程就解决了大量的并发问题。apache是如何利用的呢,简单来说:同样的4个进程,如果采用一个进程负责一个request的方式,那么,同时进来4个request之后,每个进程就负责其中一个,直至会话关闭。期间,如果有第5个request进来了。就无法及时反应了,因为4个进程都没干完活呢,因此,一般有个调度进程,每当新进来了一个request,就新开个进程来处理。nginx不这样,每进来一个request,会有一个worker进程去处理。但不是全程的处理,处理到什么程度呢?处理到可能发生阻塞的地方,比如向上游(后端)服务器转发request,并等待请求返回。那么,这个处理的worker不会这么傻等着,他会在发送完请求后,注册一个事件:“如果upstream返回了,告诉我一声,我再接着干”。于是他就休息去了。此时,如果再有request进来,他就可以很快再按这种方式处理。而一旦上游服务器返回了,就会触发这个事件,worker才会来接手,这个request才会接着往下走。由于web server的工作性质决定了每个request的大部份生命都是在网络传输中,实际上花费在server机器上的时间片不多。这是几个进程就解决高并发的秘密所在。webserver刚好属于网络io密集型应用,不算是计算密集型。异步,非阻塞,使用epoll,和大量细节处的优化。也正是nginx之所以然的技术基石。 + +#### 17.CopyOnWriteArrayList + +CopyOnWriteArrayList : 写时加锁,当添加一个元素的时候,将原来的容器进行copy,复制出一个新的容器,然后在新的容器里面写,写完之后再将原容器的引用指向新的容器,而读的时候是读旧容器的数据,所以可以进行并发的读,但这是一种弱一致性的策略。 +使用场景:CopyOnWriteArrayList适合使用在读操作远远大于写操作的场景里,比如缓存。 + +#### 18.AQS + +1. AQS使用一个int成员变量来表示同步状态,通过内置的FIFO队列来完成获取资源线程的排队工作。 + +``` +private volatile int state;//共享变量,使用volatile修饰保证线程可见性 +``` + +- 1 + +1. 2种同步方式:独占式,共享式。独占式如ReentrantLock,共享式如Semaphore,CountDownLatch,组合式的如ReentrantReadWriteLock + +2. 节点的状态 + CANCELLED,值为1,表示当前的线程被取消; + SIGNAL,值为-1,表示当前节点的后继节点包含的线程需要运行,也就是unpark; + CONDITION,值为-2,表示当前节点在等待condition,也就是在condition队列中; + PROPAGATE,值为-3,表示当前场景下后续的acquireShared能够得以执行; + 值为0,表示当前节点在sync队列中,等待着获取锁。 + +3. 模板方法模式 + +  protected boolean tryAcquire(int arg) : 独占式获取同步状态,试着获取,成功返回true,反之为false + +  protected boolean tryRelease(int arg) :独占式释放同步状态,等待中的其他线程此时将有机会获取到同步状态; + +  protected int tryAcquireShared(int arg) :共享式获取同步状态,返回值大于等于0,代表获取成功;反之获取失败; + +  protected boolean tryReleaseShared(int arg) :共享式释放同步状态,成功为true,失败为false + + AQS维护一个共享资源state,通过内置的FIFO来完成获取资源线程的排队工作。该队列由一个一个的Node结点组成,每个Node结点维护一个prev引用和next引用,分别指向自己的前驱和后继结点。双端双向链表。 + + 1. 独占式:乐观的并发策略 + **acquire** +  a.首先tryAcquire获取同步状态,成功则直接返回;否则,进入下一环节; + b.线程获取同步状态失败,就构造一个结点,加入同步队列中,这个过程要保证线程安全; +  c.加入队列中的结点线程进入自旋状态,若是老二结点(即前驱结点为头结点),才有机会尝试去获取同步状态;否则,当其前驱结点的状态为SIGNAL,线程便可安心休息,进入阻塞状态,直到被中断或者被前驱结点唤醒。 + **release** + release的同步状态相对简单,需要找到头结点的后继结点进行唤醒,若后继结点为空或处于CANCEL状态,从后向前遍历找寻一个正常的结点,唤醒其对应线程。 + +4. 共享式: + 共享式地获取同步状态.同步状态的方法tryAcquireShared返回值为int。 + a.当返回值大于0时,表示获取同步状态成功,同时还有剩余同步状态可供其他线程获取; +  b.当返回值等于0时,表示获取同步状态成功,但没有可用同步状态了; +  c.当返回值小于0时,表示获取同步状态失败。 + +5. AQS实现公平锁和非公平锁 + 非公平锁中,那些尝试获取锁且尚未进入等待队列的线程会和等待队列head结点的线程发生竞争。公平锁中,在获取锁时,增加了isFirst(current)判断,当且仅当,等待队列为空或当前线程是等待队列的头结点时,才可尝试获取锁。 +  [Java并发包基石-AQS详解](https://blog.csdn.net/u012998254/article/details/Java并发包基石-AQS详解) + +#### 19.Java里的阻塞队列 + +### 7个阻塞队列。分别是 + +ArrayBlockingQueue :一个由数组结构组成的有界阻塞队列。 +LinkedBlockingQueue :一个由链表结构组成的有界阻塞队列。 +PriorityBlockingQueue :一个支持优先级排序的无界阻塞队列。 +DelayQueue:一个使用优先级队列实现的无界阻塞队列。 +SynchronousQueue:一个不存储元素的阻塞队列。 +LinkedTransferQueue:一个由链表结构组成的无界阻塞队列。 +LinkedBlockingDeque:一个由链表结构组成的双向阻塞队列。 + +### 添加元素 + +Java中的阻塞队列接口BlockingQueue继承自Queue接口。BlockingQueue接口提供了3个添加元素方法。 +add:添加元素到队列里,添加成功返回true,由于容量满了添加失败会抛出IllegalStateException异常 +offer:添加元素到队列里,添加成功返回true,添加失败返回false +put:添加元素到队列里,如果容量满了会阻塞直到容量不满 + +### 删除方法 + +3个删除方法 +poll:删除队列头部元素,如果队列为空,返回null。否则返回元素。 +remove:基于对象找到对应的元素,并删除。删除成功返回true,否则返回false +take:删除队列头部元素,如果队列为空,一直阻塞到队列有元素并删除 + +#### 20.Fork/Join框架 + +Fork/Join框架是Java 7提供的一个用于并行执行任务的框架,是一个把大任务分割成若干个小任务,最终汇总每个小任务结果后得到大任务结果的框架。Fork/Join框架要完成两件事情: + +  1.任务分割:首先Fork/Join框架需要把大的任务分割成足够小的子任务,如果子任务比较大的话还要对子任务进行继续分割 + +  2.执行任务并合并结果:分割的子任务分别放到双端队列里,然后几个启动线程分别从双端队列里获取任务执行。子任务执行完的结果都放在另外一个队列里,启动一个线程从队列里取数据,然后合并这些数据。 + +  在Java的Fork/Join框架中,使用两个类完成上述操作 + +  1.ForkJoinTask:我们要使用Fork/Join框架,首先需要创建一个ForkJoin任务。该类提供了在任务中执行fork和join的机制。通常情况下我们不需要直接集成ForkJoinTask类,只需要继承它的子类,Fork/Join框架提供了两个子类: + +    a.RecursiveAction:用于没有返回结果的任务 + +    b.RecursiveTask:用于有返回结果的任务 + +  2.ForkJoinPool:ForkJoinTask需要通过ForkJoinPool来执行 + +  任务分割出的子任务会添加到当前工作线程所维护的双端队列中,进入队列的头部。当一个工作线程的队列里暂时没有任务时,它会随机从其他工作线程的队列的尾部获取一个任务(工作窃取算法)。 +Fork/Join框架的实现原理 +  ForkJoinPool由ForkJoinTask数组和ForkJoinWorkerThread数组组成,ForkJoinTask数组负责将存放程序提交给ForkJoinPool,而ForkJoinWorkerThread负责执行这 + +#### 参考链接 + +https://blog.csdn.net/weixin_41050155/article/details/88047556 + +https://www.cnblogs.com/jjunior/p/14113248.html + +http://www.bjpowernode.com/tutorial_baseinterviewquestions/228.html + +https://www.cnblogs.com/yang-yutao/p/11553044.html + +https://blog.csdn.net/qq_20980207/article/details/98846287 diff --git a/Jenkins.md b/Jenkins.md new file mode 100644 index 0000000..c374e4d --- /dev/null +++ b/Jenkins.md @@ -0,0 +1,96 @@ +## Jenkins + +* [1.什么是Jenkins?](#1什么是jenkins) +* [2.Maven, Ant和Jenkins有什么区别?](#2maven-ant和jenkins有什么区别) +* [3.Jenkins支持哪些SCM工具?](#3jenkins支持哪些scm工具) +* [4.在Jenkins中, 什么是持续集成?](#4在jenkins中-什么是持续集成) +* [5.Jenkins的优势是什么?](#5jenkins的优势是什么) +* [6.可以使用哪些命令手动启动Jenkins?](#6可以使用哪些命令手动启动jenkins) +* [7.如何在Jenkins中创建备份和复制文件?](#7如何在jenkins中创建备份和复制文件) +* [8.如何通过Jenkins克隆Git存储库?](#8如何通过jenkins克隆git存储库) +* [9.什么是jenkinsfile?为什么使用jenkinsfile](#9什么是jenkinsfile为什么使用jenkinsfile) +* [10.什么是Blue Ocean](#10什么是blue-ocean) + + +#### 1.什么是Jenkins? + +Jenkins是一个用Java编写的开源持续集成工具。它跟踪版本控制系统, 并在发生更改时启动和监视构建系统。 + +#### 2.Maven, Ant和Jenkins有什么区别? + +最基本的区别是: + +Maven和Ant是Build Technologies, 而Jenkins是持续集成工具。 + +#### 3.Jenkins支持哪些SCM工具? + +Jenkins支持以下SCM工具: + +- AccuRev +- CVS +- 颠覆 +- 去 +- 水星 +- Perforce +- 明箱 +- 实时时钟 + +#### 4.在Jenkins中, 什么是持续集成? + +在软件开发中, 多个开发人员或团队在同一个Web应用程序的不同部分上工作, 因此你必须通过集成所有模块来执行集成测试。为了做到这一点, 每天都要对每段代码进行自动化处理, 以便对所有代码进行测试。此过程称为连续集成。 + +#### 5.Jenkins的优势是什么? + +Jenkins的优势包括: + +- 在开发环境的早期阶段, 错误跟踪很容易。 +- 提供大量的插件支持。 +- 对代码的迭代改进。 +- 构建失败会在集成阶段进行缓存。 +- 对于每个代码提交更改, 都会生成一个自动生成报告通知。 +- 为了将构建报告的成功或失败通知开发人员, 它与LDAP邮件服务器集成在一起。 +- 实现持续集成的敏捷开发和测试驱动的开发。 +- 通过简单的步骤, 即可自动完成maven发布项目。 + +#### 6.可以使用哪些命令手动启动Jenkins? + +你可以使用以下任何命令来手动启动Jenkins: + +- (Jenkins_url)/ restart:强制重启, 而无需等待构建完成。 +- (Jenkin_url)/ safeRestart:允许所有正在运行的构建完成。 + +#### 7.如何在Jenkins中创建备份和复制文件? + +如果要创建Jenkins设置的备份, 只需复制将Jenkins的所有设置, 构建工件和日志保存在其主目录中的目录。你还可以复制作业目录以克隆或复制作业或重命名目录。 + +#### 8.如何通过Jenkins克隆Git存储库? + +如果要通过Jenkins克隆Git存储库, 则必须输入Jenkins系统的电子邮件和用户名。切换到作业目录并为此执行” git config”命令。 + +#### 9.什么是jenkinsfile?为什么使用jenkinsfile + +Jenkinsfile是一个文本文件,其中包含Jenkins Pipeline的定义,并已签入源代码管理 +虽然用于定义管道的脚本语法和jenkinsfile类似,但通常认为在项目中定义管道Jenkinsfile并检查源代码管理是最佳实践。 + +为所有分支和请求自动创建一个管道构建过程。 +管道上的代码审查/迭代。 +审核追踪管道 + +#### 10.什么是Blue Ocean + +Blue Ocean是pipeline的可视化UI。同时他兼容经典的自由模式的job。Jenkins Pipeline从头开始设计,但仍与自由式作业兼容,Blue Ocean减少了经典模式下的混乱并为团队中的每个成员增加了清晰度。Blue Ocean的主要特点包括: + +连续交付(CD)管道的复杂可视化,可以让您快速直观地理解管道状态。 +管道编辑器 - 通过引导用户通过直观和可视化的过程来创建管道,从而使管道的创建变得平易近人。 +个性化以适应团队中每个成员的基于角色的需求。 +在需要干预和/或出现问题时确定精确度。Blue Ocean显示的标注了关键步骤,促进异常处理和提高生产力。 + +#### 参考链接 + +https://blog.csdn.net/gaoping2736411763/article/details/106331998/ + +https://www.cnblogs.com/luoahong/articles/8313870.html + +https://blog.csdn.net/gaoping2736411763/article/details/106331998/ + +http://www.srcmini.com/33588.html diff --git a/Kafka.md b/Kafka.md new file mode 100644 index 0000000..da96928 --- /dev/null +++ b/Kafka.md @@ -0,0 +1,326 @@ +## Kafka + +* [1.为什么要使用 kafka?为什么要使用消息队列?](#1为什么要使用-kafka为什么要使用消息队列) +* [2.Kafka中的ISR、AR又代表什么?ISR的伸缩又指什么?](#2kafka中的israr又代表什么isr的伸缩又指什么) +* [3.kafka中的broker 是干什么的?](#3kafka中的broker-是干什么的) +* [4.kafka中的 zookeeper 起到什么作用?可以不用zookeeper么?](#4kafka中的-zookeeper-起到什么作用可以不用zookeeper么) +* [5.kafka follower如何与leader同步数据?](#5kafka-follower如何与leader同步数据) +* [6.什么情况下一个 broker 会从 ISR 中被踢出去?](#6什么情况下一个-broker-会从-isr-中被踢出去) +* [7.kafka 为什么那么快?](#7kafka-为什么那么快) +* [8.kafka producer如何优化打入速度?](#8kafka-producer如何优化打入速度) +* [9.kafka producer 打数据,ack 为 0, 1, -1 的时候代表啥, 设置 -1 的时候,什么情况下,leader 会认为一条消息 commit 了](#9kafka-producer-打数据ack--为-0-1--1-的时候代表啥-设置--1-的时候什么情况下leader-会认为一条消息-commit-了) +* [10.kafka unclean 配置代表啥?会对 spark streaming 消费有什么影响?](#10kafka--unclean-配置代表啥会对-spark-streaming-消费有什么影响) +* [11.如果leader crash时,ISR为空怎么办?](#11如果leader-crash时isr为空怎么办) +* [12.kafka的message格式是什么样的?](#12kafka的message格式是什么样的) +* [13.kafka中consumer group 是什么概念?](#13kafka中consumer-group-是什么概念) +* [14.Kafka中的消息是否会丢失和重复消费?](#14kafka中的消息是否会丢失和重复消费) +* [15.为什么Kafka不支持读写分离?](#15为什么kafka不支持读写分离) +* [16.Kafka中是怎么体现消息顺序性的?](#16kafka中是怎么体现消息顺序性的) +* [17.kafka如何实现延迟队列?](#17kafka如何实现延迟队列) +* [18.什么是消费者组?](#18什么是消费者组) +* [19.解释下 Kafka 中位移(offset)的作用。](#19解释下-kafka-中位移offset的作用) +* [20.阐述下 Kafka 中的领导者副本(Leader Replica)和追随者副本 (Follower Replica)的区别。](#20阐述下-kafka-中的领导者副本leader-replica和追随者副本-follower-replica的区别) +* [21.如何设置 Kafka 能接收的最大消息的大小?](#21如何设置-kafka-能接收的最大消息的大小) +* [22.监控 Kafka 的框架都有哪些?](#22监控-kafka-的框架都有哪些) +* [23.Broker 的 Heap Size 如何设置?](#23broker-的-heap-size-如何设置) +* [24.如何估算 Kafka 集群的机器数量?](#24如何估算-kafka-集群的机器数量) +* [25.Leader 总是 -1,怎么破?](#25leader-总是--1怎么破) +* [26.LEO、LSO、AR、ISR、HW 都表示什么含义?](#26leolsoarisrhw-都表示什么含义) +* [27.Kafka 能手动删除消息吗?](#27kafka-能手动删除消息吗) +* [28.consumer_offsets 是做什么用的?](#28consumer_offsets-是做什么用的) +* [29.分区 Leader 选举策略有几种?](#29分区-leader-选举策略有几种) +* [30.Kafka 的哪些场景中使用了零拷贝(Zero Copy)?](#30kafka-的哪些场景中使用了零拷贝zero-copy) +* [31.如何调优 Kafka?](#31如何调优-kafka) +* [32.Controller 发生网络分区(Network Partitioning)时,Kafka 会怎么样?](#32controller-发生网络分区network-partitioning时kafka-会怎么样) +* [33.Java Consumer 为什么采用单线程来获取消息?](#33java-consumer-为什么采用单线程来获取消息) +* [34.简述 Follower 副本消息同步的完整流程。](#34简述-follower-副本消息同步的完整流程) +* [参考资料](#参考资料) + + +#### 1.为什么要使用 kafka?为什么要使用消息队列? + +缓冲和削峰:上游数据时有突发流量,下游可能扛不住,或者下游没有足够多的机器来保证冗余,kafka在中间可以起到一个缓冲的作用,把消息暂存在kafka中,下游服务就可以按照自己的节奏进行慢慢处理。 +解耦和扩展性:项目开始的时候,并不能确定具体需求。消息队列可以作为一个接口层,解耦重要的业务流程。只需要遵守约定,针对数据编程即可获取扩展能力。 +冗余:可以采用一对多的方式,一个生产者发布消息,可以被多个订阅topic的服务消费到,供多个毫无关联的业务使用。 +健壮性:消息队列可以堆积请求,所以消费端业务即使短时间死掉,也不会影响主要业务的正常进行。 +异步通信:很多时候,用户不想也不需要立即处理消息。消息队列提供了异步处理机制,允许用户把一个消息放入队列,但并不立即处理它。想向队列中放入多少消息就放多少,然后在需要的时候再去处理它们。 + +#### 2.Kafka中的ISR、AR又代表什么?ISR的伸缩又指什么? + +ISR:In-Sync Replicas 副本同步队列 +AR:Assigned Replicas 所有副本 +ISR是由leader维护,follower从leader同步数据有一些延迟(包括延迟时间replica.lag.time.max.ms和延迟条数replica.lag.max.messages两个维度, 当前最新的版本0.10.x中只支持replica.lag.time.max.ms这个维度),任意一个超过阈值都会把follower剔除出ISR, 存入OSR(Outof-Sync Replicas)列表,新加入的follower也会先存放在OSR中。AR=ISR+OSR。 + +#### 3.kafka中的broker 是干什么的? + +broker 是消息的代理,Producers往Brokers里面的指定Topic中写消息,Consumers从Brokers里面拉取指定Topic的消息,然后进行业务处理,broker在中间起到一个代理保存消息的中转站。 + +#### 4.kafka中的 zookeeper 起到什么作用?可以不用zookeeper么? + +zookeeper 是一个分布式的协调组件,早期版本的kafka用zk做meta信息存储,consumer的消费状态,group的管理以及 offset的值。考虑到zk本身的一些因素以及整个架构较大概率存在单点问题,新版本中逐渐弱化了zookeeper的作用。新的consumer使用了kafka内部的group coordination协议,也减少了对zookeeper的依赖,但是broker依然依赖于ZK,zookeeper 在kafka中还用来选举controller 和 检测broker是否存活等等。 + +#### 5.kafka follower如何与leader同步数据? + +Kafka的复制机制既不是完全的同步复制,也不是单纯的异步复制。完全同步复制要求All Alive Follower都复制完,这条消息才会被认为commit,这种复制方式极大的影响了吞吐率。而异步复制方式下,Follower异步的从Leader复制数据,数据只要被Leader写入log就被认为已经commit,这种情况下,如果leader挂掉,会丢失数据,kafka使用ISR的方式很好的均衡了确保数据不丢失以及吞吐率。Follower可以批量的从Leader复制数据,而且Leader充分利用磁盘顺序读以及send file(zero copy)机制,这样极大的提高复制性能,内部批量写磁盘,大幅减少了Follower与Leader的消息量差。 + +#### 6.什么情况下一个 broker 会从 ISR 中被踢出去? + +leader会维护一个与其基本保持同步的Replica列表,该列表称为ISR(in-sync Replica),每个Partition都会有一个ISR,而且是由leader动态维护 ,如果一个follower比一个leader落后太多,或者超过一定时间未发起数据复制请求,则leader将其重ISR中移除 。 + +#### 7.kafka 为什么那么快? + +Cache Filesystem Cache PageCache缓存 +顺序。 由于现代的操作系统提供了预读和写技术,磁盘的顺序写大多数情况下比随机写内存还要快。 +Zero-copy。零拷技术减少拷贝次数 +Batching of Messages 批量量处理。合并小的请求,然后以流的方式进行交互,直顶网络上限。 +Pull 拉模式。使用拉模式进行消息的获取消费,与消费端处理能力相符。 + +#### 8.kafka producer如何优化打入速度? + +增加线程 +提高 batch.size +增加更多 producer 实例 +增加 partition 数 +设置 acks=-1 时,如果延迟增大:可以增大 num.replica.fetchers(follower 同步数据的线程数)来调解; +跨数据中心的传输:增加 socket 缓冲区设置以及 OS tcp 缓冲区设置。 + +#### 9.kafka producer 打数据,ack 为 0, 1, -1 的时候代表啥, 设置 -1 的时候,什么情况下,leader 会认为一条消息 commit 了 + +1(默认):数据发送到Kafka后,经过leader成功接收消息的的确认,就算是发送成功了。在这种情况下,如果leader宕机了,则会丢失数据。 +0:生产者将数据发送出去就不管了,不去等待任何返回。这种情况下数据传输效率最高,但是数据可靠性确是最低的。 +-1:producer需要等待ISR中的所有follower都确认接收到数据后才算一次发送完成,可靠性最高。当ISR中所有Replica都向Leader发送ACK时,leader才commit,这时候producer才能认为一个请求中的消息都commit了。 + +#### 10.kafka unclean 配置代表啥?会对 spark streaming 消费有什么影响? + +unclean.leader.election.enable 为true的话,意味着非ISR集合的broker 也可以参与选举,这样有可能就会丢数据,spark streaming在消费过程中拿到的 end offset 会突然变小,导致 spark streaming job挂掉。如果unclean.leader.election.enable参数设置为true,就有可能发生数据丢失和数据不一致的情况,Kafka的可靠性就会降低;而如果unclean.leader.election.enable参数设置为false,Kafka的可用性就会降低。 + +#### 11.如果leader crash时,ISR为空怎么办? + +kafka在Broker端提供了一个配置参数:unclean.leader.election,这个参数有两个值: +true(默认):允许不同步副本成为leader,由于不同步副本的消息较为滞后,此时成为leader,可能会出现消息不一致的情况。 +false:不允许不同步副本成为leader,此时如果发生ISR列表为空,会一直等待旧leader恢复,降低了可用性。 + +#### 12.kafka的message格式是什么样的? + +一个Kafka的Message由一个固定长度的header和一个变长的消息体body组成。 +header部分由一个字节的magic(文件格式)和四个字节的CRC32(用于判断body消息体是否正常)构成。 +当magic的值为1的时候,会在magic和crc32之间多一个字节的数据:attributes(保存一些相关属性,比如是否压缩、压缩格式等等);如果magic的值为0,那么不存在attributes属性。 +body是由N个字节构成的一个消息体,包含了具体的key/value消息。 + +#### 13.kafka中consumer group 是什么概念? + +同样是逻辑上的概念,是Kafka实现单播和广播两种消息模型的手段。同一个topic的数据,会广播给不同的group;同一个group中的worker,只有一个worker能拿到这个数据。换句话说,对于同一个topic,每个group都可以拿到同样的所有数据,但是数据进入group后只能被其中的一个worker消费。group内的worker可以使用多线程或多进程来实现,也可以将进程分散在多台机器上,worker的数量通常不超过partition的数量,且二者最好保持整数倍关系,因为Kafka在设计时假定了一个partition只能被一个worker消费(同一group内)。 + +#### 14.Kafka中的消息是否会丢失和重复消费? + +要确定Kafka的消息是否丢失或重复,从两个方面分析入手:消息发送和消息消费。 + +1)消息发送 +Kafka消息发送有两种方式:同步(sync)和异步(async),默认是同步方式,可通过producer.type属性进行配置。Kafka通过配置request.required.acks属性来确认消息的生产: + +0---表示不进行消息接收是否成功的确认; +1---表示当Leader接收成功时确认; +-1---表示Leader和Follower都接收成功时确认; +综上所述,有6种消息生产的情况,下面分情况来分析消息丢失的场景: + +(1)acks=0,不和Kafka集群进行消息接收确认,则当网络异常、缓冲区满了等情况时,消息可能丢失; + +(2)acks=1、同步模式下,只有Leader确认接收成功后但挂掉了,副本没有同步,数据可能丢失; + +2)消息消费 + +Kafka消息消费有两个consumer接口,Low-level API和High-level API: + +Low-level API:消费者自己维护offset等值,可以实现对Kafka的完全控制; + +High-level API:封装了对parition和offset的管理,使用简单; + +如果使用高级接口High-level API,可能存在一个问题就是当消息消费者从集群中把消息取出来、并提交了新的消息offset值后,还没来得及消费就挂掉了,那么下次再消费时之前没消费成功的消息就“诡异”的消失了; + +3)解决办法 + +针对消息丢失:同步模式下,确认机制设置为-1,即让消息写入Leader和Follower之后再确认消息发送成功;异步模式下,为防止缓冲区满,可以在配置文件设置不限制阻塞超时时间,当缓冲区满时让生产者一直处于阻塞状态; +针对消息重复:将消息的唯一标识保存到外部介质中,每次消费时判断是否处理过即可。 + + +#### 15.为什么Kafka不支持读写分离? + +在 Kafka 中,生产者写入消息、消费者读取消息的操作都是与 leader 副本进行交互的,从 而实现的是一种主写主读的生产消费模型。 + +Kafka 并不支持主写从读,因为主写从读有 2 个很明 显的缺点: + +(1)数据一致性问题。数据从主节点转到从节点必然会有一个延时的时间窗口,这个时间 窗口会导致主从节点之间的数据不一致。某一时刻,在主节点和从节点中 A 数据的值都为 X, 之后将主节点中 A 的值修改为 Y,那么在这个变更通知到从节点之前,应用读取从节点中的 A 数据的值并不为最新的 Y,由此便产生了数据不一致的问题。 + +(2)延时问题。类似 Redis 这种组件,数据从写入主节点到同步至从节点中的过程需要经 历网络→主节点内存→网络→从节点内存这几个阶段,整个过程会耗费一定的时间。而在 Kafka 中,主从同步会比 Redis 更加耗时,它需要经历网络→主节点内存→主节点磁盘→网络→从节 点内存→从节点磁盘这几个阶段。对延时敏感的应用而言,主写从读的功能并不太适用。 + +#### 16.Kafka中是怎么体现消息顺序性的? + +kafka每个partition中的消息在写入时都是有序的,消费时,每个partition只能被每一个group中的一个消费者消费,保证了消费时也是有序的。 +整个topic不保证有序。如果为了保证topic整个有序,那么将partition调整为1。 + +#### 17.kafka如何实现延迟队列? + +Kafka并没有使用JDK自带的Timer或者DelayQueue来实现延迟的功能,而是基于时间轮自定义了一个用于实现延迟功能的定时器(SystemTimer)。JDK的Timer和DelayQueue插入和删除操作的平均时间复杂度为O(nlog(n)),并不能满足Kafka的高性能要求,而基于时间轮可以将插入和删除操作的时间复杂度都降为O(1)。时间轮的应用并非Kafka独有,其应用场景还有很多,在Netty、Akka、Quartz、Zookeeper等组件中都存在时间轮的踪影。 + +底层使用数组实现,数组中的每个元素可以存放一个TimerTaskList对象。TimerTaskList是一个环形双向链表,在其中的链表项TimerTaskEntry中封装了真正的定时任务TimerTask. + +Kafka中到底是怎么推进时间的呢?Kafka中的定时器借助了JDK中的DelayQueue来协助推进时间轮。具体做法是对于每个使用到的TimerTaskList都会加入到DelayQueue中。Kafka中的TimingWheel专门用来执行插入和删除TimerTaskEntry的操作,而DelayQueue专门负责时间推进的任务。再试想一下,DelayQueue中的第一个超时任务列表的expiration为200ms,第二个超时任务为840ms,这里获取DelayQueue的队头只需要O(1)的时间复杂度。如果采用每秒定时推进,那么获取到第一个超时的任务列表时执行的200次推进中有199次属于“空推进”,而获取到第二个超时任务时有需要执行639次“空推进”,这样会无故空耗机器的性能资源,这里采用DelayQueue来辅助以少量空间换时间,从而做到了“精准推进”。Kafka中的定时器真可谓是“知人善用”,用TimingWheel做最擅长的任务添加和删除操作,而用DelayQueue做最擅长的时间推进工作,相辅相成。 + +#### 18.什么是消费者组? + +消费者组是 Kafka 独有的概念,如果面试官问这 个,就说明他对此是有一定了解的。我先给出标准答案: +1、定义:即消费者组是 Kafka 提供的可扩展且具有容错性的消费者机制。 +2、原理:在 Kafka 中,消费者组是一个由多个消费者实例 构成的组。多个实例共同订阅若干个主题,实现共同消费。同一个组下的每个实例都配置有 相同的组 ID,被分配不同的订阅分区。当某个实例挂掉的时候,其他实例会自动地承担起 它负责消费的分区。 + +此时,又有一个小技巧给到你:消费者组的题目,能够帮你在某种程度上掌控下面的面试方 +向。 + +如果你擅长位移值原理,就不妨再提一下消费者组的位移提交机制; +如果你擅长 Kafka Broker,可以提一下消费者组与 Broker 之间的交互; +如果你擅长与消费者组完全不相关的 Producer,那么就可以这么说:“消费者组要消 费的数据完全来自于 Producer 端生产的消息,我对 Producer 还是比较熟悉的。” + +#### 19.解释下 Kafka 中位移(offset)的作用。 + +在 Kafka 中,每个 主题分区下的每条消息都被赋予了一个唯一的 ID 数值,用于标识它在分区中的位置。这个 ID 数值,就被称为位移,或者叫偏移量。一旦消息被写入到分区日志,它的位移值将不能 被修改。 +答完这些之后,你还可以把整个面试方向转移到你希望的地方。常见方法有以下 3 种: +如果你深谙 Broker 底层日志写入的逻辑,可以强调下消息在日志中的存放格式; +如果你明白位移值一旦被确定不能修改,可以强调下“Log Cleaner 组件都不能影响位 移值”这件事情; +如果你对消费者的概念还算熟悉,可以再详细说说位移值和消费者位移值之间的区别。 + +#### 20.阐述下 Kafka 中的领导者副本(Leader Replica)和追随者副本 (Follower Replica)的区别。 + +这道题表面上是考核你对 Leader 和 Follower 区别的理解,但很容易引申到 Kafka 的同步 机制上。因此,我建议你主动出击,一次性地把隐含的考点也答出来,也许能够暂时把面试 官“唬住”,并体现你的专业性。 + +你可以这么回答:Kafka 副本当前分为领导者副本和追随者副本。只有 Leader 副本才能 对外提供读写服务,响应 Clients 端的请求。Follower 副本只是采用拉(PULL)的方 式,被动地同步 Leader 副本中的数据,并且在 Leader 副本所在的 Broker 宕机后,随时 准备应聘 Leader 副本。 + +通常来说,回答到这个程度,其实才只说了 60%,因此,我建议你再回答两个额外的加分 项。 + +强调 Follower 副本也能对外提供读服务。自 Kafka 2.4 版本开始,社区通过引入新的 Broker 端参数,允许 Follower 副本有限度地提供读服务。 +强调 Leader 和 Follower 的消息序列在实际场景中不一致。很多原因都可能造成 Leader 和 Follower 保存的消息序列不一致,比如程序 Bug、网络问题等。这是很严重 的错误,必须要完全规避。你可以补充下,之前确保一致性的主要手段是高水位机制, 但高水位值无法保证 Leader 连续变更场景下的数据一致性,因此,社区引入了 Leader Epoch 机制,来修复高水位值的弊端。关于“Leader Epoch 机制”,国内的资料不是 很多,它的普及度远不如高水位,不妨大胆地把这个概念秀出来,力求惊艳一把。 + +#### 21.如何设置 Kafka 能接收的最大消息的大小? + +这道题除了要回答消费者端的参数设置之外,一定要加上 Broker 端的设置,这样才算完整。毕竟,如果 Producer 都不能向 Broker 端发送数据很大的消息,又何来消费一说呢? 因此,你需要同时设置 Broker 端参数和 Consumer 端参数。 + +Broker 端参数:message.max.bytes、max.message.bytes(主题级别)和 replica.fetch.max.bytes。 +Consumer 端参数:fetch.message.max.bytes。 +Broker 端的最后一个参数比较容易遗漏。我们必须调整 Follower 副本能够接收的最大消 息的大小,否则,副本同步就会失败。因此,把这个答出来的话,就是一个加分项。 + +#### 22.监控 Kafka 的框架都有哪些? + +面试官其实是在 考察你对监控框架的了解广度,或者说,你是否知道很多能监控 Kafka 的框架或方法。下面这些就是 Kafka 发展历程上比较有名气的监控系统。 + +Kafka Manager:应该算是最有名的专属 Kafka 监控框架了,是独立的监控系统。 +Kafka Monitor:LinkedIn 开源的免费框架,支持对集群进行系统测试,并实时监控测 +试结果。 +CruiseControl:也是 LinkedIn 公司开源的监控框架,用于实时监测资源使用率,以及 提供常用运维操作等。无 UI 界面,只提供 REST API。 +JMX 监控:由于 Kafka 提供的监控指标都是基于 JMX 的,因此,市面上任何能够集成 JMX 的框架都可以使用,比如 Zabbix 和 Prometheus。 +已有大数据平台自己的监控体系:像 Cloudera 提供的 CDH 这类大数据平台,天然就提 供 Kafka 监控方案。 +JMXTool:社区提供的命令行工具,能够实时监控 JMX 指标。答上这一条,属于绝对 的加分项,因为知道的人很少,而且会给人一种你对 Kafka 工具非常熟悉的感觉。如果 你暂时不了解它的用法,可以在命令行以无参数方式执行一下kafka-run-class.sh kafka.tools.JmxTool,学习下它的用法。 + +#### 23.Broker 的 Heap Size 如何设置? + +如何设置 Heap Size 的问题,其实和 Kafka 关系不大,它是一类非常通用的面试题目。一 旦你应对不当,面试方向很有可能被引到 JVM 和 GC 上去,那样的话,你被问住的几率就 会增大。因此,我建议你简单地介绍一下 Heap Size 的设置方法,并把重点放在 Kafka Broker 堆大小设置的最佳实践上。 + +比如,你可以这样回复:任何 Java 进程 JVM 堆大小的设置都需要仔细地进行考量和测 试。一个常见的做法是,以默认的初始 JVM 堆大小运行程序,当系统达到稳定状态后,手动触发一次 Full GC,然后通过 JVM 工具查看 GC 后的存活对象大小。之后,将堆大小设 置成存活对象总大小的 1.5~2 倍。对于 Kafka 而言,这个方法也是适用的。不过,业界有 个最佳实践,那就是将 Broker 的 Heap Size 固定为 6GB。经过很多公司的验证,这个大 小是足够且良好的。 + +#### 24.如何估算 Kafka 集群的机器数量? + +这道题目考查的是机器数量和所用资源之间的关联关系。所谓资源,也就是 CPU、内存、磁盘和带宽。 + +通常来说,CPU 和内存资源的充足是比较容易保证的,因此,你需要从磁盘空间和带宽占用两个维度去评估机器数量。 + +在预估磁盘的占用时,你一定不要忘记计算副本同步的开销。如果一条消息占用 1KB 的磁 盘空间,那么,在有 3 个副本的主题中,你就需要 3KB 的总空间来保存这条消息。显式地 将这些考虑因素答出来,能够彰显你考虑问题的全面性,是一个难得的加分项。 + +对于评估带宽来说,常见的带宽有 1Gbps 和 10Gbps,但你要切记,这两个数字仅仅是最大值。因此,你最好和面试官确认一下给定的带宽是多少。然后,明确阐述出当带宽占用接 近总带宽的 90% 时,丢包情形就会发生。这样能显示出你的网络基本功。 + +#### 25.Leader 总是 -1,怎么破? + +在生产环境中,你一定碰到过“某个主题分区不能工作了”的情形。使用命令行查看状态的 话,会发现 Leader 是 -1,于是,你使用各种命令都无济于事,最后只能用“重启大 法”。 + +但是,有没有什么办法,可以不重启集群,就能解决此事呢?这就是此题的由来。 + +我直接给答案:删除 ZooKeeper 节点 /controller,触发 Controller 重选举。 Controller 重选举能够为所有主题分区重刷分区状态,可以有效解决因不一致导致的 Leader 不可用问题。我几乎可以断定,当面试官问出此题时,要么就是他真的不知道怎么 解决在向你寻求答案,要么他就是在等你说出这个答案。所以,千万别一上来就说“来个重 启”之类的话。 + +#### 26.LEO、LSO、AR、ISR、HW 都表示什么含义? + +LEO:Log End Offset。日志末端位移值或末端偏移量,表示日志下一条待插入消息的 位移值。举个例子,如果日志有 10 条消息,位移值从 0 开始,那么,第 10 条消息的位 移值就是 9。此时,LEO = 10。 +LSO:Log Stable Offset。这是 Kafka 事务的概念。如果你没有使用到事务,那么这个 值不存在(其实也不是不存在,只是设置成一个无意义的值)。该值控制了事务型消费 者能够看到的消息范围。它经常与 Log Start Offset,即日志起始位移值相混淆,因为 有些人将后者缩写成 LSO,这是不对的。在 Kafka 中,LSO 就是指代 Log Stable Offset。 +AR:Assigned Replicas。AR 是主题被创建后,分区创建时被分配的副本集合,副本个 数由副本因子决定。 +ISR:In-Sync Replicas。Kafka 中特别重要的概念,指代的是 AR 中那些与 Leader 保 持同步的副本集合。在 AR 中的副本可能不在 ISR 中,但 Leader 副本天然就包含在 ISR 中。关于 ISR,还有一个常见的面试题目是如何判断副本是否应该属于 ISR。目前的判断 依据是:Follower 副本的 LEO 落后 Leader LEO 的时间,是否超过了 Broker 端参数 replica.lag.time.max.ms 值。如果超过了,副本就会被从 ISR 中移除。 +HW:高水位值(High watermark)。这是控制消费者可读取消息范围的重要字段。一 个普通消费者只能“看到”Leader 副本上介于 Log Start Offset 和 HW(不含)之间的 所有消息。水位以上的消息是对消费者不可见的。关于 HW,问法有很多,我能想到的 最高级的问法,就是让你完整地梳理下 Follower 副本拉取 Leader 副本、执行同步机制 的详细步骤。这就是我们的第 20 道题的题目,一会儿我会给出答案和解析。 + +#### 27.Kafka 能手动删除消息吗? + +其实,Kafka 不需要用户手动删除消息。它本身提供了留存策略,能够自动删除过期消息。 当然,它是支持手动删除消息的。因此,你最好从这两个维度去回答。 + +对于设置了 Key 且参数 cleanup.policy=compact 的主题而言,我们可以构造一条 的消息发送给 Broker,依靠 Log Cleaner 组件提供的功能删除掉该 Key 的消息。 +对于普通主题而言,我们可以使用 kafka-delete-records 命令,或编写程序调用 Admin.deleteRecords 方法来删除消息。这两种方法殊途同归,底层都是调用 Admin 的 deleteRecords 方法,通过将分区 Log Start Offset 值抬高的方式间接删除消息。 + +#### 28.consumer_offsets 是做什么用的? + +这是一个内部主题,公开的官网资料很少涉及到。因此,我认为,此题属于面试官炫技一类 的题目。你要小心这里的考点:该主题有 3 个重要的知识点,你一定要全部答出来,才会显得对这块知识非常熟悉。 + +它是一个内部主题,无需手动干预,由 Kafka 自行管理。当然,我们可以创建该主题。 + +它的主要作用是负责注册消费者以及保存位移值。可能你对保存位移值的功能很熟悉, 但其实该主题也是保存消费者元数据的地方。千万记得把这一点也回答上。另外,这里 的消费者泛指消费者组和独立消费者,而不仅仅是消费者组。 + +Kafka 的 GroupCoordinator 组件提供对该主题完整的管理功能,包括该主题的创建、 写入、读取和 Leader 维护等。 + +#### 29.分区 Leader 选举策略有几种? + +分区的 Leader 副本选举对用户是完全透明的,它是由 Controller 独立完成的。你需要回答的是,在哪些场景下,需要执行分区 Leader 选举。每一种场景对应于一种选举策略。当前,Kafka 有 4 种分区 Leader 选举策略。 + +OfflinePartition Leader 选举:每当有分区上线时,就需要执行 Leader 选举。所谓的分区上线,可能是创建了新分区,也可能是之前的下线分区重新上线。这是最常见的分区 Leader 选举场景。 + +ReassignPartition Leader 选举:当你手动运行 kafka-reassign-partitions 命令,或者是调用 Admin 的 alterPartitionReassignments 方法执行分区副本重分配时,可能触发此类选举。假设原来的 AR 是[1,2,3],Leader 是 1,当执行副本重分配后,副本集 合 AR 被设置成[4,5,6],显然,Leader 必须要变更,此时会发生 Reassign Partition Leader 选举。 + +PreferredReplicaPartition Leader 选举:当你手动运行 kafka-preferred-replica- election 命令,或自动触发了 Preferred Leader 选举时,该类策略被激活。所谓的 Preferred Leader,指的是 AR 中的第一个副本。比如 AR 是[3,2,1],那么, Preferred Leader 就是 3。 + +ControlledShutdownPartition Leader 选举:当 Broker 正常关闭时,该 Broker 上 的所有 Leader 副本都会下线,因此,需要为受影响的分区执行相应的 Leader 选举。 + +这 4 类选举策略的大致思想是类似的,即从 AR 中挑选首个在 ISR 中的副本,作为新 Leader。当然,个别策略有些微小差异。不过,回答到这种程度,应该足以应付面试官 了。毕竟,微小差别对选举 Leader 这件事的影响很小。 + +#### 30.Kafka 的哪些场景中使用了零拷贝(Zero Copy)? + +Zero Copy 是特别容易被问到的高阶题目。在 Kafka 中,体现 Zero Copy 使用场景的地方有两处:基于 mmap 的索引和日志文件读写所用的 TransportLayer。 + +先说第一个。索引都是基于 MappedByteBuffer 的,也就是让用户态和内核态共享内核态 的数据缓冲区,此时,数据不需要复制到用户态空间。不过,mmap 虽然避免了不必要的 拷贝,但不一定就能保证很高的性能。在不同的操作系统下,mmap 的创建和销毁成本可 能是不一样的。很高的创建和销毁开销会抵消 Zero Copy 带来的性能优势。由于这种不确 定性,在 Kafka 中,只有索引应用了 mmap,最核心的日志并未使用 mmap 机制。 + +再说第二个。TransportLayer 是 Kafka 传输层的接口。它的某个实现类使用了 FileChannel 的 transferTo 方法。该方法底层使用 sendfile 实现了 Zero Copy。对 Kafka 而言,如果 I/O 通道使用普通的 PLAINTEXT,那么,Kafka 就可以利用 Zero Copy 特 性,直接将页缓存中的数据发送到网卡的 Buffer 中,避免中间的多次拷贝。相反,如果 I/O 通道启用了 SSL,那么,Kafka 便无法利用 Zero Copy 特性了。 + +#### 31.如何调优 Kafka? + +回答任何调优问题的第一步,就是确定优化目标,并且定量给出目标!这点特别重要。对于 Kafka 而言,常见的优化目标是吞吐量、延时、持久性和可用性。每一个方向的优化思路都 是不同的,甚至是相反的。 + +确定了目标之后,还要明确优化的维度。有些调优属于通用的优化思路,比如对操作系统、 JVM 等的优化;有些则是有针对性的,比如要优化 Kafka 的 TPS。我们需要从 3 个方向去考虑 + +Producer 端:增加 batch.size、linger.ms,启用压缩,关闭重试等。 +Broker 端:增加 num.replica.fetchers,提升 Follower 同步 TPS,避免 Broker Full GC 等。 +Consumer:增加 fetch.min.bytes 等 + +#### 32.Controller 发生网络分区(Network Partitioning)时,Kafka 会怎么样? + +这道题目能够诱发我们对分布式系统设计、CAP 理论、一致性等多方面的思考。不过,针 对故障定位和分析的这类问题,我建议你首先言明“实用至上”的观点,即不论怎么进行理论分析,永远都要以实际结果为准。一旦发生 Controller 网络分区,那么,第一要务就是 查看集群是否出现“脑裂”,即同时出现两个甚至是多个 Controller 组件。这可以根据 Broker 端监控指标 ActiveControllerCount 来判断。 + +现在,我们分析下,一旦出现这种情况,Kafka 会怎么样。 + +由于 Controller 会给 Broker 发送 3 类请求,即LeaderAndIsrRequest、 StopReplicaRequest 和 UpdateMetadataRequest,因此,一旦出现网络分区,这些请求将不能顺利到达 Broker 端。这将影响主题的创建、修改、删除操作的信息同步,表现为 集群仿佛僵住了一样,无法感知到后面的所有操作。因此,网络分区通常都是非常严重的问 题,要赶快修复。 + +#### 33.Java Consumer 为什么采用单线程来获取消息? + +在回答之前,如果先把这句话说出来,一定会加分:Java Consumer 是双线程的设计。一 个线程是用户主线程,负责获取消息;另一个线程是心跳线程,负责向 Kafka 汇报消费者 存活情况。将心跳单独放入专属的线程,能够有效地规避因消息处理速度慢而被视为下线 的“假死”情况。 + +单线程获取消息的设计能够避免阻塞式的消息获取方式。单线程轮询方式容易实现异步非阻塞式,这样便于将消费者扩展成支持实时流处理的操作算子。因为很多实时流处理操作算子都不能是阻塞式的。另外一个可能的好处是,可以简化代码的开发。多线程交互的代码是非常容易出错的。 + +#### 34.简述 Follower 副本消息同步的完整流程。 + +首先,Follower 发送 FETCH 请求给 Leader。接着,Leader 会读取底层日志文件中的消 息数据,再更新它内存中的 Follower 副本的 LEO 值,更新为 FETCH 请求中的 fetchOffset 值。最后,尝试更新分区高水位值。Follower 接收到 FETCH 响应之后,会把 消息写入到底层日志,接着更新 LEO 和 HW 值。 + +Leader 和 Follower 的 HW 值更新时机是不同的,Follower 的 HW 更新永远落后于 Leader 的 HW。这种时间上的错配是造成各种不一致的原因。 + + + +### 参考资料 +https://blog.csdn.net/qq_28900249/article/details/90346599 +https://www.jianshu.com/p/511962462e58 diff --git a/Kubernetes.md b/Kubernetes.md new file mode 100644 index 0000000..6c37db4 --- /dev/null +++ b/Kubernetes.md @@ -0,0 +1,130 @@ +## Kubernetes + +* [1.什么是Kubernetes?](#1什么是kubernetes) +* [2.Kubernetes与Docker有什么关系?](#2kubernetes与docker有什么关系) +* [3.什么是Container Orchestration?](#3什么是container-orchestration) +* [4.Kubernetes如何简化容器化部署?](#4kubernetes如何简化容器化部署) +* [5.什么是Google容器引擎?](#5什么是google容器引擎) +* [6.什么是Heapster?](#6什么是heapster) +* [7.什么是Minikube?](#7什么是minikube) +* [8.什么是Kubectl?](#8什么是kubectl) +* [9.什么是Kubelet?](#9什么是kubelet) +* [10.Kubernetes Architecture的不同组件有哪些?](#10kubernetes-architecture的不同组件有哪些) +* [11.你对Kube-proxy有什么了解?](#11你对kube-proxy有什么了解) +* [12.您能否介绍一下Kubernetes中主节点的工作情况?](#12您能否介绍一下kubernetes中主节点的工作情况) +* [13.kube-apiserver和kube-scheduler的作用是什么?](#13kube-apiserver和kube-scheduler的作用是什么) +* [14.你能简要介绍一下Kubernetes控制管理器吗?](#14你能简要介绍一下kubernetes控制管理器吗) +* [15.什么是etcd?](#15什么是etcd) +* [16.你对Kubernetes的负载均衡器有什么了解?](#16你对kubernetes的负载均衡器有什么了解) +* [17.什么是Ingress网络,它是如何工作的?](#17什么是ingress网络它是如何工作的) +* [18.您对云控制器管理器有何了解?](#18您对云控制器管理器有何了解) +* [19.什么是Container资源监控?](#19什么是container资源监控) +* [20.Replica Set 和 Replication Controller之间有什么区别?](#20replica-set-和-replication-controller之间有什么区别) + +#### 1.什么是Kubernetes? + +Kubernetes是一个开源容器管理工具,负责容器部署,容器扩缩容以及负载平衡。作为Google的创意之作,它提供了出色的社区,并与所有云提供商合作。因此,我们可以说Kubernetes不是一个容器化平台,而是一个多容器管理解决方案。 + +#### 2.Kubernetes与Docker有什么关系? + +众所周知,Docker提供容器的生命周期管理,Docker镜像构建运行时容器。但是,由于这些单独的容器必须通信,因此使用Kubernetes。因此,我们说Docker构建容器,这些容器通过Kubernetes相互通信。因此,可以使用Kubernetes手动关联和编排在多个主机上运行的容器。 + +#### 3.什么是Container Orchestration? + +考虑一个应用程序有5-6个微服务的场景。现在,这些微服务被放在单独的容器中,但如果没有容器编排就无法进行通信。因此,由于编排意味着所有乐器在音乐中和谐共处,所以类似的容器编排意味着各个容器中的所有服务协同工作以满足单个服务器的需求。 + +#### 4.Kubernetes如何简化容器化部署? + +由于典型应用程序将具有跨多个主机运行的容器集群,因此所有这些容器都需要相互通信。因此,要做到这一点,你需要一些能够负载平衡,扩展和监控容器的东西。由于Kubernetes与云无关并且可以在任何公共/私有提供商上运行,因此必须是您简化容器化部署的选择。 + +#### 5.什么是Google容器引擎? + +Google Container Engine(GKE)是Docker容器和集群的开源管理平台。这个基于Kubernetes的引擎仅支持在Google的公共云服务中运行的群集。 + +#### 6.什么是Heapster? + +Heapster是由每个节点上运行的Kubelet提供的集群范围的数据聚合器。此容器管理工具在Kubernetes集群上本机支持,并作为pod运行,就像集群中的任何其他pod一样。因此,它基本上发现集群中的所有节点,并通过机上Kubernetes代理查询集群中Kubernetes节点的使用信息。 + +#### 7.什么是Minikube? + +Minikube是一种工具,可以在本地轻松运行Kubernetes。这将在虚拟机中运行单节点Kubernetes群集。 + +#### 8.什么是Kubectl? + +Kubectl是一个平台,您可以使用该平台将命令传递给集群。因此,它基本上为CLI提供了针对Kubernetes集群运行命令的方法,以及创建和管理Kubernetes组件的各种方法。 + +#### 9.什么是Kubelet? + +这是一个代理服务,它在每个节点上运行,并使从服务器与主服务器通信。因此,Kubelet处理PodSpec中提供给它的容器的描述,并确保PodSpec中描述的容器运行正常。 + +#### 10.Kubernetes Architecture的不同组件有哪些? + +Kubernetes Architecture主要有两个组件 - 主节点和工作节点。如下图所示,master和worker节点中包含许多内置组件。主节点具有kube-controller-manager,kube-apiserver,kube-scheduler等。而工作节点具有在每个节点上运行的kubelet和kube-proxy。 + +#### 11.你对Kube-proxy有什么了解? + +Kube-proxy可以在每个节点上运行,并且可以跨后端网络服务进行简单的TCP / UDP数据包转发。基本上,它是一个网络代理,它反映了每个节点上Kubernetes API中配置的服务。因此,Docker可链接的兼容环境变量提供由代理打开的群集IP和端口。 + +#### 12.您能否介绍一下Kubernetes中主节点的工作情况? + +Kubernetes master控制容器存在的节点和节点内部。现在,这些单独的容器包含在容器内部和每个容器内部,您可以根据配置和要求拥有不同数量的容器。因此,如果必须部署pod,则可以使用用户界面或命令行界面部署它们。然后,在节点上调度这些pod,并根据资源需求,将pod分配给这些节点。kube-apiserver确保在Kubernetes节点和主组件之间建立通信。 + +#### 13.kube-apiserver和kube-scheduler的作用是什么? + +kube -apiserver遵循横向扩展架构,是主节点控制面板的前端。这将公开Kubernetes主节点组件的所有API,并负责在Kubernetes节点和Kubernetes主组件之间建立通信。 + +kube-scheduler负责工作节点上工作负载的分配和管理。因此,它根据资源需求选择最合适的节点来运行未调度的pod,并跟踪资源利用率。它确保不在已满的节点上调度工作负载。 + +#### 14.你能简要介绍一下Kubernetes控制管理器吗? + +多个控制器进程在主节点上运行,但是一起编译为单个进程运行,即Kubernetes控制器管理器。因此,Controller Manager是一个嵌入控制器并执行命名空间创建和垃圾收集的守护程序。它拥有责任并与API服务器通信以管理端点。 + +#### 15.什么是etcd? + +etcd是用Go编程语言编写的,是一个分布式键值存储,用于协调分布式工作。因此,Etcd存储Kubernetes集群的配置数据,表示在任何给定时间点的集群状态。 + +#### 16.你对Kubernetes的负载均衡器有什么了解? + +负载均衡器是暴露服务的最常见和标准方式之一。根据工作环境使用两种类型的负载均衡器,即内部负载均衡器或外部负载均衡器。内部负载均衡器自动平衡负载并使用所需配置分配容器,而外部负载均衡器将流量从外部负载引导至后端容器。 + +#### 17.什么是Ingress网络,它是如何工作的? + +Ingress网络是一组规则,充当Kubernetes集群的入口点。这允许入站连接,可以将其配置为通过可访问的URL,负载平衡流量或通过提供基于名称的虚拟主机从外部提供服务。因此,Ingress是一个API对象,通常通过HTTP管理集群中服务的外部访问,是暴露服务的最有效方式。 + +现在,让我以一个例子向您解释Ingress网络的工作。 + +有2个节点具有带有Linux桥接器的pod和根网络命名空间。除此之外,还有一个名为flannel0(网络插件)的新虚拟以太网设备被添加到根网络中。 + +现在,假设我们希望数据包从pod1流向pod 4。 + +因此,数据包将pod1的网络保留在eth0,并进入veth0的根网络。 +然后它被传递给cbr0,这使得ARP请求找到目的地,并且发现该节点上没有人具有目的地IP地址。 +因此,桥接器将数据包发送到flannel0,因为节点的路由表配置了flannel0。 +现在,flannel守护程序与Kubernetes的API服务器通信,以了解所有pod IP及其各自的节点,以创建pods IP到节点IP的映射。 +网络插件将此数据包封装在UDP数据包中,其中额外的标头将源和目标IP更改为各自的节点,并通过eth0发送此数据包。 +现在,由于路由表已经知道如何在节点之间路由流量,因此它将数据包发送到目标节点2。 +数据包到达node2的eth0并返回到flannel0以解封装并在根网络命名空间中将其发回。 +同样,数据包被转发到Linux网桥以发出ARP请求以找出属于veth1的IP。 +数据包最终穿过根网络并到达目标Pod4。 + +#### 18.您对云控制器管理器有何了解? + +Cloud Controller Manager负责持久存储,网络路由,从核心Kubernetes特定代码中抽象出特定于云的代码,以及管理与底层云服务的通信。它可能会分成几个不同的容器,具体取决于您运行的是哪个云平台,然后它可以使云供应商和Kubernetes代码在没有任何相互依赖的情况下开发。因此,云供应商开发他们的代码并在运行Kubernetes时与Kubernetes云控制器管理器连接。 + +#### 19.什么是Container资源监控? + +对于用户而言,了解应用程序的性能和所有不同抽象层的资源利用率非常重要,Kubernetes通过在容器,pod,服务和整个集群等不同级别创建抽象来考虑集群的管理。现在,可以监视每个级别,这只是容器资源监视。 + +#### 20.Replica Set 和 Replication Controller之间有什么区别? + +Replica Set 和 Replication Controller几乎完全相同。它们都确保在任何给定时间运行指定数量的pod副本。不同之处在于复制pod使用的选择器。Replica Set使用基于集合的选择器,而Replication Controller使用基于权限的选择器。 + +Equity-Based选择器:这种类型的选择器允许按标签键和值进行过滤。因此,在外行术语中,基于Equity的选择器将仅查找与标签具有完全相同短语的pod。 示例:假设您的标签键表示app = nginx,那么,使用此选择器,您只能查找标签应用程序等于nginx的那些pod。 + +Selector-Based选择器:此类型的选择器允许根据一组值过滤键。因此,换句话说,基于Selector的选择器将查找已在集合中提及其标签的pod。 示例:假设您的标签键在(nginx,NPS,Apache)中显示应用程序。然后,使用此选择器,如果您的应用程序等于任何nginx,NPS或Apache,则选择器将其视为真实结果。 + + + +#### 参考资料 + +https://blog.csdn.net/mingongge/article/details/100613465 diff --git a/Linux.md b/Linux.md new file mode 100644 index 0000000..2158792 --- /dev/null +++ b/Linux.md @@ -0,0 +1,252 @@ +## Linux + + +* [1.vim有几种工作模式?](#1vim有几种工作模式) +* [2.find 命令如何使用?](#2find-命令如何使用) +* [3.如何在 /usr 目录下找出大小超过 10MB 的文件?](#3如何在-usr-目录下找出大小超过-10mb-的文件) +* [4.如何在 /var 目录下找出 90 天之内未被访问过的文件?](#4如何在-var-目录下找出-90-天之内未被访问过的文件) +* [5.如何在 /home 目录下找出 120 天之前被修改过的文件?](#5如何在-home-目录下找出-120-天之前被修改过的文件) +* [6.在整个目录树下查找文件 “core” ,如发现则无需提示直接删除它们?](#6在整个目录树下查找文件-core-如发现则无需提示直接删除它们) +* [7.ls 命令](#7ls-命令) +* [8.df 命令](#8df-命令) +* [9.rm 命令](#9rm-命令) +* [10.mv 命令](#10mv-命令) +* [11.cp 命令](#11cp-命令) +* [12.tail 命令](#12tail-命令) +* [13.grep 命令](#13grep-命令) +* [14.sed 命令](#14sed-命令) +* [15.用 sed 命令将指定的路径 /usr/local/http 替换成为 /usr/src/local/http ?](#15用-sed-命令将指定的路径-usrlocalhttp-替换成为-usrsrclocalhttp-) +* [16.打印 /etc/ssh/sshd_config 的第一百行?](#16打印-etcsshsshd_config-的第一百行) +* [17.awk 命令](#17awk-命令) +* [18.打印 /etc/passwd 的 1 到 3 行?](#18打印-etcpasswd-的-1-到-3-行) +* [19.vim 命令](#19vim-命令) +* [20.diff 命令](#20diff-命令) +* [21.sort 命令](#21sort-命令) +* [22.xargs 命令](#22xargs-命令) +* [23.把当前目录下所有后缀名为 .txt 的文件的权限修改为 777 ?](#23把当前目录下所有后缀名为-txt-的文件的权限修改为-777-) +* [24.tar 命令](#24tar-命令) +* [25.gzip 命令](#25gzip-命令) +* [26.bzip2 命令](#26bzip2-命令) +* [27.unzip 命令](#27unzip-命令) +* [28.export 命令](#28export-命令) +* [29.yum 命令](#29yum-命令) +* [30.rpm 命令](#30rpm-命令) +* [31.shutdown 命令](#31shutdown-命令) +* [32.service 命令](#32service-命令) +* [33.whereis 命令](#33whereis-命令) +* [34.用一条命令显示本机 eth0 网卡的 IP 地址,不显示其它字符?](#34用一条命令显示本机-eth0-网卡的-ip-地址不显示其它字符) +* [35.如何禁止服务器被 ping ?](#35如何禁止服务器被-ping-) +* [36.设置 DNS 需要修改哪个配置文件?](#36设置-dns-需要修改哪个配置文件) +* [37.在 Linux 下如何指定dns服务器,来解析某个域名?](#37在-linux-下如何指定dns服务器来解析某个域名) +* [参考资料](#参考资料) + + + +#### 1.vim有几种工作模式? + +命令模式,行末模式,编辑模式 + +#### 2.find 命令如何使用? + +查找指定文件名的文件(不区分大小写):find -iname "MyProgram.c" 。 +对找到的文件执行某个命令:find -iname "MyProgram.c" -exec md5sum {} \; 。 +查找 home 目录下的所有空文件:find ~ -empty 。 + +#### 3.如何在 /usr 目录下找出大小超过 10MB 的文件? + +find /usr -type f -size +10240k + +#### 4.如何在 /var 目录下找出 90 天之内未被访问过的文件? + +find /var \! -atime -90 + +#### 5.如何在 /home 目录下找出 120 天之前被修改过的文件? + +find /home -mtime +120 + +#### 6.在整个目录树下查找文件 “core” ,如发现则无需提示直接删除它们? + +find / -name core -exec rm {} \; + +#### 7.ls 命令 + +以易读的方式显示文件大小(显示为 MB,GB…):ls -lh 。 +以最后修改时间升序列出文件:ls -ltr 。 +在文件名后面显示文件类型:ls -F 。 + +#### 8.df 命令 + +显示文件系统的磁盘使用情况,默认情况下 df -k 将以字节为单位输出磁盘的使用量。 +使用 df -h 选项可以以更符合阅读习惯的方式显示磁盘使用量。 +使用 df -T 选项显示文件系统类型。 + +#### 9.rm 命令 + +删除文件前先确认:rm -i filename.txt 。 +在文件名中使用 shell 的元字符会非常有用。删除文件前先打印文件名并进行确认:rm -i file* 。 +递归删除文件夹下所有文件,并删除该文件夹:rm -r example 。 + +#### 10.mv 命令 + +将 file1 重命名为 file2 ,如果 file2 存在则提示是否覆盖:mv -i file1 file2 。 +-v 会输出重命名的过程,当文件名中包含通配符时,这个选项会非常方便:mv -v file1 file2 。 + +#### 11.cp 命令 + +拷贝 file1 到 file2 ,并保持文件的权限、属主和时间戳:cp -p file1 file2 。 +拷贝 file1 到 file2 ,如果 file2 存在会提示是否覆盖:cp -i file1 file2 。 + +#### 12.tail 命令 + +tail 命令默认显示文件最后的 10 行文本:tail filename.txt 。 +你可以使用 -n 选项指定要显示的行数:tail -n N filename.txt 。 +你也可以使用 -f 选项进行实时查看,这个命令执行后会等待,如果有新行添加到文件尾部,它会继续输出新的行,在查看日志时这个选项会非常有用。你可以通过 CTRL-C 终止命令的执行:tail -f log-file 。 + +#### 13.grep 命令 + +在文件中查找字符串(不区分大小写):grep -i "the" demo_file 。 +输出成功匹配的行,以及该行之后的三行:grep -A 3 -i "example" demo_text 。 +在一个文件夹中递归查询包含指定字符串的文件:grep -r "ramesh" * 。 + +#### 14.sed 命令 + +当你将 Dos 系统中的文件复制到 Unix/Linux 后,这个文件每行都会以 \r\n 结尾,sed 可以轻易将其转换为 Unix 格式的文件,使用\n 结尾的文件:sed 's/.$//' filename 。 +反转文件内容并输出:sed -n '1!G; h; p' filename 。 +为非空行添加行号:sed '/./=' thegeekstuff.txt | sed 'N; s/\n/ /' 。 + +#### 15.用 sed 命令将指定的路径 /usr/local/http 替换成为 /usr/src/local/http ? + +echo "/usr/local/http/" | sed 's#/usr/local/#/usr/src/local/#' + +#### 16.打印 /etc/ssh/sshd_config 的第一百行? + +sed -n '100p' /etc/ssh/sshd_config + +#### 17.awk 命令 + +删除重复行:$ awk '!($0 in array) { array[$0]; print}' temp 。 +打印 /etc/passwd 中所有包含同样的 uid 和 gid 的行:awk -F ':' '$3=$4' /etc/passwd 。 +打印文件中的指定部分的字段:awk '{print $2,$5;}' employee.txt 。 + +#### 18.打印 /etc/passwd 的 1 到 3 行? + +使用 sed 命令:sed -n '1,3p' /etc/passwd +使用 awk 命令:awk 'NR>=1&&NR<=3{print $0}' /etc/passwd + +#### 19.vim 命令 + +打开文件并跳到第 10 行:vim +10 filename.txt 。 +打开文件跳到第一个匹配的行:vim +/search-term filename.txt 。 +以只读模式打开文件:vim -R /etc/passwd 。 + +#### 20.diff 命令 + +比较的时候忽略空白符:diff -w name_list.txt name_list_new.txt 。 + +#### 21.sort 命令 + +以升序对文件内容排序:sort names.txt 。 +以降序对文件内容排序:sort -r names.txt 。 +以第三个字段对 /etc/passwd 的内容排序:sort -t: -k 3n /etc/passwd | more 。 + +#### 22.xargs 命令 + +将所有图片文件拷贝到外部驱动器:ls *.jpg | xargs -n1 -i cp {} /external-hard-drive/directory 。 +将系统中所有 jpg 文件压缩打包:find / -name *.jpg -type f -print | xargs tar -cvzf images.tar.gz 。 +下载文件中列出的所有 url 对应的页面:cat url-list.txt | xargs wget –c 。 + +#### 23.把当前目录下所有后缀名为 .txt 的文件的权限修改为 777 ? + +方式一,使用 xargs 命令:find ./ -type f -name "*.txt" |xargs chmod 777 。 +方式二,使用 exec 命令:find ./ -type f -name "*.txt" -exec chmod 777 {} 。 + +#### 24.tar 命令 + +创建一个新的 tar 文件: tar cvf archive_name.tar dirname/ 。 +解压 tar 文件:tar xvf archive_name.tar 。 +查看 tar 文件:tar tvf archive_name.tar 。 + +#### 25.gzip 命令 + +创建一个 *.gz 的压缩文件:gzip test.txt 。 +解压 *.gz 文件:gzip -d test.txt.gz 。 +显示压缩的比率:gzip -l *.gz 。 + +#### 26.bzip2 命令 + +创建 *.bz2 压缩文件:bzip2 test.txt 。 +解压 *.bz2 文件:bzip2 -d test.txt.bz2 。 + +#### 27.unzip 命令 + +解压 *.zip 文件:unzip test.zip 。 +查看 *.zip 文件的内容:unzip -l jasper.zip 。 + +#### 28.export 命令 + +输出跟字符串 oracle 匹配的环境变量:export | grep ORCALE 。 +设置全局环境变量:export ORACLE_HOME=/u01/app/oracle/product/10.2.0 。 + +#### 29.yum 命令 + +使用 yum 安装 apache :yum install httpd 。 +更新 apache :yum update httpd 。 +卸载/删除 apache :yum remove httpd 。 + +#### 30.rpm 命令 + +使用 rpm 安装 apache :rpm -ivh httpd-2.2.3-22.0.1.el5.i386.rpm 。 +更新 apache :rpm -uvh httpd-2.2.3-22.0.1.el5.i386.rpm 。 +卸载/删除 apache :rpm -ev httpd 。 + +#### 31.shutdown 命令 + +关闭系统并立即关机:shutdown -h now 。 +10 分钟后关机:shutdown -h +10 。 +重启:shutdown -r now 。 +重启期间强制进行系统检查:shutdown -Fr now 。 + +#### 32.service 命令 + +service 命令用于运行 System V init 脚本,这些脚本一般位于 /etc/init.d 文件下,这个命令可以直接运行这个文件夹里面的脚本,而不用加上路径。 +查看服务状态:service ssh status 。 +查看所有服务状态:service --status-all 。 +重启服务:service ssh restart 。 + +#### 33.whereis 命令 + +当你不知道某个命令的位置时可以使用 whereis 命令,下面使用 whereis 查找 ls 的位置:whereis ls 。 +当你想查找某个可执行程序的位置,但这个程序又不在 whereis 的默认目录下,你可以使用 -B 选项,并指定目录作为这个选项的参数。下面的命令在 /tmp 目录下查找 lsmk 命令:whereis -u -B /tmp -f lsmk 。 + +#### 34.用一条命令显示本机 eth0 网卡的 IP 地址,不显示其它字符? + +方法一: +ifconfig eth0|grep inet|awk -F ':' '{print $2}'|awk '{print $1}' +方法二 +ifconfig eth0|grep "inet addr"|awk -F '[ :]+' '{print $4}' +方法三: +ifconfig eth0|awk -F '[ :]+' 'NR==2 {print $4}' +方法四: +ifconfig eth0|sed -n '2p'|sed 's#^.*addr:##g'|sed 's# Bc.*$##g' +方法五: +ifconfig eth0|sed -n '2p'|sed -r 's#^.*addr:(.*) Bc.*$#\1#g' +方法六(CENTOS7 也适用): +ip addr|grep eth0|grep inet|awk '{print $2}'|awk -F '/' '{print $1}' + +#### 35.如何禁止服务器被 ping ? + +echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all + +#### 36.设置 DNS 需要修改哪个配置文件? + +全局的配置,可以在 /etc/resolv.conf 文件中配置。 +指定网卡的配置,可以在 /etc/sysconfig/network-scripts/ifcfg-eth0 文件中配置。 + +#### 37.在 Linux 下如何指定dns服务器,来解析某个域名? + +使用谷歌 DNS 解析百度:dig @8.8.8.8 www.baidu.com + + + +### 参考资料 +https://blog.csdn.net/a303549861/article/details/93754526 diff --git a/Maven.md b/Maven.md new file mode 100644 index 0000000..10e8af4 --- /dev/null +++ b/Maven.md @@ -0,0 +1,238 @@ +## Maven + +* [1.maven是什么?](#1maven是什么) +* [2.使用Maven好处](#2使用maven好处) +* [3.Maven的坐标和依赖](#3maven的坐标和依赖) +* [4.Maven的⽣命周期](#4maven的命周期) +* [5.你们项目为什么选用 Maven 进行构建?](#5你们项目为什么选用-maven-进行构建) +* [6.Maven 规约是什么?](#6maven-规约是什么) +* [7.Maven 常用命令](#7maven-常用命令) +* [8.Maven 有哪些优点和缺点](#8maven-有哪些优点和缺点) +* [9.Maven 版本规则?](#9maven-版本规则) +* [10.对于一个多模块项目,如果管理项目依赖的版本?](#10对于一个多模块项目如果管理项目依赖的版本) +* [11.Maven 依赖原则?](#11maven-依赖原则) +* [12.如何解决 jar 冲突?](#12如何解决-jar-冲突) +* [13.什么是 Maven 插件?](#13什么是-maven-插件) +* [14.Maven依赖冲突](#14maven依赖冲突) +* [15.依赖的解析机制](#15依赖的解析机制) + + +#### 1.maven是什么? + +Apache Maven是一个软件项目管理和理解工具。基于项目对象模型(POM)的概念,Maven可以从一个中心信息管理项目的构建,报告和文档。 +项目构建 +在eclipse中新建一个WEB工程。 +进行编码及编写配置文件 +对源代码进行编译运行,生成class文件 +打成war包,部署至tomcat + +#### 2.使用Maven好处 + +Maven能提供一种项目的配置,配置好的项目,只需要运行一条简单的命令,就能完成重复的,繁琐的构建动作. +Maven能提供一种项目的依赖配置.可以自动的导入项目依赖的jar,并且自动导入这些jar包依赖的第三方的jar包. +Maven提供了一种标准的项目目录结构,测试命名规则等项目的最佳实践方案,统一了不同项目的学习成本. +maven的常用命令 +mvn clean : 清理 +mvn compile:编译 +mvn package:打包 +mvn test : 测试,⾃动运⾏所有的测试⽤例 +mvn install : 安装,将项⽬打的包安装到本地仓库,其他项⽬就可以依赖了 +mvn jetty:run : 运⾏jetty插件 + +#### 3.Maven的坐标和依赖 + +maven的坐标组成部分 +groupId: 组织机构id,org.aptech.hdax, org.springframework +artifactId: ⼦项⽬编号,springmvc, spring-test, spring-core +version: 版本号,可以⼀直迭代,平时项⽬开发⽤的是快照版本 0.0.1-SNAPSHOT +Package: jar war pom +项⽬依赖的核⼼概念: +框架整合最害怕jar包冲突,之前不使⽤maven,经常出现这个⽂件。 +依赖范围 scope标签进⾏配置 +Compile: 默认值,项⽬打包的时候会把该依赖包打进去 +Test : 测试依赖,只是在运⾏测试⽤例的时候会⽤到,打包是不打进去的 +Provided: 提供依赖,类似于test +传递依赖 +a -> b, b->c ,如果在a中导⼊到b的依赖,c会⾃动过来 +依赖调解 +如果不同的包传递依赖了⼀个相同的jar,但是版本不⼀致 +原则: +最短路径 +第⼀声明优先原则 +排除依赖 +归类依赖: ⽅便后期的依赖版本升级、降级 + +#### 4.Maven的⽣命周期 + +一个项目的构建过成通常包括清理、编译、测试、打包、集成测试、验证、部署等。Maven从中抽取了一套完善的、易扩展的生命周期。Maven的生命周期是抽象的,其中的具体任务都交由插件来完成。Maven为大多数构建任务编写并绑定了默认的插件。 +Maven定义了三套生命周期:clean、default、site,每个生命周期都包含了一些阶段(phase)。三套生命周期相互独立,但各个生命周期中的阶段却是有顺序的,且后面的夹断依赖于前面的阶段。执行某个阶段时,其前面的阶段会依顺序执行,但不会触发另外两套生命周期中的任何阶段。 + +#### 5.你们项目为什么选用 Maven 进行构建? + +- 首先,Maven 是一个优秀的项目构建工具。使用maven,可以很方便的对项目进行分模块构建,这样在开发和测试打包部署时,效率会提高很多。 +- 其次,Maven 可以进行依赖的管理。使用 Maven ,可以将不同系统的依赖进行统一管理,并且可以进行依赖之间的传递和继承。 + +#### 6.Maven 规约是什么? + +- `/src/main/java/` :Java 源码。 +- `/src/main/resource` :Java 配置文件,资源文件。 +- `/src/test/java/` :Java 测试代码。 +- `/src/test/resource` :Java 测试配置文件,资源文件。 +- `/target` :文件编译过程中生成的 `.class` 文件、jar、war 等等。 +- `pom.xml` :配置文件 + +Maven 要负责项目的自动化构建,以编译为例,Maven 要想自动进行编译,那么它必须知道 Java 的源文件保存在哪里,这样约定之后,不用我们手动指定位置,Maven 能知道位置,从而帮我们完成自动编译。 + +遵循**“约定>>>配置>>>编码”**。即能进行配置的不要去编码指定,能事先约定规则的不要去进行配置。这样既减轻了劳动力,也能防止出错。 + +#### 7.Maven 常用命令 + +- `mvn archetype:create` :创建 Maven 项目。 +- `mvn compile` :编译源代码。 +- `mvn deploy` :发布项目。 +- `mvn test-compile` :编译测试源代码。 +- `mvn test` :运行应用程序中的单元测试。 +- `mvn site` :生成项目相关信息的网站。 +- `mvn clean` :清除项目目录中的生成结果。 +- `mvn package` :根据项目生成的 jar/war 等。 +- `mvn install` :在本地 Repository 中安装 jar 。 +- `mvn eclipse:eclipse` :生成 Eclipse 项目文件。 +- `mvn jetty:run` 启动 Jetty 服务。 +- `mvn tomcat:run` :启动 Tomcat 服务。 +- `mvn clean package -Dmaven.test.skip=true` :清除以前的包后重新打包,跳过测试类。 +- 用到最多的命令 + - `mvn eclipse:clean` :清除 Project 中以前的编译的东西,重新再来。 + - `mvn eclipse:eclipse` :开始编译 Maven 的 Project 。 + - `mvn clean package` :清除以前的包后重新打包。 + +#### 8.Maven 有哪些优点和缺点 + +1)优点 + +- 简化了项目依赖管理。 + + 当年,多少人被 SSH 整合搞死搞活,很多时候,是因为依赖不完整,或者版本不正确。自从 Maven 出来后,终于可以无痛了~当然,也有一部分功劳是 Spring Boot ,这是后话。 + +- 易于上手,对于新手可能一个 `mvn clean package` 命令就可能满足我们的工作。 + +- 便于与持续集成工具(Jenkins)整合。 + +- 便于项目升级,无论是项目本身升级还是项目使用的依赖升级。 + +- 有助于多模块项目的开发,一个模块开发好后,发布到仓库,依赖该模块时可以直接从仓库更新,而不用自己去编译。 + +- Maven 有很多插件,便于功能扩展,比如生产站点,自动发布版本等。 + + 2)缺点 + +- Maven 是一个庞大的构建系统,学习难度大。 + + 这里的学习,更多指的完整学习。如果基本使用,并不会存在该问题。 + +- Maven 采用约定优于配置的策略(convention over configuration),虽然上手容易,但是一旦出了问题,难于调试。 + + 这个确实,略微痛苦。 + +- 当依赖很多时,m2eclipse 老是搞得 Eclipse 很卡。 + + 使用 IDEA ,而不是 Eclipse ,完美解决。 + +- 中国的网络环境差,很多 repository 无法访问,比如 Google Code、 JBoss 仓库无法访问等。 + + 这个也好解决,在 `` 中增加阿里巴巴的 Maven 私服,具体可以参见 [《提高 Maven 速度 —— Maven 仓库修改成国内阿里巴巴地址》](https://my.oschina.net/af8991/blog/833513) 文章。 + +#### 9.Maven 版本规则? + +Maven 主要是这样定义版本规则的:`<主版本>.<次版本>.<增量版本>` 。比如说 `1.2.3` ,主版本是 1 ,次版本是 2 ,增量版本是 3 。 + +- 主版本,一般来说代表了项目的重大的架构变更,比如说 Maven 1 和 Maven 2 ,在架构上已经两样了,将来的 Maven 3 和 Maven 2 也会有很大的变化。 +- 次版本,一般代表了一些功能的增加或变化,但没有架构的变化,比如说Nexus 1.3 较之于 Nexus 1.2 来说,增加了一系列新的或者改进的功能(仓库镜像支持,改进的仓库管理界面等等),但从大的架构上来说,1.3 和 1.2 没什么区别。 +- 增量版本,一般是一些小的 bug fix ,不会有重大的功能变化。 + +一般来说,在我们发布一次重要的版本之后,随之会开发新的版本。比如说,`myapp-1.1` 发布之后,就着手开发 `myapp-1.2` 了。由于`myapp-1.2` 有新的主要功能的添加和变化,在发布测试前,它会变得不稳定,而 `myapp-1.1` 是一个比较稳定的版本,现在的问题是,我们在`myapp-1.1中` 发现了一些 BUG(当然在 1.2 中也存在),为了能够在一段时间内修复 BUG 并仍然发布稳定的版本,我们就会用到分支(branch),我们基于 1.1 开启一个分支 1.1.1 ,在这个分支中修复 BUG ,并快速发布。这既保证了版本的稳定,也能够使bug得到快速修复,也不同停止 1.2 的开发。只是,每次修复分支 1.1.1 中的 BUG 后,需要 merge 代码到 1.2 中。 + +#### 10.对于一个多模块项目,如果管理项目依赖的版本? + +- 方式一,通过在父模块中声明 `` 和``, 然后让子模块通过元素指定父模块,这样子模块在定义依赖是就可以只定义 `groupId` 和 `artifactId`,自动使用父模块的 `version` ,这样统一整个项目的依赖的版本。 + + 继承的方式。 + +- 方式二,使用 `` 声明 `` 为 `import` 的依赖,从而引入一个 pom 的`` 的。具体的,可以看看 [《Maven Spring BOM (bill of materials)》](https://www.cnblogs.com/YLsY/p/5711103.html)文章。 + + 组合的方式。 + +#### 11.Maven 依赖原则? + +- 1、赖路径最短优先原则。 + + 一个项目 Demo 依赖了两个 jar 包,其中 `A-B-C-X(1.0)` , `A-D-X(2.0)` 。由于 `X(2.0)` 路径最短,所以项目使用的是 `X(2.0)` 。 + +- 2、pom文 件中申明顺序优先。 + + 如果 `A-B-X(1.0)` ,`A-C-X(2.0)` 这样的路径长度一样怎么办呢?这样的情况下,Maven 会根据 pom 文件声明的顺序加载,如果先声明了 B ,后声明了 C ,那就最后的依赖就会是 `X(1.0)` 。 + +- 3、覆写优先 + + 子 pom 内声明的优先于父 pom 中的依赖。 + +#### 12.如何解决 jar 冲突? + +遇到冲突的时候第一步,要找到 Maven 加载的到时是什么版本的 jar 包,通过们 `mvn dependency:tree` 查看依赖树,或者使用 [IDEA Maven Helper](https://plugins.jetbrains.com/plugin/7179-maven-helper) 插件。 + +然后,通过 Maven 的依赖原则来调整坐标在 pom 文件的申明顺序是最好的办法,或者使用将冲突中不想要的 jar 引入的 jar 进行 `` 掉。 + +#### 13.什么是 Maven 插件? + +Maven 生命周期的每一个阶段的具体实现都是由 Maven 插件实现的。插件通常提供了一个目标的集合,并且可以使用下面的语法执行:`mvn [plugin-name]:[goal-name]` + +Maven 提供了下面两种类型的插件: + +- Build plugins :在构建时执行,并在 `pom.xml` 的 元素中配置。 +- Reporting plugins :在网站生成过程中执行,并在 `pom.xml` 的元素中配置。 + +下面是一些常用插件的列表: + +- clean :构建之后清理目标文件。删除目标目录。 +- compiler :编译 Java 源文件。 +- surefile :运行 JUnit 单元测试。创建测试报告。 +- jar :从当前工程中构建 JAR 文件。 +- war :从当前工程中构建 WAR 文件。 +- javadoc :为工程生成 Javadoc 。 +- antrun :从构建过程的任意一个阶段中运行一个 ant 任务的集合。 + +#### 14.Maven依赖冲突 + +每个显式声明的类包都会依赖于一些其它的隐式类包,这些隐式的类包会被maven间接引入进来,因而可能造成一个我们不想要的类包的载入,严重的甚至会引起类包之间的冲突。 + +要解决这个问题,首先就是要查看pom.xml显式和隐式的依赖类包,然后通过这个类包树找出我们不想要的依赖类包,手工将其排除在外就可以了。 例如: + +```xml + + + unitils-database + org.unitils + + +``` + +#### 15.依赖的解析机制 + +当依赖的范围是 system 的时候,Maven 直接从本地文件系统中解析构件。 + +根据依赖坐标计算仓库路径,尝试直接从本地仓库寻找构件,如果发现对应的构件,就解析成功。 + +如果在本地仓库不存在相应的构件,就遍历所有的远程仓库,发现后,下载并解析使用。 + +如果依赖的版本是 RELEASE 或 LATEST,就基于更新策略读取所有远程仓库的元数据文件(groupId/artifactId/maven-metadata.xml),将其与本地仓库的对应元合并后,计算出 RELEASE 或者 LATEST 真实的值,然后基于该值检查本地仓库,或者从远程仓库下载。 + +如果依赖的版本是 SNAPSHOT,就基于更新策略读取所有远程仓库的元数据文件,将它与本地仓库对应的元数据合并,得到最新快照版本的值,然后根据该值检查本地仓库,或从远程仓库下载。 + +如果最后解析得到的构件版本包含有时间戳,先将该文件下载下来,再将文件名中时间戳信息删除,剩下 SNAPSHOT 并使用(以非时间戳的形式使用)。 + +#### 参考链接 + +https://blog.csdn.net/weixin_44450768/article/details/104218776 + +https://blog.csdn.net/a303549861/article/details/93752178 + +https://www.cnblogs.com/lin0/p/14153982.html diff --git a/MongoDB.md b/MongoDB.md new file mode 100644 index 0000000..0d5957d --- /dev/null +++ b/MongoDB.md @@ -0,0 +1,139 @@ +## MongoDB + +* [1.什么是MongoDB?](#1什么是mongodb) +* [2.MongoDB的优势有哪些](#2mongodb的优势有哪些) +* [3.什么是集合(表)?](#3什么是集合表) +* [4.什么是文档(记录)](#4什么是文档记录) +* [5.为什么用MOngoDB?](#5为什么用mongodb) +* [6.在哪些场景使用MongoDB](#6在哪些场景使用mongodb) +* [7.MongoDB中的命名空间是什么意思?](#7mongodb中的命名空间是什么意思) +* [8.MongoDB中的分片什么意思](#8mongodb中的分片什么意思) +* [9.为什么要在MongoDB中使用分析器](#9为什么要在mongodb中使用分析器) +* [10.MongoDB支持主键外键关系吗](#10mongodb支持主键外键关系吗) +* [11.MongoDB支持哪些数据类型](#11mongodb支持哪些数据类型) +* [12.为什么要在MongoDB中用"Code"数据类型](#12为什么要在mongodb中用code数据类型) +* [13.为什么要在MongoDB中用"Regular Expression"数据类型](#13为什么要在mongodb中用regular-expression数据类型) +* [14.为什么在MongoDB中使用"Object ID"数据类型](#14为什么在mongodb中使用object-id数据类型) +* [15."ObjectID"有哪些部分组成](#15objectid有哪些部分组成) +* [16.在MongoDb中什么是索引](#16在mongodb中什么是索引) +* [17.在MongoDB中什么是副本集](#17在mongodb中什么是副本集) +* [18.MongoDB支持存储过程吗?如果支持的话,怎么用?](#18mongodb支持存储过程吗如果支持的话怎么用) +* [19.如何理解MongoDB中的GridFS机制,MongoDB为何使用GridFS来存储文件?](#19如何理解mongodb中的gridfs机制mongodb为何使用gridfs来存储文件) +* [20.为什么MongoDB的数据文件很大?](#20为什么mongodb的数据文件很大) + +#### 1.什么是MongoDB? + +MongoDB是一个文档数据库,提供好的性能,领先的非关系型数据库。采用BSON存储文档数据。 +BSON()是一种类json的一种二进制形式的存储格式,简称Binary JSON +相对于json多了date类型和二进制数组。 + +#### 2.MongoDB的优势有哪些 + +面向文档的存储:以 JSON 格式的文档保存数据。 +任何属性都可以建立索引。 +复制以及高可扩展性。 +自动分片。 +丰富的查询功能。 +快速的即时更新。 + +#### 3.什么是集合(表)? + +集合就是一组 MongoDB文档。它相当于关系型数据库(RDBMS)中的表这种概念。集合位于单独的一个数据库中。 +一个集合内的多个文档可以有多个不同的字段。一般来说,集合中的文档都有着相同或相关的目的。 + +#### 4.什么是文档(记录) + +文档由一组key value组成。文档是动态模式,这意味着同一集合里的文档不需要有相同的字段和结构。在关系型数据库中table中的每一条记录相当于MongoDB中的一个文档。 + +#### 5.为什么用MOngoDB? + +架构简单 +没有复杂的连接 +深度查询能力,MongoDB支持动态查询。 +容易调试 +容易扩展 +不需要转化/映射应用对象到数据库对象 +使用内部内存作为存储工作区,以便更快的存取数据。 + +#### 6.在哪些场景使用MongoDB + +大数据 +内容管理系统 +移动端Apps +数据管理 + +#### 7.MongoDB中的命名空间是什么意思? + +mongodb存储bson对象在丛集(collection)中,数据库名字和丛集名字以句点连结起来叫做名字空间(namespace)。 + +一个集合命名空间又有多个数据域(extent),集合命名空间里存储着集合的元数据,比如集合名称,集合的第一个数据域和最后一个数据域的位置等等。而一个数据域由若干条文档(document)组成,每个数据域都有一个头部,记录着第一条文档和最后一条文档的为知,以及该数据域的一些元数据。extent之间,document之间通过双向链表连接。 + +索引的存储数据结构是B树,索引命名空间存储着对B树的根节点的指针。 + +#### 8.MongoDB中的分片什么意思 + +分片是将数据水平切分到不同的物理节点。当应用数据越来越大的时候,数据量也会越来越大。当数据量增长时,单台机器有可能无法存储数据或可接受的读取写入吞吐量。利用分片技术可以添加更多的机器来应对数据量增加以及读写操作的要求。 + +#### 9.为什么要在MongoDB中使用分析器 + +mongodb中包括了一个可以显示数据库中每个操作性能特点的数据库分析器.通过这个分析器你可以找到比预期慢的查询(或写操作);利用这一信息,比如,可以确定是否需要添加索引。 + +#### 10.MongoDB支持主键外键关系吗 + +默认MongoDB不支持主键和外键关系。 用Mongodb本身的API需要硬编码才能实现外键关联,不够直观且难度较大。 + +#### 11.MongoDB支持哪些数据类型 + +String +Integer +Double +Boolean +Object +Object ID +Arrays +Min/Max Keys +Datetime +Code +Regular Expression等 + +#### 12.为什么要在MongoDB中用"Code"数据类型 + +"Code"类型用于在文档中存储 JavaScript 代码。 + +#### 13.为什么要在MongoDB中用"Regular Expression"数据类型 + +"Regular Expression"类型用于在文档中存储正则表达式 + +#### 14.为什么在MongoDB中使用"Object ID"数据类型 + +"ObjectID"数据类型用于存储文档id + +#### 15."ObjectID"有哪些部分组成 + +一共有四部分组成:时间戳、客户端ID、客户进程ID、三个字节的增量计数器 + +#### 16.在MongoDb中什么是索引 + +索引用于高效的执行查询,没有索引的MongoDB将扫描整个集合中的所有文档,这种扫描效率很低,需要处理大量的数据。 +索引是一种特殊的数据结构,将一小块数据集合保存为容易遍历的形式.索引能够存储某种特殊字段或字段集的 +值,并按照索引指定的方式将字段值进行排序。 + +#### 17.在MongoDB中什么是副本集 + +在MongoDB中副本集由一组MongoDB实例组成,包括一个主节点多个次节点,MongoDB客户端的所有数据都写入主节点(Primary),副节点从主节点同步写入数据,以保持所有复制集内存储相同的数据,提高数据可用性。 + +#### 18.MongoDB支持存储过程吗?如果支持的话,怎么用? + +MongoDB支持存储过程,它是javascript写的,保存在db.system.js表中。 + +#### 19.如何理解MongoDB中的GridFS机制,MongoDB为何使用GridFS来存储文件? + +GridFS是一种将大型文件存储在MongoDB中的文件规范。使用GridFS可以将大文件分隔成多个小文档存放,这样我们能够有效的保存大文档,而且解决了BSON对象有限制的问题。 + +#### 20.为什么MongoDB的数据文件很大? + +MongoDB采用的预分配空间的方式来防止文件碎片。 + +#### 参考资料 + +https://www.cnblogs.com/angle6-liu/p/10791875.html diff --git a/MySQL.md b/MySQL.md new file mode 100644 index 0000000..1a871d6 --- /dev/null +++ b/MySQL.md @@ -0,0 +1,452 @@ +## MySQL + + +* [1. 什么是索引?](#1-什么是索引) +* [2.索引是个什么样的数据结构呢?](#2索引是个什么样的数据结构呢) +* [3.Hash索引和B+树索引有什么区别或者说优劣呢?](#3hash索引和b树索引有什么区别或者说优劣呢) +* [4.在建立索引的时候,都有哪些需要考虑的因素呢?](#4在建立索引的时候都有哪些需要考虑的因素呢) +* [5.了解过哪些存储引擎?各有什么优缺点?](#5了解过哪些存储引擎各有什么优缺点) +* [6.说一下什么是事务的ACID属性吧](#6说一下什么是事务的acid属性吧) +* [7.事务的隔离级别了解过吗?](#7事务的隔离级别了解过吗) +* [8.说说InnoDB的索引原理](#8说说innodb的索引原理) +* [说说InnoDB的MVCC机制](#说说innodb的mvcc机制) +* [9.有了解过“回表”的概念吗?什么情况下会出现“回表”?](#9有了解过回表的概念吗什么情况下会出现回表) +* [10.MySQL索引的类型](#10mysql索引的类型) +* [11.有做过MySQL的索引优化吗](#11有做过mysql的索引优化吗) +* [12.什么是聚簇索引?](#12什么是聚簇索引) +* [13.InnoDB有聚簇索引吗?MyIsam呢?](#13innodb有聚簇索引吗myisam呢) +* [14.MyIsam的数据是怎么存储的?](#14myisam的数据是怎么存储的) +* [15.InnoDB的数据是怎么存储的?](#15innodb的数据是怎么存储的) +* [16.InnoDB主键索引跟非主键索引在数据存储上的差异](#16innodb主键索引跟非主键索引在数据存储上的差异) +* [17.InnoDB删除某条记录后,内部会怎么处理?](#17innodb删除某条记录后内部会怎么处理) +* [18.InnoDB如果没有设置主键的话,它内部会怎么处理?](#18innodb如果没有设置主键的话它内部会怎么处理) +* [19.为什么InnoDB一定会生成主键?](#19为什么innodb一定会生成主键) +* [20.MySQL分库分表了解过吗?](#20mysql分库分表了解过吗) +* [21.MySQL的redo日志和undo日志分别有什么用?](#21mysql的redo日志和undo日志分别有什么用) +* [22.MySQL的redo日志的刷盘时机](#22mysql的redo日志的刷盘时机) +* [23.MySQL有哪些锁?以及各种锁的作用?](#23mysql有哪些锁以及各种锁的作用) +* [24.MySQL中varchar与char的区别以及varchar(50)中的50代表的涵义](#24mysql中varchar与char的区别以及varchar50中的50代表的涵义) +* [25.MySQL有哪些日志,分别是什么用处?](#25mysql有哪些日志分别是什么用处) +* [26.在哪些情况下会发生针对该列创建了索引但是在查询的时候并没有使用呢?](#26在哪些情况下会发生针对该列创建了索引但是在查询的时候并没有使用呢) +* [27. 为什么要尽量设定一个主键?](#27-为什么要尽量设定一个主键) +* [28.主键使用自增ID还是UUID?](#28主键使用自增id还是uuid) +* [29.字段为什么要求定义为not null?](#29字段为什么要求定义为not-null) +* [30.如果要存储用户的密码散列,应该使用什么字段进行存储?](#30如果要存储用户的密码散列应该使用什么字段进行存储) +* [31.varchar(10)和int(10)代表什么含义?](#31varchar10和int10代表什么含义) +* [32.MySQL的binlog有有几种录入格式?分别有什么区别?](#32mysql的binlog有有几种录入格式分别有什么区别) +* [33.超大分页怎么处理?](#33超大分页怎么处理) +* [34.关心过业务系统里面的sql耗时吗?统计过慢查询吗?对慢查询都怎么优化过?](#34关心过业务系统里面的sql耗时吗统计过慢查询吗对慢查询都怎么优化过) +* [35.什么是存储过程?有哪些优缺点?](#35什么是存储过程有哪些优缺点) +* [36.说一说三个范式](#36说一说三个范式) +* [37.什么情况下应不建或少建索引](#37什么情况下应不建或少建索引) +* [38.什么是表分区?](#38什么是表分区) +* [39.表分区与分表的区别](#39表分区与分表的区别) +* [40.表分区有什么好处?](#40表分区有什么好处) +* [41.MVVC了解过吗](#41mvvc了解过吗) +* [42.在MVCC并发控制中,读操作可以分成哪几类?](#42在mvcc并发控制中读操作可以分成哪几类) +* [43.行级锁定的优点](#43行级锁定的优点) +* [44.行级锁定的缺点](#44行级锁定的缺点) +* [45.MySQL优化](#45mysql优化) +* [46.key和index的区别](#46key和index的区别) +* [47.delete、truncate、drop区别](#47deletetruncatedrop区别) +* [48.MySQL主从复制原理流程](#48mysql主从复制原理流程) +* [49.自增主键最大ID记录,MyISAM和InnoDB分别是如何存储的](#49自增主键最大id记录myisam和innodb分别是如何存储的) +* [50.Mysql如何优化DISTINCT?](#50mysql如何优化distinct) +* [51.解释MySQL外连接、内连接与自连接的区别](#51解释mysql外连接内连接与自连接的区别) +* [参考链接](#参考链接) + + + +#### 1. 什么是索引? + +索引是一种数据结构,可以帮助我们快速的进行数据的查找。 + +#### 2.索引是个什么样的数据结构呢? + +索引的数据结构和具体存储引擎的实现有关, 在MySQL中使用较多的索引有Hash索引,B+树索引等,而我们经常使用的InnoDB存储引擎的默认索引实现为:B+树索引。 + +#### 3.Hash索引和B+树索引有什么区别或者说优劣呢? + +首先要知道Hash索引和B+树索引的底层实现原理: + +hash索引底层就是hash表,进行查找时,调用一次hash函数就可以获取到相应的键值,之后进行回表查询获得实际数据.B+树底层实现是多路平衡查找树.对于每一次的查询都是从根节点出发,查找到叶子节点方可以获得所查键值,然后根据查询判断是否需要回表查询数据. + +那么可以看出他们有以下的不同: + +- hash索引进行等值查询更快(一般情况下),但是却无法进行范围查询. + +因为在hash索引中经过hash函数建立索引之后,索引的顺序与原顺序无法保持一致,不能支持范围查询.而B+树的的所有节点皆遵循(左节点小于父节点,右节点大于父节点,多叉树也类似),天然支持范围. + +- hash索引不支持使用索引进行排序,原理同上. +- hash索引不支持模糊查询以及多列索引的最左前缀匹配.原理也是因为hash函数的不可预测.AAAA和AAAAB的索引没有相关性. +- hash索引任何时候都避免不了回表查询数据,而B+树在符合某些条件(聚簇索引,覆盖索引等)的时候可以只通过索引完成查询. +- hash索引虽然在等值查询上较快,但是不稳定.性能不可预测,当某个键值存在大量重复的时候,发生hash碰撞,此时效率可能极差.而B+树的查询效率比较稳定,对于所有的查询都是从根节点到叶子节点,且树的高度较低. + +因此,在大多数情况下,直接选择B+树索引可以获得稳定且较好的查询速度.而不需要使用hash索引. + +#### 4.在建立索引的时候,都有哪些需要考虑的因素呢? + +建立索引的时候一般要考虑到字段的使用频率,经常作为条件进行查询的字段比较适合.如果需要建立联合索引的话,还需要考虑联合索引中的顺序.此外也要考虑其他方面,比如防止过多的所有对表造成太大的压力.这些都和实际的表结构以及查询方式有关。 + +#### 5.了解过哪些存储引擎?各有什么优缺点? + +常用的是MyISAM和InnoDB。 +InnoDB:支持事务、支持外键、支持行级锁、不支持全文索引、 +MyISAM:不支持事务、不支持外键、不支持行级锁、支持全文索引 + +#### 6.说一下什么是事务的ACID属性吧 + +1. 原子性(atomicity) + 一个事务要么全部提交成功,要么全部失败回滚,不能只执行其中的一部分操作,这就是事务的原子性 + +2. 一致性(consistency) + 事务的执行不能破坏数据库数据的完整性和一致性,一个事务在执行之前和执行之后,数据库都必须处于一致性状态。 + 如果数据库系统在运行过程中发生故障,有些事务尚未完成就被迫中断,这些未完成的事务对数据库所作的修改有一部分已写入物理数据库,这是数据库就处于一种不正确的状态,也就是不一致的状态 + +3. 隔离性(isolation) + 事务的隔离性是指在并发环境中,并发的事务时相互隔离的,一个事务的执行不能不被其他事务干扰。不同的事务并发操作相同的数据时,每个事务都有各自完成的数据空间,即一个事务内部的操作及使用的数据对其他并发事务时隔离的,并发执行的各个事务之间不能相互干扰。 + 在标准SQL规范中,定义了4个事务隔离级别,不同的隔离级别对事务的处理不同,分别是:未授权读取,授权读取,可重复读取和串行化 + +4. 持久性(durability) + 一旦事务提交,那么它对数据库中的对应数据的状态的变更就会永久保存到数据库中。--即使发生系统崩溃或机器宕机等故障,只要数据库能够重新启动,那么一定能够将其恢复到事务成功结束的状态 + +#### 7.事务的隔离级别了解过吗? + +1、读未提交(Read Uncommited),该隔离级别允许脏读取,其隔离级别最低;比如事务A和事务B同时进行,事务A在整个执行阶段,会将某数据的值从1开始一直加到10,然后进行事务提交,此时,事务B能够看到这个数据项在事务A操作过程中的所有中间值(如1变成2,2变成3等),而对这一系列的中间值的读取就是未授权读取 + +2、授权读取也称为已提交读(Read Commited),授权读取只允许获取已经提交的数据。比如事务A和事务B同时进行,事务A进行+1操作,此时,事务B无法看到这个数据项在事务A操作过程中的所有中间值,只能看到最终的10。另外,如果说有一个事务C,和事务A进行非常类似的操作,只是事务C是将数据项从10加到20,此时事务B也同样可以读取到20,即授权读取允许不可重复读取。 + +3、可重复读(Repeatable Read) + +就是保证在事务处理过程中,多次读取同一个数据时,其值都和事务开始时刻是一致的,因此该事务级别禁止不可重复读取和脏读取,但是有可能出现幻影数据。所谓幻影数据,就是指同样的事务操作,在前后两个时间段内执行对同一个数据项的读取,可能出现不一致的结果。在上面的例子中,可重复读取隔离级别能够保证事务B在第一次事务操作过程中,始终对数据项读取到1,但是在下一次事务操作中,即使事务B(注意,事务名字虽然相同,但是指的是另一个事务操作)采用同样的查询方式,就可能读取到10或20; + +4、串行化 + +是最严格的事务隔离级别,它要求所有事务被串行执行,即事务只能一个接一个的进行处理,不能并发执行。 + +#### 8.说说InnoDB的索引原理 + +详见:https://www.cnblogs.com/williamjie/p/11081081.html + +#### 说说InnoDB的MVCC机制 + +详见:https://baijiahao.baidu.com/s?id=1629409989970483292 + +#### 9.有了解过“回表”的概念吗?什么情况下会出现“回表”? + +回表就是先通过数据库索引扫描出数据所在的行,再通过行主键id取出索引中未提供的数据,即基于非主键索引的查询需要多扫描一棵索引树。 +当查询的字段在二级索引上没有的时候,就需要“回表”在主键索引上再查一次。 + +#### 10.MySQL索引的类型 + +聚簇索引、二级(辅助)索引 +B树索引、hash索引 + +#### 11.有做过MySQL的索引优化吗 + +详见:https://blog.csdn.net/m0_37984616/article/details/81047676 + +#### 12.什么是聚簇索引? + +聚簇索引:将数据存储与索引放到了一块,找到索引也就找到了数据 +非聚簇索引:将数据与索引分开存储,索引结构的叶子节点指向了数据的对应行 + +#### 13.InnoDB有聚簇索引吗?MyIsam呢? + +InnoDB有聚簇索引,主键索引就是聚簇索引。MyIsam没有聚簇索引,因为他的索引和记录行是分开存储的。 + +#### 14.MyIsam的数据是怎么存储的? + +MyIsam索引的节点中存储的是数据的物理地址(磁道和扇区),在查找数据时,查找到索引后,根据索引节点中的物理地址,查找到具体的数据内容。 + +#### 15.InnoDB的数据是怎么存储的? + +InnoDB的主键索引文件上直接存放该行数据,称为聚簇索引,非主索引指向对主键的引用。 + +#### 16.InnoDB主键索引跟非主键索引在数据存储上的差异 + +主键索引的叶子节点存的是整行数据。在 InnoDB 里,主键索引也被称为聚簇索引(clustered index)。 +非主键索引的叶子节点内容是主键的值。在 InnoDB 里,非主键索引也被称为二级索引(secondary index)。 + +#### 17.InnoDB删除某条记录后,内部会怎么处理? + +记录头信息里的delete_mask标记位设置为1(表示该记录已删除),同时将记录从记录行链表中断开,并加入到垃圾链表中,垃圾链表的空间后续可以复用。 + +#### 18.InnoDB如果没有设置主键的话,它内部会怎么处理? + +优先使用用户自定义主键作为主键,如果用户没有定义主键,则选取一个Unique键作为主键,如果表中连Unique键都没有定义的话,则InnoDB会为表默认添加一个名为row_id的隐藏列作为主键。所以我们从上表中可以看出:InnoDB存储引擎会为每条记录都添加 transaction_id 和 roll_pointer 这两个列,但是 row_id 是可选的(在没有自定义主键以及Unique键的情况下才会添加该列)。这些隐藏列的值不用我们操心,InnoDB存储引擎会自己帮我们生成的。 + +#### 19.为什么InnoDB一定会生成主键? + +因为Innodb的数据结构是通过聚簇索引组织起来的,如果没有主键的话,通过其他索引回表的时候没法查到相应的数据行。 + +#### 20.MySQL分库分表了解过吗? + +详见:https://baijiahao.baidu.com/s?id=1622441635115622194 + +#### 21.MySQL的redo日志和undo日志分别有什么用? + +1)redo +作用:保证事务的持久性 +MySQL作为一个存储系统,为了保证数据的可靠性,最终得落盘。但是,又为了数据写入的速度,需要引入基于内存的"缓冲池"。其实不止MySQL,这种引入缓冲来解决速度问题的思想无处不在。既然数据是先缓存在缓冲池中,然后再以某种方式刷新到磁盘,那么就存在因宕机导致的缓冲池中的数据丢失,为了解决这种情况下的数据丢失问题,引入了redo log。在其他存储系统,比如Elasticsearch中,也有类似的机制,叫translog。 +但是一般讨论数据写入时,在MySQL中,一般叫事务操作,根据事务的ACID特性,如何保证一个事务提交后Durability的保证?而这就是 redo log 的作用。当向MySQL写用户数据时,先写redo log,然后redo log根据"某种方式"持久化到磁盘,变成redo log file,用户数据则在"buffer"中(比如数据页、索引页)。如果发生宕机,则读取磁盘上的 redo log file 进行数据的恢复。从这个角度来说,MySQL 事务的持久性是通过 redo log 来实现的。 + +2)undo +作用:实现事务回滚 +Undo log是InnoDB MVCC事务特性的重要组成部分。当我们对记录做了变更操作时就会产生undo记录,Undo记录默认被记录到系统表空间(ibdata)中,但从5.6开始,也可以使用独立的Undo 表空间。 +Undo记录中存储的是老版本数据,当一个旧的事务需要读取数据时,为了能读取到老版本的数据,需要顺着undo链找到满足其可见性的记录。当版本链很长时,通常可以认为这是个比较耗时的操作。 +大多数对数据的变更操作包括INSERT/DELETE/UPDATE,其中INSERT操作在事务提交前只对当前事务可见,因此产生的Undo日志可以在事务提交后直接删除(谁会对刚插入的数据有可见性需求呢!!),而对于UPDATE/DELETE则需要维护多版本信息,在InnoDB里,UPDATE和DELETE操作产生的Undo日志被归成一类,即update_undo。 + +#### 22.MySQL的redo日志的刷盘时机 + +log buffer空间不足时 +事务提交时 +后台线程不停的刷刷刷 +正常关闭服务器时 +做所谓的checkpoint时 + +#### 23.MySQL有哪些锁?以及各种锁的作用? + +详见:https://blog.csdn.net/qq_40378034/article/details/90904573 + +#### 24.MySQL中varchar与char的区别以及varchar(50)中的50代表的涵义 + +(1)、varchar与char的区别 +(2)、varchar(50)中50的涵义 +(3)、int(20)中20的涵义 +(4)、mysql为什么这么设计 + +#### 25.MySQL有哪些日志,分别是什么用处? + +mysql日志一般分为5种 + +- 错误日志:-log-err (记录启动,运行,停止mysql时出现的信息) +- 二进制日志:-log-bin (记录所有更改数据的语句,还用于复制,恢复数据库用) +- 查询日志:-log (记录建立的客户端连接和执行的语句) +- 慢查询日志: -log-slow-queries (记录所有执行超过long_query_time秒的所有查询) +- 更新日志: -log-update (二进制日志已经代替了老的更新日志,更新日志在MySQL5.1中不再使用) + +#### 26.在哪些情况下会发生针对该列创建了索引但是在查询的时候并没有使用呢? + +- 使用不等于查询, +- 列参与了数学运算或者函数 +- 在字符串like时左边是通配符.类似于'%aaa'. +- 当mysql分析全表扫描比使用索引快的时候不使用索引. +- 当使用联合索引,前面一个条件为范围查询,后面的即使符合最左前缀原则,也无法使用索引. + +以上情况,MySQL无法使用索引. + +#### 27. 为什么要尽量设定一个主键? + + 主键是数据库确保数据行在整张表唯一性的保障,即使业务上本张表没有主键,也建议添加一个自增长的ID列作为主键.设定了主键之后,在后续的删改查的时候可能更加快速以及确保操作数据范围安全。 + +#### 28.主键使用自增ID还是UUID? + +推荐使用自增ID,不要使用UUID. + +因为在InnoDB存储引擎中,主键索引是作为聚簇索引存在的,也就是说,主键索引的B+树叶子节点上存储了主键索引以及全部的数据(按照顺序),如果主键索引是自增ID,那么只需要不断向后排列即可,如果是UUID,由于到来的ID与原来的大小不确定,会造成非常多的数据插入,数据移动,然后导致产生很多的内存碎片,进而造成插入性能的下降. + +总之,在数据量大一些的情况下,用自增主键性能会好一些. + +*图片来源于《高性能MySQL》: 其中默认后缀为使用自增ID,_uuid为使用UUID为主键的测试,测试了插入100w行和300w行的性能 + +![img](https://imgs.itxueyuan.com/990913-20190806091416714-780950030.png) + +关于主键是聚簇索引,如果没有主键,InnoDB会选择一个唯一键来作为聚簇索引,如果没有唯一键,会生成一个隐式的主键。 + +#### 29.字段为什么要求定义为not null? + +MySQL官网这样介绍: + +> NULL columns require additional space in the rowto record whether their values are NULL. For MyISAM tables, each NULL columntakes one bit extra, rounded up to the nearest byte. + +null值会占用更多的字节,且会在程序中造成很多与预期不符的情况。 + +#### 30.如果要存储用户的密码散列,应该使用什么字段进行存储? + +密码散列,盐,用户身份证号等固定长度的字符串应该使用char而不是varchar来存储,这样可以节省空间且提高检索效率。 + +#### 31.varchar(10)和int(10)代表什么含义? + +varchar的10代表了申请的空间长度,也是可以存储的数据的最大长度,而int的10只是代表了展示的长度,不足10位以0填充.也就是说,int(1)和int(10)所能存储的数字大小以及占用的空间都是相同的,只是在展示时按照长度展示。 + +#### 32.MySQL的binlog有有几种录入格式?分别有什么区别? + +有三种格式,statement,row和mixed. + +- statement模式下,记录单元为语句.即每一个sql造成的影响会记录.由于sql的执行是有上下文的,因此在保存的时候需要保存相关的信息,同时还有一些使用了函数之类的语句无法被记录复制. +- row级别下,记录单元为每一行的改动,基本是可以全部记下来但是由于很多操作,会导致大量行的改动(比如alter table),因此这种模式的文件保存的信息太多,日志量太大. +- mixed. 一种折中的方案,普通操作使用statement记录,当无法使用statement的时候使用row. + +此外,新版的MySQL中对row级别也做了一些优化,当表结构发生变化的时候,会记录语句而不是逐行记录。 + +#### 33.超大分页怎么处理? + +超大的分页一般从两个方向上来解决. + +- 数据库层面,这也是我们主要集中关注的(虽然收效没那么大),类似于`select * from table where age > 20 limit 1000000,10`这种查询其实也是有可以优化的余地的. 这条语句需要load1000000数据然后基本上全部丢弃,只取10条当然比较慢. 当时我们可以修改为`select * from table where id in (select id from table where age > 20 limit 1000000,10)`.这样虽然也load了一百万的数据,但是由于索引覆盖,要查询的所有字段都在索引中,所以速度会很快. 同时如果ID连续的好,我们还可以`select * from table where id > 1000000 limit 10`,效率也是不错的,优化的可能性有许多种,但是核心思想都一样,就是减少load的数据. +- 从需求的角度减少这种请求….主要是不做类似的需求(直接跳转到几百万页之后的具体某一页.只允许逐页查看或者按照给定的路线走,这样可预测,可缓存)以及防止ID泄漏且连续被人恶意攻击. + +解决超大分页,其实主要是靠缓存,可预测性的提前查到内容,缓存至redis等k-V数据库中,直接返回即可. + +在阿里巴巴《Java开发手册》中,对超大分页的解决办法是类似于上面提到的第一种。 + +![img](https://imgs.itxueyuan.com/990913-20190806091439548-806498135.png) + +#### 34.关心过业务系统里面的sql耗时吗?统计过慢查询吗?对慢查询都怎么优化过? + +在业务系统中,除了使用主键进行的查询,其他的我都会在测试库上测试其耗时,慢查询的统计主要由运维在做,会定期将业务中的慢查询反馈给我们。 + +慢查询的优化首先要搞明白慢的原因是什么? 是查询条件没有命中索引?是load了不需要的数据列?还是数据量太大? + +所以优化也是针对这三个方向来的, + +- 首先分析语句,看看是否load了额外的数据,可能是查询了多余的行并且抛弃掉了,可能是加载了许多结果中并不需要的列,对语句进行分析以及重写。 +- 分析语句的执行计划,然后获得其使用索引的情况,之后修改语句或者修改索引,使得语句可以尽可能的命中索引。 +- 如果对语句的优化已经无法进行,可以考虑表中的数据量是否太大,如果是的话可以进行横向或者纵向的分表。 + +#### 35.什么是存储过程?有哪些优缺点? + +存储过程是一些预编译的SQL语句。 + +1、更加直白的理解:存储过程可以说是一个记录集,它是由一些T-SQL语句组成的代码块,这些T-SQL语句代码像一个方法一样实现一些功能(对单表或多表的增删改查),然后再给这个代码块取一个名字,在用到这个功能的时候调用他就行了。 + +2、存储过程是一个预编译的代码块,执行效率比较高,一个存储过程替代大量T_SQL语句 ,可以降低网络通信量,提高通信速率,可以一定程度上确保数据安全 + +但是,在互联网项目中,其实是不太推荐存储过程的,比较出名的就是阿里的《Java开发手册》中禁止使用存储过程,我个人的理解是,在互联网项目中,迭代太快,项目的生命周期也比较短,人员流动相比于传统的项目也更加频繁,在这样的情况下,存储过程的管理确实是没有那么方便,同时,复用性也没有写在服务层那么好。 + +#### 36.说一说三个范式 + +第一范式: 每个列都不可以再拆分. 第二范式: 非主键列完全依赖于主键,而不能是依赖于主键的一部分. 第三范式: 非主键列只依赖于主键,不依赖于其他非主键。 + +在设计数据库结构的时候,要尽量遵守三范式,如果不遵守,必须有足够的理由.比如性能. 事实上我们经常会为了性能而妥协数据库的设计。 + +#### 37.什么情况下应不建或少建索引 + +1、表记录太少 + +2、经常插入、删除、修改的表 + +3、数据重复且分布平均的表字段,假如一个表有10万行记录,有一个字段A只有T和F两种值,且每个值的分布概率大约为50%,那么对这种表A字段建索引一般不会提高数据库的查询速度。 + +4、经常和主字段一块查询但主字段索引值比较多的表字段 + +#### 38.什么是表分区? + +表分区,是指根据一定规则,将数据库中的一张表分解成多个更小的,容易管理的部分。从逻辑上看,只有一张表,但是底层却是由多个物理分区组成。 + +#### 39.表分区与分表的区别 + +分表:指的是通过一定规则,将一张表分解成多张不同的表。比如将用户订单记录根据时间成多个表。 + +分表与分区的区别在于:分区从逻辑上来讲只有一张表,而分表则是将一张表分解成多张表。 + +#### 40.表分区有什么好处? + +1、存储更多数据。分区表的数据可以分布在不同的物理设备上,从而高效地利用多个硬件设备。和单个磁盘或者文件系统相比,可以存储更多数据 + +2、优化查询。在where语句中包含分区条件时,可以只扫描一个或多个分区表来提高查询效率;涉及sum和count语句时,也可以在多个分区上并行处理,最后汇总结果。 + +3、分区表更容易维护。例如:想批量删除大量数据可以清除整个分区。 + +4、避免某些特殊的瓶颈,例如InnoDB的单个索引的互斥访问,ext3问价你系统的inode锁竞争等。 + +#### 41.MVVC了解过吗 + +MySQL InnoDB存储引擎,实现的是基于多版本的并发控制协议——MVCC (Multi-Version Concurrency Control) + +注:与MVCC相对的,是基于锁的并发控制,Lock-Based Concurrency Control + +MVCC最大的好处:读不加锁,读写不冲突。在读多写少的OLTP应用中,读写不冲突是非常重要的,极大的增加了系统的并发性能,现阶段几乎所有的RDBMS,都支持了MVCC。 + +1. LBCC:Lock-Based Concurrency Control,基于锁的并发控制 + +2. MVCC:Multi-Version Concurrency Control + + 基于多版本的并发控制协议。纯粹基于锁的并发机制并发量低,MVCC是在基于锁的并发控制上的改进,主要是在读操作上提高了并发量。 + +#### 42.在MVCC并发控制中,读操作可以分成哪几类? + +1. 快照读 (snapshot read):读取的是记录的可见版本 (有可能是历史版本),不用加锁(共享读锁s锁也不加,所以不会阻塞其他事务的写) +2. 当前读 (current read):读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录 + +#### 43.行级锁定的优点 + +1、当在许多线程中访问不同的行时只存在少量锁定冲突。 + +2、回滚时只有少量的更改 + +3、可以长时间锁定单一的行。 + +#### 44.行级锁定的缺点 + +1. 比页级或表级锁定占用更多的内存。 +2. 当在表的大部分中使用时,比页级或表级锁定速度慢,因为你必须获取更多的锁。 +3. 如果你在大部分数据上经常进行GROUP BY操作或者必须经常扫描整个表,比其它锁定明显慢很多。 +4. 用高级别锁定,通过支持不同的类型锁定,你也可以很容易地调节应用程序,因为其锁成本小于行级锁定。 + +#### 45.MySQL优化 + +1. 开启查询缓存,优化查询 + +2. explain你的select查询,这可以帮你分析你的查询语句或是表结构的性能瓶颈。EXPLAIN 的查询结果还会告诉你你的索引主键被如何利用的,你的数据表是如何被搜索和排序的 + +3. 当只要一行数据时使用limit 1,MySQL数据库引擎会在找到一条数据后停止搜索,而不是继续往后查少下一条符合记录的数据 + +4. 为搜索字段建索引 + +5. 使用 ENUM 而不是 VARCHAR。如果你有一个字段,比如“性别”,“国家”,“民族”,“状态”或“部门”,你知道这些字段的取值是有限而且固定的,那么,你应该使用 ENUM 而不是VARCHAR + +6. Prepared StatementsPrepared Statements很像存储过程,是一种运行在后台的SQL语句集合,我们可以从使用 prepared statements 获得很多好处,无论是性能问题还是安全问题。 + + Prepared Statements 可以检查一些你绑定好的变量,这样可以保护你的程序不会受到“SQL注入式”攻击 + +7. 垂直分表 + +8. 选择正确的存储引擎 + +#### 46.key和index的区别 + +1. key 是数据库的物理结构,它包含两层意义和作用,一是约束(偏重于约束和规范数据库的结构完整性),二是索引(辅助查询用的)。包括primary key, unique key, foreign key 等 +2. index是数据库的物理结构,它只是辅助查询的,它创建时会在另外的表空间(mysql中的innodb表空间)以一个类似目录的结构存储。索引要分类的话,分为前缀索引、全文本索引等; + +#### 47.delete、truncate、drop区别 + +- truncate和delete只删除数据,不删除表结构 ,drop删除表结构,并且释放所占的空间。 +- 删除数据的速度,drop> truncate > delete +- delete属于DML语言,需要事务管理,commit之后才能生效。drop和truncate属于DDL语言,操作立刻生效,不可回滚。使用场合: 当你不再需要该表时, 用 drop; 当你仍要保留该表,但要删除所有记录时, 用 truncate; 当你要删除部分记录时(always with a where clause), 用 delete。 + +#### 48.MySQL主从复制原理流程 + +- 主:binlog线程——记录下所有改变了数据库数据的语句,放进master上的binlog中; +- 从:io线程——在使用start slave 之后,负责从master上拉取 binlog 内容,放进 自己的relay log中; +- 从:sql执行线程——执行relay log中的语句; + +#### 49.自增主键最大ID记录,MyISAM和InnoDB分别是如何存储的 + +- MyISAM表把自增主键的最大ID记录到数据文件里 +- InnoDB表把自增主键的最大ID记录到内存中 + +#### 50.Mysql如何优化DISTINCT? + +DISTINCT在所有列上转换为GROUP BY,并与ORDER BY子句结合使用。 + +#### 51.解释MySQL外连接、内连接与自连接的区别 + +先说什么是交叉连接: 交叉连接又叫笛卡尔积,它是指不使用任何条件,直接将一个表的所有记录和另一个表中的所有记录一一匹配。 + +内连接 则是只有条件的交叉连接,根据某个条件筛选出符合条件的记录,不符合条件的记录不会出现在结果集中,即内连接只连接匹配的行。 +外连接 其结果集中不仅包含符合连接条件的行,而且还会包括左表、右表或两个表中 +的所有数据行,这三种情况依次称之为左外连接,右外连接,和全外连接。 + +左外连接,也称左连接,左表为主表,左表中的所有记录都会出现在结果集中,对于那些在右表中并没有匹配的记录,仍然要显示,右边对应的那些字段值以NULL来填充。右外连接,也称右连接,右表为主表,右表中的所有记录都会出现在结果集中。左连接和右连接可以互换,MySQL目前还不支持全外连接。 + +#### 参考链接 + +https://article.itxueyuan.com/eoJEMj + +https://www.cnblogs.com/williamjie/p/11081592.html + +http://www.100mian.com/mianshi/mysql/49909.html + +https://leisure.wang/procedural-framework/database/241.html diff --git a/Mybatis.md b/Mybatis.md new file mode 100644 index 0000000..95aaf0c --- /dev/null +++ b/Mybatis.md @@ -0,0 +1,178 @@ +## Mybatis + + + +* [1.什么是Mybatis?](#1什么是mybatis) +* [2.Mybatis的优缺点?](#2mybatis的优缺点) +* [3.Mybatis使用场合?](#3mybatis使用场合) +* [4.#{}和${}的区别是什么?](#4和的区别是什么) +* [5.当实体类的属性名和表种字段名不一致怎么办?](#5当实体类的属性名和表种字段名不一致怎么办) +* [6.Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?](#6mybatis是如何将sql执行结果封装为目标对象并返回的都有哪些映射形式) +* [7.如何获取自动生成的(主)键值?](#7如何获取自动生成的主键值) +* [8.Mybatis的Xml映射文件中,不同的Xml映射文件,id是否可以重复?](#8mybatis的xml映射文件中不同的xml映射文件id是否可以重复) +* [9. Mybatis动态SQL?](#9-mybatis动态sql) +* [10.说一下resultMap和resultType?](#10说一下resultmap和resulttype) +* [11. Mybatis全局配置文件中有哪些标签?分别代表什么意思?](#11-mybatis全局配置文件中有哪些标签分别代表什么意思) +* [12.Mybatis能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别。](#12mybatis能执行一对一一对多的关联查询吗都有哪些实现方式以及它们之间的区别) +* [13.Mybatis是否支持延迟加载?如果支持,它的实现原理是什么?](#13mybatis是否支持延迟加载如果支持它的实现原理是什么) +* [14.Mybatis都有哪些Executor执行器?它们之间的区别是什么?](#14mybatis都有哪些executor执行器它们之间的区别是什么) +* [15.Mybatis的一级、二级缓存](#15mybatis的一级二级缓存) +* [参考链接](#参考链接) + + + +#### 1.什么是Mybatis? + +1)mybatis是一个半ORM框架,它内部封装了JDBC,开发时只需要关乎sql语句本身,不需要花费精力去处理驱动,创建连接,创建1statement等繁复过程。 + +2)mybatis可以使用xml或注解来配置和映射原生信息。将pijo映射成数据库中的记录,避免了几乎所有的JDBC 代码和手动设置参数以及获取结果集。 + +3)通过xm文件或注解的方式将要执行的各种statement配置起来,并通java对象和statement中sql的动态参数进行映射生成最终的sql语句,最后由mybatis框架执行sql并将结果映射java对象返回. + +#### 2.Mybatis的优缺点? + +Mybaits的优点: + +(1)基于SQL语句编程,相当灵活,不会对应用程序或者数据库的现有设计造成任何影响,SQL写在XML里,解除sql与程序代码的耦合,便于统一管理;提供XML标签,支持编写动态SQL语句,并可重用。 + +(2)与JDBC相比,减少了50%以上的代码量,消除了JDBC大量冗余的代码,不需要手动开关连接; + +(3)很好的与各种数据库兼容(因为MyBatis使用JDBC来连接数据库,所以只要JDBC支持的数据库MyBatis都支持)。 + +(4)能够与Spring很好的集成; + +(5)提供映射标签,支持对象与数据库的ORM字段关系映射;提供对象关系映射标签,支持对象关系组件维护。 + +MyBatis框架的缺点: + +(1)SQL语句的编写工作量较大,尤其当字段多、关联表多时,对开发人员编写SQL语句的功底有一定要求。 + +(2)SQL语句依赖于数据库,导致数据库移植性差,不能随意更换数据库。 + +MyBatis框架适用场合: + +(1)MyBatis专注于SQL本身,是一个足够灵活的DAO层解决方案。 + +(2)对性能的要求很高,或者需求变化较多的项目,如互联网项目,MyBatis将是不错的选择。 + +#### 3.Mybatis使用场合? + +专注于sql本身,是一个足够灵活的dao层解决方案.,对性能的要求很高,或者需求多变的项目, + +#### 4.#{}和${}的区别是什么? + +\#{}是预编译处理,${}是字符串替换。 + +Mybatis在处理#{}时,会将sql中的#{}替换为?号,调用PreparedStatement的set方法来赋值; + +Mybatis在处理{}时,就是把时,就是把{}替换成变量的值。 + +使用#{}可以有效的防止SQL注入,提高系统安全性。 + +#### 5.当实体类的属性名和表种字段名不一致怎么办? + +有两种解决方案:可以在sql语句给字段名取别名,别名于实体类属性名同名,也可以用resultMap来映射字段名和实体类属性名一一对应. + + +#### 6.Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式? + +第一种是使用resultMap标签,逐一定义数据库列名和对象属性名之间的映射关系。 + +第二种是使用sql列的别名功能,将列的别名书写为对象属性名。 + +有了列名与属性名的映射关系后,Mybatis通过反射创建对象,同时使用反射给对象的属性逐一赋值并返回,那些找不到映射关系的属性,是无法完成赋值的。 + +#### 7.如何获取自动生成的(主)键值? + +``` + + insert into names (name) values (#{name}) + +``` + +#### 8.Mybatis的Xml映射文件中,不同的Xml映射文件,id是否可以重复? + +不同的Xml映射文件,如果配置了namespace,那么id可以重复;如果没有配置namespace,那么id不能重复 + +#### 9. Mybatis动态SQL? + +1) 传统的JDBC的方法,在组合SQL语句的时候需要去拼接,稍微不注意就会少少了一个空格,标点符号,都会导致系统错误。Mybatis的动态SQL就是为了解决这种问题而产生的;Mybatis的动态SQL语句值基于OGNL表达式的,方便在SQL语句中实现某些逻辑;可以使用标签组合成灵活的sql语句,提供开发的效率。 + + 2) Mybatis的动态SQL标签主要由以下几类: If语句(简单的条件判断) Choose(when/otherwise),相当于java语言中的switch,与jstl中choose类似 Trim(对包含的内容加上prefix,或者suffix) Where(主要是用来简化SQL语句中where条件判断,能智能的处理and/or 不用担心多余的语法导致的错误) Set(主要用于更新时候) Foreach(一般使用在mybatis in语句查询时特别有用) + +#### 10.说一下resultMap和resultType? + +resultmap是手动提交,人为提交,resulttype是自动提交 +MyBatis中在查询进行select映射的时候,返回类型可以用resultType,也可以用resultMap,resultType是直接表示返回类型的,而resultMap则是对外部ResultMap的引用,但是resultType跟resultMap不能同时存在。 +在MyBatis进行查询映射时,其实查询出来的每一个属性都是放在一个对应的Map里面的,其中键是属性名,值则是其对应的值。 +1.当提供的返回类型属性是resultType时,MyBatis会将Map里面的键值对取出赋给resultType所指定的对象对应的属性。所以其实MyBatis的每一个查询映射的返回类型都是ResultMap,只是当提供的返回类型属性是resultType的时候,MyBatis对自动的给把对应的值赋给resultType所指定对象的属性。 +2.当提供的返回类型是resultMap时,因为Map不能很好表示领域模型,就需要自己再进一步的把它转化为对应的对象,这常常在复杂查询中很有作用。 + +#### 11. Mybatis全局配置文件中有哪些标签?分别代表什么意思? + +configuration 配置 +properties 属性:可以加载properties配置文件的信息 +settings 设置:可以设置mybatis的全局属性 +typeAliases 类型命名 +typeHandlers 类型处理器 +objectFactory 对象工厂 +plugins 插件 +environments 环境 +environment 环境变量 +transactionManager 事务管理器 +dataSource 数据源 +mappers 映射器 + +#### 12.Mybatis能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别。 + +答:能,Mybatis不仅可以执行一对一、一对多的关联查询,还可以执行多对一,多对多的关联查询,多对一查询,其实就是一对一查询,只需要把selectOne()修改为selectList()即可;多对多查询,其实就是一对多查询,只需要把selectOne()修改为selectList()即可。 + +  关联对象查询,有两种实现方式,一种是单独发送一个sql去查询关联对象,赋给主对象,然后返回主对象。另一种是使用嵌套查询,嵌套查询的含义为使用join查询,一部分列是A对象的属性值,另外一部分列是关联对象B的属性值,好处是只发一个sql查询,就可以把主对象和其关联对象查出来。 + +  那么问题来了,join查询出来100条记录,如何确定主对象是5个,而不是100个?其去重复的原理是 resultMap标签内的 id 子标签,指定了唯一确定一条记录的id列,Mybatis根据 id 列值来完成100条记录的去重复功能, id 可以有多个,代表了联合主键的语意。 + +  同样主对象的关联对象,也是根据这个原理去重复的,尽管一般情况下,只有主对象会有重复记录,关联对象一般不会重复。 + +#### 13.Mybatis是否支持延迟加载?如果支持,它的实现原理是什么? + +Mybatis仅支持association关联对象和collection关联集合对象的延迟加载,association指的就是一对一,collection指的就是一对多查询。在Mybatis配置文件中,可以配置是否启用延迟加载lazyLoadingEnabled=true|false。 + +它的原理是,使用CGLIB创建目标对象的代理对象,当调用目标方法时,进入拦截器方法,比如调用a.getB().getName(),拦截器invoke()方法发现a.getB()是null值,那么就会单独发送事先保存好的查询关联B对象的sql,把B查询上来,然后调用a.setB(b),于是a的对象b属性就有值了,接着完成a.getB().getName()方法的调用。这就是延迟加载的基本原理。 + +当然了,不光是Mybatis,几乎所有的包括Hibernate,支持延迟加载的原理都是一样的。 + +#### 14.Mybatis都有哪些Executor执行器?它们之间的区别是什么? + +Mybatis有三种基本的Executor执行器,SimpleExecutor、ReuseExecutor、BatchExecutor。 + +SimpleExecutor:每执行一次update或select,就开启一个Statement对象,用完立刻关闭Statement对象。 + +ReuseExecutor:执行update或select,以sql作为key查找Statement对象,存在就使用,不存在就创建,用完后,不关闭Statement对象,而是放置于Map内,供下一次使用。简言之,就是重复使用Statement对象。 + +BatchExecutor:执行update(没有select,JDBC批处理不支持select),将所有sql都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存了多个Statement对象,每个Statement对象都是addBatch()完毕后,等待逐一执行executeBatch()批处理。与JDBC批处理相同。 + +作用范围:Executor的这些特点,都严格限制在SqlSession生命周期范围内。 + +#### 15.Mybatis的一级、二级缓存 + +(1)一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该 Session 中的所有 Cache 就将清空,默认打开一级缓存。 + +(2)二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于其存储作用域为 Mapper(Namespace),并且可自定义存储源,如 Ehcache。默认不打开二级缓存,要开启二级缓存,使用二级缓存属性类需要实现Serializable序列化接口(可用来保存对象的状态),可在它的映射文件中配置 ; + +(3)对于缓存数据更新机制,当某一个作用域(一级缓存 Session/二级缓存Namespaces)的进行了C/U/D 操作后,默认该作用域下所有 select 中的缓存将被 clear 掉并重新更新,如果开启了二级缓存,则只根据配置判断是否刷新。 + + + +### 参考链接 + +https://my.oschina.net/u/4116655/blog/3055230 + +https://www.w3cschool.cn/kzsow/kzsow-4ovb2grl.html + +https://www.cnblogs.com/lukelook/p/11099039.html + +https://zhuanlan.zhihu.com/p/60257737 + +https://www.cnblogs.com/qmillet/p/12523636.html + +https://blog.csdn.net/a745233700/article/details/80977133 diff --git a/Mycat.md b/Mycat.md new file mode 100644 index 0000000..985c71a --- /dev/null +++ b/Mycat.md @@ -0,0 +1,115 @@ +## Mycat + +* [1.Mycat是什么?](#1mycat是什么) +* [2.什么叫混合切分](#2什么叫混合切分) +* [3.在项目组中,切分后的库从哪里而来?](#3在项目组中切分后的库从哪里而来) +* [4.搭建mycat的核心配置文件有哪些?](#4搭建mycat的核心配置文件有哪些) +* [5.mycat分库可以分成100个库吗?](#5mycat分库可以分成100个库吗) +* [6.进行库表拆分时,拆分规则怎么取舍?](#6进行库表拆分时拆分规则怎么取舍) +* [7.Mycat中全局ID方案有哪些?程序自定义全局ID的方案有哪些?](#7mycat中全局id方案有哪些程序自定义全局id的方案有哪些) +* [8.Mycat的在分库分表之后,它是怎么支持联表查询的?](#8mycat的在分库分表之后它是怎么支持联表查询的) +* [9.配置文件不会变多,配置的节点主机会变多?](#9配置文件不会变多配置的节点主机会变多) +* [10.你们项目中分片的实现方式是什么?](#10你们项目中分片的实现方式是什么) +* [参考链接](#参考链接) + + +#### 1.Mycat是什么? + +Mycat是基于MySQL的数据库中间件,目的是为了降低数据库的压力。 + +#### 2.什么叫混合切分 + +项目组中如果有水平切分,那项目组里的开发方式就叫混合切分。或者项目组里就是单纯的垂直切分。 + +#### 3.在项目组中,切分后的库从哪里而来? + +在开发中是基于原有库创建出来,并且原有库和切分后的库是数据表的设计是保持一致的。dm_order1,dm_order2,dm_order3这些库是需要和dm_order的设计保持一致的!!!! + +附注:所以,切分后的库例如dm_order1,dm_order2,dm_order3这些都是有数据库维护团队创建出来的。 + +#### 4.搭建mycat的核心配置文件有哪些? + +schem.xml 配置参数:逻辑库,逻辑表,数据节点。节点主机 + +rule.xml:分片规则 + +server.xml:连接mycat的用户信息(账号和密码) + +这里是使用中间件做数据切分,感兴趣的小伙伴还可以了解一下mysql的分库分表高可用方案 + +#### 5.mycat分库可以分成100个库吗? + +我们目前项目组分的是3个库,我们说一般数据量大的话我们使用的是mycat中间件进行分片处理,如果更大的话,我们可以使用oracle数据库,如果更大的话可以使用hadoop或是云存储数据,不需要mycat作为工具手段。衡量的标准是项目有没有对应的硬件设备。 如果没有,基本就是使用mysql 因为搭建一套云环境或者大数据的环境基本都是超大型的公司。比如大数据中的所有的技术,例如hbase 或者是一大堆的服务器 一大堆的网络路由设备 或是私有云。或者是一大堆的数据库运维实施人员都是成本 + +#### 6.进行库表拆分时,拆分规则怎么取舍? + +1.不存在热点数据时,则使用连续分片 + +2.存在热点数据时,使用离散分片或者是综合分片 + +3.离散分片暂时迁移比较麻烦(但是mycat给出了数据迁移的脚本,虽然现在还是不是很完美),综合分片占用总机器数量多 + +#### 7.Mycat中全局ID方案有哪些?程序自定义全局ID的方案有哪些? + +1.mycat的全局id方案 + +(1)本地文件方式 +sequnceHandlerType = 0 + +配置sequence_conf.properties + +使用next value for MYCATSEQ_XXX + +(2)数据库方式 + +sequnceHandlerType = 1 + +配置sequence_db_conf.properties + +使用next value for MYCATSEQ_XXX或者指定autoIncrement + +(3)本地时间戳方式 + +ID= 64 位二进制 (42(毫秒)+5(机器 ID)+5(业务编码)+12(重复累加) + +sequnceHandlerType = 2 + +配置sequence_time_conf.properties + +指定autoIncrement + +\2. 程序方式 + +(1)Snowflake + +(2)UUID + +(3)Redis + +#### 8.Mycat的在分库分表之后,它是怎么支持联表查询的? + +- 使用好ER表 +- 善用全局表 +- 在sql上添加注解 + +``` +/*!mycat:catlet=io.mycat.catlets.ShareJoin */ +``` + +#### 9.配置文件不会变多,配置的节点主机会变多? + +不会 + +#### 10.你们项目中分片的实现方式是什么? + +在rule.xml中配置PartitionByMod + +#### 参考链接 + +https://www.cnblogs.com/zhaozhitong/p/12450130.html + +https://zhuanlan.zhihu.com/p/281636679 + +https://blog.csdn.net/jiongsui7605/article/details/94410680 + +https://blog.csdn.net/weixin_30682415/article/details/94993907 diff --git a/Netty.md b/Netty.md new file mode 100644 index 0000000..ea43b93 --- /dev/null +++ b/Netty.md @@ -0,0 +1,142 @@ +## Netty + +* [1.你了解过哪些IO模型?](#1你了解过哪些io模型) +* [2.什么是Reactor模型?Reactor的3种版本都知道吗?](#2什么是reactor模型reactor的3种版本都知道吗) +* [3.了解过粘包拆包吗?为什么会出现粘包拆包?怎么处理粘包拆包?](#3了解过粘包拆包吗为什么会出现粘包拆包怎么处理粘包拆包) +* [4.UDP协议会有粘包拆包的问题吗?为什么?](#4udp协议会有粘包拆包的问题吗为什么) +* [5.Netty 是什么?](#5netty-是什么) +* [6.为什么要用 Netty?](#6为什么要用-netty) +* [7.Netty 的应用场景了解么?](#7netty-的应用场景了解么) +* [8.Netty 的零拷贝了解么?](#8netty-的零拷贝了解么) +* [9.Netty 的心跳机制了解么?](#9netty-的心跳机制了解么) +* [10.Netty 中有哪些重要组件?](#10netty-中有哪些重要组件) +* [11.Netty 发送消息有几种方式?](#11netty-发送消息有几种方式) +* [12.Netty 支持哪些心跳类型设置?](#12netty-支持哪些心跳类型设置) +* [13.说说Netty的执行流程?](#13说说netty的执行流程) +* [14.Netty高性能体现在哪些方面?](#14netty高性能体现在哪些方面) +* [参考资料](#参考资料) + + + +#### 1.你了解过哪些IO模型? + +详见:https://www.cnblogs.com/sharing-java/p/10791802.html + +#### 2.什么是Reactor模型?Reactor的3种版本都知道吗? + +Reactor模式究竟是个什么东西呢?这要从事件驱动的开发方式说起。我们知道,对于应用服务器,一个主要规律就是,CPU的处理速度是要远远快于IO速度的,如果CPU为了IO操作(例如从Socket读取一段数据)而阻塞显然是不划算的。好一点的方法是分为多进程或者线程去进行处理,但是这样会带来一些进程切换的开销,试想一个进程一个数据读了500ms,期间进程切换到它3次,但是CPU却什么都不能干,就这么切换走了,是不是也不划算? +这时先驱们找到了事件驱动,或者叫回调的方式,来完成这件事情。这种方式就是,应用业务向一个中间人注册一个回调(event handler),当IO就绪后,就这个中间人产生一个事件,并通知此handler进行处理。这种回调的方式,也体现了“好莱坞原则”(Hollywood principle)-“Don't call us, we'll call you”,在我们熟悉的IoC中也有用到。看来软件开发真是互通的! +好了,我们现在来看Reactor模式。在前面事件驱动的例子里有个问题:我们如何知道IO就绪这个事件,谁来充当这个中间人?Reactor模式的答案是:由一个不断等待和循环的单独进程(线程)来做这件事,它接受所有handler的注册,并负责先操作系统查询IO是否就绪,在就绪后就调用指定handler进行处理,这个角色的名字就叫做Reactor。 + +Reactor的3种版本:单线程模式、多线程模式、主从多线程模式 + +#### 3.了解过粘包拆包吗?为什么会出现粘包拆包?怎么处理粘包拆包? + +粘包的主要原因:发送方写入数据<套接字缓冲区大小;接收方读取套接字缓冲区数据不够及时。 + +拆包的主要原因:发送方写入数据>套接字缓冲区大小;发送方发送的数据大于协议的MTU(最大传输单元),不得已必须拆包。 + +如何处理:1、消息长度固定;2、消息之间用分隔符分隔;3、在消息头保留一个字段,用于描述消息的长度。 + +#### 4.UDP协议会有粘包拆包的问题吗?为什么? + +UDP不会有这个问题。 +因为TCP是“数据流”协议,UDP是“数据报”协议。 +UDP协议的数据包之间是没有联系,而且有明确边界的。 + + +#### 5.Netty 是什么? + +Netty 是一个 基于 NIO 的 client-server(客户端服务器)框架,使用它可以快速简单地开发网络应用程序。 +它极大地简化并优化了 TCP 和 UDP 套接字服务器等网络编程,并且性能以及安全性等很多方面甚至都要更好。 +支持多种协议 如 FTP,SMTP,HTTP 以及各种二进制和基于文本的传统协议。 +用官方的总结就是:Netty 成功地找到了一种在不妥协可维护性和性能的情况下实现易于开发,性能,稳定性和灵活性的方法。 + +#### 6.为什么要用 Netty? + +统一的 API,支持多种传输类型,阻塞和非阻塞的。 +简单而强大的线程模型。 +自带编解码器解决 TCP 粘包/拆包问题。 +自带各种协议栈。 +真正的无连接数据包套接字支持。 +比直接使用 Java 核心 API 有更高的吞吐量、更低的延迟、更低的资源消耗和更少的内存复制。 +安全性不错,有完整的 SSL/TLS 以及 StartTLS 支持。 +社区活跃 +成熟稳定,经历了大型项目的使用和考验,而且很多开源项目都使用到了 Netty, 比如我们经常接触的 Dubbo、RocketMQ 等等。 + +#### 7.Netty 的应用场景了解么? + +Netty 主要用来做网络通信 : +作为 RPC 框架的网络通信工具 :我们在分布式系统中,不同服务节点之间经常需要相互调用,这个时候就需要 RPC 框架了。不同服务节点之间的通信是如何做的呢?可以使用 Netty 来做。比如我调用另外一个节点的方法的话,至少是要让对方知道我调用的是哪个类中的哪个方法以及相关参数吧! +实现一个自己的 HTTP 服务器 :通过 Netty 我们可以自己实现一个简单的 HTTP 服务器,这个大家应该不陌生。说到 HTTP 服务器的话,作为 Java 后端开发,我们一般使用 Tomcat 比较多。一个最基本的 HTTP 服务器可要以处理常见的 HTTP Method 的请求,比如 POST 请求、GET 请求等等。 +实现一个即时通讯系统 :使用 Netty 我们可以实现一个可以聊天类似微信的即时通讯系统,这方面的开源项目还蛮多的,可以自行去 Github 找一找。 +实现消息推送系统 :市面上有很多消息推送系统都是基于 Netty 来做的。 + +#### 8.Netty 的零拷贝了解么? + +维基百科是这样介绍零拷贝的:“零复制(英语:Zero-copy;也译零拷贝)技术是指计算机执行操作时,CPU 不需要先将数据从某处内存复制到另一个特定区域。这种技术通常用于通过网络传输文件时节省 CPU 周期和内存带宽。 + +在 OS 层面上的 Zero-copy 通常指避免在 用户态(User-space) 与 内核态(Kernel-space) 之间来回拷贝数据。而在 Netty 层面 ,零拷贝主要体现在对于数据操作的优化。 + +Netty 中的零拷贝体现在以下几个方面: +使用 Netty 提供的 CompositeByteBuf 类, 可以将多个ByteBuf 合并为一个逻辑上的 ByteBuf, 避免了各个 ByteBuf 之间的拷贝。 +ByteBuf 支持 slice 操作, 因此可以将 ByteBuf 分解为多个共享同一个存储区域的 ByteBuf, 避免了内存的拷贝。 +通过 FileRegion 包装的FileChannel.tranferTo 实现文件传输, 可以直接将文件缓冲区的数据发送到目标 Channel, 避免了传统通过循环 write 方式导致的内存拷贝问题。 + + +#### 9.Netty 的心跳机制了解么? + +在 TCP 保持长连接的过程中,可能会出现断网等网络异常出现,异常发生的时候, client 与 server 之间如果没有交互的话,它们是无法发现对方已经掉线的。为了解决这个问题, 我们就需要引入 心跳机制。 + +心跳机制的工作原理是: 在 client 与 server 之间在一定时间内没有数据交互时, 即处于 idle 状态时, 客户端或服务器就会发送一个特殊的数据包给对方, 当接收方收到这个数据报文后, 也立即发送一个特殊的数据报文, 回应发送方, 此即一个 PING-PONG 交互。所以, 当某一端收到心跳消息后, 就知道了对方仍然在线, 这就确保 TCP 连接的有效性. + +TCP 实际上自带的就有长连接选项,本身是也有心跳包机制,也就是 TCP 的选项:SO_KEEPALIVE。但是,TCP 协议层面的长连接灵活性不够。所以,一般情况下我们都是在应用层协议上实现自定义心跳机制的,也就是在 Netty 层面通过编码实现。通过 Netty 实现心跳机制的话,核心类是 IdleStateHandler 。 + +#### 10.Netty 中有哪些重要组件? + +Channel:Netty 网络操作抽象类,它除了包括基本的 I/O 操作,如 bind、connect、read、write 等。 + +EventLoop:主要是配合 Channel 处理 I/O 操作,用来处理连接的生命周期中所发生的事情。 + +ChannelFuture:Netty 框架中所有的 I/O 操作都为异步的,因此我们需要 ChannelFuture 的 addListener()注册一个 ChannelFutureListener 监听事件,当操作执行成功或者失败时,监听就会自动触发返回结果。 + +ChannelHandler:充当了所有处理入站和出站数据的逻辑容器。ChannelHandler 主要用来处理各种事件,这里的事件很广泛,比如可以是连接、数据接收、异常、数据转换等。 + +ChannelPipeline:为 ChannelHandler 链提供了容器,当 channel 创建时,就会被自动分配到它专属的 ChannelPipeline,这个关联是永久性的。 + +#### 11.Netty 发送消息有几种方式? + +Netty 有两种发送消息的方式: + +直接写入 Channel 中,消息从 ChannelPipeline 当中尾部开始移动; +写入和 ChannelHandler 绑定的 ChannelHandlerContext 中,消息从 ChannelPipeline 中的下一个 ChannelHandler 中移动。 + +#### 12.Netty 支持哪些心跳类型设置? + +readerIdleTime:为读超时时间(即测试端一定时间内未接受到被测试端消息)。 +writerIdleTime:为写超时时间(即测试端一定时间内向被测试端发送消息)。 +allIdleTime:所有类型的超时时间。 + +#### 13.说说Netty的执行流程? + +创建ServerBootStrap实例 +设置并绑定Reactor线程池:EventLoopGroup,EventLoop就是处理所有注册到本线程的Selector上面的Channel +设置并绑定服务端的channel +创建处理网络事件的ChannelPipeline和handler,网络时间以流的形式在其中流转,handler完成多数的功能定制:比如编解码 SSl安全认证 +绑定并启动监听端口 +当轮训到准备就绪的channel后,由Reactor线程:NioEventLoop执行pipline中的方法,最终调度并执行channelHandler + +#### 14.Netty高性能体现在哪些方面? + +1)传输:IO模型在很大程度上决定了框架的性能,相比于bio,netty建议采用异步通信模式,因为nio一个线程可以并发处理N个客户端连接和读写操作,这从根本上解决了传统同步阻塞IO一连接一线程模型,架构的性能、弹性伸缩能力和可靠性都得到了极大的提升。正如代码中所示,使用的是NioEventLoopGroup和NioSocketChannel来提升传输效率。 +2)协议:采用什么样的通信协议,对系统的性能极其重要,netty默认提供了对Google Protobuf的支持,也可以通过扩展Netty的编解码接口,用户可以实现其它的高性能序列化框架。 +3)线程:netty使用了Reactor线程模型,但Reactor模型不同,对性能的影响也非常大,下面介绍常用的Reactor线程模型有三种,分别如下: +Reactor单线程模型:单线程模型的线程即作为NIO服务端接收客户端的TCP连接,又作为NIO客户端向服务端发起TCP连接,即读取通信对端的请求或者应答消息,又向通信对端发送消息请求或者应答消息。理论上一个线程可以独立处理所有IO相关的操作,但一个NIO线程同时处理成百上千的链路,性能上无法支撑,即便NIO线程的CPU负荷达到100%,也无法满足海量消息的编码、解码、读取和发送,又因为当NIO线程负载过重之后,处理速度将变慢,这会导致大量客户端连接超时,超时之后往往会进行重发,这更加重了NIO线程的负载,最终会导致大量消息积压和处理超时,NIO线程会成为系统的性能瓶颈。 +Reactor多线程模型:有专门一个NIO线程用于监听服务端,接收客户端的TCP连接请求;网络IO操作(读写)由一个NIO线程池负责,线程池可以采用标准的JDK线程池实现。但百万客户端并发连接时,一个nio线程用来监听和接受明显不够,因此有了主从多线程模型。 +主从Reactor多线程模型:利用主从NIO线程模型,可以解决1个服务端监听线程无法有效处理所有客户端连接的性能不足问题,即把监听服务端,接收客户端的TCP连接请求分给一个线程池。因此,在代码中可以看到,我们在server端选择的就是这种方式,并且也推荐使用该线程模型。在启动类中创建不同的EventLoopGroup实例并通过适当的参数配置,就可以支持上述三种Reactor线程模型。 + +### 参考资料 +https://baijiahao.baidu.com/s?id=1669639041722396699 +https://blog.csdn.net/PCCEO1/article/details/95899920 +https://www.cnblogs.com/xiaoyangjia/p/11526197.html + diff --git a/Nginx.md b/Nginx.md new file mode 100644 index 0000000..40bbc39 --- /dev/null +++ b/Nginx.md @@ -0,0 +1,178 @@ +## Nginx + + +* [1.请解释一下什么是 Nginx ?](#1请解释一下什么是-nginx-) +* [2.为什么要用Nginx?](#2为什么要用nginx) +* [3.Nginx怎么处理请求的?](#3nginx怎么处理请求的) +* [4.Nginx的优缺点?](#4nginx的优缺点) +* [5.Nginx应用场景?](#5nginx应用场景) +* [6.使用“反向代理服务器”的优点是什么?](#6使用反向代理服务器的优点是什么) +* [7.列举Nginx服务器的最佳用途。](#7列举nginx服务器的最佳用途) +* [8.请解释Nginx如何处理HTTP请求。](#8请解释nginx如何处理http请求) +* [9.在Nginx中,如何使用未定义的服务器名称来阻止处理请求?](#9在nginx中如何使用未定义的服务器名称来阻止处理请求) +* [10.在Nginx中如何在URL中保留双斜线?](#10在nginx中如何在url中保留双斜线) +* [11.ngx_http_upstream_module的作用是什么?](#11ngx_http_upstream_module的作用是什么) +* [12. fastcgi 与 cgi 的区别?](#12-fastcgi-与-cgi-的区别) +* [13. Nginx 常用命令?](#13-nginx-常用命令) +* [14.Nginx 常用配置?](#14nginx-常用配置) +* [15.请陈述stub_status和sub_filter指令的作用是什么?](#15请陈述stub_status和sub_filter指令的作用是什么) +* [参考链接](#参考链接) + + +#### 1.请解释一下什么是 Nginx ? + +Nginx ,是一个 Web 服务器和反向代理服务器,用于 HTTP、HTTPS、SMTP、POP3 和 IMAP 协议。 + +目前使用的最多的 Web 服务器或者代理服务器,像淘宝、新浪、网易、迅雷等都在使用。 + +Nginx 的主要功能如下: +作为 http server (代替 Apache ,对 PHP 需要 FastCGI 处理器支持) +FastCGI:Nginx 本身不支持 PHP 等语言,但是它可以通过 FastCGI 来将请求扔给某些语言或框架处理。 +反向代理服务器 +实现负载均衡 +虚拟主机 + +#### 2.为什么要用Nginx? + +跨平台、配置简单、方向代理、高并发连接:处理2-3万并发连接数,官方监测能支持5万并发,内存消耗小:开启10个nginx才占150M内存 ,nginx处理静态文件好,耗费内存少, + +而且Nginx内置的健康检查功能:如果有一个服务器宕机,会做一个健康检查,再发送的请求就不会发送到宕机的服务器了。重新将请求提交到其他的节点上。 + +使用Nginx的话还能: + +节省宽带:支持GZIP压缩,可以添加浏览器本地缓存 +稳定性高:宕机的概率非常小 +接收用户请求是异步的 + +#### 3.Nginx怎么处理请求的? + +- nginx接收一个请求后,首先由listen和server_name指令匹配server模块,再匹配server模块里的location,location就是实际地址 + +``` + server { # 第一个Server区块开始,表示一个独立的虚拟主机站点 + listen 80; # 提供服务的端口,默认80 + server_name localhost; # 提供服务的域名主机名 + location / { # 第一个location区块开始 + root html; # 站点的根目录,相当于Nginx的安装目录 + index index.html index.htm; # 默认的首页文件,多个用空格分开 + } + +``` + + +#### 4.Nginx的优缺点? + +优点: +占内存小,可实现高并发连接,处理响应快 +可实现http服务器、虚拟主机、方向代理、负载均衡 +Nginx配置简单 +可以不暴露正式的服务器IP地址 + +缺点: +动态处理差:nginx处理静态文件好,耗费内存少,但是处理动态页面则很鸡肋,现在一般前端用nginx作为反向代理抗住压力, + +#### 5.Nginx应用场景? + +http服务器。Nginx是一个http服务可以独立提供http服务。可以做网页静态服务器。 +虚拟主机。可以实现在一台服务器虚拟出多个网站,例如个人网站使用的虚拟机。 +反向代理,负载均衡。当网站的访问量达到一定程度后,单台服务器不能满足用户的请求时,需要用多台服务器集群可以使用nginx做反向代理。并且多台服务器可以平均分担负载,不会应为某台服务器负载高宕机而某台服务器闲置的情况。 +nginz 中也可以配置安全管理、比如可以使用Nginx搭建API接口网关,对每个接口服务进行拦截。 + +#### 6.使用“反向代理服务器”的优点是什么? + +反向代理服务器可以隐藏源服务器的存在和特征。它充当互联网云和web服务器之间的中间层。这对于安全方面来说是很好的,特别是当您使用web托管服务时。 + +#### 7.列举Nginx服务器的最佳用途。 + +Nginx服务器的最佳用法是在网络上部署动态HTTP内容,使用SCGI、WSGI应用程序服务器、用于脚本的FastCGI处理程序。它还可以作为负载均衡器。 + +#### 8.请解释Nginx如何处理HTTP请求。 + +Nginx使用反应器模式。主事件循环等待操作系统发出准备事件的信号,这样数据就可以从套接字读取,在该实例中读取到缓冲区并进行处理。单个线程可以提供数万个并发连接。 + +#### 9.在Nginx中,如何使用未定义的服务器名称来阻止处理请求? + +只需将请求删除的服务器就可以定义为: + +``` +Server { + +listen 80; + +server_name “ “ ; + +return 444; + +} +``` + +这里,服务器名被保留为一个空字符串,它将在没有“主机”头字段的情况下匹配请求,而一个特殊的`Nginx`的非标准代码`444`被返回,从而终止连接。 + +#### 10.在Nginx中如何在URL中保留双斜线? + +要在URL中保留双斜线,就必须使用merge_slashes_off;语法:merge_slashes [on/off] ; 默认值: merge_slashes on ;环境: http,server + +#### 11.ngx_http_upstream_module的作用是什么? + +ngx_http_upstream_module用于定义可通过fastcgi传递、proxy传递、uwsgi传递、memcached传递和scgi传递指令来引用的服务器组。 + +#### 12. fastcgi 与 cgi 的区别? + +1)cgi + +web 服务器会根据请求的内容,然后会 fork 一个新进程来运行外部 c 程序(或 perl 脚本…), 这个进程会把处理完的数据返回给 web 服务器,最后 web 服务器把内容发送给用户,刚才 fork 的进程也随之退出。 + +如果下次用户还请求改动态脚本,那么 web 服务器又再次 fork 一个新进程,周而复始的进行。 + +2)fastcgi + +web 服务器收到一个请求时,他不会重新 fork 一个进程(因为这个进程在 web 服务器启动时就开启了,而且不会退出),web 服务器直接把内容传递给这个进程(进程间通信,但 fastcgi 使用了别的方式,tcp 方式通信),这个进程收到请求后进行处理,把结果返回给 web 服务器,最后自己接着等待下一个请求的到来,而不是退出。 + +综上,差别在于是否重复 fork 进程,处理请求。 + +#### 13. Nginx 常用命令? + +启动 nginx 。 +停止 nginx -s stop 或 nginx -s quit 。 +重载配置 ./sbin/nginx -s reload(平滑重启) 或 service nginx reload 。 +重载指定配置文件 .nginx -c /usr/local/nginx/conf/nginx.conf 。 +查看 nginx 版本 nginx -v 。 +检查配置文件是否正确 nginx -t 。 +显示帮助信息 nginx -h 。 + +#### 14.Nginx 常用配置? + +```nginx +worker_processes 8; # 工作进程个数 +worker_connections 65535; # 每个工作进程能并发处理(发起)的最大连接数(包含所有连接数) +error_log /data/logs/nginx/error.log; # 错误日志打印地址 +access_log /data/logs/nginx/access.log; # 进入日志打印地址 +log_format main '$remote_addr"$request" ''$status $upstream_addr "$request_time"'; # 进入日志格式 + +## 如果未使用 fastcgi 功能的,可以无视 +fastcgi_connect_timeout=300; # 连接到后端 fastcgi 超时时间 +fastcgi_send_timeout=300; # 向 fastcgi 请求超时时间(这个指定值已经完成两次握手后向fastcgi传送请求的超时时间) +fastcgi_rend_timeout=300; # 接收 fastcgi 应答超时时间,同理也是2次握手后 +fastcgi_buffer_size=64k; # 读取 fastcgi 应答第一部分需要多大缓冲区,该值表示使用1个64kb的缓冲区读取应答第一部分(应答头),可以设置为fastcgi_buffers选项缓冲区大小 +fastcgi_buffers 4 64k; # 指定本地需要多少和多大的缓冲区来缓冲fastcgi应答请求,假设一个php或java脚本所产生页面大小为256kb,那么会为其分配4个64kb的缓冲来缓存 +fastcgi_cache TEST; # 开启fastcgi缓存并为其指定为TEST名称,降低cpu负载,防止502错误发生 + +listen 80; # 监听端口 +server_name rrc.test.jiedaibao.com; # 允许域名 +root /data/release/rrc/web; # 项目根目录 +index index.php index.html index.htm; # 访问根文件 +``` + +#### 15.请陈述stub_status和sub_filter指令的作用是什么? + +(1)Stub_status指令:该指令用于了解Nginx当前状态的当前状态,如当前的活动连接,接受和处理当前读/写/等待连接的总数 ; + +(2)Sub_filter指令:它用于搜索和替换响应中的内容,并快速修复陈旧的数据 + +#### 参考链接 + +https://blog.csdn.net/a303549861/article/details/88672901 + +https://blog.csdn.net/weixin_43122090/article/details/105461971 + +https://www.wkcto.com/article/detail/233 diff --git a/README.md b/README.md index d4f5f62..0f2d7e2 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,1039 @@ -# JavaInterview -全网最齐全的Java面试题库-附答案-持续更新 + + +这个Repo主要用来分享Java面试题,目前已经涵盖Java基础、Java多线程、Java虚拟机、MySQL、Redis、消息中间件、Kafka、RabbitMQ、微服务、Spring、MyBatis、Netty、Zookeeper、计算机网络、数据结构与算法、设计模式等内容,后续还会不断更新。 + +如果对于有所帮助,可以给个star。有纰漏的地方,欢迎给我们提PR。 + +如果想获取本Repo的PDF版本,可以用微信扫描下方二维码,回复 “pdf” ,即可获取。如果二维码加载不出来,可以在微信搜索公众号 “Java面试攻略”,回复 “pdf” ,即可获取PDF版本。 + + + + + + +* [Java基础](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#Java基础) + * [1.说下面向对象四大特性](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#1说下面向对象四大特性) + * [2.Java语言有哪些特点](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#2java语言有哪些特点) + * [3.什么是Java程序的主类?应用程序和小程序的主类有何不同?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#3什么是java程序的主类应用程序和小程序的主类有何不同) + * [4.访问修饰符public,private,protected,以及不写(默认)时的区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#4访问修饰符publicprivateprotected以及不写默认时的区别) + * [5.float f=3.4;是否正确?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#5float-f34是否正确) + * [6.Java有没有goto?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#6java有没有goto) + * [7.&和&&的区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#7和的区别) + * [8.Math.round(11.5) 等于多少?Math.round(-11.5)等于多少?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#8mathround115-等于多少mathround-115等于多少) + * [9.用最有效率的方法计算2乘以8?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#9用最有效率的方法计算2乘以8) + * [10.什么是Java注释](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#10什么是java注释) + * [11.Java有哪些数据类型](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#11java有哪些数据类型) + * [12.final 有什么用?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#12final-有什么用) + * [13.final finally finalize的区别](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#13final-finally-finalize的区别) + * [14.String str = "i" 和String str = new String("1")一样吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#14string-str--i-和string-str--new-string1一样吗) + * [15.Java 中操作字符串都有哪些类?它们之间有什么区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#15java-中操作字符串都有哪些类它们之间有什么区别) + * [16.Java中为什么要用 clone?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#16java中为什么要用-clone) + * [17.深克隆和浅克隆?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#17深克隆和浅克隆) + * [18.new一个对象的过程和clone一个对象的区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#18new一个对象的过程和clone一个对象的区别) + * [19.Java中实现多态的机制是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#19java中实现多态的机制是什么) + * [20.谈谈你对多态的理解?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#20谈谈你对多态的理解) + * [21.构造器(constructor)是否可被重写(override)?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#21构造器constructor是否可被重写override) + * [22.两个对象值相同(x.equals(y) == true),但却可有不同的hash code,这句话对不对?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#22两个对象值相同xequalsy--true但却可有不同的hash-code这句话对不对) + * [23.是否可以继承String类?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#23是否可以继承string类) + * [24.String类的常用方法有哪些?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#24string类的常用方法有哪些) + * [25.char型变量中能否能不能存储一个中文汉字,为什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#25char型变量中能否能不能存储一个中文汉字为什么) + * [26.this关键字的用法](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#26this关键字的用法) + * [27.super关键字的用法](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#27super关键字的用法) + * [28.this与super的区别](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#28this与super的区别) + * [29.static存在的主要意义](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#29static存在的主要意义) + * [30.static的独特之处](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#30static的独特之处) + * [31.static应用场景](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#31static应用场景) + * [32.static注意事项](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#32static注意事项) + * [33.break ,continue ,return 的区别及作用](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#33break-continue-return-的区别及作用) + * [34.在Java中定义一个不做事且没有参数的构造方法的作用](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#34在java中定义一个不做事且没有参数的构造方法的作用) + * [35.构造方法有哪些特性?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#35构造方法有哪些特性) + * [36.静态变量和实例变量区别](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#36静态变量和实例变量区别) + * [37.静态方法和实例方法有何不同?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#37静态方法和实例方法有何不同) + * [38.什么是方法的返回值?返回值的作用是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#38什么是方法的返回值返回值的作用是什么) + * [39.什么是内部类?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#39什么是内部类) + * [40.内部类的分类有哪些](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#40内部类的分类有哪些) + * [41.Java中异常分为哪些种类?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#41java中异常分为哪些种类) + * [42.hashCode 与 equals (重要)](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#42hashcode-与-equals-重要) + * [43.hashCode()介绍](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#43hashcode介绍) + * [44.为什么要有 hashCode](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#44为什么要有-hashcode) + * [45.抽象类和接口(Java7)的区别](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#45抽象类和接口java7的区别) + * [46.Java 8的接口新增了哪些特性?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#46java-8的接口新增了哪些特性) + * [47.重写和重载的区别](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#47重写和重载的区别) + * [48.ArrayList和LinkedList有什么区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#48arraylist和linkedlist有什么区别) + * [49.HashMap是怎么实现的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#49hashmap是怎么实现的) + * [50.HashMap在Java7和Java8中的实现有什么不同?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#50hashmap在java7和java8中的实现有什么不同) + * [51.HashMap有时候会死循环,你知道是什么原因吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#51hashmap有时候会死循环你知道是什么原因吗) + * [52.ConcurrentHashMap是怎么实现的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#52concurrenthashmap是怎么实现的) + * [53.静态代理和动态代理的区别](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#53静态代理和动态代理的区别) + * [54.JDK动态代理和CGLIB动态代理的区别](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#54jdk动态代理和cglib动态代理的区别) + * [参考链接](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E5%9F%BA%E7%A1%80.md#参考链接) + +* [多线程](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md) + + * [1.说说synchronized的实现原理](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#1说说synchronized的实现原理) + * [2.ReentrantLock与synchronized的区别](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#2reentrantlock与synchronized的区别) + * [3.ReentrantLock实现原理](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#3reentrantlock实现原理) + * [4.Java原子类AtomicInteger实现原理](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#4java原子类atomicinteger实现原理) + * [5.Java线程池实现原理](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#5java线程池实现原理) + * [6.ThreadLocal实现原理](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#6threadlocal实现原理) + * [7.InheritableThreadLocal原理知道吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#7inheritablethreadlocal原理知道吗) + * [8.说一下synchronized锁升级过程](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#8说一下synchronized锁升级过程) + * [9.了解过什么是“伪共享”吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#9了解过什么是伪共享吗) + * [10.“伪共享”出现的原因是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#10伪共享出现的原因是什么) + * [11.如何避免“伪共享”?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#11如何避免伪共享) + * [12.Java里的线程有哪些状态?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#12java里的线程有哪些状态) + * [13.什么是悲观锁?什么是乐观锁?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#13什么是悲观锁什么是乐观锁) + * [14.怎么停止一个运行中的线程?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#14怎么停止一个运行中的线程) + * [15.说一下你对volatile的理解?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#15说一下你对volatile的理解) + * [16.并发编程三要素?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#16并发编程三要素) + * [17.创建线程有哪些方式?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#17创建线程有哪些方式) + * [18.线程池的优点?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#18线程池的优点) + * [19.CyclicBarrier和CountDownLatch的区别](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#19cyclicbarrier和countdownlatch的区别) + * [20.什么是CAS?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#20什么是cas) + * [21.CAS的问题](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#21cas的问题) + * [22.什么是AQS?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#22什么是aqs) + * [23.AQS支持几种同步方式?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#23aqs支持几种同步方式) + * [24.什么是自旋锁?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#24什么是自旋锁) + * [25.什么是多线程的上下文切换?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#25什么是多线程的上下文切换) + * [26.什么是线程和进程?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#26什么是线程和进程) + * [27.程序计数器为什么是私有的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#27程序计数器为什么是私有的) + * [28.虚拟机栈和本地方法栈为什么是私有的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#28虚拟机栈和本地方法栈为什么是私有的) + * [29.并发与并行的区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#29并发与并行的区别) + * [30.什么是线程死锁?如何避免死锁?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#30什么是线程死锁如何避免死锁) + * [31.sleep() 方法和 wait() 方法的区别和共同点?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#31sleep-方法和-wait-方法的区别和共同点) + * [32.为什么我们调用 start() 方法时会执行 run() 方法,为什么我们不能直接调用 run() 方法?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#32为什么我们调用-start-方法时会执行-run-方法为什么我们不能直接调用-run-方法) + * [33.什么是线程安全问题?如何解决?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#33什么是线程安全问题如何解决) + * [34.什么是活锁?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#34什么是活锁) + * [35.什么是线程的饥饿问题?如何解决?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#35什么是线程的饥饿问题如何解决) + * [36.什么是线程的阻塞问题?如何解决?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#36什么是线程的阻塞问题如何解决) + * [37.synchronized 关键字和 volatile 关键字的区别](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#37synchronized-关键字和-volatile-关键字的区别) + * [38.说一说几种常见的线程池及适用场景?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#38说一说几种常见的线程池及适用场景) + * [39.线程池都有哪几种工作队列?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#39线程池都有哪几种工作队列) + * [40.什么是线程安全?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#40什么是线程安全) + * [41.Java中如何获取到线程dump文件](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#41java中如何获取到线程dump文件) + * [42.Java中用到的线程调度算法是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#42java中用到的线程调度算法是什么) + * [43.Thread.sleep(0)的作用是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#43threadsleep0的作用是什么) + * [44.单例模式的线程安全性](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#44单例模式的线程安全性) + * [45.Semaphore有什么作用?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#45semaphore有什么作用) + * [46.Hashtable的size()方法中明明只有一条语句"return count",为什么还要做同步?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#46hashtable的size方法中明明只有一条语句return-count为什么还要做同步) + * [47.同步方法和同步块,哪个是更好的选择?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#47同步方法和同步块哪个是更好的选择) + * [48.高并发、任务执行时间短的业务怎样使用线程池?并发不高、任务执行时间长的业务怎样使用线程池?并发高、业务执行时间长的业务怎样使用线程池?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#48高并发任务执行时间短的业务怎样使用线程池并发不高任务执行时间长的业务怎样使用线程池并发高业务执行时间长的业务怎样使用线程池) + * [49.在Java中Lock接口比synchronized块的优势是什么?你需要实现一个高效的缓存,它允许多个用户读,但只允许一个用户写,以此来保持它的完整性,你会怎样去实现它?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#49在java中lock接口比synchronized块的优势是什么你需要实现一个高效的缓存它允许多个用户读但只允许一个用户写以此来保持它的完整性你会怎样去实现它) + * [50.你将如何使用thread dump?你将如何分析Thread dump?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#50你将如何使用thread-dump你将如何分析thread-dump) + * [参考资料](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%A4%9A%E7%BA%BF%E7%A8%8B.md#参考资料) + +* [Java虚拟机](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md) + * [1.说一下JVM的内存结构?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#1说一下jvm的内存结构) + * [2.栈帧里面包含哪些东西?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#2栈帧里面包含哪些东西) + * [3.程序计数器有什么作用?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#3程序计数器有什么作用) + * [4.字符串常量存放在哪个区域?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#4字符串常量存放在哪个区域) + * [5.你熟悉哪些垃圾收集算法?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#5你熟悉哪些垃圾收集算法) + * [6.Java里有哪些引用类型?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#6java里有哪些引用类型) + * [7.JVM怎么判断一个对象是不是要回收?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#7jvm怎么判断一个对象是不是要回收) + * [8.GC Roots 有哪些?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#8gc-roots-有哪些) + * [9.你知道哪些GC类型?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#9你知道哪些gc类型) + * [10.对象都是优先分配在年轻代上的吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#10对象都是优先分配在年轻代上的吗) + * [11.你了解过哪些垃圾收集器?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#11你了解过哪些垃圾收集器) + * [12.说说CMS垃圾收集器的工作原理](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#12说说cms垃圾收集器的工作原理) + * [13.说说G1垃圾收集器的工作原理](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#13说说g1垃圾收集器的工作原理) + * [14.说说ZGC垃圾收集器的工作原理](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#14说说zgc垃圾收集器的工作原理) + * [15.ZGC收集器中的染色指针有什么用?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#15zgc收集器中的染色指针有什么用) + * [16.说说类加载的过程](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#16说说类加载的过程) + * [17.说下有哪些类加载器?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#17说下有哪些类加载器) + * [18.什么是双亲委派机制?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#18什么是双亲委派机制) + * [19.双亲委派机制可以被违背吗?请举例说明。](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#19双亲委派机制可以被违背吗请举例说明) + * [20.Tomcat是怎么打破双亲委派机制的呢?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#20tomcat是怎么打破双亲委派机制的呢) + * [21.Java对象的布局了解过吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#21java对象的布局了解过吗) + * [22.什么情况下会发生栈内存溢出?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#22什么情况下会发生栈内存溢出) + * [23.JVM新生代中为什么要分为Eden和Survivor?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#23jvm新生代中为什么要分为eden和survivor) + * [24.JVM中一次完整的GC流程是怎样的,对象如何晋升到老年代?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#24jvm中一次完整的gc流程是怎样的对象如何晋升到老年代) + * [25.什么是指令重排序?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#25什么是指令重排序) + * [26.什么是内存屏障?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#26什么是内存屏障) + * [27.什么是happen-before原则?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#27什么是happen-before原则) + * [28.说说你知道的几种主要的JVM参数](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#28说说你知道的几种主要的jvm参数) + * [29.怎么打出线程栈信息?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#29怎么打出线程栈信息) + * [30.为什么需要双亲委派模式?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#30为什么需要双亲委派模式) + * [31.怎么打破双亲委派模型?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#31怎么打破双亲委派模型) + * [32.说一下堆和栈的区别](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#32说一下堆和栈的区别) + * [33.Java 8 为什么要将永久代(PermGen)替换为元空间(MetaSpace)呢?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#33java-8-为什么要将永久代permgen替换为元空间metaspace呢) + * [34.说一下Java对象的创建过程](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#34说一下java对象的创建过程) + * [35.对象的访问定位有哪几种方式?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#35对象的访问定位有哪几种方式) + * [36.说一下堆内存中对象的分配的基本策略](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#36说一下堆内存中对象的分配的基本策略) + * [37.Minor Gc和Full GC 有什么不同呢?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#37minor-gc和full-gc-有什么不同呢) + * [38.Java会存在内存泄漏吗?请简单描述。](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#38java会存在内存泄漏吗请简单描述) + * [39.如何判断一个类是无用的类?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#39如何判断一个类是无用的类) + * [40.介绍一下类文件结构吧!](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#40介绍一下类文件结构吧) + * [41.说一下 JVM 调优的工具?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#41说一下-jvm-调优的工具) + * [42.JVM调优命令有哪些?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#42jvm调优命令有哪些) + * [43.JRE、JDK、JVM 及 JIT 之间有什么不同?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#43jrejdkjvm-及-jit-之间有什么不同) + * [44.程序计数器为什么是私有的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#44程序计数器为什么是私有的) + * [45.如何判断一个常量是废弃常量 ?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#45如何判断一个常量是废弃常量-) + * [参考资料](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E8%99%9A%E6%8B%9F%E6%9C%BA.md#参考资料) + +* [Java IO](https://github.com/JavaInterviewHub/JavaInterview/blob/main/JavaIO.md) + * [1.Java 中有几种类型的流?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/JavaIO.md#1java-中有几种类型的流) + * [2.什么是 java序列化?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/JavaIO.md#2什么是-java序列化) + * [3.如何实现 java 序列化?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/JavaIO.md#3如何实现-java-序列化) + * [4.字节流和字符流的区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/JavaIO.md#4字节流和字符流的区别) + * [5.PrintStream、BufferedWriter、PrintWriter的比较?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/JavaIO.md#5printstreambufferedwriterprintwriter的比较) + * [6.什么是节点流,什么是处理流,它们各有什么用处,处理流的创建有什么特征?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/JavaIO.md#6什么是节点流什么是处理流它们各有什么用处处理流的创建有什么特征) + * [7.流一般需要不需要关闭,如果关闭的话在用什么方法,一般要在那个代码块里面关闭比较好,处理流是怎么关闭的,如果有多个流互相调用传入是怎么关闭的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/JavaIO.md#7流一般需要不需要关闭如果关闭的话在用什么方法一般要在那个代码块里面关闭比较好处理流是怎么关闭的如果有多个流互相调用传入是怎么关闭的) + * [8.什么是BIO](https://github.com/JavaInterviewHub/JavaInterview/blob/main/JavaIO.md#8什么是bio) + * [9.什么是NIO](https://github.com/JavaInterviewHub/JavaInterview/blob/main/JavaIO.md#9什么是nio) + * [10.什么是AIO](https://github.com/JavaInterviewHub/JavaInterview/blob/main/JavaIO.md#10什么是aio) + * [11.同步与异步](https://github.com/JavaInterviewHub/JavaInterview/blob/main/JavaIO.md#11同步与异步) + * [12.阻塞与非阻塞](https://github.com/JavaInterviewHub/JavaInterview/blob/main/JavaIO.md#12阻塞与非阻塞) + * [13.同步、异步、阻塞、非堵塞](https://github.com/JavaInterviewHub/JavaInterview/blob/main/JavaIO.md#13同步异步阻塞非堵塞) + * [14.通道是个什么意思?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/JavaIO.md#14通道是个什么意思) + * [15.缓冲区是什么意思?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/JavaIO.md#15缓冲区是什么意思) + * [16.IO多路复用的底层原理](https://github.com/JavaInterviewHub/JavaInterview/blob/main/JavaIO.md#16io多路复用的底层原理) + * [参考链接](https://github.com/JavaInterviewHub/JavaInterview/blob/main/JavaIO.md#参考链接) + +* [MySQL](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md) + * [1. 什么是索引?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#1-什么是索引) + * [2.索引是个什么样的数据结构呢?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#2索引是个什么样的数据结构呢) + * [3.Hash索引和B+树索引有什么区别或者说优劣呢?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#3hash索引和b树索引有什么区别或者说优劣呢) + * [4.在建立索引的时候,都有哪些需要考虑的因素呢?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#4在建立索引的时候都有哪些需要考虑的因素呢) + * [5.了解过哪些存储引擎?各有什么优缺点?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#5了解过哪些存储引擎各有什么优缺点) + * [6.说一下什么是事务的ACID属性吧](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#6说一下什么是事务的acid属性吧) + * [7.事务的隔离级别了解过吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#7事务的隔离级别了解过吗) + * [8.说说InnoDB的索引原理](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#8说说innodb的索引原理) + * [说说InnoDB的MVCC机制](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#说说innodb的mvcc机制) + * [9.有了解过“回表”的概念吗?什么情况下会出现“回表”?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#9有了解过回表的概念吗什么情况下会出现回表) + * [10.MySQL索引的类型](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#10mysql索引的类型) + * [11.有做过MySQL的索引优化吗](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#11有做过mysql的索引优化吗) + * [12.什么是聚簇索引?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#12什么是聚簇索引) + * [13.InnoDB有聚簇索引吗?MyIsam呢?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#13innodb有聚簇索引吗myisam呢) + * [14.MyIsam的数据是怎么存储的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#14myisam的数据是怎么存储的) + * [15.InnoDB的数据是怎么存储的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#15innodb的数据是怎么存储的) + * [16.InnoDB主键索引跟非主键索引在数据存储上的差异](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#16innodb主键索引跟非主键索引在数据存储上的差异) + * [17.InnoDB删除某条记录后,内部会怎么处理?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#17innodb删除某条记录后内部会怎么处理) + * [18.InnoDB如果没有设置主键的话,它内部会怎么处理?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#18innodb如果没有设置主键的话它内部会怎么处理) + * [19.为什么InnoDB一定会生成主键?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#19为什么innodb一定会生成主键) + * [20.MySQL分库分表了解过吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#20mysql分库分表了解过吗) + * [21.MySQL的redo日志和undo日志分别有什么用?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#21mysql的redo日志和undo日志分别有什么用) + * [22.MySQL的redo日志的刷盘时机](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#22mysql的redo日志的刷盘时机) + * [23.MySQL有哪些锁?以及各种锁的作用?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#23mysql有哪些锁以及各种锁的作用) + * [24.MySQL中varchar与char的区别以及varchar(50)中的50代表的涵义](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#24mysql中varchar与char的区别以及varchar50中的50代表的涵义) + * [25.MySQL有哪些日志,分别是什么用处?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#25mysql有哪些日志分别是什么用处) + * [26.在哪些情况下会发生针对该列创建了索引但是在查询的时候并没有使用呢?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#26在哪些情况下会发生针对该列创建了索引但是在查询的时候并没有使用呢) + * [27. 为什么要尽量设定一个主键?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#27-为什么要尽量设定一个主键) + * [28.主键使用自增ID还是UUID?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#28主键使用自增id还是uuid) + * [29.字段为什么要求定义为not null?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#29字段为什么要求定义为not-null) + * [30.如果要存储用户的密码散列,应该使用什么字段进行存储?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#30如果要存储用户的密码散列应该使用什么字段进行存储) + * [31.varchar(10)和int(10)代表什么含义?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#31varchar10和int10代表什么含义) + * [32.MySQL的binlog有有几种录入格式?分别有什么区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#32mysql的binlog有有几种录入格式分别有什么区别) + * [33.超大分页怎么处理?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#33超大分页怎么处理) + * [34.关心过业务系统里面的sql耗时吗?统计过慢查询吗?对慢查询都怎么优化过?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#34关心过业务系统里面的sql耗时吗统计过慢查询吗对慢查询都怎么优化过) + * [35.什么是存储过程?有哪些优缺点?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#35什么是存储过程有哪些优缺点) + * [36.说一说三个范式](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#36说一说三个范式) + * [37.什么情况下应不建或少建索引](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#37什么情况下应不建或少建索引) + * [38.什么是表分区?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#38什么是表分区) + * [39.表分区与分表的区别](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#39表分区与分表的区别) + * [40.表分区有什么好处?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#40表分区有什么好处) + * [41.MVVC了解过吗](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#41mvvc了解过吗) + * [42.在MVCC并发控制中,读操作可以分成哪几类?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#42在mvcc并发控制中读操作可以分成哪几类) + * [43.行级锁定的优点](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#43行级锁定的优点) + * [44.行级锁定的缺点](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#44行级锁定的缺点) + * [45.MySQL优化](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#45mysql优化) + * [46.key和index的区别](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#46key和index的区别) + * [47.delete、truncate、drop区别](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#47deletetruncatedrop区别) + * [48.MySQL主从复制原理流程](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#48mysql主从复制原理流程) + * [49.自增主键最大ID记录,MyISAM和InnoDB分别是如何存储的](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#49自增主键最大id记录myisam和innodb分别是如何存储的) + * [50.Mysql如何优化DISTINCT?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#50mysql如何优化distinct) + * [51.解释MySQL外连接、内连接与自连接的区别](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#51解释mysql外连接内连接与自连接的区别) + * [参考链接](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MySQL.md#参考链接) + +* [Redis](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md) + * [1.什么是Redis?简述它的优缺点?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#1什么是redis简述它的优缺点) + * [2.Redis相比memcached有哪些优势?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#2redis相比memcached有哪些优势) + * [3.Redis有哪些数据结构?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#3redis有哪些数据结构) + * [4.Redis主要消耗什么物理资源?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#4redis主要消耗什么物理资源) + * [5.Redis的全称是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#5redis的全称是什么) + * [6.一个字符串类型的值能存储最大容量是多少?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#6一个字符串类型的值能存储最大容量是多少) + * [7.Redis为什么那么快?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#7redis为什么那么快) + * [8.Redis如何实现分布式锁?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#8redis如何实现分布式锁) + * [9.Redis是单线程还是多线程?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#9redis是单线程还是多线程) + * [10.Redis 官方为什么不提供 Windows 版本?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#10redis-官方为什么不提供-windows-版本) + * [11.为什么 Redis 需要把所有数据放到内存中?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#11为什么-redis-需要把所有数据放到内存中) + * [12.Redis如何设置密码及验证密码?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#12redis如何设置密码及验证密码) + * [13.Redis集群如何选择数据库?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#13redis集群如何选择数据库) + * [14.缓存失效?缓存穿透?缓存雪崩?缓存并发?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#14缓存失效缓存穿透缓存雪崩缓存并发) + * [15.Redis中的热key怎么处理?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#15redis中的热key怎么处理) + * [16.Redis中的大key怎么处理?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#16redis中的大key怎么处理) + * [17.使用Redis统计网站的UV,应该怎么做?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#17使用redis统计网站的uv应该怎么做) + * [18.Redis事务机制了解过吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#18redis事务机制了解过吗) + * [19.Redis key的淘汰策略有哪些?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#19redis-key的淘汰策略有哪些) + * [20.Redis在什么情况下会触发key的回收?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#20redis在什么情况下会触发key的回收) + * [21.Redis的持久化了解过吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#21redis的持久化了解过吗) + * [22.Redis在集群种查找key的时候,是怎么定位到具体节点的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#22redis在集群种查找key的时候是怎么定位到具体节点的) + * [23.Redis集群各个节点之间是怎么保持数据一致性的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#23redis集群各个节点之间是怎么保持数据一致性的) + * [24.用Redis做延时队列,具体应该怎么实现?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#24用redis做延时队列具体应该怎么实现) + * [25.Redis String的内部编码有哪些?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#25redis-string的内部编码有哪些) + * [26.Redis 集群方案应该怎么做?都有哪些方案?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#26redis-集群方案应该怎么做都有哪些方案) + * [27.Redis 集群方案什么情况下会导致整个集群不可用?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#27redis-集群方案什么情况下会导致整个集群不可用) + * [28.MySQL 里有 2000w 数据,redis 中只存 20w 的数据,如何保证 redis 中的数据都是热点数据?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#28mysql-里有-2000w-数据redis-中只存-20w-的数据如何保证-redis-中的数据都是热点数据) + * [29.Redis有哪些适合的场景?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#29redis有哪些适合的场景) + * [30.Redis和Redisson有什么关系?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#30redis和redisson有什么关系) + * [31.Redis中的管道有什么用?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#31redis中的管道有什么用) + * [32.Redis如何做内存优化?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#32redis如何做内存优化) + * [参考链接](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Redis.md#参考链接) + + +* [Spring](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md) + * [1.什么是spring?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md#1什么是spring) + * [2.使用Spring框架的好处是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md#2使用spring框架的好处是什么) + * [3.Spring由哪些模块组成?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md#3spring由哪些模块组成) + * [4.Spring是怎么解决循环依赖的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md#4spring是怎么解决循环依赖的) + * [5.Spring Boot手动装配有哪几种方式?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md#5spring-boot手动装配有哪几种方式) + * [6.Spring Boot自动配置原理](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md#6spring-boot自动配置原理) + * [7.谈谈自己对于Spring IOC的理解](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md#7谈谈自己对于spring-ioc的理解) + * [8.谈谈自己对于Spring AOP的理解](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md#8谈谈自己对于spring-aop的理解) + * [9.Spring AOP和AspectJ AOP有什么区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md#9spring-aop和aspectj-aop有什么区别) + * [10.Spring中的bean的作用域有哪些?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md#10spring中的bean的作用域有哪些) + * [11.Spring中的单例bean的线程安全问题了解吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md#11spring中的单例bean的线程安全问题了解吗) + * [12.Spring中的bean生命周期了解过吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md#12spring中的bean生命周期了解过吗) + * [13.Spring MVC的工作原理了解嘛?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md#13spring-mvc的工作原理了解嘛) + * [14.Spring框架中用到了哪些设计模式?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md#14spring框架中用到了哪些设计模式) + * [15.@Component和@Bean的区别是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md#15component和bean的区别是什么) + * [16.将一个类声明为Spring的bean的注解有哪些?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md#16将一个类声明为spring的bean的注解有哪些) + * [17.Spring事务管理的方式有几种?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md#17spring事务管理的方式有几种) + * [18.Spring事务中的隔离级别有哪几种?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md#18spring事务中的隔离级别有哪几种) + * [19.Spring事务中有哪几种事务传播行为?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md#19spring事务中有哪几种事务传播行为) + * [20.Spring 事务底层原理](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md#20spring-事务底层原理) + * [21.BeanFactory和ApplicationContext有什么区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md#21beanfactory和applicationcontext有什么区别) + * [22.Resource 是如何被查找、加载的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md#22resource-是如何被查找加载的) + * [23.解释自动装配的各种模式?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md#23解释自动装配的各种模式) + * [24.有哪些不同类型的IOC(依赖注入)?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md#24有哪些不同类型的ioc依赖注入) + * [25.Spring AOP 实现原理](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md#25spring-aop-实现原理) + * [26.ApplicationContext通常的实现是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md#26applicationcontext通常的实现是什么) + * [27. Bean 工厂和 Application contexts 有什么区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md#27-bean-工厂和-application-contexts-有什么区别) + * [参考资料](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Spring.md#参考资料) + + +* [Spring Boot](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringBoot.md) + + * [1.什么是springboot](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringBoot.md#1什么是springboot) + * [2.Spring Boot 有哪些优点?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringBoot.md#2spring-boot-有哪些优点) + * [3. 创建一个 Spring Boot Project 的最简单的方法是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringBoot.md#3-创建一个-spring-boot-project-的最简单的方法是什么) + * [4.Spring 和 SpringBoot 有什么不同?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringBoot.md#4spring-和-springboot-有什么不同) + * [5.如何重新加载 Spring Boot 上的更改,而无需重新启动服务器?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringBoot.md#5如何重新加载-spring-boot-上的更改而无需重新启动服务器) + * [6.Spring Boot 中的监视器是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringBoot.md#6spring-boot-中的监视器是什么) + * [7.如何在 Spring Boot 中禁用 Actuator 端点安全性?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringBoot.md#7如何在-spring-boot-中禁用-actuator-端点安全性) + * [8.怎么使用 Maven 来构建一个 SpringBoot 程序?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringBoot.md#8怎么使用-maven-来构建一个-springboot-程序) + * [9.Spring Initializr 是创建 Spring Boot Projects 的唯一方法吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringBoot.md#9spring-initializr-是创建-spring-boot-projects-的唯一方法吗) + * [10.为什么我们需要 spring-boot-maven-plugin?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringBoot.md#10为什么我们需要-spring-boot-maven-plugin) + * [11.什么是嵌入式服务器?我们为什么要使用嵌入式服务器呢?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringBoot.md#11什么是嵌入式服务器我们为什么要使用嵌入式服务器呢) + * [12.如何在 Spring Boot 中添加通用的 JS 代码?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringBoot.md#12如何在-spring-boot-中添加通用的-js-代码) + * [13.如何使用 Spring Boot 部署到不同的服务器?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringBoot.md#13如何使用-spring-boot-部署到不同的服务器) + * [14.如何使用配置文件通过 Spring Boot 配置特定环境的配置?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringBoot.md#14如何使用配置文件通过-spring-boot-配置特定环境的配置) + * [15.什么是Swagger?你用Spring Boot实现了吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringBoot.md#15什么是swagger你用spring-boot实现了吗) + * [16.如何实现Spring Boot应用程序的安全性?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringBoot.md#16如何实现spring-boot应用程序的安全性) + * [17.比较一下Spring Security和Shiro各自的优缺点?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringBoot.md#17比较一下spring-security和shiro各自的优缺点) + * [18.Spring Boot中如何解决跨域问题?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringBoot.md#18spring-boot中如何解决跨域问题) + * [19.Spring Boot的核心注解是哪些?他由哪几个注解组成的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringBoot.md#19spring-boot的核心注解是哪些他由哪几个注解组成的) + * [20.保护SpringBoot应用有哪些方法?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringBoot.md#20保护springboot应用有哪些方法) + * [21.SpringBoot 2.X有哪些新特性?与1.X有什么区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringBoot.md#21springboot-2x有哪些新特性与1x有什么区别) + * [参考链接](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringBoot.md#参考链接) + +* [Spring Cloud](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringCloud.md) + + * [1.什么是 Spring Cloud?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringCloud.md#1什么是-spring-cloud) + * [2.使用Spring Cloud有什么优势?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringCloud.md#2使用spring-cloud有什么优势) + * [3.服务注册和发现是什么意思?Spring Cloud如何实现?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringCloud.md#3服务注册和发现是什么意思spring-cloud如何实现) + * [4.Spring Cloud由哪些组件组成?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringCloud.md#4spring-cloud由哪些组件组成) + * [5.什么是Hystrix?它如何实现容错?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringCloud.md#5什么是hystrix它如何实现容错) + * [6.什么是Hystrix断路器?我们需要它吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringCloud.md#6什么是hystrix断路器我们需要它吗) + * [7.什么是Netflix Feign?它的优点是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringCloud.md#7什么是netflix-feign它的优点是什么) + * [8.Eureka的工作原理?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringCloud.md#8eureka的工作原理) + * [9.说说Eureka的自我保护机制?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringCloud.md#9说说eureka的自我保护机制) + * [10.什么是zuul?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringCloud.md#10什么是zuul) + * [11.zuul的工作流程?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringCloud.md#11zuul的工作流程) + * [12.什么是服务熔断?什么是服务降级?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringCloud.md#12什么是服务熔断什么是服务降级) + * [13.什么是服务雪崩效应?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringCloud.md#13什么是服务雪崩效应) + * [14.ZuulFilter有哪些常用方法?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringCloud.md#14zuulfilter有哪些常用方法) + * [15.如何实现动态Zuul网关路由转发?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringCloud.md#15如何实现动态zuul网关路由转发) + * [16.什么是 Spring Cloud Bus?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringCloud.md#16什么是-spring-cloud-bus) + * [17.Spring Cloud Bus 原理?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringCloud.md#17spring-cloud-bus-原理) + * [18.SpringCloud Config可以实现实时刷新吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringCloud.md#18springcloud-config可以实现实时刷新吗) + * [19.Eureka和zookeeper都可以提供服务注册与发现的功能,两者的区别](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringCloud.md#19eureka和zookeeper都可以提供服务注册与发现的功能两者的区别) + * [参考链接](https://github.com/JavaInterviewHub/JavaInterview/blob/main/SpringCloud.md#参考链接) + + + +* [Mybatis](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mybatis.md) + + * [1.什么是Mybatis?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mybatis.md#1什么是mybatis) + * [2.Mybatis的优缺点?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mybatis.md#2mybatis的优缺点) + * [3.Mybatis使用场合?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mybatis.md#3mybatis使用场合) + * [4.https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mybatis.md#{}和${}的区别是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mybatis.md#4和的区别是什么) + * [5.当实体类的属性名和表种字段名不一致怎么办?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mybatis.md#5当实体类的属性名和表种字段名不一致怎么办) + * [6.Mybatis是如何将sql执行结果封装为目标对象并返回的?都有哪些映射形式?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mybatis.md#6mybatis是如何将sql执行结果封装为目标对象并返回的都有哪些映射形式) + * [7.如何获取自动生成的(主)键值?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mybatis.md#7如何获取自动生成的主键值) + * [8.Mybatis的Xml映射文件中,不同的Xml映射文件,id是否可以重复?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mybatis.md#8mybatis的xml映射文件中不同的xml映射文件id是否可以重复) + * [9. Mybatis动态SQL?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mybatis.md#9-mybatis动态sql) + * [10.说一下resultMap和resultType?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mybatis.md#10说一下resultmap和resulttype) + * [11. Mybatis全局配置文件中有哪些标签?分别代表什么意思?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mybatis.md#11-mybatis全局配置文件中有哪些标签分别代表什么意思) + * [12.Mybatis能执行一对一、一对多的关联查询吗?都有哪些实现方式,以及它们之间的区别。](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mybatis.md#12mybatis能执行一对一一对多的关联查询吗都有哪些实现方式以及它们之间的区别) + * [13.Mybatis是否支持延迟加载?如果支持,它的实现原理是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mybatis.md#13mybatis是否支持延迟加载如果支持它的实现原理是什么) + * [14.Mybatis都有哪些Executor执行器?它们之间的区别是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mybatis.md#14mybatis都有哪些executor执行器它们之间的区别是什么) + * [15.Mybatis的一级、二级缓存](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mybatis.md#15mybatis的一级二级缓存) + * [参考链接](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mybatis.md#参考链接) + +* [Netty](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Netty.md) + + * [1.你了解过哪些IO模型?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Netty.md#1你了解过哪些io模型) + * [2.什么是Reactor模型?Reactor的3种版本都知道吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Netty.md#2什么是reactor模型reactor的3种版本都知道吗) + * [3.了解过粘包拆包吗?为什么会出现粘包拆包?怎么处理粘包拆包?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Netty.md#3了解过粘包拆包吗为什么会出现粘包拆包怎么处理粘包拆包) + * [4.UDP协议会有粘包拆包的问题吗?为什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Netty.md#4udp协议会有粘包拆包的问题吗为什么) + * [5.Netty 是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Netty.md#5netty-是什么) + * [6.为什么要用 Netty?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Netty.md#6为什么要用-netty) + * [7.Netty 的应用场景了解么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Netty.md#7netty-的应用场景了解么) + * [8.Netty 的零拷贝了解么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Netty.md#8netty-的零拷贝了解么) + * [9.Netty 的心跳机制了解么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Netty.md#9netty-的心跳机制了解么) + * [10.Netty 中有哪些重要组件?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Netty.md#10netty-中有哪些重要组件) + * [11.Netty 发送消息有几种方式?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Netty.md#11netty-发送消息有几种方式) + * [12.Netty 支持哪些心跳类型设置?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Netty.md#12netty-支持哪些心跳类型设置) + * [13.说说Netty的执行流程?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Netty.md#13说说netty的执行流程) + * [14.Netty高性能体现在哪些方面?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Netty.md#14netty高性能体现在哪些方面) + * [参考资料](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Netty.md#参考资料) + +* [微服务](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%BE%AE%E6%9C%8D%E5%8A%A1.md) + + * [1.微服务有哪些优缺点?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%BE%AE%E6%9C%8D%E5%8A%A1.md#1微服务有哪些优缺点) + * [2.作为注册中心,Zookeeper和Eureka有什么区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%BE%AE%E6%9C%8D%E5%8A%A1.md#2作为注册中心zookeeper和eureka有什么区别) + * [3.Service Mesh了解过吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%BE%AE%E6%9C%8D%E5%8A%A1.md#3service-mesh了解过吗) + * [4.微服务有哪些特点?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%BE%AE%E6%9C%8D%E5%8A%A1.md#4微服务有哪些特点) + * [5.单片,SOA 和微服务架构有什么区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%BE%AE%E6%9C%8D%E5%8A%A1.md#5单片soa-和微服务架构有什么区别) + * [6.Spring Cloud 解决了哪些问题?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%BE%AE%E6%9C%8D%E5%8A%A1.md#6spring-cloud-解决了哪些问题) + * [7.服务注册和发现是什么意思?Spring Cloud 如何实现?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%BE%AE%E6%9C%8D%E5%8A%A1.md#7服务注册和发现是什么意思spring-cloud-如何实现) + * [8.Spring Cloud 和dubbo的区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%BE%AE%E6%9C%8D%E5%8A%A1.md#8spring-cloud-和dubbo的区别) + * [9.什么是微服务?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%BE%AE%E6%9C%8D%E5%8A%A1.md#9什么是微服务) + * [10.微服务之间是如何通讯的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%BE%AE%E6%9C%8D%E5%8A%A1.md#10微服务之间是如何通讯的) + * [11.请谈谈对SpringBoot 和SpringCloud的理解](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%BE%AE%E6%9C%8D%E5%8A%A1.md#11请谈谈对springboot-和springcloud的理解) + * [12.什么是服务熔断,什么是服务降级](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%BE%AE%E6%9C%8D%E5%8A%A1.md#12什么是服务熔断什么是服务降级) + * [13.你所知道的微服务技术栈有哪些?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%BE%AE%E6%9C%8D%E5%8A%A1.md#13你所知道的微服务技术栈有哪些) + * [14.什么是 Eureka服务注册与发现?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%BE%AE%E6%9C%8D%E5%8A%A1.md#14什么是-eureka服务注册与发现) + * [15.Eureka的基本架构是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%BE%AE%E6%9C%8D%E5%8A%A1.md#15eureka的基本架构是什么) + * [16.作为服务注册中心,Eureka比Zookeeper好在哪里?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%BE%AE%E6%9C%8D%E5%8A%A1.md#16作为服务注册中心eureka比zookeeper好在哪里) + * [参考资料](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%BE%AE%E6%9C%8D%E5%8A%A1.md#参考资料) + +* [Zookeeper](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md) + + * [1.Zookeeper有哪些节点类型?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md#1zookeeper有哪些节点类型) + * [2.了解过Zookeeper的ZAB协议吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md#2了解过zookeeper的zab协议吗) + * [3.Zookeeper怎么实现分布式锁?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md#3zookeeper怎么实现分布式锁) + * [4.Zookeeper是怎么保证数据一致性的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md#4zookeeper是怎么保证数据一致性的) + * [5.Zookeeper Leader选举过程是怎样的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md#5zookeeper-leader选举过程是怎样的) + * [6.Zookeeper怎么实现服务注册?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md#6zookeeper怎么实现服务注册) + * [7.ZooKeeper是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md#7zookeeper是什么) + * [8.ZooKeeper提供了什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md#8zookeeper提供了什么) + * [9.Zookeeper文件系统](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md#9zookeeper文件系统) + * [10.Zookeeper Watcher 机制](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md#10zookeeper-watcher-机制) + * [11.客户端注册Watcher实现](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md#11客户端注册watcher实现) + * [12.服务端处理Watcher实现](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md#12服务端处理watcher实现) + * [13.ACL权限控制机制](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md#13acl权限控制机制) + * [14.服务器角色](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md#14服务器角色) + * [15.Zookeeper 下 Server工作状态](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md#15zookeeper-下-server工作状态) + * [16.数据同步](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md#16数据同步) + * [17.zookeeper是如何保证事务的顺序一致性的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md#17zookeeper是如何保证事务的顺序一致性的) + * [18.分布式集群中为什么会有Master?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md#18分布式集群中为什么会有master) + * [19.zk节点宕机如何处理?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md#19zk节点宕机如何处理) + * [20.Zookeeper有哪几种部署模式?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md#20zookeeper有哪几种部署模式) + * [21.集群最少要几台机器,集群规则是怎样的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md#21集群最少要几台机器集群规则是怎样的) + * [22.集群支持动态添加机器吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md#22集群支持动态添加机器吗) + * [23.Zookeeper对节点的watch监听通知是永久的吗?为什么不是永久的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md#23zookeeper对节点的watch监听通知是永久的吗为什么不是永久的) + * [24.ZAB和Paxos算法的联系与区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md#24zab和paxos算法的联系与区别) + * [25.Zookeeper的典型应用场景](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md#25zookeeper的典型应用场景) + * [26.Zookeeper 和 Dubbo 的关系?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md#26zookeeper-和-dubbo-的关系) + * [27.zookeeper负载均衡和nginx负载均衡区别](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md#27zookeeper负载均衡和nginx负载均衡区别) + * [参考资料](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Zookeeper.md#参考资料) + + +* [消息队列](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97.md) + * [1.消息队列有哪些应用场景?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97.md#1消息队列有哪些应用场景) + * [2.消息队列的弊端有哪些?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97.md#2消息队列的弊端有哪些) + * [3.使用消息队列,怎么确保消息不丢失?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97.md#3使用消息队列怎么确保消息不丢失) + * [4.使用消息队列,如果处理重复消息?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97.md#4使用消息队列如果处理重复消息) + * [5.Kafka的消息是有序的吗?如果保证Kafka消息的顺序性?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97.md#5kafka的消息是有序的吗如果保证kafka消息的顺序性) + * [6.消息如何保证幂等性](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97.md#6消息如何保证幂等性) + * [7.消息队列积压怎么办](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97.md#7消息队列积压怎么办) + * [8.各种MQ的比较](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97.md#8各种mq的比较) + * [9.如何解决消息队列的延时以及过期失效问题?消息队列满了以后该怎么处理?有几百万消息持续积压几小时怎么解决?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97.md#9如何解决消息队列的延时以及过期失效问题消息队列满了以后该怎么处理有几百万消息持续积压几小时怎么解决) + * [10.为什么使用消息队列?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97.md#10为什么使用消息队列) + * [参考链接](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97.md#参考链接) + +* [Kafka](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md) + * [1.为什么要使用 kafka?为什么要使用消息队列?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#1为什么要使用-kafka为什么要使用消息队列) + * [2.Kafka中的ISR、AR又代表什么?ISR的伸缩又指什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#2kafka中的israr又代表什么isr的伸缩又指什么) + * [3.kafka中的broker 是干什么的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#3kafka中的broker-是干什么的) + * [4.kafka中的 zookeeper 起到什么作用?可以不用zookeeper么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#4kafka中的-zookeeper-起到什么作用可以不用zookeeper么) + * [5.kafka follower如何与leader同步数据?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#5kafka-follower如何与leader同步数据) + * [6.什么情况下一个 broker 会从 ISR 中被踢出去?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#6什么情况下一个-broker-会从-isr-中被踢出去) + * [7.kafka 为什么那么快?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#7kafka-为什么那么快) + * [8.kafka producer如何优化打入速度?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#8kafka-producer如何优化打入速度) + * [9.kafka producer 打数据,ack 为 0, 1, -1 的时候代表啥, 设置 -1 的时候,什么情况下,leader 会认为一条消息 commit 了](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#9kafka-producer-打数据ack--为-0-1--1-的时候代表啥-设置--1-的时候什么情况下leader-会认为一条消息-commit-了) + * [10.kafka unclean 配置代表啥?会对 spark streaming 消费有什么影响?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#10kafka--unclean-配置代表啥会对-spark-streaming-消费有什么影响) + * [11.如果leader crash时,ISR为空怎么办?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#11如果leader-crash时isr为空怎么办) + * [12.kafka的message格式是什么样的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#12kafka的message格式是什么样的) + * [13.kafka中consumer group 是什么概念?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#13kafka中consumer-group-是什么概念) + * [14.Kafka中的消息是否会丢失和重复消费?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#14kafka中的消息是否会丢失和重复消费) + * [15.为什么Kafka不支持读写分离?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#15为什么kafka不支持读写分离) + * [16.Kafka中是怎么体现消息顺序性的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#16kafka中是怎么体现消息顺序性的) + * [17.kafka如何实现延迟队列?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#17kafka如何实现延迟队列) + * [18.什么是消费者组?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#18什么是消费者组) + * [19.解释下 Kafka 中位移(offset)的作用。](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#19解释下-kafka-中位移offset的作用) + * [20.阐述下 Kafka 中的领导者副本(Leader Replica)和追随者副本 (Follower Replica)的区别。](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#20阐述下-kafka-中的领导者副本leader-replica和追随者副本-follower-replica的区别) + * [21.如何设置 Kafka 能接收的最大消息的大小?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#21如何设置-kafka-能接收的最大消息的大小) + * [22.监控 Kafka 的框架都有哪些?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#22监控-kafka-的框架都有哪些) + * [23.Broker 的 Heap Size 如何设置?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#23broker-的-heap-size-如何设置) + * [24.如何估算 Kafka 集群的机器数量?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#24如何估算-kafka-集群的机器数量) + * [25.Leader 总是 -1,怎么破?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#25leader-总是--1怎么破) + * [26.LEO、LSO、AR、ISR、HW 都表示什么含义?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#26leolsoarisrhw-都表示什么含义) + * [27.Kafka 能手动删除消息吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#27kafka-能手动删除消息吗) + * [28.consumer_offsets 是做什么用的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#28consumer_offsets-是做什么用的) + * [29.分区 Leader 选举策略有几种?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#29分区-leader-选举策略有几种) + * [30.Kafka 的哪些场景中使用了零拷贝(Zero Copy)?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#30kafka-的哪些场景中使用了零拷贝zero-copy) + * [31.如何调优 Kafka?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#31如何调优-kafka) + * [32.Controller 发生网络分区(Network Partitioning)时,Kafka 会怎么样?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#32controller-发生网络分区network-partitioning时kafka-会怎么样) + * [33.Java Consumer 为什么采用单线程来获取消息?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#33java-consumer-为什么采用单线程来获取消息) + * [34.简述 Follower 副本消息同步的完整流程。](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#34简述-follower-副本消息同步的完整流程) + * [参考资料](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kafka.md#参考资料) + +* [RabbitMQ](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RabbitMQ.md) + * [1.什么是RabbitMQ?为什么使用RabbitMQ?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RabbitMQ.md#1什么是rabbitmq为什么使用rabbitmq) + * [2.RabbitMQ有什么优缺点?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RabbitMQ.md#2rabbitmq有什么优缺点) + * [3.什么是元数据?元数据分为哪些类型?包括哪些内容?与cluster相关的元数据有哪些?元数据是如何保存的?元数据在cluster中是如何分布的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RabbitMQ.md#3什么是元数据元数据分为哪些类型包括哪些内容与cluster相关的元数据有哪些元数据是如何保存的元数据在cluster中是如何分布的) + * [4.在单node系统和多node构成的cluster系统中声明queue、exchange,以及进行binding会有什么不同?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RabbitMQ.md#4在单node系统和多node构成的cluster系统中声明queueexchange以及进行binding会有什么不同) + * [5.客户端连接到cluster中的任意node上是否都能正常工作?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RabbitMQ.md#5客户端连接到cluster中的任意node上是否都能正常工作) + * [6.若cluster中拥有某个queue的owner node失效了,且该queue 被声明具有durable属性,是否能够成功从其他node上重新声明该 queue ?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RabbitMQ.md#6若cluster中拥有某个queue的owner-node失效了且该queue-被声明具有durable属性是否能够成功从其他node上重新声明该-queue-) + * [7.RabbitMQ 的消息是怎么发送的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RabbitMQ.md#7rabbitmq-的消息是怎么发送的) + * [8.RabbitMQ 怎么避免消息丢失?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RabbitMQ.md#8rabbitmq-怎么避免消息丢失) + * [9.RabbitMQ的使用场景有哪些?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RabbitMQ.md#9rabbitmq的使用场景有哪些) + * [10.RabbitMQ有哪些重要的角色?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RabbitMQ.md#10rabbitmq有哪些重要的角色) + * [11.如何确保消息正确地发送至RabbitMQ?如何确保消息接收方消费了消息?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RabbitMQ.md#11如何确保消息正确地发送至rabbitmq如何确保消息接收方消费了消息) + * [12.要保证消息持久化成功的条件有哪些?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RabbitMQ.md#12要保证消息持久化成功的条件有哪些) + * [13.RabbitMQ 有几种广播类型?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RabbitMQ.md#13rabbitmq-有几种广播类型) + * [14.vhost 是什么?起什么作用?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RabbitMQ.md#14vhost-是什么起什么作用) + * [15.消息基于什么传输?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RabbitMQ.md#15消息基于什么传输) + * [16.消息如何分发?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RabbitMQ.md#16消息如何分发) + * [17.消息怎么路由?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RabbitMQ.md#17消息怎么路由) + * [18.如何确保消息接收方消费了消息?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RabbitMQ.md#18如何确保消息接收方消费了消息) + * [19.如何避免消息重复投递或重复消费?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RabbitMQ.md#19如何避免消息重复投递或重复消费) + * [20.死信队列和延迟队列的使用](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RabbitMQ.md#20死信队列和延迟队列的使用) + * [参考链接:](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RabbitMQ.md#参考链接) + + +* [计算机网络](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C.md) + * [1.请简述TCP/UDP的区别](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C.md#1请简述tcpudp的区别) + * [2.TCP对应的协议和UDP对应的协议](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C.md#2tcp对应的协议和udp对应的协议) + * [3.有哪些私有(保留)地址?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C.md#3有哪些私有保留地址) + * [4.你能说一说OSI七层模型?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C.md#4你能说一说osi七层模型) + * [5.说一说TCP/IP四层模型](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C.md#5说一说tcpip四层模型) + * [6. 简述IP地址的分类?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C.md#6-简述ip地址的分类) + * [7.简述ARP地址解析协议工作原理](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C.md#7简述arp地址解析协议工作原理) + * [8.简述ICMP、TFTP、HTTP、NAT、DHCP协议](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C.md#8简述icmptftphttpnatdhcp协议) + * [9.说一说TCP的三次握手](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C.md#9说一说tcp的三次握手) + * [10.为什么TCP要三次握手](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C.md#10为什么tcp要三次握手) + * [11.TCP建立连接时为什么要传回 SYN](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C.md#11tcp建立连接时为什么要传回-syn) + * [12.TCP为什么要四次挥手](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C.md#12tcp为什么要四次挥手) + * [13.滑动窗口和流量控制](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C.md#13滑动窗口和流量控制) + * [14.拥塞控制](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C.md#14拥塞控制) + * [15.在浏览器中输入url地址到显示主页的过程](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C.md#15在浏览器中输入url地址到显示主页的过程) + * [16.HTTP协议包括哪些请求?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C.md#16http协议包括哪些请求) + * [参考链接](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BD%91%E7%BB%9C.md#参考链接) + + +* [数据结构与算法](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95.md) + * [1.什么是算法?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95.md#1什么是算法) + * [2.TreeMap和TreeSet在排序时如何比较元素?Collections工具类中的sort()方法如何比较元素?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95.md#2treemap和treeset在排序时如何比较元素collections工具类中的sort方法如何比较元素) + * [3.如何知道二叉树的深度?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95.md#3如何知道二叉树的深度) + * [4.介绍一下,堆排序的原理是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95.md#4介绍一下堆排序的原理是什么) + * [5.数组和链表的区别](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95.md#5数组和链表的区别) + * [6.二分查找了解过吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95.md#6二分查找了解过吗) + * [7.说下你熟悉的排序算法](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95.md#7说下你熟悉的排序算法) + * [8.布隆过滤器了解过吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95.md#8布隆过滤器了解过吗) + * [9.一致性hash算法了解过吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95.md#9一致性hash算法了解过吗) + * [10.如何在一个1到100的整数数组中找到丢失的数字?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95.md#10如何在一个1到100的整数数组中找到丢失的数字) + * [11.请你讲讲LRU算法的实现原理?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95.md#11请你讲讲lru算法的实现原理) + * [12.为什么要设计后缀表达式,有什么好处?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95.md#12为什么要设计后缀表达式有什么好处) + * [13. 什么是B树?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95.md#13-什么是b树) + * [14.什么是B+树?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95.md#14什么是b树) + * [15.谈一谈,id全局唯一且自增,如何实现?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95.md#15谈一谈id全局唯一且自增如何实现) + * [参考链接](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%95%B0%E6%8D%AE%E7%BB%93%E6%9E%84%E4%B8%8E%E7%AE%97%E6%B3%95.md#参考链接) + + +* [设计模式](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md) + * [1.接口是什么?为什么要使用接口而不是直接使用具体类?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md#1接口是什么为什么要使用接口而不是直接使用具体类) + * [2.设计模式六大原则?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md#2设计模式六大原则) + * [3.Java怎么实现单例模式?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md#3java怎么实现单例模式) + * [4.什么是代理模式?什么是动态代理?Java中动态代理有哪些实现方式?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md#4什么是代理模式什么是动态代理java中动态代理有哪些实现方式) + * [5.设计模式的类型](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md#5设计模式的类型) + * [6.说说你所熟悉或听说过的 j2ee 中的几种常用模式?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md#6说说你所熟悉或听说过的-j2ee-中的几种常用模式) + * [7.简述一下你了解的 Java 设计模式(总结)](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md#7简述一下你了解的-java-设计模式总结) + * [8.适配器模式是什么?什么时候使用?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md#8适配器模式是什么什么时候使用) + * [9.适配器模式与装饰器模式有什么区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md#9适配器模式与装饰器模式有什么区别) + * [10.适配器模式和代理模式之间有什么不同?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md#10适配器模式和代理模式之间有什么不同) + * [11.什么是模板方法模式?试举例说明。](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md#11什么是模板方法模式试举例说明) + * [12.OOP中的组合、聚合和关联有什么区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md#12oop中的组合聚合和关联有什么区别) + * [13.给我一个符合开闭原则的设计模式的例子?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md#13给我一个符合开闭原则的设计模式的例子) + * [14.工厂模式与抽象工厂模式的区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md#14工厂模式与抽象工厂模式的区别) + * [15.举出一个例子,在这种情况你会更倾向于使用抽象类,而不是接口?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md#15举出一个例子在这种情况你会更倾向于使用抽象类而不是接口) + * [16.Dubbo 源码使用了哪些设计模式?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md#16dubbo-源码使用了哪些设计模式) + * [17.Spring 当中用到了哪些设计模式?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md#17spring-当中用到了哪些设计模式) + * [参考链接](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F.md#参考链接) + + +* [分布式](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%88%86%E5%B8%83%E5%BC%8F.md) + * [1.分布式id如何生成?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%88%86%E5%B8%83%E5%BC%8F.md#1分布式id如何生成) + * [2.雪花算法了解过吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%88%86%E5%B8%83%E5%BC%8F.md#2雪花算法了解过吗) + * [3.什么是CAP定理?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%88%86%E5%B8%83%E5%BC%8F.md#3什么是cap定理) + * [4.分布式事务了解过吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%88%86%E5%B8%83%E5%BC%8F.md#4分布式事务了解过吗) + * [5.什么是二阶段提交(2PC)?什么是三阶段提交(3PC)?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%88%86%E5%B8%83%E5%BC%8F.md#5什么是二阶段提交2pc什么是三阶段提交3pc) + * [6.TCC了解过吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%88%86%E5%B8%83%E5%BC%8F.md#6tcc了解过吗) + * [7.Paxos算法了解过吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%88%86%E5%B8%83%E5%BC%8F.md#7paxos算法了解过吗) + * [8.Zookeeper的Zab协议了解过吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%88%86%E5%B8%83%E5%BC%8F.md#8zookeeper的zab协议了解过吗) + * [9.知道什么是Gossip协议吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%88%86%E5%B8%83%E5%BC%8F.md#9知道什么是gossip协议吗) + * [10.了解过哪些负载均衡算法?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%88%86%E5%B8%83%E5%BC%8F.md#10了解过哪些负载均衡算法) + * [11.负载均衡的实现方案有哪些?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%88%86%E5%B8%83%E5%BC%8F.md#11负载均衡的实现方案有哪些) + * [12.正向代理和反向代理的区别](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%88%86%E5%B8%83%E5%BC%8F.md#12正向代理和反向代理的区别) + * [13.分布式 Session了解过吗?如何实现?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%88%86%E5%B8%83%E5%BC%8F.md#13分布式-session了解过吗如何实现) + * [14.如何防止表单重复提交?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%88%86%E5%B8%83%E5%BC%8F.md#14如何防止表单重复提交) + * [15.如何设计一个秒杀系统?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%88%86%E5%B8%83%E5%BC%8F.md#15如何设计一个秒杀系统) + * [16.分布式系统的接口幂等性设计](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%88%86%E5%B8%83%E5%BC%8F.md#16分布式系统的接口幂等性设计) + * [17.如何保障请求执行顺序](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%88%86%E5%B8%83%E5%BC%8F.md#17如何保障请求执行顺序) + * [18.BASE理论了解过吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%88%86%E5%B8%83%E5%BC%8F.md#18base理论了解过吗) + * [19.SOA和微服务架构有哪些区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%88%86%E5%B8%83%E5%BC%8F.md#19soa和微服务架构有哪些区别) + * [参考资料](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%88%86%E5%B8%83%E5%BC%8F.md#参考资料) + + +* [Linux](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md) + * [1.vim有几种工作模式?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#1vim有几种工作模式) + * [2.find 命令如何使用?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#2find-命令如何使用) + * [3.如何在 /usr 目录下找出大小超过 10MB 的文件?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#3如何在-usr-目录下找出大小超过-10mb-的文件) + * [4.如何在 /var 目录下找出 90 天之内未被访问过的文件?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#4如何在-var-目录下找出-90-天之内未被访问过的文件) + * [5.如何在 /home 目录下找出 120 天之前被修改过的文件?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#5如何在-home-目录下找出-120-天之前被修改过的文件) + * [6.在整个目录树下查找文件 “core” ,如发现则无需提示直接删除它们?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#6在整个目录树下查找文件-core-如发现则无需提示直接删除它们) + * [7.ls 命令](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#7ls-命令) + * [8.df 命令](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#8df-命令) + * [9.rm 命令](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#9rm-命令) + * [10.mv 命令](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#10mv-命令) + * [11.cp 命令](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#11cp-命令) + * [12.tail 命令](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#12tail-命令) + * [13.grep 命令](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#13grep-命令) + * [14.sed 命令](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#14sed-命令) + * [15.用 sed 命令将指定的路径 /usr/local/http 替换成为 /usr/src/local/http ?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#15用-sed-命令将指定的路径-usrlocalhttp-替换成为-usrsrclocalhttp-) + * [16.打印 /etc/ssh/sshd_config 的第一百行?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#16打印-etcsshsshd_config-的第一百行) + * [17.awk 命令](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#17awk-命令) + * [18.打印 /etc/passwd 的 1 到 3 行?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#18打印-etcpasswd-的-1-到-3-行) + * [19.vim 命令](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#19vim-命令) + * [20.diff 命令](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#20diff-命令) + * [21.sort 命令](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#21sort-命令) + * [22.xargs 命令](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#22xargs-命令) + * [23.把当前目录下所有后缀名为 .txt 的文件的权限修改为 777 ?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#23把当前目录下所有后缀名为-txt-的文件的权限修改为-777-) + * [24.tar 命令](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#24tar-命令) + * [25.gzip 命令](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#25gzip-命令) + * [26.bzip2 命令](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#26bzip2-命令) + * [27.unzip 命令](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#27unzip-命令) + * [28.export 命令](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#28export-命令) + * [29.yum 命令](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#29yum-命令) + * [30.rpm 命令](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#30rpm-命令) + * [31.shutdown 命令](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#31shutdown-命令) + * [32.service 命令](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#32service-命令) + * [33.whereis 命令](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#33whereis-命令) + * [34.用一条命令显示本机 eth0 网卡的 IP 地址,不显示其它字符?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#34用一条命令显示本机-eth0-网卡的-ip-地址不显示其它字符) + * [35.如何禁止服务器被 ping ?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#35如何禁止服务器被-ping-) + * [36.设置 DNS 需要修改哪个配置文件?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#36设置-dns-需要修改哪个配置文件) + * [37.在 Linux 下如何指定dns服务器,来解析某个域名?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#37在-linux-下如何指定dns服务器来解析某个域名) + * [参考资料](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Linux.md#参考资料) + + +* [Mycat](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mycat.md) + + * [1.Mycat是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mycat.md#1mycat是什么) + * [2.什么叫混合切分](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mycat.md#2什么叫混合切分) + * [3.在项目组中,切分后的库从哪里而来?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mycat.md#3在项目组中切分后的库从哪里而来) + * [4.搭建mycat的核心配置文件有哪些?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mycat.md#4搭建mycat的核心配置文件有哪些) + * [5.mycat分库可以分成100个库吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mycat.md#5mycat分库可以分成100个库吗) + * [6.进行库表拆分时,拆分规则怎么取舍?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mycat.md#6进行库表拆分时拆分规则怎么取舍) + * [7.Mycat中全局ID方案有哪些?程序自定义全局ID的方案有哪些?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mycat.md#7mycat中全局id方案有哪些程序自定义全局id的方案有哪些) + * [8.Mycat的在分库分表之后,它是怎么支持联表查询的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mycat.md#8mycat的在分库分表之后它是怎么支持联表查询的) + * [9.配置文件不会变多,配置的节点主机会变多?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mycat.md#9配置文件不会变多配置的节点主机会变多) + * [10.你们项目中分片的实现方式是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mycat.md#10你们项目中分片的实现方式是什么) + * [参考链接](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Mycat.md#参考链接) + +* [Nginx](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Nginx.md) + * [1.请解释一下什么是 Nginx ?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Nginx.md#1请解释一下什么是-nginx-) + * [2.为什么要用Nginx?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Nginx.md#2为什么要用nginx) + * [3.Nginx怎么处理请求的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Nginx.md#3nginx怎么处理请求的) + * [4.Nginx的优缺点?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Nginx.md#4nginx的优缺点) + * [5.Nginx应用场景?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Nginx.md#5nginx应用场景) + * [6.使用“反向代理服务器”的优点是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Nginx.md#6使用反向代理服务器的优点是什么) + * [7.列举Nginx服务器的最佳用途。](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Nginx.md#7列举nginx服务器的最佳用途) + * [8.请解释Nginx如何处理HTTP请求。](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Nginx.md#8请解释nginx如何处理http请求) + * [9.在Nginx中,如何使用未定义的服务器名称来阻止处理请求?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Nginx.md#9在nginx中如何使用未定义的服务器名称来阻止处理请求) + * [10.在Nginx中如何在URL中保留双斜线?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Nginx.md#10在nginx中如何在url中保留双斜线) + * [11.ngx_http_upstream_module的作用是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Nginx.md#11ngx_http_upstream_module的作用是什么) + * [12. fastcgi 与 cgi 的区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Nginx.md#12-fastcgi-与-cgi-的区别) + * [13. Nginx 常用命令?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Nginx.md#13-nginx-常用命令) + * [14.Nginx 常用配置?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Nginx.md#14nginx-常用配置) + * [15.请陈述stub_status和sub_filter指令的作用是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Nginx.md#15请陈述stub_status和sub_filter指令的作用是什么) + * [参考链接](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Nginx.md#参考链接) + + +* [RocketMQ](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RocketMQ.md) + * [1.RocketMQ中的Topic和JMS的queue有什么区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RocketMQ.md#1rocketmq中的topic和jms的queue有什么区别) + * [2.RocketMQ Broker中的消息被消费后会立即删除吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RocketMQ.md#2rocketmq-broker中的消息被消费后会立即删除吗) + * [3.RocketMQ消费模式有几种?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RocketMQ.md#3rocketmq消费模式有几种) + * [4.消费消息是push还是pull?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RocketMQ.md#4消费消息是push还是pull) + * [5.broker如何处理拉取请求的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RocketMQ.md#5broker如何处理拉取请求的) + * [6.RocketMQ如何做负载均衡?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RocketMQ.md#6rocketmq如何做负载均衡) + * [7.消息重复消费如何解决?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RocketMQ.md#7消息重复消费如何解决) + * [8.如何让RocketMQ保证消息的顺序消费?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RocketMQ.md#8如何让rocketmq保证消息的顺序消费) + * [9.RocketMQ如何保证消息不丢失?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RocketMQ.md#9rocketmq如何保证消息不丢失) + * [10.rocketMQ的消息堆积如何处理](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RocketMQ.md#10rocketmq的消息堆积如何处理) + * [11.RocketMQ在分布式事务支持这块机制的底层原理?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RocketMQ.md#11rocketmq在分布式事务支持这块机制的底层原理) + * [12.如果让你来动手实现一个分布式消息中间件,整体架构你会如何设计实现?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RocketMQ.md#12如果让你来动手实现一个分布式消息中间件整体架构你会如何设计实现) + * [13.高吞吐量下如何优化生产者和消费者的性能?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RocketMQ.md#13高吞吐量下如何优化生产者和消费者的性能) + * [14.再说说RocketMQ 是如何保证数据的高容错性的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RocketMQ.md#14再说说rocketmq-是如何保证数据的高容错性的) + * [15.任何一台Broker突然宕机了怎么办?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RocketMQ.md#15任何一台broker突然宕机了怎么办) + * [参考资料](https://github.com/JavaInterviewHub/JavaInterview/blob/main/RocketMQ.md#参考资料) + + +* [Servlet](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Servlet.md) + * [1.Servlet的生命周期?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Servlet.md#1servlet的生命周期) + * [2.Servlet和JSP的区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Servlet.md#2servlet和jsp的区别) + * [3.Servlet的基本架构](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Servlet.md#3servlet的基本架构) + * [4.什么情况下调用doGet()和doPost()?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Servlet.md#4什么情况下调用doget和dopost) + * [5.页面间对象传递的方法](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Servlet.md#5页面间对象传递的方法) + * [6.四种会话跟踪技术](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Servlet.md#6四种会话跟踪技术) + * [7.Request对象的主要方法](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Servlet.md#7request对象的主要方法) + * [8.如何配置Servlet的初始化参数?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Servlet.md#8如何配置servlet的初始化参数) + * [9.如何读取Servlet的初始化参数?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Servlet.md#9如何读取servlet的初始化参数) + * [10.init(ServletConfig)方法执行次数](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Servlet.md#10initservletconfig方法执行次数) + * [11.init(ServletConfig)方法与异常](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Servlet.md#11initservletconfig方法与异常) + * [参考链接](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Servlet.md#参考链接) + +* [Shiro](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Shiro.md) + * [1.什么是shiro](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Shiro.md#1什么是shiro) + * [2.解释下Shiro的核心概念:Subject、SecurityManager、Realm](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Shiro.md#2解释下shiro的核心概念subjectsecuritymanagerrealm) + * [3.Shiro的优点](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Shiro.md#3shiro的优点) + * [4.Shiro有哪些组件?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Shiro.md#4shiro有哪些组件) + * [5.说下Authentication 身份验证的流程](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Shiro.md#5说下authentication-身份验证的流程) + * [6.Authorization 授权的方式和流程是怎样的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Shiro.md#6authorization-授权的方式和流程是怎样的) + * [7.Cryptography 加密的过程是这样的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Shiro.md#7cryptography-加密的过程是这样的) + * [8.Realm 域如何使用?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Shiro.md#8realm-域如何使用) + * [9.shiro拦截器的执行流程](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Shiro.md#9shiro拦截器的执行流程) + * [10.Session Manager 会话管理介绍一下](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Shiro.md#10session-manager-会话管理介绍一下) + * [参考资料](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Shiro.md#参考资料) + +* [Tomcat](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Tomcat.md) + * [1.Tomcat的缺省端口是多少,怎么修改?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Tomcat.md#1tomcat的缺省端口是多少怎么修改) + * [2.tomcat 有哪几种Connector 运行模式(优化)?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Tomcat.md#2tomcat-有哪几种connector-运行模式优化) + * [3.Tomcat有几种部署方式?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Tomcat.md#3tomcat有几种部署方式) + * [4.tomcat容器是如何创建servlet类实例?用到了什么原理?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Tomcat.md#4tomcat容器是如何创建servlet类实例用到了什么原理) + * [5.tomcat 如何优化?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Tomcat.md#5tomcat-如何优化) + * [6.tomcat内存调优了解过吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Tomcat.md#6tomcat内存调优了解过吗) + * [7.tomcat垃圾回收策略调优了解吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Tomcat.md#7tomcat垃圾回收策略调优了解吗) + * [8.tomcat共享session如何处理?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Tomcat.md#8tomcat共享session如何处理) + * [9.如何添加JMS远程监控](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Tomcat.md#9如何添加jms远程监控) + * [10.Tomcat一个请求的完整过程](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Tomcat.md#10tomcat一个请求的完整过程) + * [参考资料](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Tomcat.md#参考资料) + +* [密码学](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%AF%86%E7%A0%81%E5%AD%A6.md) + * [1.Java中常用的加密算法](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%AF%86%E7%A0%81%E5%AD%A6.md#1java中常用的加密算法) + * [2.什么是base64](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%AF%86%E7%A0%81%E5%AD%A6.md#2什么是base64) + * [3.MD5](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%AF%86%E7%A0%81%E5%AD%A6.md#3md5) + * [4.SHA](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%AF%86%E7%A0%81%E5%AD%A6.md#4sha) + * [5.HMAC](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%AF%86%E7%A0%81%E5%AD%A6.md#5hmac) + * [6.密码的常用术语](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%AF%86%E7%A0%81%E5%AD%A6.md#6密码的常用术语) + * [7.单向加密算法](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%AF%86%E7%A0%81%E5%AD%A6.md#7单向加密算法) + * [8.复杂的对称加密(DES、PBE)、非对称加密算法](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%AF%86%E7%A0%81%E5%AD%A6.md#8复杂的对称加密despbe非对称加密算法) + * [9.非对称加密](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%AF%86%E7%A0%81%E5%AD%A6.md#9非对称加密) + * [10.DES](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%AF%86%E7%A0%81%E5%AD%A6.md#10des) + * [参考链接](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E5%AF%86%E7%A0%81%E5%AD%A6.md#参考链接) + + + +* [操作系统](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.md) + * [1.说下进程的状态](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.md#1说下进程的状态) + * [2.说下进程和线程的联系与区别](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.md#2说下进程和线程的联系与区别) + * [3.为什么进程上下文切换比线程上下文切换代价高?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.md#3为什么进程上下文切换比线程上下文切换代价高) + * [4.说下你对进程同步的理解](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.md#4说下你对进程同步的理解) + * [5.进程的通信方式有哪些](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.md#5进程的通信方式有哪些) + * [6.进程调度的种类有哪些?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.md#6进程调度的种类有哪些) + * [7.非抢占式调度与抢占式调度的区别是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.md#7非抢占式调度与抢占式调度的区别是什么) + * [8.说下你知道的调度算法](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.md#8说下你知道的调度算法) + * [9.一个程序从开始运行到结束的完整过程(四个过程)](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.md#9一个程序从开始运行到结束的完整过程四个过程) + * [10.死锁出现的条件?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.md#10死锁出现的条件) + * [11.如何处理死锁问题](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.md#11如何处理死锁问题) + * [12.如何处理死锁问题](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.md#12如何处理死锁问题) + * [13.什么是临界资源](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.md#13什么是临界资源) + * [14.介绍一下内存池、进程池、线程池](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.md#14介绍一下内存池进程池线程池) + * [15.动态链接库与静态链接库的区别](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.md#15动态链接库与静态链接库的区别) + * [16.说下对虚拟内存的理解](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.md#16说下对虚拟内存的理解) + * [17.页面置换算法了解多少?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.md#17页面置换算法了解多少) + * [18.中断与系统调用了解吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.md#18中断与系统调用了解吗) + * [19.用户态切换到内核态的方式有哪些?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.md#19用户态切换到内核态的方式有哪些) + * [20.用户态和核心态(内核态)之间的区别是什么呢?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.md#20用户态和核心态内核态之间的区别是什么呢) + * [21.内部碎片与外部碎片分别是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.md#21内部碎片与外部碎片分别是什么) + * [22.系统调用与库函数的区别](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.md#22系统调用与库函数的区别) + * [23.守护、僵尸、孤儿进程的概念](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.md#23守护僵尸孤儿进程的概念) + * [参考资料](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E6%93%8D%E4%BD%9C%E7%B3%BB%E7%BB%9F.md#参考资料) + + + +* [编译原理](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86.md) + * [1.词法分析](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86.md#1词法分析) + * [2.语法分析](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86.md#2语法分析) + * [3.语义分析](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86.md#3语义分析) + * [4.中间代码生成](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86.md#4中间代码生成) + * [5.目标代码生成](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86.md#5目标代码生成) + * [6.表格管理程序](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86.md#6表格管理程序) + * [7.出错处理](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86.md#7出错处理) + * [8.句型、句子、语言](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86.md#8句型句子语言) + * [9.有穷自动机(有限自动机)](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86.md#9有穷自动机有限自动机) + * [10.全局优化](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86.md#10全局优化) + * [参考链接](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E7%BC%96%E8%AF%91%E5%8E%9F%E7%90%86.md#参考链接) + + +* [计算机组成原理](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86.md) + * [1.计算机系统由哪两部分组成?计算机系统性能取决于什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86.md#1计算机系统由哪两部分组成计算机系统性能取决于什么) + * [2.计算机系统5层层次结构从下到上由哪五层组成?哪些是物理机,哪些是虚拟机?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86.md#2计算机系统5层层次结构从下到上由哪五层组成哪些是物理机哪些是虚拟机) + * [3.在计算机系统结构中,什么是翻译?什么是解释?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86.md#3在计算机系统结构中什么是翻译什么是解释) + * [4.什么是计算机体系结构?什么是计算机组成?以乘法指令为例说明二者区别。](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86.md#4什么是计算机体系结构什么是计算机组成以乘法指令为例说明二者区别) + * [5.冯诺依曼机器的主要特点?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86.md#5冯诺依曼机器的主要特点) + * [6.程序访问的局部性](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86.md#6程序访问的局部性) + * [7.字长](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86.md#7字长) + * [8.Cache的基本工作原理](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86.md#8cache的基本工作原理) + * [9.Cache和主存之间的映射方式](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86.md#9cache和主存之间的映射方式) + * [10. Cache中主存块的替换算法](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86.md#10-cache中主存块的替换算法) + * [11.二进制一般使用什么方法转换成十进制?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86.md#11二进制一般使用什么方法转换成十进制) + * [12.计算机直接使用原码计算有什么缺点?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86.md#12计算机直接使用原码计算有什么缺点) + * [13.请计算12、124、1023、-1、-127的二进制原码。](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86.md#13请计算121241023-1-127的二进制原码) + * [14.计算机的补码解决了什么问题?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86.md#14计算机的补码解决了什么问题) + * [15.什么是溢出?什么是上溢?什么是下溢?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86.md#15什么是溢出什么是上溢什么是下溢) + * [16.浮点数之间做加减法运算需要几个步骤?每个步骤都是必须的吗?为什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86.md#16浮点数之间做加减法运算需要几个步骤每个步骤都是必须的吗为什么) + * [17.虚拟存储器的基本概念](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86.md#17虚拟存储器的基本概念) + * [18.页式虚拟存储器](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86.md#18页式虚拟存储器) + * [19.段式虚拟存储器](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86.md#19段式虚拟存储器) + * [20.段页式虚拟存储器](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86.md#20段页式虚拟存储器) + * [参考链接](https://github.com/JavaInterviewHub/JavaInterview/blob/main/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%BB%84%E6%88%90%E5%8E%9F%E7%90%86.md#参考链接) + + + +* [Docker](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Docker.md) + * [1.什么Docker](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Docker.md#1什么docker) + * [2.Docker与虚拟机有何不同](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Docker.md#2docker与虚拟机有何不同) + * [3.什么是Docker镜像](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Docker.md#3什么是docker镜像) + * [4.什么是Docker容器](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Docker.md#4什么是docker容器) + * [5.Docker容器有几种状态](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Docker.md#5docker容器有几种状态) + * [6.DockerFile中最常见的指定是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Docker.md#6dockerfile中最常见的指定是什么) + * [7.DockerFile中的命令COPY和ADD命令有什么区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Docker.md#7dockerfile中的命令copy和add命令有什么区别) + * [8.Docker的常用命令?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Docker.md#8docker的常用命令) + * [9.容器与主机之间的数据拷贝命令?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Docker.md#9容器与主机之间的数据拷贝命令) + * [10.启动nginx容器(随机端口映射),并挂载本地文件目录到容器html的命令?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Docker.md#10启动nginx容器随机端口映射并挂载本地文件目录到容器html的命令) + * [11.如何使用 Docker 技术创建与环境无关的容器系统?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Docker.md#11如何使用-docker-技术创建与环境无关的容器系统) + * [12.有什么方法确定一个 Docker 容器运行状态](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Docker.md#12有什么方法确定一个-docker-容器运行状态) + * [13. Docker Image 和 Docker Layer (层) 有什么不同](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Docker.md#13-docker-image-和-docker-layer-层-有什么不同) + * [14.如何停止所有正在运行的容器?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Docker.md#14如何停止所有正在运行的容器) + * [15.如何清理批量后台停止的容器?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Docker.md#15如何清理批量后台停止的容器) + * [16.如何临时退出一个正在交互的容器的终端,而不终止它?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Docker.md#16如何临时退出一个正在交互的容器的终端而不终止它) + * [17.Docker 群(Swarm)是什么](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Docker.md#17docker-群swarm是什么) + * [18.在使用 Docker 技术的产品中如何监控其运行](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Docker.md#18在使用-docker-技术的产品中如何监控其运行) + * [19.什么是孤儿卷及如何删除它?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Docker.md#19什么是孤儿卷及如何删除它) + * [20.在 Windows 系统上可以运行原生的 Docker 容器吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Docker.md#20在-windows-系统上可以运行原生的-docker-容器吗) + * [21.在 非 Linux 操作系统平台上如何运行 Docker ?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Docker.md#21在-非-linux-操作系统平台上如何运行-docker-) + * [参考链接](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Docker.md#参考链接) + + +* [Dubbo](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Dubbo.md) + * [1.Dubbo是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Dubbo.md#1dubbo是什么) + * [2.为什么要用Dubbo?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Dubbo.md#2为什么要用dubbo) + * [3.Dubbo 和 Dubbox 有什么区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Dubbo.md#3dubbo-和-dubbox-有什么区别) + * [4.dubbo都支持什么协议,推荐用哪种?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Dubbo.md#4dubbo都支持什么协议推荐用哪种) + * [5.Dubbo需要 Web 容器吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Dubbo.md#5dubbo需要-web-容器吗) + * [6.Dubbo内置了哪几种服务容器?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Dubbo.md#6dubbo内置了哪几种服务容器) + * [7.Dubbo默认使用什么注册中心,还有别的选择吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Dubbo.md#7dubbo默认使用什么注册中心还有别的选择吗) + * [8.Dubbo有哪几种配置方式?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Dubbo.md#8dubbo有哪几种配置方式) + * [9.在 Provider 上可以配置的 Consumer 端的属性有哪些?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Dubbo.md#9在-provider-上可以配置的-consumer-端的属性有哪些) + * [10.Dubbo启动时如果依赖的服务不可用会怎样?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Dubbo.md#10dubbo启动时如果依赖的服务不可用会怎样) + * [11.Dubbo推荐使用什么序列化框架,你知道的还有哪些?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Dubbo.md#11dubbo推荐使用什么序列化框架你知道的还有哪些) + * [12.Dubbo默认使用的是什么通信框架,还有别的选择吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Dubbo.md#12dubbo默认使用的是什么通信框架还有别的选择吗) + * [13.注册了多个同一样的服务,如果测试指定的某一个服务呢?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Dubbo.md#13注册了多个同一样的服务如果测试指定的某一个服务呢) + * [14.Dubbo支持服务多协议吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Dubbo.md#14dubbo支持服务多协议吗) + * [15.当一个服务接口有多种实现时怎么做?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Dubbo.md#15当一个服务接口有多种实现时怎么做) + * [16.服务上线怎么兼容旧版本?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Dubbo.md#16服务上线怎么兼容旧版本) + * [17.Dubbo可以对结果进行缓存吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Dubbo.md#17dubbo可以对结果进行缓存吗) + * [18.Dubbo服务之间的调用是阻塞的吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Dubbo.md#18dubbo服务之间的调用是阻塞的吗) + * [19.Dubbo支持分布式事务吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Dubbo.md#19dubbo支持分布式事务吗) + * [20.Dubbo支持服务降级吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Dubbo.md#20dubbo支持服务降级吗) + * [21.Dubbo如何优雅停机?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Dubbo.md#21dubbo如何优雅停机) + * [22.服务提供者能实现失效踢出是什么原理?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Dubbo.md#22服务提供者能实现失效踢出是什么原理) + * [23.如何解决服务调用链过长的问题?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Dubbo.md#23如何解决服务调用链过长的问题) + * [24.服务读写推荐的容错策略是怎样的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Dubbo.md#24服务读写推荐的容错策略是怎样的) + * [25.Dubbo必须依赖的包有哪些?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Dubbo.md#25dubbo必须依赖的包有哪些) + * [26.Dubbo的管理控制台能做什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Dubbo.md#26dubbo的管理控制台能做什么) + * [27.说说 Dubbo 服务暴露的过程。](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Dubbo.md#27说说-dubbo-服务暴露的过程) + + + + +* [Elasticsearch](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Elasticsearch.md) + * [1.为什么要使用Elasticsearch?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Elasticsearch.md#1为什么要使用elasticsearch) + * [2.Elasticsearch是如何实现Master选举的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Elasticsearch.md#2elasticsearch是如何实现master选举的) + * [3.Elasticsearch中的节点(比如共20个),其中的10个选了一个master,另外10个选了另一个master,怎么办?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Elasticsearch.md#3elasticsearch中的节点比如共20个其中的10个选了一个master另外10个选了另一个master怎么办) + * [4.详细描述一下Elasticsearch索引文档的过程。](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Elasticsearch.md#4详细描述一下elasticsearch索引文档的过程) + * [5.详细描述一下Elasticsearch更新和删除文档的过程](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Elasticsearch.md#5详细描述一下elasticsearch更新和删除文档的过程) + * [6.详细描述一下Elasticsearch搜索的过程](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Elasticsearch.md#6详细描述一下elasticsearch搜索的过程) + * [7.Elasticsearch对于大数据量(上亿量级)的聚合如何实现?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Elasticsearch.md#7elasticsearch对于大数据量上亿量级的聚合如何实现) + * [8.在并发情况下,Elasticsearch如果保证读写一致?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Elasticsearch.md#8在并发情况下elasticsearch如果保证读写一致) + * [9.ElasticSearch中的集群、节点、索引、文档、类型是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Elasticsearch.md#9elasticsearch中的集群节点索引文档类型是什么) + * [10.ElasticSearch中的分片是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Elasticsearch.md#10elasticsearch中的分片是什么) + * [11.什么是ElasticSearch?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Elasticsearch.md#11什么是elasticsearch) + * [12.Elasticsearch中的倒排索引是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Elasticsearch.md#12elasticsearch中的倒排索引是什么) + * [13.Elasticsearch中的分析器是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Elasticsearch.md#13elasticsearch中的分析器是什么) + * [14.说说Elasticsearch常用的调优手段?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Elasticsearch.md#14说说elasticsearch常用的调优手段) + * [15.Elasticsearch 在部署时,对 Linux 的设置有哪些优化方法?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Elasticsearch.md#15elasticsearch-在部署时对-linux-的设置有哪些优化方法) + * [16.客户端在和集群连接时,如何选择特定的节点执行请求?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Elasticsearch.md#16客户端在和集群连接时如何选择特定的节点执行请求) + * [17.在 Elasticsearch 中,是怎么根据一个词找到对应的倒排索引的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Elasticsearch.md#17在-elasticsearch-中是怎么根据一个词找到对应的倒排索引的) + * [18.对于 GC 方面,在使用 Elasticsearch 时要注意什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Elasticsearch.md#18对于-gc-方面在使用-elasticsearch-时要注意什么) + * [19.在并发情况下,Elasticsearch 如果保证读写一致?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Elasticsearch.md#19在并发情况下elasticsearch-如果保证读写一致) + * [20.如何监控 Elasticsearch 集群状态?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Elasticsearch.md#20如何监控-elasticsearch-集群状态) + + + + +* [Java集合](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%9B%86%E5%90%88.md) + * [1.常见的集合有哪些?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%9B%86%E5%90%88.md#1常见的集合有哪些) + * [2.常见的集合底层实现](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%9B%86%E5%90%88.md#2常见的集合底层实现) + * [3.HashMap与HashTable的区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%9B%86%E5%90%88.md#3hashmap与hashtable的区别) + * [4.ConcurrentHashMap和Hashtable的区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%9B%86%E5%90%88.md#4concurrenthashmap和hashtable的区别) + * [5.ConcurrentHashMap实现原理](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%9B%86%E5%90%88.md#5concurrenthashmap实现原理) + * [6.ArrayList 和 Vector 的区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%9B%86%E5%90%88.md#6arraylist-和-vector-的区别) + * [7.ArrayList和LinkedList的区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%9B%86%E5%90%88.md#7arraylist和linkedlist的区别) + * [8.HashMap 默认的初始化长度是多少?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%9B%86%E5%90%88.md#8hashmap-默认的初始化长度是多少) + * [9.谈谈对HashMap 构造方法中初始容量、加载因子的理解](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%9B%86%E5%90%88.md#9谈谈对hashmap-构造方法中初始容量加载因子的理解) + * [10.Java集合框架是什么?说出一些集合框架的优点?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%9B%86%E5%90%88.md#10java集合框架是什么说出一些集合框架的优点) + * [11.集合框架中的泛型有什么优点?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%9B%86%E5%90%88.md#11集合框架中的泛型有什么优点) + * [12.为何Collection不从Cloneable和Serializable接口继承?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%9B%86%E5%90%88.md#12为何collection不从cloneable和serializable接口继承) + * [13.为何Map接口不继承Collection接口?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%9B%86%E5%90%88.md#13为何map接口不继承collection接口) + * [14.Iterator是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%9B%86%E5%90%88.md#14iterator是什么) + * [15.Enumeration和Iterator接口的区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%9B%86%E5%90%88.md#15enumeration和iterator接口的区别) + * [16.Iterater和ListIterator之间有什么区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%9B%86%E5%90%88.md#16iterater和listiterator之间有什么区别) + * [17.fail-fast与fail-safe有什么区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%9B%86%E5%90%88.md#17fail-fast与fail-safe有什么区别) + * [18.hashCode()和equals()方法有何重要性?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%9B%86%E5%90%88.md#18hashcode和equals方法有何重要性) + * [19.我们能否使用任何类作为Map的key?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%9B%86%E5%90%88.md#19我们能否使用任何类作为map的key) + * [20.如何决定选用HashMap还是TreeMap?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%9B%86%E5%90%88.md#20如何决定选用hashmap还是treemap) + * [21.哪些集合类提供对元素的随机访问?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%9B%86%E5%90%88.md#21哪些集合类提供对元素的随机访问) + * [22.BlockingQueue是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%9B%86%E5%90%88.md#22blockingqueue是什么) + * [23.队列和栈是什么,列出它们的区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%9B%86%E5%90%88.md#23队列和栈是什么列出它们的区别) + * [24.Collections类是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%9B%86%E5%90%88.md#24collections类是什么) + * [25.Comparable和Comparator接口有何区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%9B%86%E5%90%88.md#25comparable和comparator接口有何区别) + + +* [Java高并发](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%AB%98%E5%B9%B6%E5%8F%91.md) + * [1.什么是进程](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%AB%98%E5%B9%B6%E5%8F%91.md#1什么是进程) + * [2.什么是线程](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%AB%98%E5%B9%B6%E5%8F%91.md#2什么是线程) + * [3.进程间如何通讯](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%AB%98%E5%B9%B6%E5%8F%91.md#3进程间如何通讯) + * [4.线程间如何通讯](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%AB%98%E5%B9%B6%E5%8F%91.md#4线程间如何通讯) + * [5.同步和异步有何不同,在什么情况下分别使用它们?举例说明](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%AB%98%E5%B9%B6%E5%8F%91.md#5同步和异步有何不同在什么情况下分别使用它们举例说明) + * [6.进程调度算法](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%AB%98%E5%B9%B6%E5%8F%91.md#6进程调度算法) + * [7.Java中Unsafe类详解](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%AB%98%E5%B9%B6%E5%8F%91.md#7java中unsafe类详解) + * [8.如何测试并发量?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%AB%98%E5%B9%B6%E5%8F%91.md#8如何测试并发量) + * [9.有三个线程T1,T2,T3,怎么确保它们按顺序执行?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%AB%98%E5%B9%B6%E5%8F%91.md#9有三个线程t1t2t3怎么确保它们按顺序执行) + * [10.什么是线程调度器(Thread Scheduler)和时间分片(Time Slicing)?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%AB%98%E5%B9%B6%E5%8F%91.md#10什么是线程调度器thread-scheduler和时间分片time-slicing) + * [11.数据库死锁?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%AB%98%E5%B9%B6%E5%8F%91.md#11数据库死锁) + * [12.什么是锁顺序死锁?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%AB%98%E5%B9%B6%E5%8F%91.md#12什么是锁顺序死锁) + * [13.死锁的避免与诊断?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%AB%98%E5%B9%B6%E5%8F%91.md#13死锁的避免与诊断) + * [14.常见的并发容器?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%AB%98%E5%B9%B6%E5%8F%91.md#14常见的并发容器) + * [15.常见的同步工具类?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%AB%98%E5%B9%B6%E5%8F%91.md#15常见的同步工具类) + * [16.Nginx多进程模型是如何实现高并发的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%AB%98%E5%B9%B6%E5%8F%91.md#16nginx多进程模型是如何实现高并发的) + * [17.CopyOnWriteArrayList](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%AB%98%E5%B9%B6%E5%8F%91.md#17copyonwritearraylist) + * [18.AQS](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%AB%98%E5%B9%B6%E5%8F%91.md#18aqs) + * [19.Java里的阻塞队列](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%AB%98%E5%B9%B6%E5%8F%91.md#19java里的阻塞队列) + * [20.Fork/Join框架](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Java%E9%AB%98%E5%B9%B6%E5%8F%91.md#20forkjoin框架) + + + +* [Jenkins](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Jenkins.md) + * [1.什么是Jenkins?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Jenkins.md#1什么是jenkins) + * [2.Maven, Ant和Jenkins有什么区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Jenkins.md#2maven-ant和jenkins有什么区别) + * [3.Jenkins支持哪些SCM工具?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Jenkins.md#3jenkins支持哪些scm工具) + * [4.在Jenkins中, 什么是持续集成?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Jenkins.md#4在jenkins中-什么是持续集成) + * [5.Jenkins的优势是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Jenkins.md#5jenkins的优势是什么) + * [6.可以使用哪些命令手动启动Jenkins?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Jenkins.md#6可以使用哪些命令手动启动jenkins) + * [7.如何在Jenkins中创建备份和复制文件?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Jenkins.md#7如何在jenkins中创建备份和复制文件) + * [8.如何通过Jenkins克隆Git存储库?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Jenkins.md#8如何通过jenkins克隆git存储库) + * [9.什么是jenkinsfile?为什么使用jenkinsfile](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Jenkins.md#9什么是jenkinsfile为什么使用jenkinsfile) + * [10.什么是Blue Ocean](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Jenkins.md#10什么是blue-ocean) + + +* [Kubernetes](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kubernetes.md) + * [1.什么是Kubernetes?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kubernetes.md#1什么是kubernetes) + * [2.Kubernetes与Docker有什么关系?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kubernetes.md#2kubernetes与docker有什么关系) + * [3.什么是Container Orchestration?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kubernetes.md#3什么是container-orchestration) + * [4.Kubernetes如何简化容器化部署?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kubernetes.md#4kubernetes如何简化容器化部署) + * [5.什么是Google容器引擎?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kubernetes.md#5什么是google容器引擎) + * [6.什么是Heapster?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kubernetes.md#6什么是heapster) + * [7.什么是Minikube?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kubernetes.md#7什么是minikube) + * [8.什么是Kubectl?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kubernetes.md#8什么是kubectl) + * [9.什么是Kubelet?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kubernetes.md#9什么是kubelet) + * [10.Kubernetes Architecture的不同组件有哪些?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kubernetes.md#10kubernetes-architecture的不同组件有哪些) + * [11.你对Kube-proxy有什么了解?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kubernetes.md#11你对kube-proxy有什么了解) + * [12.您能否介绍一下Kubernetes中主节点的工作情况?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kubernetes.md#12您能否介绍一下kubernetes中主节点的工作情况) + * [13.kube-apiserver和kube-scheduler的作用是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kubernetes.md#13kube-apiserver和kube-scheduler的作用是什么) + * [14.你能简要介绍一下Kubernetes控制管理器吗?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kubernetes.md#14你能简要介绍一下kubernetes控制管理器吗) + * [15.什么是etcd?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kubernetes.md#15什么是etcd) + * [16.你对Kubernetes的负载均衡器有什么了解?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kubernetes.md#16你对kubernetes的负载均衡器有什么了解) + * [17.什么是Ingress网络,它是如何工作的?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kubernetes.md#17什么是ingress网络它是如何工作的) + * [18.您对云控制器管理器有何了解?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kubernetes.md#18您对云控制器管理器有何了解) + * [19.什么是Container资源监控?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kubernetes.md#19什么是container资源监控) + * [20.Replica Set 和 Replication Controller之间有什么区别?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Kubernetes.md#20replica-set-和-replication-controller之间有什么区别) + + +* [Maven](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Maven.md) + * [1.maven是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Maven.md#1maven是什么) + * [2.使用Maven好处](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Maven.md#2使用maven好处) + * [3.Maven的坐标和依赖](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Maven.md#3maven的坐标和依赖) + * [4.Maven的⽣命周期](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Maven.md#4maven的命周期) + * [5.你们项目为什么选用 Maven 进行构建?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Maven.md#5你们项目为什么选用-maven-进行构建) + * [6.Maven 规约是什么?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Maven.md#6maven-规约是什么) + * [7.Maven 常用命令](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Maven.md#7maven-常用命令) + * [8.Maven 有哪些优点和缺点](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Maven.md#8maven-有哪些优点和缺点) + * [9.Maven 版本规则?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Maven.md#9maven-版本规则) + * [10.对于一个多模块项目,如果管理项目依赖的版本?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Maven.md#10对于一个多模块项目如果管理项目依赖的版本) + * [11.Maven 依赖原则?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Maven.md#11maven-依赖原则) + * [12.如何解决 jar 冲突?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Maven.md#12如何解决-jar-冲突) + * [13.什么是 Maven 插件?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Maven.md#13什么是-maven-插件) + * [14.Maven依赖冲突](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Maven.md#14maven依赖冲突) + * [15.依赖的解析机制](https://github.com/JavaInterviewHub/JavaInterview/blob/main/Maven.md#15依赖的解析机制) + + +* [MongoDB](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MongoDB.md) + * [1.什么是MongoDB?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MongoDB.md#1什么是mongodb) + * [2.MongoDB的优势有哪些](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MongoDB.md#2mongodb的优势有哪些) + * [3.什么是集合(表)?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MongoDB.md#3什么是集合表) + * [4.什么是文档(记录)](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MongoDB.md#4什么是文档记录) + * [5.为什么用MOngoDB?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MongoDB.md#5为什么用mongodb) + * [6.在哪些场景使用MongoDB](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MongoDB.md#6在哪些场景使用mongodb) + * [7.MongoDB中的命名空间是什么意思?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MongoDB.md#7mongodb中的命名空间是什么意思) + * [8.MongoDB中的分片什么意思](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MongoDB.md#8mongodb中的分片什么意思) + * [9.为什么要在MongoDB中使用分析器](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MongoDB.md#9为什么要在mongodb中使用分析器) + * [10.MongoDB支持主键外键关系吗](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MongoDB.md#10mongodb支持主键外键关系吗) + * [11.MongoDB支持哪些数据类型](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MongoDB.md#11mongodb支持哪些数据类型) + * [12.为什么要在MongoDB中用"Code"数据类型](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MongoDB.md#12为什么要在mongodb中用code数据类型) + * [13.为什么要在MongoDB中用"Regular Expression"数据类型](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MongoDB.md#13为什么要在mongodb中用regular-expression数据类型) + * [14.为什么在MongoDB中使用"Object ID"数据类型](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MongoDB.md#14为什么在mongodb中使用object-id数据类型) + * [15."ObjectID"有哪些部分组成](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MongoDB.md#15objectid有哪些部分组成) + * [16.在MongoDb中什么是索引](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MongoDB.md#16在mongodb中什么是索引) + * [17.在MongoDB中什么是副本集](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MongoDB.md#17在mongodb中什么是副本集) + * [18.MongoDB支持存储过程吗?如果支持的话,怎么用?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MongoDB.md#18mongodb支持存储过程吗如果支持的话怎么用) + * [19.如何理解MongoDB中的GridFS机制,MongoDB为何使用GridFS来存储文件?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MongoDB.md#19如何理解mongodb中的gridfs机制mongodb为何使用gridfs来存储文件) + * [20.为什么MongoDB的数据文件很大?](https://github.com/JavaInterviewHub/JavaInterview/blob/main/MongoDB.md#20为什么mongodb的数据文件很大) + + + + + + diff --git a/RabbitMQ.md b/RabbitMQ.md new file mode 100644 index 0000000..85c68b7 --- /dev/null +++ b/RabbitMQ.md @@ -0,0 +1,280 @@ +## RabbitMQ + + +* [1.什么是RabbitMQ?为什么使用RabbitMQ?](#1什么是rabbitmq为什么使用rabbitmq) +* [2.RabbitMQ有什么优缺点?](#2rabbitmq有什么优缺点) +* [3.什么是元数据?元数据分为哪些类型?包括哪些内容?与cluster相关的元数据有哪些?元数据是如何保存的?元数据在cluster中是如何分布的?](#3什么是元数据元数据分为哪些类型包括哪些内容与cluster相关的元数据有哪些元数据是如何保存的元数据在cluster中是如何分布的) +* [4.在单node系统和多node构成的cluster系统中声明queue、exchange,以及进行binding会有什么不同?](#4在单node系统和多node构成的cluster系统中声明queueexchange以及进行binding会有什么不同) +* [5.客户端连接到cluster中的任意node上是否都能正常工作?](#5客户端连接到cluster中的任意node上是否都能正常工作) +* [6.若cluster中拥有某个queue的owner node失效了,且该queue 被声明具有durable属性,是否能够成功从其他node上重新声明该 queue ?](#6若cluster中拥有某个queue的owner-node失效了且该queue-被声明具有durable属性是否能够成功从其他node上重新声明该-queue-) +* [7.RabbitMQ 的消息是怎么发送的?](#7rabbitmq-的消息是怎么发送的) +* [8.RabbitMQ 怎么避免消息丢失?](#8rabbitmq-怎么避免消息丢失) +* [9.RabbitMQ的使用场景有哪些?](#9rabbitmq的使用场景有哪些) +* [10.RabbitMQ有哪些重要的角色?](#10rabbitmq有哪些重要的角色) +* [11.如何确保消息正确地发送至RabbitMQ?如何确保消息接收方消费了消息?](#11如何确保消息正确地发送至rabbitmq如何确保消息接收方消费了消息) +* [12.要保证消息持久化成功的条件有哪些?](#12要保证消息持久化成功的条件有哪些) +* [13.RabbitMQ 有几种广播类型?](#13rabbitmq-有几种广播类型) +* [14.vhost 是什么?起什么作用?](#14vhost-是什么起什么作用) +* [15.消息基于什么传输?](#15消息基于什么传输) +* [16.消息如何分发?](#16消息如何分发) +* [17.消息怎么路由?](#17消息怎么路由) +* [18.如何确保消息接收方消费了消息?](#18如何确保消息接收方消费了消息) +* [19.如何避免消息重复投递或重复消费?](#19如何避免消息重复投递或重复消费) +* [20.死信队列和延迟队列的使用](#20死信队列和延迟队列的使用) +* [参考链接:](#参考链接) + + + +#### 1.什么是RabbitMQ?为什么使用RabbitMQ? + +RabbitMQ是一款开源的,Erlang编写的,基于AMQP协议的,消息中间件; + +可以用它来:解耦、异步、削峰。 + +#### 2.RabbitMQ有什么优缺点? + +优点:解耦、异步、削峰; + +缺点:降低了系统的稳定性:本来系统运行好好的,现在你非要加入个消息队列进去,那消息队列挂了,你的系统不是呵呵了。因此,系统可用性会降低; + +增加了系统的复杂性:加入了消息队列,要多考虑很多方面的问题,比如:一致性问题、如何保证消息不被重复消费、如何保证消息可靠性传输等。因此,需要考虑的东西更多,复杂性增大。 + +#### 3.什么是元数据?元数据分为哪些类型?包括哪些内容?与cluster相关的元数据有哪些?元数据是如何保存的?元数据在cluster中是如何分布的? + +在非cluster模式下,元数据主要分为Queue元数据(queue名字和属性 等)、Exchange元数据(exchange名字、类型和属性等)、Binding元数据 (存放路由关系的查找表)、Vhost元数据(vhost范围内针对前三者的名字空 间约束和安全属性设置)。 + +在cluster模式下,还包括cluster中node位置信息和node关系信息。元数据按照erlang node的类型确定是仅保存于RAM中,还是同时保存在RAM和disk上。元数据在cluster中是全node 分布的。 + +#### 4.在单node系统和多node构成的cluster系统中声明queue、exchange,以及进行binding会有什么不同? + +当你在单node上声明queue时,只要该node上相关元数据进行了变 更,你就会得到Queue.Declare-ok回应;而在cluster上声明queue,则要 求cluster上的全部node都要进行元数据成功更新,才会得到 Queue.Declare-ok回应。另外,若node类型为RAM node则变更的数据 仅保存在内存中,若类型为disk node则还要变更保存在磁盘上的数据。 + +#### 5.客户端连接到cluster中的任意node上是否都能正常工作? + +是的。客户端感觉不到有何不同。 + +#### 6.若cluster中拥有某个queue的owner node失效了,且该queue 被声明具有durable属性,是否能够成功从其他node上重新声明该 queue ? + +不能,在这种情况下,将得到404 NOT_FOUND错误。只能等queue所 属的node恢复后才能使用该queue。但若该queue本身不具有durable 属性,则可在其他node上重新声明。 + +#### 7.RabbitMQ 的消息是怎么发送的? + +首先客户端必须连接到 RabbitMQ 服务器才能发布和消费消息,客户端和 rabbit server 之间会创建一个 tcp 连接,一旦 tcp 打开并通过了认证(认证就是你发送给 rabbit 服务器的用户名和密码),你的客户端和 RabbitMQ 就创建了一条 amqp 信道(channel),信道是创建在“真实” tcp 上的虚拟连接,amqp 命令都是通过信道发送出去的,每个信道都会有一个唯一的 id,不论是发布消息,订阅队列都是通过这个信道完成的。 + +#### 8.RabbitMQ 怎么避免消息丢失? + +①消息持久化; + +②ACK确认机制; + +③设置集群镜像模式; + +④消息补偿机制。 + +#### 9.RabbitMQ的使用场景有哪些? + +①跨系统的异步通信,所有需要异步交互的地方都可以使用消息队列。就像我们除了打电话(同步)以外,还需要发短信,发电子邮件(异步)的通讯方式。 + +②多个应用之间的耦合,由于消息是平台无关和语言无关的,而且语义上也不再是函数调用,因此更适合作为多个应用之间的松耦合的接口。基于消息队列的耦合,不需要发送方和接收方同时在线。在企业应用集成(EAI)中,文件传输,共享数据库,消息队列,远程过程调用都可以作为集成的方法。 + +③应用内的同步变异步,比如订单处理,就可以由前端应用将订单信息放到队列,后端应用从队列里依次获得消息处理,高峰时的大量订单可以积压在队列里慢慢处理掉。由于同步通常意味着阻塞,而大量线程的阻塞会降低计算机的性能。 + +④消息驱动的架构(EDA),系统分解为消息队列,和消息制造者和消息消费者,一个处理流程可以根据需要拆成多个阶段(Stage),阶段之间用队列连接起来,前一个阶段处理的结果放入队列,后一个阶段从队列中获取消息继续处理。 + +⑤应用需要更灵活的耦合方式,如发布订阅,比如可以指定路由规则。 + +⑥跨局域网,甚至跨城市的通讯(CDN行业),比如北京机房与广州机房的应用程序的通信。 + +#### 10.RabbitMQ有哪些重要的角色? + +RabbitMQ中重要的角色有:生产者、消费者和代理: + +①生产者:消息的创建者,负责创建和推送数据到消息服务器; + +②消费者:消息的接收方,用于处理数据和确认消息; + +③代理:就是RabbitMQ本身,用于扮演“快递”的角色,本身不生产消息,只是扮演“快递”的角色。 + +#### 11.如何确保消息正确地发送至RabbitMQ?如何确保消息接收方消费了消息? + +1、发送方确认模式 + +①将信道设置成confirm模式(发送方确认模式),则所有在信道上发布的消息都会被指派一个唯一的ID。 + +②一旦消息被投递到目的队列后,或者消息被写入磁盘后(可持久化的消息),信道会发送一个确认给生产者(包含消息唯一 ID)。 + +③如果RabbitMQ发生内部错误从而导致消息丢失,会发送一条 nack(notacknowledged,未确认)消息。 + +④发送方确认模式是异步的,生产者应用程序在等待确认的同时,可以继续发送消息。当确认消息到达生产者应用程序,生产者应用程序的回调方法就会被触发来处理确认消息。 + +2、接收方确认机制 + +①消费者接收每一条消息后都必须进行确认(消息接收和消息确认是两个不同操作)。只有消费者确认了消息,RabbitMQ 才能安全地把消息从队列中删除。 + +②这里并没有用到超时机制,RabbitMQ仅通过Consumer的连接中断来确认是否需要重新发送消息。也就是说,只要连接不中断,RabbitMQ给了Consumer足够长的时间来处理消息。保证数据的最终一致性。 + +3、下面罗列几种特殊情况 + +①如果消费者接收到消息,在确认之前断开了连接或取消订阅,RabbitMQ会认为消息没有被分发,然后重新分发给下一个订阅的消费者。(可能存在消息重复消费的隐患,需要去重) + +②如果消费者接收到消息却没有确认消息,连接也未断开,则RabbitMQ认为该消费者繁忙,将不会给该消费者分发更多的消息。 + +#### 12.要保证消息持久化成功的条件有哪些? + +①声明队列必须设置持久化durable设置为 true。 + +②消息推送投递模式必须设置持久化,deliveryMode设置为2(持久)。 + +③消息已经到达持久化交换器。 + +④消息已经到达持久化队列。 + +以上四个条件都满足才能保证消息持久化成功。 + +#### 13.RabbitMQ 有几种广播类型? + +三种广播模式: + +①fanout:所有bind到此exchange的queue都可以接收消息(纯广播,绑定到RabbitMQ的接受者都能收到消息); + +②direct:通过routingKey和exchange决定的那个唯一的queue可以接收消息; + +③topic:所有符合routingKey(此时可以是一个表达式)的routingKey所bind的queue可以接收消息; + +#### 14.vhost 是什么?起什么作用? + +vhost 可以理解为虚拟 broker ,即 mini-RabbitMQ server。其内部均含有独立的 queue、exchange 和 binding 等,但最最重要的是,其拥有独立的权限系统,可以做到 vhost 范围的用户控制。当然,从 RabbitMQ 的全局角度,vhost 可以作为不同权限隔离的手段(一个典型的例子就是不同的应用可以跑在不同的 vhost 中)。 + +#### 15.消息基于什么传输? + +由于TCP连接的创建和销毁开销较大,且并发数受系统资源限制,会造成性能瓶颈。RabbitMQ使用信道的方式来传输数据。信道是建立在真实的TCP连接内的虚拟连接,且每条TCP连接上的信道数量没有限制。 + +#### 16.消息如何分发? + +若该队列至少有一个消费者订阅,消息将以循环(round-robin)的方式发送给消费者。每条消息只会分发给一个订阅的消费者(前提是消费者能够正常处理消息并进行确认)。 + +#### 17.消息怎么路由? + +从概念上来说,消息路由必须有三部分:交换器、路由、绑定。生产者把消息发布到交换器上;绑定决定了消息如何从路由器路由到特定的队列;消息最终到达队列,并被消费者接收。 + +消息发布到交换器时,消息将拥有一个路由键(routing key),在消息创建时设定。 +通过队列路由键,可以把队列绑定到交换器上。 +消息到达交换器后,RabbitMQ会将消息的路由键与队列的路由键进行匹配(针对不同的交换器有不同的路由规则)。如果能够匹配到队列,则消息会投递到相应队列中;如果不能匹配到任何队列,消息将进入 “黑洞”。 +常用的交换器主要分为一下三种: + +direct:如果路由键完全匹配,消息就被投递到相应的队列 +fanout:如果交换器收到消息,将会广播到所有绑定的队列上 +topic:可以使来自不同源头的消息能够到达同一个队列。 使用topic交换器时,可以使用通配符,比如:“*” 匹配特定位置的任意文本, “.” 把路由键分为了几部分,“#” 匹配所有规则等。特别注意:发往topic交换器的消息不能随意的设置选择键(routing_key),必须是由"."隔开的一系列的标识符组成。 + +#### 18.如何确保消息接收方消费了消息? + +接收方消息确认机制:消费者接收每一条消息后都必须进行确认(消息接收和消息确认是两个不同操作)。只有消费者确认了消息,RabbitMQ才能安全地把消息从队列中删除。这里并没有用到超时机制,RabbitMQ仅通过Consumer的连接中断来确认是否需要重新发送消息。也就是说,只要连接不中断,RabbitMQ给了Consumer足够长的时间来处理消息。 + +下面罗列几种特殊情况: + +如果消费者接收到消息,在确认之前断开了连接或取消订阅,RabbitMQ会认为消息没有被分发,然后重新分发给下一个订阅的消费者。(可能存在消息重复消费的隐患,需要根据bizId去重) +如果消费者接收到消息却没有确认消息,连接也未断开,则RabbitMQ认为该消费者繁忙,将不会给该消费者分发更多的消息。 + +#### 19.如何避免消息重复投递或重复消费? + +在消息生产时,MQ内部针对每条生产者发送的消息生成一个inner-msg-id,作为去重和幂等的依据(消息投递失败并重传),避免重复的消息进入队列;在消息消费时,要求消息体中必须要有一个bizId(对于同一业务全局唯一,如支付ID、订单ID、帖子ID等)作为去重和幂等的依据,避免同一条消息被重复消费。 + +这个问题针对业务场景来答分以下几点: + +1.比如,你拿到这个消息做数据库的insert操作。那就容易了,给这个消息做一个唯一主键,那么就算出现重复消费的情况,就会导致主键冲突,避免数据库出现脏数据。 + +2.再比如,你拿到这个消息做redis的set的操作,那就容易了,不用解决,因为你无论set几次结果都是一样的,set操作本来就算幂等操作。 + +3.如果上面两种情况还不行,上大招。准备一个第三方介质,来做消费记录。以redis为例,给消息分配一个全局id,只要消费过该消息,将以K-V形式写入redis。那消费者开始消费前,先去redis中查询有没消费记录即可。 + +#### 20.死信队列和延迟队列的使用 + +死信消息: + +消息被拒绝(Basic.Reject或Basic.Nack)并且设置 requeue 参数的值为 false +消息过期了 +队列达到最大的长度 +过期消息: + +在 rabbitmq 中存在2种方可设置消息的过期时间,第一种通过对队列进行设置,这种设置后,该队列中所有的消息都存在相同的过期时间,第二种通过对消息本身进行设置,那么每条消息的过期时间都不一样。如果同时使用这2种方法,那么以过期时间小的那个数值为准。当消息达到过期时间还没有被消费,那么那个消息就成为了一个 死信 消息。 + +队列设置:在队列申明的时候使用 x-message-ttl 参数,单位为 毫秒 + +单个消息设置:是设置消息属性的 expiration 参数的值,单位为 毫秒 + +延时队列:在rabbitmq中不存在延时队列,但是我们可以通过设置消息的过期时间和死信队列来模拟出延时队列。消费者监听死信交换器绑定的队列,而不要监听消息发送的队列。 + +有了以上的基础知识,我们完成以下需求: + +需求:用户在系统中创建一个订单,如果超过时间用户没有进行支付,那么自动取消订单。 + +分析: + +1、上面这个情况,我们就适合使用延时队列来实现,那么延时队列如何创建 + +2、延时队列可以由 过期消息+死信队列 来时间 + +3、过期消息通过队列中设置 x-message-ttl 参数实现 + +4、死信队列通过在队列申明时,给队列设置 x-dead-letter-exchange 参数,然后另外申明一个队列绑定x-dead-letter-exchange对应的交换器。 +```java +ConnectionFactory factory = new ConnectionFactory(); +factory.setHost("127.0.0.1"); +factory.setPort(AMQP.PROTOCOL.PORT); +factory.setUsername("guest"); +factory.setPassword("guest"); +Connection connection = factory.newConnection(); +Channel channel = connection.createChannel(); + +// 声明一个接收被删除的消息的交换机和队列 +String EXCHANGE_DEAD_NAME = "exchange.dead"; +String QUEUE_DEAD_NAME = "queue_dead"; +channel.exchangeDeclare(EXCHANGE_DEAD_NAME, BuiltinExchangeType.DIRECT); +channel.queueDeclare(QUEUE_DEAD_NAME, false, false, false, null); +channel.queueBind(QUEUE_DEAD_NAME, EXCHANGE_DEAD_NAME, "routingkey.dead"); + +String EXCHANGE_NAME = "exchange.fanout"; +String QUEUE_NAME = "queue_name"; +channel.exchangeDeclare(EXCHANGE_NAME, BuiltinExchangeType.FANOUT); +Map arguments = new HashMap(); +// 统一设置队列中的所有消息的过期时间 +arguments.put("x-message-ttl", 30000); +// 设置超过多少毫秒没有消费者来访问队列,就删除队列的时间 +arguments.put("x-expires", 20000); +// 设置队列的最新的N条消息,如果超过N条,前面的消息将从队列中移除掉 +arguments.put("x-max-length", 4); +// 设置队列的内容的最大空间,超过该阈值就删除之前的消息 +arguments.put("x-max-length-bytes", 1024); +// 将删除的消息推送到指定的交换机,一般x-dead-letter-exchange和x-dead-letter-routing-key需要同时设置 +arguments.put("x-dead-letter-exchange", "exchange.dead"); +// 将删除的消息推送到指定的交换机对应的路由键 +arguments.put("x-dead-letter-routing-key", "routingkey.dead"); +// 设置消息的优先级,优先级大的优先被消费 +arguments.put("x-max-priority", 10); +channel.queueDeclare(QUEUE_NAME, false, false, false, arguments); +channel.queueBind(QUEUE_NAME, EXCHANGE_NAME, ""); +String message = "Hello RabbitMQ: "; + +for(int i = 1; i <= 5; i++) { + // expiration: 设置单条消息的过期时间 + AMQP.BasicProperties.Builder properties = new AMQP.BasicProperties().builder() + .priority(i).expiration( i * 1000 + ""); + channel.basicPublish(EXCHANGE_NAME, "", properties.build(), (message + i).getBytes("UTF-8")); +} +channel.close(); +connection.close(); +``` + + +### 参考链接: + +https://blog.csdn.net/jerryDzan/article/details/89183625 + +https://www.cnblogs.com/woadmin/p/10537174.html + +https://blog.csdn.net/weixin_48272905/article/details/108988269 + +http://www.mianshigee.com/topic/1009ada/ + +http://blog.itpub.net/69902581/viewspace-2673724/ + diff --git a/Redis.md b/Redis.md new file mode 100644 index 0000000..0f915da --- /dev/null +++ b/Redis.md @@ -0,0 +1,292 @@ +## Redis + +* [1.什么是Redis?简述它的优缺点?](#1什么是redis简述它的优缺点) +* [2.Redis相比memcached有哪些优势?](#2redis相比memcached有哪些优势) +* [3.Redis有哪些数据结构?](#3redis有哪些数据结构) +* [4.Redis主要消耗什么物理资源?](#4redis主要消耗什么物理资源) +* [5.Redis的全称是什么?](#5redis的全称是什么) +* [6.一个字符串类型的值能存储最大容量是多少?](#6一个字符串类型的值能存储最大容量是多少) +* [7.Redis为什么那么快?](#7redis为什么那么快) +* [8.Redis如何实现分布式锁?](#8redis如何实现分布式锁) +* [9.Redis是单线程还是多线程?](#9redis是单线程还是多线程) +* [10.Redis 官方为什么不提供 Windows 版本?](#10redis-官方为什么不提供-windows-版本) +* [11.为什么 Redis 需要把所有数据放到内存中?](#11为什么-redis-需要把所有数据放到内存中) +* [12.Redis如何设置密码及验证密码?](#12redis如何设置密码及验证密码) +* [13.Redis集群如何选择数据库?](#13redis集群如何选择数据库) +* [14.缓存失效?缓存穿透?缓存雪崩?缓存并发?](#14缓存失效缓存穿透缓存雪崩缓存并发) +* [15.Redis中的热key怎么处理?](#15redis中的热key怎么处理) +* [16.Redis中的大key怎么处理?](#16redis中的大key怎么处理) +* [17.使用Redis统计网站的UV,应该怎么做?](#17使用redis统计网站的uv应该怎么做) +* [18.Redis事务机制了解过吗?](#18redis事务机制了解过吗) +* [19.Redis key的淘汰策略有哪些?](#19redis-key的淘汰策略有哪些) +* [20.Redis在什么情况下会触发key的回收?](#20redis在什么情况下会触发key的回收) +* [21.Redis的持久化了解过吗?](#21redis的持久化了解过吗) +* [22.Redis在集群种查找key的时候,是怎么定位到具体节点的?](#22redis在集群种查找key的时候是怎么定位到具体节点的) +* [23.Redis集群各个节点之间是怎么保持数据一致性的?](#23redis集群各个节点之间是怎么保持数据一致性的) +* [24.用Redis做延时队列,具体应该怎么实现?](#24用redis做延时队列具体应该怎么实现) +* [25.Redis String的内部编码有哪些?](#25redis-string的内部编码有哪些) +* [26.Redis 集群方案应该怎么做?都有哪些方案?](#26redis-集群方案应该怎么做都有哪些方案) +* [27.Redis 集群方案什么情况下会导致整个集群不可用?](#27redis-集群方案什么情况下会导致整个集群不可用) +* [28.MySQL 里有 2000w 数据,redis 中只存 20w 的数据,如何保证 redis 中的数据都是热点数据?](#28mysql-里有-2000w-数据redis-中只存-20w-的数据如何保证-redis-中的数据都是热点数据) +* [29.Redis有哪些适合的场景?](#29redis有哪些适合的场景) +* [30.Redis和Redisson有什么关系?](#30redis和redisson有什么关系) +* [31.Redis中的管道有什么用?](#31redis中的管道有什么用) +* [32.Redis如何做内存优化?](#32redis如何做内存优化) +* [参考链接](#参考链接) + + +#### 1.什么是Redis?简述它的优缺点? + +Redis本质上是一个Key-Value类型的内存数据库,很像memcached,整个数据库统统加载在内存当中进行操作,定期通过异步操作把数据库数据flush到硬盘上进行保存。 + +因为是纯内存操作,Redis的性能非常出色,每秒可以处理超过 10万次读写操作,是已知性能最快的Key-Value DB。 + +Redis的出色之处不仅仅是性能,Redis最大的魅力是支持保存多种数据结构,此外单个value的最大限制是1GB,不像 memcached只能保存1MB的数据,因此Redis可以用来实现很多有用的功能。 + +比方说用他的List来做FIFO双向链表,实现一个轻量级的高性 能消息队列服务,用他的Set可以做高性能的tag系统等等。 + +另外Redis也可以对存入的Key-Value设置expire时间,因此也可以被当作一 个功能加强版的memcached来用。 Redis的主要缺点是数据库容量受到物理内存的限制,不能用作海量数据的高性能读写,因此Redis适合的场景主要局限在较小数据量的高性能操作和运算上。 + +#### 2.Redis相比memcached有哪些优势? + +(1) memcached所有的值均是简单的字符串,redis作为其替代者,支持更为丰富的数据类型 + +(2) redis的速度比memcached快很多 + +(3) redis可以持久化其数据 + +#### 3.Redis有哪些数据结构? + +Redis 有 5 种基础数据结构,它们分别是:string(字符串)、list(列表)、hash(字典)、set(集合) 和 zset(有序集合)。这 5 种是 Redis 相关知识中最基础、最重要的部分。 + +#### 4.Redis主要消耗什么物理资源? + +内存。 + +#### 5.Redis的全称是什么? + +Remote Dictionary Server。 + +#### 6.一个字符串类型的值能存储最大容量是多少? + +512M + +#### 7.Redis为什么那么快? + +1、内存操作; +2、单线程,省去线程切换、锁竞争的开销; +3、非阻塞IO模型,epoll。 + +#### 8.Redis如何实现分布式锁? + +详见:https://www.cnblogs.com/wlwl/p/11651409.html + +#### 9.Redis是单线程还是多线程? + +Redis6.0采用多线程IO,不过命令的执行还是单线程的。 +Redis6.0之前,IO线程和执行线程都是单线程的。 + +#### 10.Redis 官方为什么不提供 Windows 版本? + +因为目前 Linux 版本已经相当稳定,而且用户量很大,无需开发 windows 版本,反而会带来兼容性等问题。 + +#### 11.为什么 Redis 需要把所有数据放到内存中? + +Redis 为了达到最快的读写速度将数据都读到内存中,并通过异步的方式将数据写入磁盘。 + +所以 redis 具有快速和数据持久化的特征,如果不将数据放在内存中,磁盘 I/O 速度为严重影响 redis 的性能。 + +在内存越来越便宜的今天,redis 将会越来越受欢迎, 如果设置了最大使用的内存,则数据已有记录数达到内存限值后不能继续插入新值。 + +#### 12.Redis如何设置密码及验证密码? + +设置密码:config set requirepass 123456 + +授权密码:auth 123456 + +#### 13.Redis集群如何选择数据库? + +Redis集群目前无法做数据库选择,默认在0数据库。 + +#### 14.缓存失效?缓存穿透?缓存雪崩?缓存并发? + +1. 缓存失效 + 缓存失效指的是大量的缓存在同一时间失效,到时DB的瞬间压力飙升。造成这种现象的原因是,key的过期时间都设置成一样了。解决方案是,key的过期时间引入随机因素,比如5分钟+随机秒这种方式。 + +2. 缓存穿透 + 缓存穿透是指查询一条数据库和缓存都没有的一条数据,就会一直查询数据库,对数据库的访问压力就会增大,缓存穿透的解决方案,有以下2种: + 缓存空对象:代码维护较简单,但是效果不好。 + 布隆过滤器:代码维护复杂,效果很好。 + +3. 缓存雪崩 + 缓存雪崩 是指在某一个时间段,缓存集中过期失效。此刻无数的请求直接绕开缓存,直接请求数据库。 + 造成缓存雪崩的原因,有以下2种: + reids宕机。 + 大部分数据失效。 + +对于缓存雪崩的解决方案有以下2种: +搭建高可用的集群,防止单机的redis宕机。 +设置不同的过期时间,防止同意之间内大量的key失效。 + +4. 缓存并发 + 有时候如果网站并发访问高,一个缓存如果失效,可能出现多个进程同时查询DB,同时设置缓存的情况,如果并发确实很大,这也可能造成DB压力过大,还有缓存频繁更新的问题。 + 一般处理方案是在查DB的时候进行加锁,如果KEY不存在,就加锁,然后查DB入缓存,然后解锁;其他进程如果发现有锁就等待,然后等解锁后再查缓存或者进入DB查询。 + +#### 15.Redis中的热key怎么处理? + +1、对热key进行分散处理。比如:在key上加上不同的前后缀,缓存多个key,使得各个key分散到不同的节点上。 +2、采用多级缓存。 + +#### 16.Redis中的大key怎么处理? + +大key指的是value特别大的key。比如很长的字符串,或者很大的set等等。 +大key会造成2个问题:1、数据倾斜,比如某些节点内存占用过高。2、当删除大key或者大key自动过期的时候,会造成QPS突降,因为Redis是单线程的缘故。 +处理方案:可以将一个大key进行分片处理,比如:将一个大set分成多个小的set。 + +#### 17.使用Redis统计网站的UV,应该怎么做? + +UV与PV不同,UV需要去重。一般有2种方案: +1、用BitMap。存的是用户的uid,计算UV的时候,做下bitcount就行了。 +2、用布隆过滤器。将每次访问的用户uid都放到布隆过滤器中。优点是省内存,缺点是无法得到精确的UV。但是对于不需要精确知道具体UV,只需要大概的数量级的场景,是个不错的选择。 + +#### 18.Redis事务机制了解过吗? + +Redis事务的概念: +Redis 事务的本质是一组命令的集合。事务支持一次执行多个命令,一个事务中所有命令都会被序列化。在事务执行过程,会按照顺序串行化执行队列中的命令,其他客户端提交的命令请求不会插入到事务执行命令序列中。 +Redis事务就是一次性、顺序性、排他性的执行一个队列中的一系列命令。   + +Redis事务没有隔离级别的概念: +批量操作在发送 EXEC 命令前被放入队列缓存,并不会被实际执行,也就不存在事务内的查询要看到事务里的更新,事务外查询不能看到。 +Redis不保证原子性: +Redis中,单条命令是原子性执行的,但事务不保证原子性,且没有回滚。事务中任意命令执行失败,其余的命令仍会被执行。 + +Redis事务的三个阶段: +开始事务 +命令入队 +执行事务 + +Redis事务相关命令: +watch key1 key2 ... : 监视一或多个key,如果在事务执行之前,被监视的key被其他命令改动,则事务被打断 ( 类似乐观锁 ) +multi : 标记一个事务块的开始( queued ) +exec : 执行所有事务块的命令 ( 一旦执行exec后,之前加的监控锁都会被取消掉 )  +discard : 取消事务,放弃事务块中的所有命令 +unwatch : 取消watch对所有key的监控 + +#### 19.Redis key的淘汰策略有哪些? + +8种:noeviction,volatile-lru,volatile-lfu,volatile-ttl,volatile-random,allkey-lru,allkeys-lfu,allkeys-random + +#### 20.Redis在什么情况下会触发key的回收? + +2种情况:1、定时(抽样)清理;2、执行命令时,判断内存是否超过maxmemory。 + +#### 21.Redis的持久化了解过吗? + +Redis持久化有RDB和AOF这2种方式。 +RDB:将数据库快照以二进制的方式保存到磁盘中。 +AOF:以协议文本方式,将所有对数据库进行过写入的命令和参数记录到AOF文件,从而记录数据库状态。 + +#### 22.Redis在集群种查找key的时候,是怎么定位到具体节点的? + +使用crc16算法对key进行hash +将hash值对16384取模,得到具体的槽位 +根据节点和槽位的映射信息(与集群建立连接后,客户端可以取得槽位映射信息),找到具体的节点地址 +去具体的节点找key +如果key不在这个节点上,则redis集群会返回moved指令,加上新的节点地址给客户端,同时,客户端会刷新本地的节点槽位映射关系 +如果槽位正在迁移中,那么redis集群会返回asking指令给客户端,这是临时纠正,客户端不会刷新本地的节点槽位映射关系 + +#### 23.Redis集群各个节点之间是怎么保持数据一致性的? + +主要考察点是Redis的Gossip协议。 +详见:https://mp.weixin.qq.com/s/dW0I29Sw86lU0qHpxyhdmw + +#### 24.用Redis做延时队列,具体应该怎么实现? + +可以使用Zset实现。member是任务描述,score是执行时间,然后用定时器定时去扫描,一旦有执行时间小于或等于当前时间的任务,就立即执行。 + +#### 25.Redis String的内部编码有哪些? + +int、embstr、raw +10000以下的整数会使用缓存里的int常量。 +长度小于等于44字节:embstr编码 +长度大于44字节:raw编码 + +#### 26.Redis 集群方案应该怎么做?都有哪些方案? + +- codis +- 目前用的最多的集群方案,基本和 twemproxy 一致的效果,但它支持在节点数量改变情况下,旧节点数据可恢复到新 hash 节点。 +- redis cluster3.0 自带的集群,特点在于他的分布式算法不是一致性 hash,而是 hash 槽的概念,以及自身支持节点设置从节点。具体看官方文档介绍。 +- 在业务代码层实现,起几个毫无关联的 redis 实例,在代码层,对 key 进行 hash 计算,然后去对应的redis 实例操作数据。这种方式对 hash 层代码要求比较高,考虑部分包括,节点失效后的替代算法方案,数据震荡后的自动脚本恢复,实例的监控,等等。 +- Java 架构学习资料(里面有高可用、高并发、高性能及分布式、Jvm 性能调优、Spring 源码,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx 等多个知识点的架构资料)合理利用自己每一分每一秒的时间来学习提升自己,不要再用"没有时间“来掩饰自己思想上的懒惰!趁年轻,使劲拼,给未来的自己一个交代! + +#### 27.Redis 集群方案什么情况下会导致整个集群不可用? + +有 A,B,C 三个节点的集群,在没有复制模型的情况下,如果节点 B 失败了,那么整个集群就会以为缺少5501-11000 这个范围的槽而不可用。 + +#### 28.MySQL 里有 2000w 数据,redis 中只存 20w 的数据,如何保证 redis 中的数据都是热点数据? + +redis 内存数据集大小上升到一定大小的时候,就会施行数据淘汰策略。 + +其实面试除了考察 Redis,不少公司都很重视高并发高可用的技术,特别是一线互联网公司,分布式、 + +JVM、spring 源码分析、微服务等知识点已是面试的必考题。 + +#### 29.Redis有哪些适合的场景? + +(1)会话缓存(Session Cache) + +最常用的一种使用Redis的情景是会话缓存(session cache)。用Redis缓存会话比其他存储(如Memcached)的优势在于:Redis提供持久化。当维护一个不是严格要求一致性的缓存时,如果用户的购物车信息全部丢失,大部分人都会不高兴的,现在,他们还会这样吗? + +幸运的是,随着 Redis 这些年的改进,很容易找到怎么恰当的使用Redis来缓存会话的文档。甚至广为人知的商业平台Magento也提供Redis的插件。 + +(2)全页缓存(FPC) + +除基本的会话token之外,Redis还提供很简便的FPC平台。回到一致性问题,即使重启了Redis实例,因为有磁盘的持久化,用户也不会看到页面加载速度的下降,这是一个极大改进,类似PHP本地FPC。 + +再次以Magento为例,Magento提供一个插件来使用Redis作为全页缓存后端。 + +此外,对WordPress的用户来说,Pantheon有一个非常好的插件 wp-redis,这个插件能帮助你以最快速度加载你曾浏览过的页面。 + +(3)队列 + +Reids在内存存储引擎领域的一大优点是提供 list 和 set 操作,这使得Redis能作为一个很好的消息队列平台来使用。Redis作为队列使用的操作,就类似于本地程序语言(如Python)对 list 的 push/pop 操作。 + +如果你快速的在Google中搜索“Redis queues”,你马上就能找到大量的开源项目,这些项目的目的就是利用Redis创建非常好的后端工具,以满足各种队列需求。例如,Celery有一个后台就是使用Redis作为broker,你可以从这里去查看。 + +(4)排行榜/计数器 + +Redis在内存中对数字进行递增或递减的操作实现的非常好。集合(Set)和有序集合(Sorted Set)也使得我们在执行这些操作的时候变的非常简单,Redis只是正好提供了这两种数据结构。 + +所以,我们要从排序集合中获取到排名最靠前的10个用户–我们称之为“user_scores”,我们只需要像下面一样执行即可: + +当然,这是假定你是根据你用户的分数做递增的排序。如果你想返回用户及用户的分数,你需要这样执行: + +ZRANGE user_scores 0 10 WITHSCORES + +Agora Games就是一个很好的例子,用Ruby实现的,它的排行榜就是使用Redis来存储数据的,你可以在这里看到。 + +(5)发布/订阅 + +最后(但肯定不是最不重要的)是Redis的发布/订阅功能。发布/订阅的使用场景确实非常多。我已看见人们在社交网络连接中使用,还可作为基于发布/订阅的脚本触发器,甚至用Redis的发布/订阅功能来建立聊天系统! + +#### 30.Redis和Redisson有什么关系? + +Redisson是一个高级的分布式协调Redis客服端,能帮助用户在分布式环境中轻松实现一些Java的对象 (Bloom filter, BitSet, Set, SetMultimap, ScoredSortedSet, SortedSet, Map, ConcurrentMap, List, ListMultimap, Queue, BlockingQueue, Deque, BlockingDeque, Semaphore, Lock, ReadWriteLock, AtomicLong, CountDownLatch, Publish / Subscribe, HyperLogLog)。 + +#### 31.Redis中的管道有什么用? + +一次请求/响应服务器能实现处理新的请求即使旧的请求还未被响应。这样就可以将多个命令发送到服务器,而不用等待回复,最后在一个步骤中读取该答复。 + +这就是管道(pipelining),是一种几十年来广泛使用的技术。例如许多POP3协议已经实现支持这个功能,大大加快了从服务器下载新邮件的过程。 + +#### 32.Redis如何做内存优化? + +尽可能使用散列表(hashes),散列表(是说散列表里面存储的数少)使用的内存非常小,所以你应该尽可能的将你的数据模型抽象到一个散列表里面。 + +比如你的web系统中有一个用户对象,不要为这个用户的名称,姓氏,邮箱,密码设置单独的key,而是应该把这个用户的所有信息存储到一张散列表里面。 + +#### 参考链接 + +http://blog.itpub.net/31545684/viewspace-2213990/ + +https://blog.csdn.net/weixin_34081595/article/details/92420220 diff --git a/RocketMQ.md b/RocketMQ.md new file mode 100644 index 0000000..ba989eb --- /dev/null +++ b/RocketMQ.md @@ -0,0 +1,194 @@ +## RocketMQ + +* [1.RocketMQ中的Topic和JMS的queue有什么区别?](#1rocketmq中的topic和jms的queue有什么区别) +* [2.RocketMQ Broker中的消息被消费后会立即删除吗?](#2rocketmq-broker中的消息被消费后会立即删除吗) +* [3.RocketMQ消费模式有几种?](#3rocketmq消费模式有几种) +* [4.消费消息是push还是pull?](#4消费消息是push还是pull) +* [5.broker如何处理拉取请求的?](#5broker如何处理拉取请求的) +* [6.RocketMQ如何做负载均衡?](#6rocketmq如何做负载均衡) +* [7.消息重复消费如何解决?](#7消息重复消费如何解决) +* [8.如何让RocketMQ保证消息的顺序消费?](#8如何让rocketmq保证消息的顺序消费) +* [9.RocketMQ如何保证消息不丢失?](#9rocketmq如何保证消息不丢失) +* [10.rocketMQ的消息堆积如何处理](#10rocketmq的消息堆积如何处理) +* [11.RocketMQ在分布式事务支持这块机制的底层原理?](#11rocketmq在分布式事务支持这块机制的底层原理) +* [12.如果让你来动手实现一个分布式消息中间件,整体架构你会如何设计实现?](#12如果让你来动手实现一个分布式消息中间件整体架构你会如何设计实现) +* [13.高吞吐量下如何优化生产者和消费者的性能?](#13高吞吐量下如何优化生产者和消费者的性能) +* [14.再说说RocketMQ 是如何保证数据的高容错性的?](#14再说说rocketmq-是如何保证数据的高容错性的) +* [15.任何一台Broker突然宕机了怎么办?](#15任何一台broker突然宕机了怎么办) +* [参考资料](#参考资料) + + +#### 1.RocketMQ中的Topic和JMS的queue有什么区别? + +queue就是来源于数据结构的FIFO队列。而Topic是个抽象的概念,每个Topic底层对应N个queue,而数据也真实存在queue上的。 + +#### 2.RocketMQ Broker中的消息被消费后会立即删除吗? + +不会,每条消息都会持久化到CommitLog中,每个Consumer连接到Broker后会维持消费进度信息,当有消息消费后只是当前Consumer的消费进度(CommitLog的offset)更新了。 + +#### 3.RocketMQ消费模式有几种? + +集群消费 +一条消息只会被同Group中的一个Consumer消费 +多个Group同时消费一个Topic时,每个Group都会有一个Consumer消费到数据 + +广播消费 +消息将对一 个Consumer Group 下的各个 Consumer 实例都消费一遍。即即使这些 Consumer 属于同一个Consumer Group ,消息也会被 Consumer Group 中的每个 Consumer 都消费一次。 + +#### 4.消费消息是push还是pull? + +RocketMQ没有真正意义的push,都是pull,虽然有push类,但实际底层实现采用的是长轮询机制,即拉取方式。 + +broker端属性 longPollingEnable 标记是否开启长轮询。默认开启。 + +#### 5.broker如何处理拉取请求的? + +Consumer首次请求Broker + +Broker中是否有符合条件的消息 +如果有 +响应Consumer +等待下次Consumer的请求 + +如果没有 +DefaultMessageStore#ReputMessageService#run方法 +PullRequestHoldService 来Hold连接,每个5s执行一次检查pullRequestTable有没有消息,有的话立即推送 +每隔1ms检查commitLog中是否有新消息,有的话写入到pullRequestTable +当有新消息的时候返回请求 +挂起consumer的请求,即不断开连接,也不返回数据 +使用consumer的offset + +#### 6.RocketMQ如何做负载均衡? + +通过Topic在多Broker中分布式存储实现。 + +1)producer端 +发送端指定message queue发送消息到相应的broker,来达到写入时的负载均衡: +提升写入吞吐量,当多个producer同时向一个broker写入数据的时候,性能会下降 +消息分布在多broker中,为负载消费做准备 + +默认策略是随机选择: +producer维护一个index +每次取节点会自增 +index向所有broker个数取余 +自带容错策略 + +其他实现: +SelectMessageQueueByHash +hash的是传入的args +SelectMessageQueueByRandom +SelectMessageQueueByMachineRoom 没有实现 +也可以自定义实现MessageQueueSelector接口中的select方法 + + +2)consumer端 + +采用的是平均分配算法来进行负载均衡。 + +其他负载均衡算法 +平均分配策略(默认)(AllocateMessageQueueAveragely) 环形分配策略(AllocateMessageQueueAveragelyByCircle) 手动配置分配策略(AllocateMessageQueueByConfig) 机房分配策略(AllocateMessageQueueByMachineRoom) 一致性哈希分配策略(AllocateMessageQueueConsistentHash) 靠近机房策略(AllocateMachineRoomNearby) + +#### 7.消息重复消费如何解决? + +影响消息正常发送和消费的重要原因是网络的不确定性。 + +引起重复消费的原因 +1)ACK +正常情况下在consumer真正消费完消息后应该发送ack,通知broker该消息已正常消费,从queue中剔除 +当ack因为网络原因无法发送到broker,broker会认为词条消息没有被消费,此后会开启消息重投机制把消息再次投递到consumer +2)消费模式 +在CLUSTERING模式下,消息在broker中会保证相同group的consumer消费一次,但是针对不同group的consumer会推送多次 + +解决方案 +1)数据库表 +处理消息前,使用消息主键在表中带有约束的字段中insert +2)Map +单机时可以使用map ConcurrentHashMap -> putIfAbsent guava cache +3)Redis +分布式锁搞起来。 + +#### 8.如何让RocketMQ保证消息的顺序消费? + +首先多个queue只能保证单个queue里的顺序,queue是典型的FIFO,天然顺序。多个queue同时消费是无法绝对保证消息的有序性的。所以总结如下: + +同一topic,同一个QUEUE,发消息的时候一个线程去发送消息,消费的时候 一个线程去消费一个queue里的消息。 + +#### 9.RocketMQ如何保证消息不丢失? + +首先在如下三个部分都可能会出现丢失消息的情况: +Producer端 +Broker端 +Consumer端 + +1)Producer端如何保证消息不丢失 +采取send()同步发消息,发送结果是同步感知的。 +发送失败后可以重试,设置重试次数。默认3次。 +producer.setRetryTimesWhenSendFailed(10); + +集群部署,比如发送失败了的原因可能是当前Broker宕机了,重试的时候会发送到其他Broker上。 + +2)Broker端如何保证消息不丢失 +修改刷盘策略为同步刷盘。默认情况下是异步刷盘的。 +flushDiskType = SYNC_FLUSH + +集群部署,主从模式,高可用。 + +3)Consumer端如何保证消息不丢失 +完全消费正常后在进行手动ack确认。 + +#### 10.rocketMQ的消息堆积如何处理 + +首先要找到是什么原因导致的消息堆积,是Producer太多了,Consumer太少了导致的还是说其他情况,总之先定位问题。 + +然后看下消息消费速度是否正常,正常的话,可以通过上线更多consumer临时解决消息堆积问题。 + +#### 11.RocketMQ在分布式事务支持这块机制的底层原理? + +分布式系统中的事务可以使用TCC(Try、Confirm、Cancel)、2pc来解决分布式系统中的消息原子性 +RocketMQ 4.3+提供分布事务功能,通过 RocketMQ 事务消息能达到分布式事务的最终一致 + +RocketMQ实现方式: +Half Message:预处理消息,当broker收到此类消息后,会存储到RMQ_SYS_TRANS_HALF_TOPIC的消息消费队列中 + +检查事务状态:Broker会开启一个定时任务,消费RMQ_SYS_TRANS_HALF_TOPIC队列中的消息,每次执行任务会向消息发送者确认事务执行状态(提交、回滚、未知),如果是未知,Broker会定时去回调在重新检查。 + +超时:如果超过回查次数,默认回滚消息。 + +也就是他并未真正进入Topic的queue,而是用了临时queue来放所谓的half message,等提交事务后才会真正的将half message转移到topic下的queue。 + +#### 12.如果让你来动手实现一个分布式消息中间件,整体架构你会如何设计实现? + +需要考虑能快速扩容、天然支持集群 +持久化的姿势 +高可用性 +数据0丢失的考虑 +服务端部署简单、client端使用简单 + +#### 13.高吞吐量下如何优化生产者和消费者的性能? + +1)开发 +同一group下,多机部署,并行消费 +单个Consumer提高消费线程个数 +批量消费。消息批量拉取,业务逻辑批量处理。 + +2)运维 +网卡调优 +jvm调优 +多线程与cpu调优 +Page Cache + +#### 14.再说说RocketMQ 是如何保证数据的高容错性的? + +在不开启容错的情况下,轮询队列进行发送,如果失败了,重试的时候过滤失败的Broker +如果开启了容错策略,会通过RocketMQ的预测机制来预测一个Broker是否可用 +如果上次失败的Broker可用那么还是会选择该Broker的队列 +如果上述情况失败,则随机选择一个进行发送 +在发送消息的时候会记录一下调用的时间与是否报错,根据该时间去预测broker的可用时间 + +#### 15.任何一台Broker突然宕机了怎么办? + +Broker主从架构以及多副本策略。Master收到消息后会同步给Slave,这样一条消息就不止一份了,Master宕机了还有slave中的消息可用,保证了MQ的可靠性和高可用性。而且Rocket MQ4.5.0开始就支持了Dlegder模式,基于raft的,做到了真正意义的HA。 + +#### 参考资料 + +https://www.cnblogs.com/javazhiyin/p/13327925.html diff --git a/Servlet.md b/Servlet.md new file mode 100644 index 0000000..66062a6 --- /dev/null +++ b/Servlet.md @@ -0,0 +1,160 @@ +## Servlet + +* [1.Servlet的生命周期?](#1servlet的生命周期) +* [2.Servlet和JSP的区别?](#2servlet和jsp的区别) +* [3.Servlet的基本架构](#3servlet的基本架构) +* [4.什么情况下调用doGet()和doPost()?](#4什么情况下调用doget和dopost) +* [5.页面间对象传递的方法](#5页面间对象传递的方法) +* [6.四种会话跟踪技术](#6四种会话跟踪技术) +* [7.Request对象的主要方法](#7request对象的主要方法) +* [8.如何配置Servlet的初始化参数?](#8如何配置servlet的初始化参数) +* [9.如何读取Servlet的初始化参数?](#9如何读取servlet的初始化参数) +* [10.init(ServletConfig)方法执行次数](#10initservletconfig方法执行次数) +* [11.init(ServletConfig)方法与异常](#11initservletconfig方法与异常) +* [参考链接](#参考链接) + +#### 1.Servlet的生命周期? + +---根据Servlet的配置参数1来决定实例化时机,没有配置该参数项或者为负数,则第一次访问的时候才会被实例化并调用init () 函数,如果为0或者正整数,则服务器启动的时候就会被加载,加载顺序由小到达。Servlet 通过调用 init () 方法进行初始化。 + +---客户端请求到达后,Servlet 调用 service() 方法来处理客户端的请求。 + +---服务器关闭,或者Servlet长时间没有使用,Servlet 通过调用 destroy() 方法终止(结束)。 + +---最后,Servlet 是由 JVM 的垃圾回收器进行垃圾回收的。 + +#### 2.Servlet和JSP的区别? + +Servlet是服务器端的程序,动态生成html页面发送到客户端,但是这样程序里会有很多out.println(),java与html语言混在一起很乱,造成编写逻辑控制的后台工程师和设计前端网页的前端工程师彼此很难独立开展工作,所以后来sun公司推出了JSP,其实JSP就是Servlet,每次运行的时候JSP都首先被编译成servlet文件,然后再被编译成.class文件运行。有了jsp,在MVC项目中servlet不再负责动态生成页面,转而去负责控制程序逻辑的作用,控制jsp与javabean之间的流转。其实对jsp也有封装的模板工具velocity和freemarker。 + + +#### 3.Servlet的基本架构 + +``` +public class ServletName extends HttpServlet { +  public void doPost(HttpServletRequest request, HttpServletResponse response) throws + +      ServletException, IOException  { +      } + +  public void doGet(HttpServletRequest request, HttpServletResponse response) throws + +      ServletException, IOException  { +      } + +} +``` + +#### 4.什么情况下调用doGet()和doPost()? + +JSP页面中的form标签里的method属性为get时调用doGet(),为post时调用doPost();超链接跳转页面时调用doGet() + +#### 5.页面间对象传递的方法 + +request,session,application,cookie等 + +#### 6.四种会话跟踪技术 + +会话作用域ServletsJSP 页面描述 + +1)page否是代表与一个页面相关的对象和属性。一个页面由一个编译好的 Java servlet 类(可以带有任何的 include 指令,但是没有 include 动作)表示。这既包括 servlet 又包括被编译成 servlet 的 JSP 页面 + +2)request是是代表与 Web 客户机发出的一个请求相关的对象和属性。一个请求可能跨越多个页面,涉及多个 Web 组件(由于 forward 指令和 include 动作的关系) + +3)session是是代表与用于某个 Web 客户机的一个用户体验相关的对象和属性。一个 Web 会话可以也经常会跨越多个客户机请求 + +4)application是是代表与整个 Web 应用程序相关的对象和属性。这实质上是跨越整个 Web 应用程序,包括多个页面、请求和会话的一个全局作用域 + +#### 7.Request对象的主要方法 + +setAttribute(String name,Object):设置名字为name的request的参数值 + +getAttribute(String name):返回由name指定的属性值 + +getAttributeNames():返回request对象所有属性的名字集合,结果是一个枚举的实例 + +getCookies():返回客户端的所有Cookie对象,结果是一个Cookie数组 + +getCharacterEncoding():返回请求中的字符编码方式 + +getContentLength():返回请求的Body的长度 + +getHeader(String name):获得HTTP协议定义的文件头信息 + +getHeaders(String name):返回指定名字的request Header的所有值,结果是一个枚举的实例 + +getHeaderNames():返回所以request Header的名字,结果是一个枚举的实例 + +getInputStream():返回请求的输入流,用于获得请求中的数据 + +getMethod():获得客户端向服务器端传送数据的方法 + +getParameter(String name):获得客户端传送给服务器端的有name指定的参数值 + +getParameterNames():获得客户端传送给服务器端的所有参数的名字,结果是一个枚举的实例 + +getParameterValues(String name):获得有name指定的参数的所有值 + +getProtocol():获取客户端向服务器端传送数据所依据的协议名称 + +getQueryString():获得查询字符串 + +getRequestURI():获取发出请求字符串的客户端地址 + +getRemoteAddr():获取客户端的IP地址 + +getRemoteHost():获取客户端的名字 + +getSession([Boolean create]):返回和请求相关Session + +getServerName():获取服务器的名字 + +getServletPath():获取客户端所请求的脚本文件的路径 + +getServerPort():获取服务器的端口号 + +removeAttribute(String name):删除请求中的一个属性 + +#### 8.如何配置Servlet的初始化参数? + +在web.xml中该Servlet的定义标记中,比如: + +``` xaml + + TimeServlet + com.allanlxf.servlet.basic.TimeServlet + ** + user + username + + + blog + http://。。。 + + +``` + +配置了两个初始化参数user和blog它们的值分别为**username**和[http://](http://allanlxf.blog.sohu.com/)。。。, 这样以后要修改用户名和博客的地址不需要修改Servlet代码,只需修改配置文件即可。 + +#### 9.如何读取Servlet的初始化参数? + + ServletConfig中定义了如下的方法用来读取初始化参数的信息: + +​ public String getInitParameter(String name) + +​ 参数:初始化参数的名称。 +​ 返回:初始化参数的值,如果没有配置,返回null。 + +#### 10.init(ServletConfig)方法执行次数 + + 该方法执行在单线程的环境下,因此开发者不用考虑线程安全的问题。 + +#### 11.init(ServletConfig)方法与异常 + +该方法在执行过程中可以抛出ServletException来通知Web服务器Servlet实例初始化失败。一旦ServletException抛出,Web服务器不会将客户端请求交给该Servlet实例来处理,而是报告初始化失败异常信息给客户端,该Servlet实例将被从内存中销毁。如果在来新的请求,Web服务器会创建新的Servlet实例,并执行新实例的初始化操作 + +#### 参考链接 + +https://blog.csdn.net/hipilee/article/details/78743087 + +https://blog.csdn.net/Jeff_Seid/article/details/80761076 diff --git a/Shiro.md b/Shiro.md new file mode 100644 index 0000000..87026db --- /dev/null +++ b/Shiro.md @@ -0,0 +1,235 @@ +## Shiro + +* [1.什么是shiro](#1什么是shiro) +* [2.解释下Shiro的核心概念:Subject、SecurityManager、Realm](#2解释下shiro的核心概念subjectsecuritymanagerrealm) +* [3.Shiro的优点](#3shiro的优点) +* [4.Shiro有哪些组件?](#4shiro有哪些组件) +* [5.说下Authentication 身份验证的流程](#5说下authentication-身份验证的流程) +* [6.Authorization 授权的方式和流程是怎样的?](#6authorization-授权的方式和流程是怎样的) +* [7.Cryptography 加密的过程是这样的?](#7cryptography-加密的过程是这样的) +* [8.Realm 域如何使用?](#8realm-域如何使用) +* [9.shiro拦截器的执行流程](#9shiro拦截器的执行流程) +* [10.Session Manager 会话管理介绍一下](#10session-manager-会话管理介绍一下) +* [参考资料](#参考资料) + +#### 1.什么是shiro + +Shiro是一个强大易用的java安全框架,提供了认证、授权、加密、会话管理、与web集成、缓存等功能,对于任何一个应用程序,都可以提供全面的安全服务,相比其他安全框架,shiro要简单的多。 + +#### 2.解释下Shiro的核心概念:Subject、SecurityManager、Realm + +Subject:主体,代表了当前“用户”,这个用户不一定是一个具体的人,与当前应用交互的任何东西都是Subject,如爬虫、机器人等;即一个抽象概念;所有Subject都绑定到SecurityManager,与Subject的所有交互都会委托给SecurityManager;可以把Subject认为是一个门面;SecurityManager才是实际的执行者。 +SecurityManager:安全管理器;即所有与安全有关的操作都会与SecurityManager交互;且它管理着所有Subject;可以看出它是shiro的核心, SecurityManager相当于spring mvc中的dispatcherServlet前端控制器。 +Realm:域,shiro从Realm获取安全数据(如用户、角色、权限),就是说SecurityManager要验证用户身份,那么它需要从Realm获取相应的用户进行比较以确定用户身份是否合法;也需要从Realm得到用户相应的角色/权限进行验证用户是否能进行操作;可以把Realm看成DataSource,即安全数据源。 + +#### 3.Shiro的优点 + +1、 简单的身份验证,支持多种数据源 +2、对角色的简单授权,支持细粒度的授权(方法) +3、支持一级缓存,以提升应用程序的性能 +4、内置基于POJO的企业会话管理,适用于web及非web环境 +5、非常简单的API加密 +6、不跟任何框架绑定,可以独立运行 + +#### 4.Shiro有哪些组件? + +Authentication:身份认证/登录,验证用户是不是拥有相应的身份; + +Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;即判断用户是否能做事情,常见的如:验证某个用户是否拥有某个角色。或者细粒度的验证某个用户对某个资源是否具有某个权限; + +Session Manager:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有信息都在会话中;会话可以是普通JavaSE环境的,也可以是如Web环境的; + +Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储; + +Web Support:Web支持,可以非常容易的集成到Web环境; + +Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可以提高效率; + +Concurrency:shiro支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去; + +Testing:提供测试支持; + +Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问; + +Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了。 + +记住一点,Shiro不会去维护用户、维护权限;这些需要我们自己去设计/提供;然后通过相应的接口注入给Shiro即可。 + + +#### 5.说下Authentication 身份验证的流程 + +principals:身份,即主体的标识属性,可以是任何东西,如用户名、邮箱等,唯一即可。 +credentials:证明/凭证,即只有主体知道的安全值,如密码/数字证书等。 + +身份认证流程: +1)首先调用Subject.login(token)进行登录,其会自动委托给SecurityManager,调用之前必须通过SecurityUtils.setSecurityManager()设置; + +2)SecurityManager负责真正的身份验证逻辑;它会委托给Authenticator进行身份验证; + +3)Authenticator才是真正的身份验证者,shiro api中核心的身份认证入口点,此处可以自定义插入自己的实现; + +4)Authenticator可能会委托给相应的AuthenticationStrategy进行多Realm身份验证,默认ModularRealmAuthenticator会调用AuthenticationStrategy进行多Realm身份验证; + +5)Authenticator会把相应的token传入Realm,从Realm获取身份验证信息,如果没有返回/抛出异常表示身份验证失败了。此处可以配置多个Realm,将按照相应的顺序及策略进行访问。 + +6)Authenticator的职责是验证用户账号,是shiro api中身份验证核心的入口点。 + +7)AuthenticationStrategy 认证策略 ModularRealmAuthenticator默认使用AtLeastOneSuccessfulStrategy策略 +1> FirstSuccessfulStrategy:只要有一个Realm验证成功即可,只返回第一个Realm身份验证成功的认证信息,其他的忽略; +2> AtLeastOneSuccessfulStrategy:只要有一个Realm验证成功即可,和FirstSuccessfulStrategy不同,返回所有Realm身份验证成功的认证信息; +3> AllSuccessfulStrategy:所有Realm验证成功才算成功,且返回所有Realm身份验证成功的认证信息,如果有一个失败就失败了。 + + +#### 6.Authorization 授权的方式和流程是怎样的? + +授权,也叫访问控制,即在应用中控制谁能访问哪些资源(如访问页面/编辑数据/页面操作等)。在授权中需了解的几个关键对象:主体(Subject)、资源(Resource)、权限(Permission)、角色(Role) + +授权方式: +1)编程式:通过写if/else授权代码完成 +Subject subject = SecurityUtils.getSubject(); +If(subject.hasRole(“admin”){ +// 有权限 +}else{ +// 无权限 +} +2)注解 +@RequiresRoles(“admin”) +public void helloWord(){ +// 有权限 +} +3)Jsp/gsp标签 + + +基于资源的访问控制 +1. 隐式角色:硬编码的方式(if/else);粗粒度造成的问题:如果有一天不需要了那么就需要修改相应代码把所有相关的地方进行删除; +4)显示角色:规则:资源标识符:操作(user:create,user:update)这种方式叫资源级别的粒度;好处:如果需要修改都是一个资源级别的修改,不会对其他模块代码产生影响,粒度小;但实现起来可能稍微复杂点,需要维护“用户—角色,角色—权限(资源:操作)”之间的关系 +Permission +字符串通配符权限 +规则:资源标识符 : 操作 : 对象实例ID +“:”表示资源/操作/实例的分割 +“,”表示操作的分割 +“*”表示任意资源/操作/实例 +5)单个资源多个权限 +Role=system:user:update,system:user:delete +等价于role=system:user:update,delete,但是反过来是规则不成立 +代码判断 +subject().checkPermissions(“system:user:update,delete”) +6)单个资源全部权限:role=sys:user:*/sys:user +7)所有资源全部权限:role=*:view;subject.checkPermissions(“user:view”); +8)实例级别的权限 +单实多限:role=”user:update,delete:1”; +subject().checkPermissions(”user:update,delete:1”); +all实单限:role=”user:auth:”; +subject().checkPermissions(“user:auth:1”, “user:auth:2”); +all实all限:role=”user:?”; +subject().checkPermissions(“user:view:1”, “user:auth:2”); + +授权流程: +1)首先调用Subject.isPermitted*/hasRole*接口,其会委托给SecurityManager,而SecurityManager接着会委托给Authorizer; +2)Authorizer是真正的授权者,如果我们调用如isPermitted(“user:view”), 其首先会通过PermissionResolver把字符串转换成相应的Permission实例; +3)在进行授权之前,其会调用相应的Realm获取Subject相应的角色/权限用于匹配传入的角色/权限; +4)Authorizer会判断Realm的角色/权限是否和传入的匹配,如果有多个Realm,会委托给ModularRealmAuthorizer进行循环判断,如果匹配如isPermitted*/hasRole*会返回true, 否则返回false表示授权失败。 + +#### 7.Cryptography 加密的过程是这样的? + +编码/解码 +Shiro提供了base64和16进制字符串编码/解码的API支持,方便一些编码解码操作 +Base64.encodeToString(str.getBytes())编码 +Base64.decodeToString(base64Encoded) 解码 +散列算法 +常见散列算法如MD5,SHA等 + +1)首先创建一个DfaultHashService,默认使用SHA-512算法; +2)可以通过hashAlgorithmName属性修改算法; +3)可以通过privateSalt设置一个私盐,其在散列时自动与用户传入的公盐混合产生一个新盐; +4)可以通过generatePublicSalt属性在用户没有传入公盐的情况下是否生成公盐; +5)可以设置randomNumberGenerator用于生成公盐; +6)可以设置hashIterations属性来修改默认加密迭代次数; +7)需要构建一个HashRequest,传入算法、数据、公盐、迭代次数。 +生成随机数 +SecureRandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator(); +randomNumberGenerator.setSeed(“159”.getBytes()); +String hex = randomNumberGenerator.nextBytes().toHex(); +加密/解密 +提供对称式加密/解密算法的支持,如AES、Blowfish等 +PasswordService/CredentialsMatcher +用于提供加密密码及验证密码服务 +Shiro默认提供了PasswordService实现DefaultPasswordService;CredentialsMatcher实现PasswordMatcher及HashedCredentialsMatcher(更强大) +HashedCredentialsMatcher实现密码验证服务 +Shiro提供了CredentialsMatcher的散列实现HashedCredentialsMatcher,和PasswordMatcher不同的是,它只是用于密码验证,且可以提供自己的盐,而不是随机生成盐,且生成密码散列值的算法需要自己写,因为能提供自己的盐 + +#### 8.Realm 域如何使用? + +定义Realm(自定义Realm继承AuthorizingRealm即可) + +1)UserRealm父类AuthorizingRealm将获取Subject相关信息分成两步:获取身份验证信息(doGetAuthenticationInfo)及授权信息(doGetAuthorizationInfo) +2)doGetAuthenticationInfo获取身份验证相关信息:首先根据传入的用户名获取User信息;如果user为空,那么抛出没找到账号异常UnknownAccountExecption;如果user找到但却被锁定了抛出锁定异常LockedAccountException;最后生成AuthenticationInfo信息,交给间接父类AuthenticatingRealm使用CredentialsMatcher进行判断密码是否匹配,如果不匹配将抛出密码错误异常信息IncorrectCredentialsException;如果密码重试次数太多将抛出超出重试次数异常ExcessiveAttemptsException;在组装SimpleAuthenticationInfo信息时,需要传入:身份信息(用户名)、凭据(密文密码)、盐(username+salt),CredentialsMatcher使用盐加密传入的明文密码和此处的密文密码进行匹配。 +3)doGetAuthorizationInfo获取授权信息:PrincipalCollection是一个身份集合,因为只用到了一个Realm,所以直接调用getPrimaryPrincipal得到之前传入的用户名即可;然后根据用户名调用UserService接口获取角色及权限信息。 + + +AuthenticationInfo的两个作用 + +1)如果Realm是AuthenticatingRealm子类,则提供给AuthenticatingRealm内部使用的CredentialsMatcher进行凭据验证;(如果没有继承它需要在自己的Realm中实现验证); +2)提供给SecurityManager来创建Subject(提供身份信息); + +#### 9.shiro拦截器的执行流程 + +基于表单登录拦截器 +onPreHandle主要流程: +1)首先判断是否已经登录过了,如果已经登录过了继续拦截器链即可; +2)如果没有登录,看看是否是登录请求,如果是get方法的登录页面请求,则继续拦截器链(到请求页面),否则如果是get方法的其他页面请求则保存当前请求并重定向到登录页面; +3)如果是post方法的登录页面表单提交请求,则收集用户名/密码登录即可,如果失败了保存错误消息到“shiroLoginFailure”并返回到登录页面; +4)如果登录成功了,且之前有保存的请求,则重定向到之前的这个请求,否则到默认的成功页面。 + +任意角色授权拦截器 +流程: +1)首先判断用户有没有任意角色,如果没有返回false,将到onAccessDenied进行处理; +2)如果用户没有角色,接着判断用户有没有登录,如果没有登录先重定向到登录; +3)如果用户没有角色且设置了未授权页面(unauthorizedUrl),那么重定向到未授权页面;否则直接返回401未授权错误码。 + +默认拦截器 +身份验证相关的 +authc 基于表单的拦截器,即验证成功之后才能访问 /=authc +authcBasic Basic HTTP身份验证拦截器,主要属性:applicationName +logout 退出 /logout=logout +user 用户拦截器 /=user +anon 匿名拦截器,一般用于静态资源过滤 /static/=anon + +授权相关的 +roles 角色授权拦截器,主要属性:loginUrl,unauthorizedUrl /admin/=roles[admin] +perms 权限授权拦截器 /user/=perms[“user:create”] +port 端口拦截器,主要属性: port(80) /test=port[80] +rest rest风格拦截器 /users=rest[user],会自动拼接出“user:read,user:create,user:update,user:delete” +ssl ssl拦截器,只有请求协议是https才能通过 + +#### 10.Session Manager 会话管理介绍一下 + +Session +所谓session,即用户访问应用时保持的连接关系,在多次交互中应用能够识别出当前访问的用户是谁,且可以在多次交互中保存一些数据。 +Subject subject = SecurityUtils.getSubject(); +Session session = subject.getSession(); +session.getId(); // 获取当前session的唯一标识 +session.getHost(); // 获取当前Subject的主机地址,该地址是通过HostAuthenticationToken.getHost()提供的 +session.getTimeOut(); // 获取超时时间 +session.setTimeOut(); // 设置超时时间(不设置默认是全局过期时间) +session.touch(); // 更新最后访问时间 +session.stop(); // 销毁session,当Subject.logout()时会自动调用stop方法来销毁会话。如果在web中,调用javax.servlet.http.HttpSession.invalidate()也会自动调用shiro session.top方法进行销毁shiro的会话 +session.setAttribute(“key”,”123”); // 设置session属性 +session.getAttribute(“key”); // 获取session属性 +session.removeAttribute(“key”); // 删除属性 +注:Shiro提供的会话可以用于javaSE/javaEE环境,不依赖于任何底层容器,可以独立使用,是完整的会话模块。 + +Session manager 会话管理器 +会话管理器管理着应用中所有Subject的会话的创建、维护、删除、失效、验证等工作。是Shiro的核心组件,顶层组件SecurityManager直接继承了SessionManager,且提供了SessionSecurityManager实现直接把会话管理委托给相应的SessionManager、DefaultSecurityManager及DefaultWebSecurityManager 默认SecurityManager都继承了SessionSecurityManager。 + +Shiro提供了三个默认实现: +DefaultSessionManager:DefaultSecurityManager使用的默认实现,用于JavaSE环境; +ServletContainerSessionManager: DefaultWebSecurityManager使用的默认实现,用于Web环境,其直接使用Servlet容器的会话; +DefaultWebSessionManager:用于Web环境的实现,可以替代ServletContainerSessionManager,自己维护着会话,直接废弃了Servlet容器的会话管理。 + +#### 参考资料 + +https://blog.csdn.net/qq_37254736/article/details/99350029 + +https://blog.csdn.net/pzq915981048/article/details/88971300 diff --git a/Spring.md b/Spring.md new file mode 100644 index 0000000..a276de4 --- /dev/null +++ b/Spring.md @@ -0,0 +1,303 @@ +## Spring + + +* [1.什么是spring?](#1什么是spring) +* [2.使用Spring框架的好处是什么?](#2使用spring框架的好处是什么) +* [3.Spring由哪些模块组成?](#3spring由哪些模块组成) +* [4.Spring是怎么解决循环依赖的?](#4spring是怎么解决循环依赖的) +* [5.Spring Boot手动装配有哪几种方式?](#5spring-boot手动装配有哪几种方式) +* [6.Spring Boot自动配置原理](#6spring-boot自动配置原理) +* [7.谈谈自己对于Spring IOC的理解](#7谈谈自己对于spring-ioc的理解) +* [8.谈谈自己对于Spring AOP的理解](#8谈谈自己对于spring-aop的理解) +* [9.Spring AOP和AspectJ AOP有什么区别?](#9spring-aop和aspectj-aop有什么区别) +* [10.Spring中的bean的作用域有哪些?](#10spring中的bean的作用域有哪些) +* [11.Spring中的单例bean的线程安全问题了解吗?](#11spring中的单例bean的线程安全问题了解吗) +* [12.Spring中的bean生命周期了解过吗?](#12spring中的bean生命周期了解过吗) +* [13.Spring MVC的工作原理了解嘛?](#13spring-mvc的工作原理了解嘛) +* [14.Spring框架中用到了哪些设计模式?](#14spring框架中用到了哪些设计模式) +* [15.@Component和@Bean的区别是什么?](#15component和bean的区别是什么) +* [16.将一个类声明为Spring的bean的注解有哪些?](#16将一个类声明为spring的bean的注解有哪些) +* [17.Spring事务管理的方式有几种?](#17spring事务管理的方式有几种) +* [18.Spring事务中的隔离级别有哪几种?](#18spring事务中的隔离级别有哪几种) +* [19.Spring事务中有哪几种事务传播行为?](#19spring事务中有哪几种事务传播行为) +* [20.Spring 事务底层原理](#20spring-事务底层原理) +* [21.BeanFactory和ApplicationContext有什么区别?](#21beanfactory和applicationcontext有什么区别) +* [22.Resource 是如何被查找、加载的?](#22resource-是如何被查找加载的) +* [23.解释自动装配的各种模式?](#23解释自动装配的各种模式) +* [24.有哪些不同类型的IOC(依赖注入)?](#24有哪些不同类型的ioc依赖注入) +* [25.Spring AOP 实现原理](#25spring-aop-实现原理) +* [26.ApplicationContext通常的实现是什么?](#26applicationcontext通常的实现是什么) +* [27. Bean 工厂和 Application contexts 有什么区别?](#27-bean-工厂和-application-contexts-有什么区别) +* [参考资料](#参考资料) + + + +#### 1.什么是spring? + +Spring 是个java企业级应用的开源开发框架。Spring主要用来开发Java应用,但是有些扩展是针对构建J2EE平台的web应用。Spring 框架目标是简化Java企业级应用开发,并通过POJO为基础的编程模型促进良好的编程习惯。 + +#### 2.使用Spring框架的好处是什么? + +- 轻量:Spring 是轻量的,基本的版本大约2MB。 +- 控制反转:Spring通过控制反转实现了松散耦合,对象们给出它们的依赖,而不是创建或查找依赖的对象们。 +- 面向切面的编程(AOP):Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开。 +- 容器:Spring 包含并管理应用中对象的生命周期和配置。 +- MVC框架:Spring的WEB框架是个精心设计的框架,是Web框架的一个很好的替代品。 +- 事务管理:Spring 提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA)。 +- 异常处理:Spring 提供方便的API把具体技术相关的异常(比如由JDBC,Hibernate or JDO抛出的)转化为一致的unchecked 异常。 + +#### 3.Spring由哪些模块组成? + +以下是Spring 框架的基本模块: + +- Core module +- Bean module +- Context module +- Expression Language module +- JDBC module +- ORM module +- OXM module +- Java Messaging Service(JMS) module +- Transaction module +- Web module +- Web-Servlet module +- Web-Struts module +- Web-Portlet module + +#### 4.Spring是怎么解决循环依赖的? + +整个IOC容器解决循环依赖,用到的几个重要成员: +singletonObjects:一级缓存,存放完全初始化好的Bean的集合,从这个集合中取出来的Bean可以立马返回 +earlySingletonObjects:二级缓存,存放创建好但没有初始化属性的Bean的集合,它用来解决循环依赖 +singletonFactories:三级缓存,存放单实例Bean工厂的集合 +singletonsCurrentlyInCreation:存放正在被创建的Bean的集合 + +IOC容器解决循环依赖的思路: + +1. 初始化Bean之前,将这个BeanName放入三级缓存 +2. 创建Bean将准备创建的Bean放入 singletonsCurrentlyInCreation (正在创建的Bean) +3. createNewInstance 方法执行完后执行 addSingletonFactory,将这个实例化但没有属性赋值的Bean放入二级缓存,并从三级缓存中移除 +4. 属性赋值&自动注入时,引发关联创建 +5. 关联创建时,检查“正在被创建的Bean”中是否有即将注入的Bean。如果有,检查二级缓存中是否有当前创建好但没有赋值初始化的Bean。如果没有,检查三级缓存中是否有正在创建中的Bean。至此一般会有,将这个Bean放入二级缓存,并从三级缓存中移除 +6. 之后Bean被成功注入,最后执行 addSingleton,将这个完全创建好的Bean放入一级缓存,从二级缓存和三级缓存移除,并记录已经创建了的单实例Bean + +#### 5.Spring Boot手动装配有哪几种方式? + +1. 使用模式注解 @Component 等(Spring2.5+) +2. 使用配置类 @Configuration 与 @Bean (Spring3.0+) +3. 使用模块装配 @EnableXXX 与 @Import (Spring3.1+) + +其中使用 @Component 及衍生注解很常见,咱开发中常用的套路,不再赘述。 +但模式注解只能在自己编写的代码中标注,无法装配jar包中的组件。为此可以使用 @Configuration 与 @Bean,手动装配组件(如上一篇的 @Configuration 示例)。但这种方式一旦注册过多,会导致编码成本高,维护不灵活等问题。 +SpringFramework 提供了模块装配功能,通过给配置类标注 @EnableXXX 注解,再在注解上标注 @Import 注解,即可完成组件装配的效果。 + +#### 6.Spring Boot自动配置原理 + +详见:https://blog.csdn.net/Dongguabai/article/details/80865599 + + +#### 7.谈谈自己对于Spring IOC的理解 + +IOC(Inversion Of Controll,控制反转)是一种设计思想,就是将原本在程序中手动创建对象的控制权,交由给Spring框架来管理。IOC在其他语言中也有应用,并非Spring特有。IOC容器是Spring用来实现IOC的载体,IOC容器实际上就是一个Map(key, value),Map中存放的是各种对象。 + +将对象之间的相互依赖关系交给IOC容器来管理,并由IOC容器完成对象的注入。这样可以很大程度上简化应用的开发,把应用从复杂的依赖关系中解放出来。IOC容器就像是一个工厂一样,当我们需要创建一个对象的时候,只需要配置好配置文件/注解即可,完全不用考虑对象是如何被创建出来的。在实际项目中一个Service类可能由几百甚至上千个类作为它的底层,假如我们需要实例化这个Service,可能要每次都搞清楚这个Service所有底层类的构造函数,这可能会把人逼疯。如果利用IOC的话,你只需要配置好,然后在需要的地方引用就行了,大大增加了项目的可维护性且降低了开发难度。 + +Spring时代我们一般通过XML文件来配置Bean,后来开发人员觉得用XML文件来配置不太好,于是Sprng Boot注解配置就慢慢开始流行起来。 + +#### 8.谈谈自己对于Spring AOP的理解 + +AOP(Aspect-Oriented Programming,面向切面编程)能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可扩展性和可维护性。 + +Spring AOP是基于动态代理的,如果要代理的对象实现了某个接口,那么Spring AOP就会使用JDK动态代理去创建代理对象;而对于没有实现接口的对象,就无法使用JDK动态代理,转而使用CGlib动态代理生成一个被代理对象的子类来作为代理。 +当然也可以使用AspectJ,Spring AOP中已经集成了AspectJ,AspectJ应该算得上是Java生态系统中最完整的AOP框架了。使用AOP之后我们可以把一些通用功能抽象出来,在需要用到的地方直接使用即可,这样可以大大简化代码量。我们需要增加新功能也方便,提高了系统的扩展性。日志功能、事务管理和权限管理等场景都用到了AOP。 + +#### 9.Spring AOP和AspectJ AOP有什么区别? + +Spring AOP是属于运行时增强,而AspectJ是编译时增强。Spring AOP基于代理(Proxying),而AspectJ基于字节码操作(Bytecode Manipulation)。 + +Spring AOP已经集成了AspectJ,AspectJ应该算得上是Java生态系统中最完整的AOP框架了。AspectJ相比于Spring AOP功能更加强大,但是Spring AOP相对来说更简单。 + +如果我们的切面比较少,那么两者性能差异不大。但是,当切面太多的话,最好选择AspectJ,它比SpringAOP快很多。 + +#### 10.Spring中的bean的作用域有哪些? + +1.singleton:唯一bean实例,Spring中的bean默认都是单例的。 +2.prototype:每次请求都会创建一个新的bean实例。 +3.request:每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP request内有效。 +4.session:每一次HTTP请求都会产生一个新的bean,该bean仅在当前HTTP session内有效。 +5.global-session:全局session作用域,仅仅在基于Portlet的Web应用中才有意义,Spring5中已经没有了。Portlet是能够生成语义代码(例如HTML)片段的小型Java Web插件。它们基于Portlet容器,可以像Servlet一样处理HTTP请求。但是与Servlet不同,每个Portlet都有不同的会话。 + +#### 11.Spring中的单例bean的线程安全问题了解吗? + +大部分时候我们并没有在系统中使用多线程,所以很少有人会关注这个问题。单例bean存在线程问题,主要是因为当多个线程操作同一个对象的时候,对这个对象的非静态成员变量的写操作会存在线程安全问题。 +有两种常见的解决方案: +1.在bean对象中尽量避免定义可变的成员变量(不太现实)。 +2.在类中定义一个ThreadLocal成员变量,将需要的可变成员变量保存在ThreadLocal中(推荐的一种方式)。 + +#### 12.Spring中的bean生命周期了解过吗? + +1.Bean容器找到配置文件中Spring Bean的定义。 +2.Bean容器利用Java Reflection API创建一个Bean的实例。 +3.如果涉及到一些属性值,利用set()方法设置一些属性值。 +4.如果Bean实现了BeanNameAware接口,调用setBeanName()方法,传入Bean的名字。 +5.如果Bean实现了BeanClassLoaderAware接口,调用setBeanClassLoader()方法,传入ClassLoader对象的实例。 +6.如果Bean实现了BeanFactoryAware接口,调用setBeanClassFacotory()方法,传入ClassLoader对象的实例。 +7.与上面的类似,如果实现了其他*Aware接口,就调用相应的方法。 +8.如果有和加载这个Bean的Spring容器相关的BeanPostProcessor对象,执行postProcessBeforeInitialization()方法。 +9.如果Bean实现了InitializingBean接口,执行afeterPropertiesSet()方法。 +10.如果Bean在配置文件中的定义包含init-method属性,执行指定的方法。 +11.如果有和加载这个Bean的Spring容器相关的BeanPostProcess对象,执行postProcessAfterInitialization()方法。 +12.当要销毁Bean的时候,如果Bean实现了DisposableBean接口,执行destroy()方法。 +13.当要销毁Bean的时候,如果Bean在配置文件中的定义包含destroy-method属性,执行指定的方法。 + +#### 13.Spring MVC的工作原理了解嘛? + +1.客户端(浏览器)发送请求,直接请求到DispatcherServlet。 +2.DispatcherServlet根据请求信息调用HandlerMapping,解析请求对应的Handler。 +3.解析到对应的Handler(也就是我们平常说的Controller控制器)。 +4.HandlerAdapter会根据Handler来调用真正的处理器来处理请求和执行相对应的业务逻辑。 +5.处理器处理完业务后,会返回一个ModelAndView对象,Model是返回的数据对象,View是逻辑上的View。 +6.ViewResolver会根据逻辑View去查找实际的View。 +7.DispatcherServlet把返回的Model传给View(视图渲染)。 +8.把View返回给请求者(浏览器)。 + +#### 14.Spring框架中用到了哪些设计模式? + +1.工厂设计模式:Spring使用工厂模式通过BeanFactory和ApplicationContext创建bean对象。 +2.代理设计模式:Spring AOP功能的实现。 +3.单例设计模式:Spring中的bean默认都是单例的。 +4.模板方法模式:Spring中的jdbcTemplate、hibernateTemplate等以Template结尾的对数据库操作的类,它们就使用到了模板模式。 +5.包装器设计模式:我们的项目需要连接多个数据库,而且不同的客户在每次访问中根据需要会去访问不同的数据库。这种模式让我们可以根据客户的需求能够动态切换不同的数据源。 +6.观察者模式:Spring事件驱动模型就是观察者模式很经典的一个应用。 +7.适配器模式:Spring AOP的增强或通知(Advice)使用到了适配器模式、Spring MVC中也是用到了适配器模式适配Controller。 + +#### 15.@Component和@Bean的区别是什么? + +1.作用对象不同。@Component注解作用于类,而@Bean注解作用于方法。 +2.@Component注解通常是通过类路径扫描来自动侦测以及自动装配到Spring容器中(我们可以使用@ComponentScan注解定义要扫描的路径)。@Bean注解通常是在标有该注解的方法中定义产生这个bean,告诉Spring这是某个类的实例,当我需要用它的时候还给我。 +3.@Bean注解比@Component注解的自定义性更强,而且很多地方只能通过@Bean注解来注册bean。比如当引用第三方库的类需要装配到Spring容器的时候,就只能通过@Bean注解来实现。 + +#### 16.将一个类声明为Spring的bean的注解有哪些? + +我们一般使用@Autowired注解去自动装配bean。而想要把一个类标识为可以用@Autowired注解自动装配的bean,可以采用以下的注解实现: +1.@Component注解。通用的注解,可标注任意类为Spring组件。如果一个Bean不知道属于哪一个层,可以使用@Component注解标注。 +2.@Repository注解。对应持久层,即Dao层,主要用于数据库相关操作。 +3.@Service注解。对应服务层,即Service层,主要涉及一些复杂的逻辑,需要用到Dao层(注入)。 +4.@Controller注解。对应Spring MVC的控制层,即Controller层,主要用于接受用户请求并调用Service层的方法返回数据给前端页面。 + +#### 17.Spring事务管理的方式有几种? + +1.编程式事务:在代码中硬编码(不推荐使用)。 +2.声明式事务:在配置文件中配置(推荐使用),分为基于XML的声明式事务和基于注解的声明式事务。 + +#### 18.Spring事务中的隔离级别有哪几种? + +在TransactionDefinition接口中定义了五个表示隔离级别的常量: + +ISOLATION_DEFAULT:使用后端数据库默认的隔离级别,Mysql默认采用的REPEATABLE_READ隔离级别;Oracle默认采用的READ_COMMITTED隔离级别。 + +ISOLATION_READ_UNCOMMITTED:最低的隔离级别,允许读取尚未提交的数据变更,可能会导致脏读、幻读或不可重复读。 + +ISOLATION_READ_COMMITTED:允许读取并发事务已经提交的数据,可以阻止脏读,但是幻读或不可重复读仍有可能发生 + +ISOLATION_REPEATABLE_READ:对同一字段的多次读取结果都是一致的,除非数据是被本身事务自己所修改,可以阻止脏读和不可重复读,但幻读仍有可能发生。 + +ISOLATION_SERIALIZABLE:最高的隔离级别,完全服从ACID的隔离级别。所有的事务依次逐个执行,这样事务之间就完全不可能产生干扰,也就是说,该级别可以防止脏读、不可重复读以及幻读。但是这将严重影响程序的性能。通常情况下也不会用到该级别。 + +#### 19.Spring事务中有哪几种事务传播行为? + +在TransactionDefinition接口中定义了八个表示事务传播行为的常量。 + +支持当前事务的情况: +PROPAGATION_REQUIRED:如果当前存在事务,则加入该事务;如果当前没有事务,则创建一个新的事务。 +PROPAGATION_SUPPORTS: 如果当前存在事务,则加入该事务;如果当前没有事务,则以非事务的方式继续运行。 +PROPAGATION_MANDATORY: 如果当前存在事务,则加入该事务;如果当前没有事务,则抛出异常。(mandatory:强制性)。 + +不支持当前事务的情况: +PROPAGATION_REQUIRES_NEW: 创建一个新的事务,如果当前存在事务,则把当前事务挂起。 +PROPAGATION_NOT_SUPPORTED: 以非事务方式运行,如果当前存在事务,则把当前事务挂起。 +PROPAGATION_NEVER: 以非事务方式运行,如果当前存在事务,则抛出异常。 + +其他情况: +PROPAGATION_NESTED: 如果当前存在事务,则创建一个事务作为当前事务的嵌套事务来运行;如果当前没有事务,则该取值等价于PROPAGATION_REQUIRED。 + +#### 20.Spring 事务底层原理 + +划分处理单元——IoC +由于spring解决的问题是对单个数据库进行局部事务处理的,具体的实现首先用spring中的IoC划分了事务处理单元。并且将对事务的各种配置放到了ioc容器中(设置事务管理器,设置事务的传播特性及隔离机制)。 + +AOP拦截需要进行事务处理的类 +Spring事务处理模块是通过AOP功能来实现声明式事务处理的,具体操作(比如事务实行的配置和读取,事务对象的抽象),用TransactionProxyFactoryBean接口来使用AOP功能,生成proxy代理对象,通过TransactionInterceptor完成对代理方法的拦截,将事务处理的功能编织到拦截的方法中。读取ioc容器事务配置属性,转化为spring事务处理需要的内部数据结构(TransactionAttributeSourceAdvisor),转化为TransactionAttribute表示的数据对象。 + +对事务处理实现(事务的生成、提交、回滚、挂起) +spring委托给具体的事务处理器实现。实现了一个抽象和适配。适配的具体事务处理器:DataSource数据源支持、hibernate数据源事务处理支持、JDO数据源事务处理支持,JPA、JTA数据源事务处理支持。这些支持都是通过设计PlatformTransactionManager、AbstractPlatforTransaction一系列事务处理的支持。 为常用数据源支持提供了一系列的TransactionManager。 + +总结 +PlatformTransactionManager实现了TransactionInterception接口,让其与TransactionProxyFactoryBean结合起来,形成一个Spring声明式事务处理的设计体系。 + +#### 21.BeanFactory和ApplicationContext有什么区别? + +ApplicationContext提供了一种解决文档信息的方法,一种加载文件资源的方式(如图片),他们可以向监听他们的beans发送消息。另外,容器或者容器中beans的操作,这些必须以bean工厂的编程方式处理的操作可以在应用上下文中以声明的方式处理。应用上下文实现了MessageSource,该接口用于获取本地消息,实际的实现是可选的。 + +相同点:两者都是通过xml配置文件加载bean,ApplicationContext和BeanFacotry相比,提供了更多的扩展功能。 + +不同点:BeanFactory是延迟加载,如果Bean的某一个属性没有注入,BeanFacotry加载后,直至第一次使用调用getBean方法才会抛出异常;而ApplicationContext则在初始化自身是检验,这样有利于检查所依赖属性是否注入;所以通常情况下我们选择使用ApplicationContext。 + + +#### 22.Resource 是如何被查找、加载的? + +Resource 接口是 Spring 资源访问策略的抽象,它本身并不提供任何资源访问实现,具体的资源访问由该接口的实现类完成——每个实现类代表一种资源访问策略。 Spring 为 Resource 接口提供了如下实现类: + +UrlResource:访问网络资源的实现类。ClassPathResource:访问类加载路径里资源的实现类。FileSystemResource:访问文件系统里资源的实现类。ServletContextResource:访问相对于 ServletContext 路径里的资源的实现类:InputStreamResource:访问输入流资源的实现类。ByteArrayResource:访问字节数组资源的实现类。 这些 Resource 实现类,针对不同的的底层资源,提供了相应的资源访问逻辑,并提供便捷的包装,以利于客户端程序的资源访问。 + +#### 23.解释自动装配的各种模式? + +自动装配提供五种不同的模式供Spring容器用来自动装配beans之间的依赖注入: + +no:默认的方式是不进行自动装配,通过手工设置ref 属性来进行装配bean。 + +byName:通过参数名自动装配,Spring容器查找beans的属性,这些beans在XML配置文件中被设置为byName。之后容器试图匹配、装配和该bean的属性具有相同名字的bean。 + +byType:通过参数的数据类型自动自动装配,Spring容器查找beans的属性,这些beans在XML配置文件中被设置为byType。之后容器试图匹配和装配和该bean的属性类型一样的bean。如果有多个bean符合条件,则抛出错误。 + +constructor:这个同byType类似,不过是应用于构造函数的参数。如果在BeanFactory中不是恰好有一个bean与构造函数参数相同类型,则抛出一个严重的错误。 + +autodetect:如果有默认的构造方法,通过 construct的方式自动装配,否则使用 byType的方式自动装配。 + +#### 24.有哪些不同类型的IOC(依赖注入)? + +构造器依赖注入:构造器依赖注入在容器触发构造器的时候完成,该构造器有一系列的参数,每个参数代表注入的对象。 + +Setter方法依赖注入:首先容器会触发一个无参构造函数或无参静态工厂方法实例化对象,之后容器调用bean中的setter方法完成Setter方法依赖注入。 + +#### 25.Spring AOP 实现原理 + +实现AOP的技术,主要分为两大类: + +一是采用动态代理技术,利用截取消息的方式,对该消息进行装饰,以取代原有对象行为的执行;二是采用静态织入的方式,引入特定的语法创建“方面”,从而使得编译器可以在编译期间织入有关“方面”的代码。 +Spring AOP 的实现原理其实很简单:AOP 框架负责动态地生成 AOP 代理类,这个代理类的方法则由 Advice和回调目标对象的方法所组成, 并将该对象可作为目标对象使用。AOP 代理包含了目标对象的全部方法,但AOP代理中的方法与目标对象的方法存在差异,AOP方法在特定切入点添加了增强处理,并回调了目标对象的方法。 + +Spring AOP使用动态代理技术在运行期织入增强代码。使用两种代理机制:基于JDK的动态代理(JDK本身只提供接口的代理)和基于CGlib的动态代理。 + +(1) JDK的动态代理 +JDK的动态代理主要涉及java.lang.reflect包中的两个类:Proxy和InvocationHandler。其中InvocationHandler只是一个接口,可以通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态的将横切逻辑与业务逻辑织在一起。而Proxy利用InvocationHandler动态创建一个符合某一接口的实例,生成目标类的代理对象。 +其代理对象必须是某个接口的实现, 它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理.只能实现接口的类生成代理,而不能针对类。 +(2)CGLib +CGLib采用底层的字节码技术,为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类的调用方法,并顺势织入横切逻辑.它运行期间生成的代理对象是目标类的扩展子类.所以无法通知final、private的方法,因为它们不能被覆写.是针对类实现代理,主要是为指定的类生成一个子类,覆盖其中方法。 +在spring中默认。况下使用JDK动态代理实现AOP,如果proxy-target-class设置为true或者使用了优化策略那么会使用CGLIB来创建动态代理.Spring AOP在这两种方式的实现上基本一样.以JDK代理为例,会使用JdkDynamicAopProxy来创建代理,在invoke()方法首先需要织入到当前类的增强器封装到拦截器链中,然后递归的调用这些拦截器完成功能的织入,最终返回代理对象。 + +#### 26.ApplicationContext通常的实现是什么? + +- FileSystemXmlApplicationContext :此容器从一个XML文件中加载beans的定义,XML Bean 配置文件的全路径名必须提供给它的构造函数。 +- ClassPathXmlApplicationContext:此容器也从一个XML文件中加载beans的定义,这里,你需要正确设置classpath因为这个容器将在classpath里找bean配置。 +- WebXmlApplicationContext:此容器加载一个XML文件,此文件定义了一个WEB应用的所有bean。 + +#### 27. Bean 工厂和 Application contexts 有什么区别? + +Application contexts提供一种方法处理文本消息,一个通常的做法是加载文件资源(比如镜像),它们可以向注册为监听器的bean发布事件。另外,在容器或容器内的对象上执行的那些不得不由bean工厂以程序化方式处理的操作,可以在Application contexts中以声明的方式处理。Application contexts实现了MessageSource接口,该接口的实现以可插拔的方式提供获取本地化消息的方法。 + + +### 参考资料 +https://www.cnblogs.com/yanggb/p/11004887.html +https://www.jianshu.com/p/a5d960c6f6dd +https://ifeve.com/spring-interview-questions-and-answers/ diff --git a/SpringBoot.md b/SpringBoot.md new file mode 100644 index 0000000..28cd654 --- /dev/null +++ b/SpringBoot.md @@ -0,0 +1,373 @@ +## Spring Boot + + +* [1.什么是springboot](#1什么是springboot) +* [2.Spring Boot 有哪些优点?](#2spring-boot-有哪些优点) +* [3. 创建一个 Spring Boot Project 的最简单的方法是什么?](#3-创建一个-spring-boot-project-的最简单的方法是什么) +* [4.Spring 和 SpringBoot 有什么不同?](#4spring-和-springboot-有什么不同) +* [5.如何重新加载 Spring Boot 上的更改,而无需重新启动服务器?](#5如何重新加载-spring-boot-上的更改而无需重新启动服务器) +* [6.Spring Boot 中的监视器是什么?](#6spring-boot-中的监视器是什么) +* [7.如何在 Spring Boot 中禁用 Actuator 端点安全性?](#7如何在-spring-boot-中禁用-actuator-端点安全性) +* [8.怎么使用 Maven 来构建一个 SpringBoot 程序?](#8怎么使用-maven-来构建一个-springboot-程序) +* [9.Spring Initializr 是创建 Spring Boot Projects 的唯一方法吗?](#9spring-initializr-是创建-spring-boot-projects-的唯一方法吗) +* [10.为什么我们需要 spring-boot-maven-plugin?](#10为什么我们需要-spring-boot-maven-plugin) +* [11.什么是嵌入式服务器?我们为什么要使用嵌入式服务器呢?](#11什么是嵌入式服务器我们为什么要使用嵌入式服务器呢) +* [12.如何在 Spring Boot 中添加通用的 JS 代码?](#12如何在-spring-boot-中添加通用的-js-代码) +* [13.如何使用 Spring Boot 部署到不同的服务器?](#13如何使用-spring-boot-部署到不同的服务器) +* [14.如何使用配置文件通过 Spring Boot 配置特定环境的配置?](#14如何使用配置文件通过-spring-boot-配置特定环境的配置) +* [15.什么是Swagger?你用Spring Boot实现了吗?](#15什么是swagger你用spring-boot实现了吗) +* [16.如何实现Spring Boot应用程序的安全性?](#16如何实现spring-boot应用程序的安全性) +* [17.比较一下Spring Security和Shiro各自的优缺点?](#17比较一下spring-security和shiro各自的优缺点) +* [18.Spring Boot中如何解决跨域问题?](#18spring-boot中如何解决跨域问题) +* [19.Spring Boot的核心注解是哪些?他由哪几个注解组成的?](#19spring-boot的核心注解是哪些他由哪几个注解组成的) +* [20.保护SpringBoot应用有哪些方法?](#20保护springboot应用有哪些方法) +* [21.SpringBoot 2.X有哪些新特性?与1.X有什么区别?](#21springboot-2x有哪些新特性与1x有什么区别) +* [参考链接](#参考链接) + + +#### 1.什么是springboot + +用来简化spring应用的初始搭建以及开发过程 使用特定的方式来进行配置(properties或yml文件) +创建独立的spring引用程序 main方法运行 +嵌入的Tomcat 无需部署war文件 +简化maven配置 +自动配置spring添加对应功能starter自动化配置 + +spring boot来简化spring应用开发,约定大于配置,去繁从简,just run就能创建一个独立的,产品级别的应用 + +#### 2.Spring Boot 有哪些优点? + +Spring Boot 的优点有: + +1、减少开发,测试时间和努力。 + +2、使用 JavaConfig 有助于避免使用 XML。 + +3、避免大量的 Maven 导入和各种版本冲突。 + +4、提供意见发展方法。 + +5、通过提供默认值快速开始开发。 + +6、没有单独的 Web 服务器需要。这意味着你不再需要启动 Tomcat,Glassfish或其他任何东西。 + +7、需要更少的配置 因为没有 web.xml 文件。只需添加用@ Configuration 注释的类,然后添加用@Bean 注释的方法,Spring 将自动加载对象并像以前一样对其进行管理。您甚至可以将@Autowired 添加到 bean 方法中,以使 Spring 自动装入需要的依赖关系中。 + +8、基于环境的配置 使用这些属性,您可以将您正在使用的环境传递到应用程序:-Dspring.profiles.active = {enviornment}。在加载主应用程序属性文件后,Spring 将在(application{environment} .properties)中加载后续的应用程序属性文件。 + +#### 3. 创建一个 Spring Boot Project 的最简单的方法是什么? + +Spring Initializr是启动 Spring Boot Projects 的一个很好的工具。 + +![img](https://mmbiz.qpic.cn/mmbiz_png/z1ViaEyjXTiasVydib8iavtBEG3AxK2Z11pdsWll8fxLf3DloRzpRt6eh38xbSSycexCKsYJxB6bzgk4qMAYAp6xZg/640) + +- 就像上图中所展示的一样,我们需要做一下几步: +- 登录 Spring Initializr,按照以下方式进行选择: +- 选择 com.in28minutes.springboot 为组 +- 选择 studet-services 为组件 +- 选择下面的依赖项 +- Web +- Actuator +- DevTools +- 点击生 GenerateProject +- 将项目导入 Eclipse。文件 - 导入 - 现有的 Maven 项目 + +#### 4.Spring 和 SpringBoot 有什么不同? + +Spring 框架提供多种特性使得 web 应用开发变得更简便,包括依赖注入、数据绑定、切面编程、数据存取等等。 + +随着时间推移,Spring 生态变得越来越复杂了,并且应用程序所必须的配置文件也令人觉得可怕。这就是 Spirng Boot 派上用场的地方了 – 它使得 Spring 的配置变得更轻而易举。 + +实际上,Spring 是 *unopinionated*(予以配置项多,倾向性弱) 的,Spring Boot 在平台和库的做法中更 *opinionated* ,使得我们更容易上手。 + +这里有两条 SpringBoot 带来的好处: + +- 根据 classpath 中的 artifacts 的自动化配置应用程序 +- 提供非功能性特性例如安全和健康检查给到生产环境中的应用程序 + +#### 5.如何重新加载 Spring Boot 上的更改,而无需重新启动服务器? + +这可以使用 DEV 工具来实现。通过这种依赖关系,您可以节省任何更改,嵌入式tomcat 将重新启动。Spring Boot 有一个开发工具(DevTools)模块,它有助于提高开发人员的生产力。Java 开发人员面临的一个主要挑战是将文件更改自动部署到服务器并自动重启服务器。开发人员可以重新加载 Spring Boot 上的更改,而无需重新启动服务器。这将消除每次手动部署更改的需要。Spring Boot 在发布它的第一个版本时没有这个功能。这是开发人员最需要的功能。DevTools 模块完全满足开发人员的需求。该模块将在生产环境中被禁用。它还提供 H2 数据库控制台以更好地测试应用程序。 + +```xml + +org.springframework.boot +spring-boot-devtools +true + +``` + +#### 6.Spring Boot 中的监视器是什么? + +Spring boot actuator 是 spring 启动框架中的重要功能之一。Spring boot 监视器可帮助您访问生产环境中正在运行的应用程序的当前状态。有几个指标必须在生产环境中进行检查和监控。即使一些外部应用程序可能正在使用这些服务来向相关人员触发警报消息。监视器模块公开了一组可直接作为 HTTP URL 访问的REST 端点来检查状态。 + +#### 7.如何在 Spring Boot 中禁用 Actuator 端点安全性? + +默认情况下,所有敏感的 HTTP 端点都是安全的,只有具有 ACTUATOR 角色的用户才能访问它们。安全性是使用标准的 HttpServletRequest.isUserInRole 方法实施的。 我们可以使用来禁用安全性。只有在执行机构端点在防火墙后访问时,才建议禁用安全性。 + +#### 8.怎么使用 Maven 来构建一个 SpringBoot 程序? + +就像引入其他库一样,我们可以在 Maven 工程中加入 SpringBoot 依赖。然而,最好是从 *spring-boot-starter-parent* 项目中继承以及声明依赖到 Spring Boot starters。这样做可以使我们的项目可以重用 SpringBoot 的默认配置。 + +继承 *spring-boot-starter-parent* 项目依赖很简单 – 我们只需要在 *pom.xml* 中定义一个 *parent* 节点: + +``` + + org.springframework.boot + spring-boot-starter-parent + 2.1.1.RELEASE + +``` + +我们可以在 Maven central 中找到 *spring-boot-starter-parent* 的最新版本。 + +使用 starter 父项目依赖很方便,但并非总是可行。例如,如果我们公司都要求项目继承标准 POM,我们就不能依赖 SpringBoot starter 了。 + +这种情况,我们可以通过对 POM 元素的依赖管理来处理: + +```xml + + + + org.springframework.boot + spring-boot-dependencies + 2.1.1.RELEASE + pom + import + + + +``` + + + +#### 9.Spring Initializr 是创建 Spring Boot Projects 的唯一方法吗? + +不是的。 + +Spring Initiatlizr 让创建 Spring Boot 项目变的很容易,但是,你也可以通过设置一个 maven 项目并添加正确的依赖项来开始一个项目。 + +在我们的 Spring 课程中,我们使用两种方法来创建项目。 + +第一种方法是 start.spring.io 。 + +另外一种方法是在项目的标题为“Basic Web Application”处进行手动设置。 + +手动设置一个 maven 项目 + +这里有几个重要的步骤: + +- 在 Eclipse 中,使用文件 - 新建 Maven 项目来创建一个新项目 +- 添加依赖项。 +- 添加 maven 插件。 +- 添加 Spring Boot 应用程序类。 + +到这里,准备工作已经做好! + +#### 10.为什么我们需要 spring-boot-maven-plugin? + +spring-boot-maven-plugin 提供了一些像 jar 一样打包或者运行应用程序的命令。 + +- spring-boot:run 运行你的 SpringBooty 应用程序。 +- spring-boot:repackage 重新打包你的 jar 包或者是 war 包使其可执行 +- spring-boot:start 和 spring-boot:stop 管理 Spring Boot 应用程序的生命周期(也可以说是为了集成测试)。 +- spring-boot:build-info 生成执行器可以使用的构造信息。 + +#### 11.什么是嵌入式服务器?我们为什么要使用嵌入式服务器呢? + +思考一下在你的虚拟机上部署应用程序需要些什么。 + +第一步: 安装 Java + +第二部: 安装 Web 或者是应用程序的服务器(Tomat/Wbesphere/Weblogic 等等) + +第三部: 部署应用程序 war 包 + +如果我们想简化这些步骤,应该如何做呢? + +让我们来思考如何使服务器成为应用程序的一部分? + +你只需要一个安装了 Java 的虚拟机,就可以直接在上面部署应用程序了, + +是不是很爽? + +这个想法是嵌入式服务器的起源。 + +当我们创建一个可以部署的应用程序的时候,我们将会把服务器(例如,tomcat)嵌入到可部署的服务器中。 + +例如,对于一个 Spring Boot 应用程序来说,你可以生成一个包含 Embedded Tomcat 的应用程序 jar。你就可以想运行正常 Java 应用程序一样来运行 web 应用程序了。 + +嵌入式服务器就是我们的可执行单元包含服务器的二进制文件(例如,tomcat.jar)。 + +#### 12.如何在 Spring Boot 中添加通用的 JS 代码? + +在源文件夹下,创建一个名为 static 的文件夹。然后,你可以把你的静态的内容放在这里面。 + +例如,myapp.js 的路径是 resources\static\js\myapp.js + +你可以参考它在 jsp 中的使用方法: + +![35道SpringBoot面试题及答案,面试常被问到!](https://img1.3s78.com/codercto/34a11ffc02e104dcfdaa76884a206650) + +错误:HAL browser gives me unauthorized error - Full authenticaition is required to access this resource. + +该如何来修复这个错误呢? + +![35道SpringBoot面试题及答案,面试常被问到!](https://img1.3s78.com/codercto/39f610d8c91c1b667bf9280a91a38e21) + +两种方法: + +方法 1:关闭安全验证 + +application.properties + +``` +management.security.enabled:FALSE +``` + +方法二:在日志中搜索密码并传递至请求标头中 + +#### 13.如何使用 Spring Boot 部署到不同的服务器? + +你需要做下面两个步骤: + +- 在一个项目中生成一个 war 文件。 +- 将它部署到你最喜欢的服务器(websphere 或者 Weblogic 或者 Tomcat and so on)。 + +第一步:这本入门指南应该有所帮助: + +https://spring.io/guides/gs/convert-jar-to-war/ + +第二步:取决于你的服务器。 + +#### 14.如何使用配置文件通过 Spring Boot 配置特定环境的配置? + +配置文件不是设别环境的关键。 + +在下面的例子中,我们将会用到两个配置文件 + +- dev +- prod + +缺省的应用程序配置在 application.properties 中。让我们来看下面的例子: + +application.properties + +``` +basic.value= true + basic.message= Dynamic Message + basic.number= 100 +``` + +我们想要为 dev 文件自定义 application.properties 属性。我们需要创建一个名为 application-dev.properties 的文件,并且重写我们想要自定义的属性。 + +application-dev.properties + +``` +basic.message: Dynamic Message in DEV +``` + +一旦你特定配置了配置文件,你需要在环境中设定一个活动的配置文件。 + +有多种方法可以做到这一点: + +- 在 VM 参数中使用 Dspring.profiles.active=prod +- 在 application.properties 中使用 spring.profiles.active=prod + +#### 15.什么是Swagger?你用Spring Boot实现了吗? + +Swagger 广泛用于可视化 API,使用 Swagger UI 为前端开发人员提供在线沙箱。Swagger 是用于生成 RESTful Web 服务的可视化表示的工具,规范和完整框架实现。它使文档能够以与服务器相同的速度更新。当通过 Swagger 正确定义时,消费者可以使用最少量的实现逻辑来理解远程服务并与其进行交互。因此,Swagger消除了调用服务时的猜测。 + +#### 16.如何实现Spring Boot应用程序的安全性? + +为了实现Spring Boot的安全性,使用spring-boot-starter-security依赖项,并且必须添加安全配置。它只需要很少代码。配置类将必须扩展WebSecurityConfigurerAdapter并覆盖其方法。 + +#### 17.比较一下Spring Security和Shiro各自的优缺点? + +由于Spring Boot官方提供了大量的非常方便的开箱即用的Starter,包括Spring Security的Starter,使得在SpringBoot中使用Spring Security变得更加容易,甚至只需要添加一个一来就可以保护所有接口,所以如果是SpringBoot项目,一般选择Spring Security。当然这只是一个建议的组合,单纯从技术上来说,无论怎么组合,都是没有问题的。 + +Shiro和Spring Security相比,主要有如下特点: + +Spring Security是一个重量级的安全管理框架;Shiro则是一个轻量级的安全管理框架; +Spring Security概念复杂,配置繁琐;Shiro概念简单、配置简单; +Spring Security功能强大;Shiro功能简单 + +#### 18.Spring Boot中如何解决跨域问题? + +跨域可以在前端通过JSONP来解决,但是JSONP只可以发送GET请求,无法发送其他类型的请求,在RESTful风格的应用中,就显得非常鸡肋,因此推荐在后端通过(CORS,Cross-origin resource sharing)来解决跨域问题。这种解决方案并非Spring Boot特有的,在传统的SSM框架中,就可以通过CORS来解决跨域问题,只不过之前我们是在XML文件中配置CORS,现在可以通过实现WebMvcConfigurer接口然后重写addCorsMappings方法解决跨域问题。 + +```java +@Configuration +public class CorsConfig implements WebMvcConfigurer { + + @Override + public void addCorsMappings(CorsRegistry registry) { + registry.addMapping("/**") + .allowedOrigins("*") + .allowCredentials(true) + .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") + .maxAge(3600); + } + +} + + +``` + +项目中前后端分离部署,所以需要解决跨域的问题。 +我们使用cookie存放用户登录的信息,在spring拦截器进行权限控制,当权限不符合时,直接返回给用户固定的json结果。 +当用户登录以后,正常使用;当用户退出登录状态时或者token过期时,由于拦截器和跨域的顺序有问题,出现了跨域的现象。 +我们知道一个http请求,先走filter,到达servlet后才进行拦截器的处理,如果我们把cors放在filter里,就可以优先于权限拦截器执行。 + +```java +@Configuration +public class CorsConfig { + + @Bean + public CorsFilter corsFilter() { + CorsConfiguration corsConfiguration = new CorsConfiguration(); + corsConfiguration.addAllowedOrigin("*"); + corsConfiguration.addAllowedHeader("*"); + corsConfiguration.addAllowedMethod("*"); + corsConfiguration.setAllowCredentials(true); + UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource(); + urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration); + return new CorsFilter(urlBasedCorsConfigurationSource); + } + +} + +``` + +#### 19.Spring Boot的核心注解是哪些?他由哪几个注解组成的? + +启动类上面的注解是@SpringBootApplication,他也是SpringBoot的核心注解,主要组合包含了以下3个注解: + +@SpringBootConfiguration:组合了@Configuration注解,实现配置文件的功能; +@EnableAutoConfiguration:打开自动配置的功能,也可以关闭某个自动配置的选项,如关闭数据源自动配置的功能:@SpringBootApplication(exclude={DataSourceAutoConfiguration.class}); +@ComponentScan:Spring组件扫描。 + +#### 20.保护SpringBoot应用有哪些方法? + +- 在生产中使用HTTPS +- 使用Snyk检查你的依赖关系 +- 升级到最新版本 +- 启用CSRF保护 +- 使用内容安全策略防止XSS攻击 + +#### 21.SpringBoot 2.X有哪些新特性?与1.X有什么区别? + +- 配置变更 +- JDK版本升级 +- 第三方类库升级 +- 响应式Spring编程支持 +- HTTP/2支持 +- 配置属性绑定 +- 更多改进与加强 + +#### 参考链接 + +https://blog.csdn.net/yuzongtao/article/details/84295732 +https://www.cnblogs.com/aishangJava/p/10546741.html +https://www.codercto.com/a/77896.html +https://blog.csdn.net/u012068483/article/details/105039330/ diff --git a/SpringCloud.md b/SpringCloud.md new file mode 100644 index 0000000..a45f05d --- /dev/null +++ b/SpringCloud.md @@ -0,0 +1,230 @@ +## Spring Cloud + + +* [1.什么是 Spring Cloud?](#1什么是-spring-cloud) +* [2.使用Spring Cloud有什么优势?](#2使用spring-cloud有什么优势) +* [3.服务注册和发现是什么意思?Spring Cloud如何实现?](#3服务注册和发现是什么意思spring-cloud如何实现) +* [4.Spring Cloud由哪些组件组成?](#4spring-cloud由哪些组件组成) +* [5.什么是Hystrix?它如何实现容错?](#5什么是hystrix它如何实现容错) +* [6.什么是Hystrix断路器?我们需要它吗?](#6什么是hystrix断路器我们需要它吗) +* [7.什么是Netflix Feign?它的优点是什么?](#7什么是netflix-feign它的优点是什么) +* [8.Eureka的工作原理?](#8eureka的工作原理) +* [9.说说Eureka的自我保护机制?](#9说说eureka的自我保护机制) +* [10.什么是zuul?](#10什么是zuul) +* [11.zuul的工作流程?](#11zuul的工作流程) +* [12.什么是服务熔断?什么是服务降级?](#12什么是服务熔断什么是服务降级) +* [13.什么是服务雪崩效应?](#13什么是服务雪崩效应) +* [14.ZuulFilter有哪些常用方法?](#14zuulfilter有哪些常用方法) +* [15.如何实现动态Zuul网关路由转发?](#15如何实现动态zuul网关路由转发) +* [16.什么是 Spring Cloud Bus?](#16什么是-spring-cloud-bus) +* [17.Spring Cloud Bus 原理?](#17spring-cloud-bus-原理) +* [18.SpringCloud Config可以实现实时刷新吗?](#18springcloud-config可以实现实时刷新吗) +* [19.Eureka和zookeeper都可以提供服务注册与发现的功能,两者的区别](#19eureka和zookeeper都可以提供服务注册与发现的功能两者的区别) +* [参考链接](#参考链接) + + +#### 1.什么是 Spring Cloud? + +spring cloud 是一系列框架的有序集合。它利用 spring boot 的开发便利性巧妙地简化了分布式系统基础设施的开发,如服务发现注册、配置中心、消息总线、负载均衡、断路器、数据监控等,都可以用 spring boot 的开发风格做到一键启动和部署。 + +#### 2.使用Spring Cloud有什么优势? + +使用Spring Boot开发分布式微服务时,我们面临以下问题 + +- 与分布式系统相关的复杂性-这种开销包括网络问题,延迟开销,带宽问题,安全问题。 +- 服务发现-服务发现工具管理群集中的流程和服务如何查找和互相交谈。它涉及一个服务目录,在该目录中注册服务,然后能够查找并连接到该目录中的服务。 +- 冗余-分布式系统中的冗余问题。 +- 负载平衡 --负载平衡改善跨多个计算资源的工作负荷,诸如计算机,计算机集群,网络链路,中央处理单元,或磁盘驱动器的分布。 +- 性能-问题 由于各种运营开销导致的性能问题。 +- 部署复杂性-Devops技能的要求。 + +#### 3.服务注册和发现是什么意思?Spring Cloud如何实现? + +当我们开始一个项目时,我们通常在属性文件中进行所有的配置。随着越来越多的服务开发和部署,添加和修改这些属性变得更加复杂。有些服务可能会下降,而某些位置可能会发生变化。手动更改属性可能会产生问题。 Eureka服务注册和发现可以在这种情况下提供帮助。由于所有服务都在Eureka服务器上注册并通过调用Eureka服务器完成查找,因此无需处理服务地点的任何更改和处理。 + +#### 4.Spring Cloud由哪些组件组成? + +`Eureka`:服务注册与发现 + +`Zuul`:服务网关 + +`Ribbon`:客户端负载均衡 + +`Feign`:声明性的Web服务客户端 + +`Hystrix`:断路器 + +`Config`:分布式统一配置管理 + +等20几个框架,开源一直在更新 + +![0e9c7b73ca58fcbd7ee8f5b7c3fe450.png](http://img1.sycdn.imooc.com/5f309a610001d87510410539.jpg) + + +#### 5.什么是Hystrix?它如何实现容错? + +Hystrix是一个延迟和容错库,旨在隔离远程系统,服务和第三方库的访问点,当出现故障是不可避免的故障时,停止级联故障并在复杂的分布式系统中实现弹性。 + +通常对于使用微服务架构开发的系统,涉及到许多微服务。这些微服务彼此协作。 + +思考以下微服务 + +![img](https://img-blog.csdn.net/20180922211907901?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21vYWt1bg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) + +假设如果上图中的微服务9失败了,那么使用传统方法我们将传播一个异常。但这仍然会导致整个系统崩溃。 + +随着微服务数量的增加,这个问题变得更加复杂。微服务的数量可以高达1000.这是hystrix出现的地方 我们将使用Hystrix在这种情况下的Fallback方法功能。我们有两个服务employee-consumer使用由employee-consumer公开的服务。 + +简化图如下所示 + +![img](https://img-blog.csdn.net/20180922211919539?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21vYWt1bg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) + +现在假设由于某种原因,employee-producer公开的服务会抛出异常。我们在这种情况下使用Hystrix定义了一个回退方法。这种后备方法应该具有与公开服务相同的返回类型。如果暴露服务中出现异常,则回退方法将返回一些值。 + +#### 6.什么是Hystrix断路器?我们需要它吗? + +由于某些原因,employee-consumer公开服务会引发异常。在这种情况下使用Hystrix我们定义了一个回退方法。如果在公开服务中发生异常,则回退方法返回一些默认值。 + +![img](https://img-blog.csdn.net/20180922211937187?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21vYWt1bg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) + +如果firstPage method() 中的异常继续发生,则Hystrix电路将中断,并且员工使用者将一起跳过firtsPage方法,并直接调用回退方法。 断路器的目的是给第一页方法或第一页方法可能调用的其他方法留出时间,并导致异常恢复。可能发生的情况是,在负载较小的情况下,导致异常的问题有更好的恢复机会 。 + +![img](https://img-blog.csdn.net/20180922211948793?watermark/2/text/aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L21vYWt1bg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70) + +#### 7.什么是Netflix Feign?它的优点是什么? + +Feign是受到Retrofit,JAXRS-2.0和WebSocket启发的java客户端联编程序。Feign的第一个目标是将约束分母的复杂性统一到http apis,而不考虑其稳定性。在employee-consumer的例子中,我们使用了employee-producer使用REST模板公开的REST服务。 + +但是我们必须编写大量代码才能执行以下步骤 + +- 使用功能区进行负载平衡。 +- 获取服务实例,然后获取基本URL。 +- 利用REST模板来使用服务。 前面的代码如下 + +```java +@Controller +public class ConsumerControllerClient { + +@Autowired +private LoadBalancerClient loadBalancer; + +public void getEmployee() throws RestClientException, IOException { + +    ServiceInstance serviceInstance=loadBalancer.choose("employee-producer"); + +    System.out.println(serviceInstance.getUri()); + +    String baseUrl=serviceInstance.getUri().toString(); + +    baseUrl=baseUrl+"/employee"; + +    RestTemplate restTemplate = new RestTemplate(); +    ResponseEntity response=null; +    try{ +    response=restTemplate.exchange(baseUrl, +            HttpMethod.GET, getHeaders(),String.class); +    }catch (Exception ex) +    { +        System.out.println(ex); +    } +    System.out.println(response.getBody()); +} +``` + +之前的代码,有像NullPointer这样的例外的机会,并不是最优的。我们将看到如何使用Netflix Feign使呼叫变得更加轻松和清洁。如果Netflix Ribbon依赖关系也在类路径中,那么Feign默认也会负责负载平衡。 + +#### 8.Eureka的工作原理? + +`Eureka`:服务注册中心(可以是一个集群),对外暴露自己的地址 +`提供者`:启动后向Eureka注册自己信息(地址,提供什么服务) +`消费者`:向Eureka订阅服务,Eureka会将对应服务的所有提供者地址列表发送给消费者,并且定期更新 +`心跳(续约)`:提供者定期通过http方式向Eureka刷新自己的状态(每30s定时向EurekaServer发起请求) + +#### 9.说说Eureka的自我保护机制? + +当一个服务未按时进行心跳续约时,在生产环境下,因为网络延迟等原因,此时就把服务剔除列表并不妥当,因为服务可能没有宕机。 Eureka就会把当前实例的注册信息保护起来,不予剔除。生产环境下这很有效,保证了大多数服务依然可用。但是有可能会造成一些挂掉的服务被剔除有延迟。 + +#### 10.什么是zuul? + +zuul是对SpringCloud提供的成熟对的`路由方案`,他会根据请求的路径不同,网关会定位到指定的微服务,并代理请求到不同的微服务接口,他对外隐蔽了微服务的真正接口地址。 +三个重要概念: + +- `动态路由表`:Zuul支持Eureka路由,手动配置路由,这俩种都支持自动更新 + +- `路由定位`:根据请求路径,Zuul有自己的一套定位服务规则以及路由表达式匹配 + +- `反向代理`:客户端请求到路由网关,网关受理之后,在对目标发送请求,拿到响应之后在 给客户端 + +Zuul的应用场景: 对外暴露,权限校验,服务聚合,日志审计等 + + +#### 11.zuul的工作流程? + +在Spring Cloud Netflix中,Zuul巧妙的整合了Eureka来实现面向服务的路由。 +实际上,API网关将自己注册到Eureka服务注册中心上,也会从注册中心获取所有服务以及它们的实例清单。在Eureka的帮助下,API网关已经维护了系统中所有`serviceId与实例地址的映射关系`。当有外部请求到达API网关的时候,根据请求的URL找到最匹配的path,API网关就可以知道要将该请求"路由"到哪个具体的serviceId上去。 最终通过`Ribbon的负载均衡策略`实现请求的路由。 + + +#### 12.什么是服务熔断?什么是服务降级? + +服务熔断: +熔断机制是应对`雪崩效应`的一种微服务`链路保护机制`。 +当某个微服务不可用或者响应时间太长时,会进行服务降级,进而熔断该节点微服务的调用,快速返回“错误”的响应信息。当检测到该节点微服务调用响应正常后恢复调用链路。 +在SpringCloud框架里熔断机制通过`Hystrix`实现,Hystrix会监控微服务间调用的状况,当失败的调用到一定阈值,缺省是5秒内调用20次,如果失败,就会启动熔断机制。 +服务降级: +服务降级,一般是从整体负荷考虑。就是当某个服务熔断之后,服务器将不再被调用,此时客户端可以自己准备一个本地的`fallback回调`,返回一个缺省值。 + +#### 13.什么是服务雪崩效应? + +雪崩效应是在大型互联网项目中,当某个服务发生宕机时,调用这个服务的其他服务也会发生宕机,大型项目的微服务之间的调用是互通的,这样就会将服务的不可用逐步扩大到各个其他服务中,从而使整个项目的服务宕机崩溃。 + + +#### 14.ZuulFilter有哪些常用方法? + +`Run()`:过滤器的具体业务逻辑 + +`shouldFilter()`:判断过滤器是否有效 + +`filterOrder()`:过滤器执行顺序 + +`filterType()`:过滤器拦截位置 + +#### 15.如何实现动态Zuul网关路由转发? + +通过`path`配置拦截请求,通过 `Serviceld`到配置中心获取转发的服务列表,zuul内部使用 `Ribbon`实现本地负载均衡和转发。 + +#### 16.什么是 Spring Cloud Bus? + +Spring Cloud Bus就像个分布式执行器,用于扩展的 Spring Boot应用程序的配置文件,但也可以用作应用程序之间的通信通道。 + +Spring Cloud Bus不能单独完成通信,需要配合MQ支持 + +Spring Cloud Bus一般是配合Spring Cloud Config做配置中心的 + +Spring Cloud config实时刷新也必须采用 SpringCloud Bus消息总线 + +#### 17.Spring Cloud Bus 原理? + +发送端(endpoint)构造事件event,将其publish到context上下文中(spring cloud bus有一个父上下文,bootstrap),然后将事件发送到channel中(json串message),接收端从channel中获取到message,将message转为事件event,然后将event事件publish到context上下文中,最后接收端(Listener)收到event,调用服务进行处理。 +整个流程中,只有发送/接收端从context上下文中取事件和发送事件是需要我们在代码中明确写出来的,其它部分都由框架封装完成。 + +#### 18.SpringCloud Config可以实现实时刷新吗? + +springcloud config实时刷新采用 `SpringCloud Bus`消息总线 + +#### 19.Eureka和zookeeper都可以提供服务注册与发现的功能,两者的区别 + +Zookeeper保证了CP(C:一致性,P:分区容错性),Eureka保证了AP(A:高可用,P:分区容错) +1、Zookeeper-----当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的信息,但不能容忍直接down掉不可用的。也就是说服务注册功能对高可用性要求比较高,但是zk会出现这样的一种情况,当master节点因为网络故障与其他节点失去联系时,剩余的节点会重新选leader。问题在于,选取leader的时间过长(30~120s),且选取期间zk集群都不可用,这样就会导致选取期间注册服务瘫痪。在云部署的环境下,因网络问题使得zk集群失去master节点是较大概率会发生的事,虽然服务最终恢复,但是漫长的选择时间导致的注册长期不可用是不能容忍的 +2、Eureka则看明白这一点,因此再设计的优先保证了高可用性。Eureka各个节点都是平等的,几个节点挂掉不会影响到正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端再向某个Eureka注册时如果发现连接失败,则会自动切换至其他节点,只要有一台Eureka还在,就能保证注册服务的可用(保证可用性),只不过查到的信息可能不是最新的(不保证一致性)。除此之外Eureka还有一种自我保护机制,如果在15分钟内超过85%的节点都没有正常心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时就会出现以下几种情况: +1>、Eureka不再从注册列表移除因为长时间没收到心跳而应该过期的服务 +2>、Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上(保证当前节点可用) +3>、当网络稳定时,当前实例新的注册信息会被同步到其它节点中 +Eureka还有客户端缓存功能(Eureka分为客户端程序和服务器端程序两个部分,客户端程序负责向外提供注册与发现服务接口)。所以即便Eureka集群中所有节点都失效,或者发生网络分隔故障导致客户端不能访问任何一台Eureka服务器;Eureka服务的消费者任然可以通过Eureka客户端缓存来获取所有的服务注册信息。甚至最极端的环境下,所有正常的Eureka节点都不对请求产生响应也没有更好的服务器解决方案来解决这种问题时;得益于Eureka的客户端缓存技术,消费者服务仍然可以通过Eureka客户端查询与获取注册服务信息,这点很重要,因此Eureka可以很好的应对网络故障导致部分节点失去联系的情况,而不像Zookeeper那样使整个注册服务瘫痪。 + +#### 参考链接 + +https://blog.csdn.net/qq_39827935/article/details/96282405 + +https://blog.csdn.net/moakun/article/details/82817757 + +https://www.imooc.com/article/309292 diff --git a/Tomcat.md b/Tomcat.md new file mode 100644 index 0000000..e75c79f --- /dev/null +++ b/Tomcat.md @@ -0,0 +1,304 @@ +## Tomcat + +* [1.Tomcat的缺省端口是多少,怎么修改?](#1tomcat的缺省端口是多少怎么修改) +* [2.tomcat 有哪几种Connector 运行模式(优化)?](#2tomcat-有哪几种connector-运行模式优化) +* [3.Tomcat有几种部署方式?](#3tomcat有几种部署方式) +* [4.tomcat容器是如何创建servlet类实例?用到了什么原理?](#4tomcat容器是如何创建servlet类实例用到了什么原理) +* [5.tomcat 如何优化?](#5tomcat-如何优化) +* [6.tomcat内存调优了解过吗?](#6tomcat内存调优了解过吗) +* [7.tomcat垃圾回收策略调优了解吗?](#7tomcat垃圾回收策略调优了解吗) +* [8.tomcat共享session如何处理?](#8tomcat共享session如何处理) +* [9.如何添加JMS远程监控](#9如何添加jms远程监控) +* [10.Tomcat一个请求的完整过程](#10tomcat一个请求的完整过程) +* [参考资料](#参考资料) + + +#### 1.Tomcat的缺省端口是多少,怎么修改? + +``` +1)找到Tomcat目录下的conf文件夹 + +2)进入conf文件夹里面找到server.xml文件 + +3)打开server.xml文件 + +4)在server.xml文件里面找到下列信息 + + +port="8080"改成你想要的端口 +``` + +#### 2.tomcat 有哪几种Connector 运行模式(优化)? + +``` +bio:传统的Java I/O操作,同步且阻塞IO。 +maxThreads="150"//Tomcat使用线程来处理接收的每个请求。这个值表示Tomcat可创建的最大的线程数。默认值200。可以根据机器的时期性能和内存大小调整,一般可以在400-500。最大可以在800左右。 +minSpareThreads="25"---Tomcat初始化时创建的线程数。默认值4。如果当前没有空闲线程,且没有超过maxThreads,一次性创建的空闲线程数量。Tomcat初始化时创建的线程数量也由此值设置。 +maxSpareThreads="75"--一旦创建的线程超过这个值,Tomcat就会关闭不再需要的socket线程。默认值50。一旦创建的线程超过此数值,Tomcat会关闭不再需要的线程。线程数可以大致上用 “同时在线人数*每秒用户操作次数*系统平均操作时间” 来计算。 +acceptCount="100"----指定当所有可以使用的处理请求的线程数都被使用时,可以放到处理队列中的请求数,超过这个数的请求将不予处理。默认值10。如果当前可用线程数为0,则将请求放入处理队列中。这个值限定了请求队列的大小,超过这个数值的请求将不予处理。 +connectionTimeout="20000" --网络连接超时,默认值20000,单位:毫秒。设置为0表示永不超时,这样设置有隐患的。通常可设置为30000毫秒。 + +nio:JDK1.4开始支持,同步阻塞或同步非阻塞IO。 +指定使用NIO模型来接受HTTP请求 +protocol="org.apache.coyote.http11.Http11NioProtocol" 指定使用NIO模型来接受HTTP请求。默认是BlockingIO,配置为protocol="HTTP/1.1" +acceptorThreadCount="2" 使用NIO模型时接收线程的数目 + +aio(nio.2):JDK7开始支持,异步非阻塞IO。 + +apr:Tomcat将以JNI的形式调用Apache HTTP服务器的核心动态链接库来处理文件读取或网络传输操作,从而大大地 提高Tomcat对静态文件的处理性能。 + + + + + + + + + + +其他配置 + +maxHttpHeaderSize="8192" http请求头信息的最大程度,超过此长度的部分不予处理。一般8K。 +URIEncoding="UTF-8" 指定Tomcat容器的URL编码格式。 +disableUploadTimeout="true" 上传时是否使用超时机制 +enableLookups="false"--是否反查域名,默认值为true。为了提高处理能力,应设置为false +compression="on" 打开压缩功能 +compressionMinSize="10240" 启用压缩的输出内容大小,默认为2KB +noCompressionUserAgents="gozilla, traviata" 对于以下的浏览器,不启用压缩 +compressableMimeType="text/html,text/xml,text/javascript,text/css,text/plain" 哪些资源类型需要压缩 + +``` + +#### 3.Tomcat有几种部署方式? + +1)直接把Web项目放在webapps下,Tomcat会自动将其部署 + +2)在server.xml文件上配置 Context 节点,设置相关的属性即可 + +3)通过Catalina来进行配置:进入到conf\Catalina\localhost文件下,创建一个xml文件,该文件的名字就是站点的名字。 + +编写XML的方式来进行设置。 + +#### 4.tomcat容器是如何创建servlet类实例?用到了什么原理? + +当容器启动时,会读取在webapps目录下所有的web应用中的web.xml文件,然后对xml文件进行解析, + +并读取servlet注册信息。然后,将每个应用中注册的servlet类都进行加载,并通过反射的方式实例化。 + +(有时候也是在第一次请求时实例化)在servlet注册时加上如果为正数,则在一开始就实例化, + +如果不写或为负数,则第一次请求实例化。 + +#### 5.tomcat 如何优化? + +``` +1、优化连接配置.这里以tomcat7的参数配置为例,需要修改conf/server.xml文件,修改连接数,关闭客户端dns查询。 + +参数解释: + +URIEncoding=”UTF-8″ :使得tomcat可以解析含有中文名的文件的url,真方便,不像apache里还有搞个mod_encoding,还要手工编译 + +maxSpareThreads : 如果空闲状态的线程数多于设置的数目,则将这些线程中止,减少这个池中的线程总数。 + +minSpareThreads : 最小备用线程数,tomcat启动时的初始化的线程数。 + +enableLookups : 这个功效和Apache中的HostnameLookups一样,设为关闭。 + +connectionTimeout : connectionTimeout为网络连接超时时间毫秒数。 + +maxThreads : maxThreads Tomcat使用线程来处理接收的每个请求。这个值表示Tomcat可创建的最大的线程数,即最大并发数。 + +acceptCount : acceptCount是当线程数达到maxThreads后,后续请求会被放入一个等待队列,这个acceptCount是这个队列的大小,如果这个队列也满了,就直接refuse connection + +maxProcessors与minProcessors : 在 Java中线程是程序运行时的路径,是在一个程序中与其它控制线程无关的、能够独立运行的代码段。它们共享相同的地址空间。多线程帮助程序员写出CPU最 大利用率的高效程序,使空闲时间保持最低,从而接受更多的请求。 + +通常Windows是1000个左右,Linux是2000个左右。 + +useURIValidationHack: + +我们来看一下tomcat中的一段源码: + +【security】 + +if (connector.getUseURIValidationHack()) { + +String uri = validate(request.getRequestURI()); + +if (uri == null) { + +res.setStatus(400); + +res.setMessage(“Invalid URI”); + +throw new IOException(“Invalid URI”); + +} else { + +req.requestURI().setString(uri); + +// Redoing the URI decoding + +req.decodedURI().duplicate(req.requestURI()); + +req.getURLDecoder().convert(req.decodedURI(), true); + +可以看到如果把useURIValidationHack设成”false”,可以减少它对一些url的不必要的检查从而减省开销。 + +enableLookups=”false” : 为了消除DNS查询对性能的影响我们可以关闭DNS查询,方式是修改server.xml文件中的enableLookups参数值。 + +disableUploadTimeout :类似于Apache中的keeyalive一样 + +给Tomcat配置gzip压缩(HTTP压缩)功能 + +compression=”on” compressionMinSize=”2048″ + +compressableMimeType=”text/html,text/xml,text/JavaScript,text/css,text/plain” + +HTTP 压缩可以大大提高浏览网站的速度,它的原理是,在客户端请求网页后,从服务器端将网页文件压缩,再下载到客户端,由客户端的浏览器负责解压缩并浏览。相对于普通的浏览过程HTML,CSS,javascript , Text ,它可以节省40%左右的流量。更为重要的是,它可以对动态生成的,包括CGI、PHP , JSP , ASP , Servlet,SHTML等输出的网页也能进行压缩,压缩效率惊人。 + +1)compression=”on” 打开压缩功能 + +2)compressionMinSize=”2048″ 启用压缩的输出内容大小,这里面默认为2KB + +3)noCompressionUserAgents=”gozilla, traviata” 对于以下的浏览器,不启用压缩 + +4)compressableMimeType=”text/html,text/xml” 压缩类型 + +最后不要忘了把8443端口的地方也加上同样的配置,因为如果我们走https协议的话,我们将会用到8443端口这个段的配置,对吧? + + + + + +好了,所有的Tomcat优化的地方都加上了。 + +``` + +#### 6.tomcat内存调优了解过吗? + +``` +内存方式的设置是在catalina.sh中,调整一下JAVA_OPTS变量即可,因为后面的启动参数会把JAVA_OPTS作为JVM的启动参数来处理。 +具体设置如下: +JAVA_OPTS="$JAVA_OPTS -Xmx3550m -Xms3550m -Xss128k -XX:NewRatio=4 -XX:SurvivorRatio=4" +其各项参数如下: +-Xmx3550m:设置JVM最大可用内存为3550M。 +-Xms3550m:设置JVM促使内存为3550m。此值可以设置与-Xmx相同,以避免每次垃圾回收完成后JVM重新分配内存。 +-Xmn2g:设置年轻代大小为2G。整个堆大小=年轻代大小 + 年老代大小 + 持久代大小。持久代一般固定大小为64m,所以增大年轻代后,将会减小年老代大小。此值对系统性能影响较大,Sun官方推荐配置为整个堆的3/8。 +-Xss128k:设置每个线程的堆栈大小。JDK5.0以后每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。更具应用的线程所需内存大小进行调整。在相同物理内存下,减小这个值能生成更多的线程。但是操作系统对一个进程内的线程数还是有限制的,不能无限生成,经验值在3000~5000左右。 +-XX:NewRatio=4:设置年轻代(包括Eden和两个Survivor区)与年老代的比值(除去持久代)。设置为4,则年轻代与年老代所占比值为1:4,年轻代占整个堆栈的1/5 +-XX:SurvivorRatio=4:设置年轻代中Eden区与Survivor区的大小比值。设置为4,则两个Survivor区与一个Eden区的比值为2:4,一个Survivor区占整个年轻代的1/6 +-XX:MaxPermSize=16m:设置持久代大小为16m。 +-XX:MaxTenuringThreshold=0:设置垃圾最大年龄。如果设置为0的话,则年轻代对象不经过Survivor区,直接进入年老代。对于年老代比较多的应用,可以提高效率。如果将此值设置为一个较大值,则年轻代对象会在Survivor区进行多次复制,这样可以增加对象再年轻代的存活时间,增加在年轻代即被回收的概论。 + +``` + +#### 7.tomcat垃圾回收策略调优了解吗? + +``` +垃圾回收的设置也是在catalina.sh中,调整JAVA_OPTS变量。 +具体设置如下: +JAVA_OPTS="$JAVA_OPTS -Xmx3550m -Xms3550m -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100" +具体的垃圾回收策略及相应策略的各项参数如下: +串行收集器(JDK1.5以前主要的回收方式) +-XX:+UseSerialGC:设置串行收集器 +并行收集器(吞吐量优先) +示例: +java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseParallelGC -XX:MaxGCPauseMillis=100 + +-XX:+UseParallelGC:选择垃圾收集器为并行收集器。此配置仅对年轻代有效。即上述配置下,年轻代使用并发收集,而年老代仍旧使用串行收集。 +-XX:ParallelGCThreads=20:配置并行收集器的线程数,即:同时多少个线程一起进行垃圾回收。此值最好配置与处理器数目相等。 +-XX:+UseParallelOldGC:配置年老代垃圾收集方式为并行收集。JDK6.0支持对年老代并行收集 +-XX:MaxGCPauseMillis=100:设置每次年轻代垃圾回收的最长时间,如果无法满足此时间,JVM会自动调整年轻代大小,以满足此值。 +-XX:+UseAdaptiveSizePolicy:设置此选项后,并行收集器会自动选择年轻代区大小和相应的Survivor区比例,以达到目标系统规定的最低相应时间或者收集频率等,此值建议使用并行收集器时,一直打开。 +并发收集器(响应时间优先) +示例:java -Xmx3550m -Xms3550m -Xmn2g -Xss128k -XX:+UseConcMarkSweepGC +-XX:+UseConcMarkSweepGC:设置年老代为并发收集。测试中配置这个以后,-XX:NewRatio=4的配置失效了,原因不明。所以,此时年轻代大小最好用-Xmn设置。 +-XX:+UseParNewGC: 设置年轻代为并行收集。可与CMS收集同时使用。JDK5.0以上,JVM会根据系统配置自行设置,所以无需再设置此值。 +-XX:CMSFullGCsBeforeCompaction:由于并发收集器不对内存空间进行压缩、整理,所以运行一段时间以后会产生“碎片”,使得运行效率降低。此值设置运行多少次GC以后对内存空间进行压缩、整理。 +-XX:+UseCMSCompactAtFullCollection:打开对年老代的压缩。可能会影响性能,但是可以消除碎片 + +``` + +#### 8.tomcat共享session如何处理? + +目前的处理方式有如下几种: +1).使用Tomcat本身的Session复制功能 +参考http://ajita.iteye.com/blog/1715312(Session复制的配置) +方案的有点是配置简单,缺点是当集群数量较多时,Session复制的时间会比较长,影响响应的效率 +2).使用第三方来存放共享Session +目前用的较多的是使用memcached来管理共享Session,借助于memcached-sesson-manager来进行Tomcat的Session管理 +参考http://ajita.iteye.com/blog/1716320(使用MSM管理Tomcat集群session) +3).使用黏性session的策略 +对于会话要求不太强(不涉及到计费,失败了允许重新请求下等)的场合,同一个用户的session可以由nginx或者apache交给同一个Tomcat来处理,这就是所谓的session sticky策略,目前应用也比较多 +参考:http://ajita.iteye.com/blog/1848665(tomcat session sticky) +nginx默认不包含session sticky模块,需要重新编译才行(windows下我也不知道怎么重新编译) +优点是处理效率高多了,缺点是强会话要求的场合不合适 + +#### 9.如何添加JMS远程监控 + +``` +对于部署在局域网内其它机器上的Tomcat,可以打开JMX监控端口,局域网其它机器就可以通过这个端口查看一些常用的参数(但一些比较复杂的功能不支持),同样是在JVM启动参数中配置即可,配置如下: +-Dcom.sun.management.jmxremote.ssl=false -Dcom.sun.management.jmxremote.authenticate=false +-Djava.rmi.server.hostname=192.168.71.38 设置JVM的JMS监控监听的IP地址,主要是为了防止错误的监听成127.0.0.1这个内网地址 +-Dcom.sun.management.jmxremote.port=1090 设置JVM的JMS监控的端口 +-Dcom.sun.management.jmxremote.ssl=false 设置JVM的JMS监控不实用SSL +-Dcom.sun.management.jmxremote.authenticate=false 设置JVM的JMS监控不需要认证 + +``` + +#### 10.Tomcat一个请求的完整过程 + +首先 dns 解析 wo.de.tian机器,一般是ng服务器ip地址 +然后 ng根据server的配置,寻找路径为 yy/的机器列表,ip和端口 +最后 选择其中一台机器进行访问—->下面为详细过程 + +1) 请求被发送到本机端口8080,被在那里侦听的Coyote HTTP/1.1 Connector获得 +2) Connector把该请求交给它所在的Service的Engine来处理,并等待来自Engine的回应 +3) Engine获得请求localhost/yy/index.jsp,匹配它所拥有的所有虚拟主机Host +4) Engine匹配到名为localhost的Host(即使匹配不到也把请求交给该Host处理,因为该Host被定义为该Engine的默认主机) +5) localhost Host获得请求/yy/index.jsp,匹配它所拥有的所有Context +6) Host匹配到路径为/yy的Context(如果匹配不到就把该请求交给路径名为”“的Context去处理) +7) path=”/yy”的Context获得请求/index.jsp,在它的mapping table中寻找对应的servlet +8) Context匹配到URL PATTERN为*.jsp的servlet,对应于JspServlet类 +9) 构造HttpServletRequest对象和HttpServletResponse对象,作为参数调用JspServlet的doGet或doPost方法 +10)Context把执行完了之后的HttpServletResponse对象返回给Host +11)Host把HttpServletResponse对象返回给Engine +12)Engine把HttpServletResponse对象返回给Connector +13)Connector把HttpServletResponse对象返回给客户browser + + +#### 参考资料 + +https://blog.csdn.net/qq_25934401/article/details/81536958 diff --git a/Zookeeper.md b/Zookeeper.md new file mode 100644 index 0000000..e1b985f --- /dev/null +++ b/Zookeeper.md @@ -0,0 +1,332 @@ +## Zookeeper + + +* [1.Zookeeper有哪些节点类型?](#1zookeeper有哪些节点类型) +* [2.了解过Zookeeper的ZAB协议吗?](#2了解过zookeeper的zab协议吗) +* [3.Zookeeper怎么实现分布式锁?](#3zookeeper怎么实现分布式锁) +* [4.Zookeeper是怎么保证数据一致性的?](#4zookeeper是怎么保证数据一致性的) +* [5.Zookeeper Leader选举过程是怎样的?](#5zookeeper-leader选举过程是怎样的) +* [6.Zookeeper怎么实现服务注册?](#6zookeeper怎么实现服务注册) +* [7.ZooKeeper是什么?](#7zookeeper是什么) +* [8.ZooKeeper提供了什么?](#8zookeeper提供了什么) +* [9.Zookeeper文件系统](#9zookeeper文件系统) +* [10.Zookeeper Watcher 机制](#10zookeeper-watcher-机制) +* [11.客户端注册Watcher实现](#11客户端注册watcher实现) +* [12.服务端处理Watcher实现](#12服务端处理watcher实现) +* [13.ACL权限控制机制](#13acl权限控制机制) +* [14.服务器角色](#14服务器角色) +* [15.Zookeeper 下 Server工作状态](#15zookeeper-下-server工作状态) +* [16.数据同步](#16数据同步) +* [17.zookeeper是如何保证事务的顺序一致性的?](#17zookeeper是如何保证事务的顺序一致性的) +* [18.分布式集群中为什么会有Master?](#18分布式集群中为什么会有master) +* [19.zk节点宕机如何处理?](#19zk节点宕机如何处理) +* [20.Zookeeper有哪几种部署模式?](#20zookeeper有哪几种部署模式) +* [21.集群最少要几台机器,集群规则是怎样的?](#21集群最少要几台机器集群规则是怎样的) +* [22.集群支持动态添加机器吗?](#22集群支持动态添加机器吗) +* [23.Zookeeper对节点的watch监听通知是永久的吗?为什么不是永久的?](#23zookeeper对节点的watch监听通知是永久的吗为什么不是永久的) +* [24.ZAB和Paxos算法的联系与区别?](#24zab和paxos算法的联系与区别) +* [25.Zookeeper的典型应用场景](#25zookeeper的典型应用场景) +* [26.Zookeeper 和 Dubbo 的关系?](#26zookeeper-和-dubbo-的关系) +* [27.zookeeper负载均衡和nginx负载均衡区别](#27zookeeper负载均衡和nginx负载均衡区别) +* [参考资料](#参考资料) + + +#### 1.Zookeeper有哪些节点类型? + +PERSISTENT-持久节点 +除非手动删除,否则节点一直存在于Zookeeper上 + +EPHEMERAL-临时节点 +临时节点的生命周期与客户端会话绑定,一旦客户端会话失效(客户端与zookeeper连接断开不一定会话失效),那么这个客户端创建的所有临时节点都会被移除。 + +PERSISTENT_SEQUENTIAL-持久顺序节点 +基本特性同持久节点,只是增加了顺序属性,节点名后边会追加一个由父节点维护的自增整型数字。 + +EPHEMERAL_SEQUENTIAL-临时顺序节点 +基本特性同临时节点,增加了顺序属性,节点名后边会追加一个由父节点维护的自增整型数字。 + +#### 2.了解过Zookeeper的ZAB协议吗? + +ZAB协议是为分布式协调服务Zookeeper专门设计的一种支持崩溃恢复的原子广播协议。 + +ZAB协议包括两种基本的模式:崩溃恢复和消息广播。 + +当整个zookeeper集群刚刚启动或者Leader服务器宕机、重启或者网络故障导致不存在过半的服务器与Leader服务器保持正常通信时,所有进程(服务器)进入崩溃恢复模式,首先选举产生新的Leader服务器,然后集群中Follower服务器开始与新的Leader服务器进行数据同步,当集群中超过半数机器与该Leader服务器完成数据同步之后,退出恢复模式进入消息广播模式,Leader服务器开始接收客户端的事务请求生成事物提案来进行事务请求处理。 + +#### 3.Zookeeper怎么实现分布式锁? + +有了zookeeper的一致性文件系统,锁的问题变得容易。锁服务可以分为两类,一个是保持独占,另一个是控制时序。 +对于第一类,我们将zookeeper上的一个znode看作是一把锁,通过createznode的方式来实现。所有客户端都去创建 /distribute_lock 节点,最终成功创建的那个客户端也即拥有了这把锁。用完删除掉自己创建的distribute_lock 节点就释放出锁。 +对于第二类, /distribute_lock 已经预先存在,所有客户端在它下面创建临时顺序编号目录节点,和选master一样,编号最小的获得锁,用完删除,依次方便。 + +#### 4.Zookeeper是怎么保证数据一致性的? + +详见:https://blog.csdn.net/liuchang19950703/article/details/111406622 + +#### 5.Zookeeper Leader选举过程是怎样的? + +详见:https://blog.csdn.net/liuchang19950703/article/details/111406622 + +#### 6.Zookeeper怎么实现服务注册? + +详见:https://segmentfault.com/a/1190000019670015 + +#### 7.ZooKeeper是什么? + +ZooKeeper是一个开放源码的分布式协调服务,它是集群的管理者,监视着集群中各个节点的状态根据节点提交的反馈进行下一步合理操作。最终,将简单易用的接口和性能高效、功能稳定的系统提供给用户。 + +分布式应用程序可以基于Zookeeper实现诸如数据发布/订阅、负载均衡、命名服务、分布式协调/通知、集群管理、Master选举、分布式锁和分布式队列等功能。 + +Zookeeper保证了如下分布式一致性特性: +顺序一致性 +原子性 +单一视图 +可靠性 +实时性(最终一致性) + +客户端的读请求可以被集群中的任意一台机器处理,如果读请求在节点上注册了监听器,这个监听器也是由所连接的zookeeper机器来处理。对于写请求,这些请求会同时发给其他zookeeper机器并且达成一致后,请求才会返回成功。因此,随着zookeeper的集群机器增多,读请求的吞吐会提高但是写请求的吞吐会下降。 + +有序性是zookeeper中非常重要的一个特性,所有的更新都是全局有序的,每个更新都有一个唯一的时间戳,这个时间戳称为zxid(Zookeeper Transaction Id)。而读请求只会相对于更新有序,也就是读请求的返回结果中会带有这个zookeeper最新的zxid。 + +#### 8.ZooKeeper提供了什么? + +1、文件系统 +2、通知机制 + +#### 9.Zookeeper文件系统 + +Zookeeper提供一个多层级的节点命名空间(节点称为znode)。与文件系统不同的是,这些节点都可以设置关联的数据,而文件系统中只有文件节点可以存放数据而目录节点不行。 +Zookeeper为了保证高吞吐和低延迟,在内存中维护了这个树状的目录结构,这种特性使得Zookeeper不能用于存放大量的数据,每个节点的存放数据上限为1M。 + +#### 10.Zookeeper Watcher 机制 + +Zookeeper允许客户端向服务端的某个Znode注册一个Watcher监听,当服务端的一些指定事件触发了这个Watcher,服务端会向指定客户端发送一个事件通知来实现分布式的通知功能,然后客户端根据Watcher通知状态和事件类型做出业务上的改变。 + +工作机制: +客户端注册watcher +服务端处理watcher +客户端回调watcher +Watcher特性总结: + +一次性 +无论是服务端还是客户端,一旦一个Watcher被触发,Zookeeper都会将其从相应的存储中移除。这样的设计有效的减轻了服务端的压力,不然对于更新非常频繁的节点,服务端会不断的向客户端发送事件通知,无论对于网络还是服务端的压力都非常大。 + +客户端串行执行 +客户端Watcher回调的过程是一个串行同步的过程。 + +轻量 +Watcher通知非常简单,只会告诉客户端发生了事件,而不会说明事件的具体内容。 +客户端向服务端注册Watcher的时候,并不会把客户端真实的Watcher对象实体传递到服务端,仅仅是在客户端请求中使用boolean类型属性进行了标记。 + +watcher event异步发送watcher的通知事件从server发送到client是异步的,这就存在一个问题,不同的客户端和服务器之间通过socket进行通信,由于网络延迟或其他因素导致客户端在不通的时刻监听到事件,由于Zookeeper本身提供了ordering guarantee,即客户端监听事件后,才会感知它所监视znode发生了变化。所以我们使用Zookeeper不能期望能够监控到节点每次的变化。Zookeeper只能保证最终的一致性,而无法保证强一致性。 + +注册watcher getData、exists、getChildren + +触发watcher create、delete、setData + +当一个客户端连接到一个新的服务器上时,watch将会被以任意会话事件触发。当与一个服务器失去连接的时候,是无法接收到watch的。而当client重新连接时,如果需要的话,所有先前注册过的watch,都会被重新注册。通常这是完全透明的。只有在一个特殊情况下,watch可能会丢失:对于一个未创建的znode的exist watch,如果在客户端断开连接期间被创建了,并且随后在客户端连接上之前又删除了,这种情况下,这个watch事件可能会被丢失。 + +#### 11.客户端注册Watcher实现 + +调用getData()/getChildren()/exist()三个API,传入Watcher对象 +标记请求request,封装Watcher到WatchRegistration +封装成Packet对象,发服务端发送request +收到服务端响应后,将Watcher注册到ZKWatcherManager中进行管理 +请求返回,完成注册。 + +#### 12.服务端处理Watcher实现 + +1)服务端接收Watcher并存储 +接收到客户端请求,处理请求判断是否需要注册Watcher,需要的话将数据节点的节点路径和ServerCnxn(ServerCnxn代表一个客户端和服务端的连接,实现了Watcher的process接口,此时可以看成一个Watcher对象)存储在WatcherManager的WatchTable和watch2Paths中去。 + +2)Watcher触发 +以服务端接收到 setData() 事务请求触发NodeDataChanged事件为例: + +封装WatchedEvent +将通知状态(SyncConnected)、事件类型(NodeDataChanged)以及节点路径封装成一个WatchedEvent对象 +查询Watcher +从WatchTable中根据节点路径查找Watcher +没找到;说明没有客户端在该数据节点上注册过Watcher +找到;提取并从WatchTable和Watch2Paths中删除对应Watcher(从这里可以看出Watcher在服务端是一次性的,触发一次就失效了) + +3)调用process方法来触发Watcher +这里process主要就是通过ServerCnxn对应的TCP连接发送Watcher事件通知。 + +#### 13.ACL权限控制机制 + +1)UGO(User/Group/Others) +目前在Linux/Unix文件系统中使用,也是使用最广泛的权限控制方式。是一种粗粒度的文件系统权限控制模式。 + +2)ACL(Access Control List)访问控制列表 +包括三个方面: + +权限模式(Scheme) +IP:从IP地址粒度进行权限控制 +Digest:最常用,用类似于 username:password 的权限标识来进行权限配置,便于区分不同应用来进行权限控制 +World:最开放的权限控制方式,是一种特殊的digest模式,只有一个权限标识“world:anyone” +Super:超级用户 + +授权对象 +授权对象指的是权限赋予的用户或一个指定实体,例如IP地址或是机器灯。 + +权限 Permission +CREATE:数据节点创建权限,允许授权对象在该Znode下创建子节点 +DELETE:子节点删除权限,允许授权对象删除该数据节点的子节点 +READ:数据节点的读取权限,允许授权对象访问该数据节点并读取其数据内容或子节点列表等 +WRITE:数据节点更新权限,允许授权对象对该数据节点进行更新操作 +ADMIN:数据节点管理权限,允许授权对象对该数据节点进行ACL相关设置操作 + +#### 14.服务器角色 + +Leader +事务请求的唯一调度和处理者,保证集群事务处理的顺序性 +集群内部各服务的调度者 + +Follower +处理客户端的非事务请求,转发事务请求给Leader服务器 +参与事务请求Proposal的投票 +参与Leader选举投票 + +Observer +3.3.0版本以后引入的一个服务器角色,在不影响集群事务处理能力的基础上提升集群的非事务处理能力 +处理客户端的非事务请求,转发事务请求给Leader服务器 +不参与任何形式的投票 + +#### 15.Zookeeper 下 Server工作状态 + +服务器具有四种状态,分别是LOOKING、FOLLOWING、LEADING、OBSERVING。 +LOOKING:寻找Leader状态。当服务器处于该状态时,它会认为当前集群中没有Leader,因此需要进入Leader选举状态。 +FOLLOWING:跟随者状态。表明当前服务器角色是Follower。 +LEADING:领导者状态。表明当前服务器角色是Leader。 +OBSERVING:观察者状态。表明当前服务器角色是Observer。 + +#### 16.数据同步 + +整个集群完成Leader选举之后,Learner(Follower和Observer的统称)回向Leader服务器进行注册。当Learner服务器想Leader服务器完成注册后,进入数据同步环节。 + +数据同步流程:(均以消息传递的方式进行) +i. Learner向Learder注册 +ii. 数据同步 +iii. 同步确认 + +Zookeeper的数据同步通常分为四类: + +直接差异化同步(DIFF同步) +先回滚再差异化同步(TRUNC+DIFF同步) +仅回滚同步(TRUNC同步) +全量同步(SNAP同步) +在进行数据同步前,Leader服务器会完成数据同步初始化: +peerLastZxid:从learner服务器注册时发送的ACKEPOCH消息中提取lastZxid(该Learner服务器最后处理的ZXID) +minCommittedLog:Leader服务器Proposal缓存队列committedLog中最小ZXID +maxCommittedLog:Leader服务器Proposal缓存队列committedLog中最大ZXID + +直接差异化同步(DIFF同步) +场景:peerLastZxid介于minCommittedLog和maxCommittedLog之间 + +先回滚再差异化同步(TRUNC+DIFF同步) +场景:当新的Leader服务器发现某个Learner服务器包含了一条自己没有的事务记录,那么就需要让该Learner服务器进行事务回滚--回滚到Leader服务器上存在的,同时也是最接近于peerLastZxid的ZXID + +仅回滚同步(TRUNC同步) +场景:peerLastZxid 大于 maxCommittedLog + +全量同步(SNAP同步) +场景一:peerLastZxid 小于 minCommittedLog +场景二:Leader服务器上没有Proposal缓存队列且peerLastZxid不等于lastProcessZxid + +#### 17.zookeeper是如何保证事务的顺序一致性的? + +zookeeper采用了全局递增的事务Id来标识,所有的proposal(提议)都在被提出的时候加上了zxid,zxid实际上是一个64位的数字,高32位是epoch(时期; 纪元; 世; 新时代)用来标识leader周期,如果有新的leader产生出来,epoch会自增,低32位用来递增计数。当新产生proposal的时候,会依据数据库的两阶段过程,首先会向其他的server发出事务执行请求,如果超过半数的机器都能执行并且能够成功,那么就会开始执行。 + +#### 18.分布式集群中为什么会有Master? + +在分布式环境中,有些业务逻辑只需要集群中的某一台机器进行执行,其他的机器可以共享这个结果,这样可以大大减少重复计算,提高性能,于是就需要进行leader选举。 + +#### 19.zk节点宕机如何处理? + +Zookeeper本身也是集群,推荐配置不少于3个服务器。Zookeeper自身也要保证当一个节点宕机时,其他节点会继续提供服务。 +如果是一个Follower宕机,还有2台服务器提供访问,因为Zookeeper上的数据是有多个副本的,数据并不会丢失; +如果是一个Leader宕机,Zookeeper会选举出新的Leader。 +ZK集群的机制是只要超过半数的节点正常,集群就能正常提供服务。只有在ZK节点挂得太多,只剩一半或不到一半节点能工作,集群才失效。 + +所以 +3个节点的cluster可以挂掉1个节点(leader可以得到2票>1.5) +2个节点的cluster就不能挂掉任何1个节点了(leader可以得到1票<=1) + +#### 20.Zookeeper有哪几种部署模式? + +单机模式、伪集群模式、集群模式。 + +#### 21.集群最少要几台机器,集群规则是怎样的? + +集群规则为2N+1台,N>0,即3台。 + +#### 22.集群支持动态添加机器吗? + +其实就是水平扩容了,Zookeeper在这方面不太好。两种方式: +全部重启:关闭所有Zookeeper服务,修改配置之后启动。不影响之前客户端的会话。 +逐个重启:在过半存活即可用的原则下,一台机器重启不影响整个集群对外提供服务。这是比较常用的方式。 +3.5版本开始支持动态扩容。 + +#### 23.Zookeeper对节点的watch监听通知是永久的吗?为什么不是永久的? + +不是。官方声明:一个Watch事件是一个一次性的触发器,当被设置了Watch的数据发生了改变的时候,则服务器将这个改变发送给设置了Watch的客户端,以便通知它们。 + +为什么不是永久的,举个例子,如果服务端变动频繁,而监听的客户端很多情况下,每次变动都要通知到所有的客户端,给网络和服务器造成很大压力。 +一般是客户端执行getData(“/节点A”,true),如果节点A发生了变更或删除,客户端会得到它的watch事件,但是在之后节点A又发生了变更,而客户端又没有设置watch事件,就不再给客户端发送。 +在实际应用中,很多情况下,我们的客户端不需要知道服务端的每一次变动,我只要最新的数据即可。 + +#### 24.ZAB和Paxos算法的联系与区别? + +相同点: +两者都存在一个类似于Leader进程的角色,由其负责协调多个Follower进程的运行 +Leader进程都会等待超过半数的Follower做出正确的反馈后,才会将一个提案进行提交 +ZAB协议中,每个Proposal中都包含一个 epoch 值来代表当前的Leader周期,Paxos中名字为Ballot + +不同点: +ZAB用来构建高可用的分布式数据主备系统(Zookeeper),Paxos是用来构建分布式一致性状态机系统。 + +#### 25.Zookeeper的典型应用场景 + +数据发布/订阅 +负载均衡 +命名服务 +分布式协调/通知 +集群管理 +Master选举 +分布式锁 +分布式队列 + +#### 26.Zookeeper 和 Dubbo 的关系? + +Zookeeper的作用: +zookeeper用来注册服务和进行负载均衡,哪一个服务由哪一个机器来提供必需让调用者知道,简单来说就是ip地址和服务名称的对应关系。当然也可以通过硬编码的方式把这种对应关系在调用方业务代码中实现,但是如果提供服务的机器挂掉调用者无法知晓,如果不更改代码会继续请求挂掉的机器提供服务。zookeeper通过心跳机制可以检测挂掉的机器并将挂掉机器的ip和服务对应关系从列表中删除。至于支持高并发,简单来说就是横向扩展,在不更改代码的情况通过添加机器来提高运算能力。通过添加新的机器向zookeeper注册服务,服务的提供者多了能服务的客户就多了。 + +dubbo: +是管理中间层的工具,在业务层到数据仓库间有非常多服务的接入和服务提供者需要调度,dubbo提供一个框架解决这个问题。 +注意这里的dubbo只是一个框架,至于你架子上放什么是完全取决于你的,就像一个汽车骨架,你需要配你的轮子引擎。这个框架中要完成调度必须要有一个分布式的注册中心,储存所有服务的元数据,你可以用zk,也可以用别的,只是大家都用zk。 + +zookeeper和dubbo的关系: +Dubbo 的将注册中心进行抽象,它可以外接不同的存储媒介给注册中心提供服务,有 ZooKeeper,Memcached,Redis 等。 +引入了 ZooKeeper 作为存储媒介,也就把 ZooKeeper 的特性引进来。首先是负载均衡,单注册中心的承载能力是有限的,在流量达到一定程度的时 候就需要分流,负载均衡就是为了分流而存在的,一个 ZooKeeper 群配合相应的 Web 应用就可以很容易达到负载均衡;资源同步,单单有负载均衡还不 够,节点之间的数据和资源需要同步,ZooKeeper 集群就天然具备有这样的功能;命名服务,将树状结构用于维护全局的服务地址列表,服务提供者在启动 的时候,向 ZooKeeper 上的指定节点 /dubbo/${serviceName}/providers 目录下写入自己的 URL 地址,这个操作就完成了服务的发布。 其他特性还有 Mast 选举,分布式锁等。 + +#### 27.zookeeper负载均衡和nginx负载均衡区别 + +zookeeper +不存在单点问题,zab机制保证单点故障可重新选举一个leader +只负责服务的注册与发现,不负责转发,减少一次数据交换(消费方与服务方直接通信) +需要自己实现相应的负载均衡算法 + +nginx +存在单点问题,单点负载高数据量大,需要通过KeepAlived+LVS备机实现高可用 +每次负载,都充当一次中间人转发角色,增加网络负载量(消费方与服务方间接通信) +自带负载均衡算法 + + + + +### 参考资料 +https://www.cnblogs.com/lanqiu5ge/p/9405601.html +https://blog.csdn.net/weixin_43122090/article/details/103645642 +https://www.cnblogs.com/liulong99/p/13036794.html +https://zhuanlan.zhihu.com/p/94146775 +https://segmentfault.com/a/1190000014479433 diff --git "a/imgs/Java\351\235\242\350\257\225\346\224\273\347\225\245.jpg" "b/imgs/Java\351\235\242\350\257\225\346\224\273\347\225\245.jpg" new file mode 100644 index 0000000..340b9cf Binary files /dev/null and "b/imgs/Java\351\235\242\350\257\225\346\224\273\347\225\245.jpg" differ diff --git "a/imgs/\347\250\213\345\272\217\345\221\230\347\231\276\347\247\221\345\205\250\344\271\246.jpg" "b/imgs/\347\250\213\345\272\217\345\221\230\347\231\276\347\247\221\345\205\250\344\271\246.jpg" new file mode 100644 index 0000000..ee76cdb Binary files /dev/null and "b/imgs/\347\250\213\345\272\217\345\221\230\347\231\276\347\247\221\345\205\250\344\271\246.jpg" differ diff --git a/java8.md b/java8.md new file mode 100644 index 0000000..8ceed05 --- /dev/null +++ b/java8.md @@ -0,0 +1,90 @@ +### Java8 + +#### 1.Java 8 新特性简介: + +``` +1. 代码更少(增加了新语法:Lambda 表达式) +2. 强大的 Stream API(集合数据的操作) +3. 最大化的减少空指针 异常:Optional 类 的使用 +4. 接口的新特性 +5. 注解的新特性 +6. 集合的底层 源码实现 +7. 新日期时间的 api +``` + +#### 2.抽象类 和 接口的 异同? + +``` +抽象类:含有 abstract 修饰符的 class 就算 抽象类;它既可以有抽象方法,也可以有 普通方法,构造方法,静态方法,但是不能有抽象构造方法 和 抽象静态方法。且如果其子类没有实现其所有的 抽象方法,那么该 子类 也必须是 抽象类; +接口:他可以看成是 抽象类的 一个特例,使用 interface 修饰符; +内部结构: + jdk7:接口只有常量和抽象方法,无构造器 + jdk8:接口增加了 默认方法 和 静态方法,无构造器 + jdk9:接口允许 以 private 修饰的方法,无构造器 +共同点: + 不能实例化; + 多态方式的一种使用; +不同点: + 抽象类是单继承的,而接口可以多继承(实现); + +``` + +#### 3.Java8支持函数编程是什么意思? + +在Java 8之前,所有东西都是面向对象的。除了原语之外,java中的 所有内容都作为对象存在。对方法/函数的所有调用都是使用对象或类引用进行的。 + +方法/功能本身并不是独立存在的。 + +使用Java 8,引入了函数式编程。所以我们可以使用匿名函数。Java是一种一流的面向对象语言。除了原始数据类型之外,Java中的所有内容都是一个对象。即使是一个数组也是一个对象。每个类都创建对象的实例。没有办法只定义一个独立于Java的函数/方法。无法将方法作为参数传递或返回该实例的方法体。 + +#### 4.Java 8中的可选项是什么? + +Java 8引入了一个新的容器类java.util.Optional 。如果该值可用,它将包装一个值。如果该值不可用,则应返回空的可选项。因此它代表空值,缺失值。这个类有各种实用方法,如isPresent(),它可以帮助用户避免使用空值检查。由于不直接返回值,而是返回包装器对象,所以用户可以避免空指针异常。 + +#### 5.hashMap原理,java8做的改变 + +从结构实现来讲,HashMap是数组+链表+红黑树(JDK1.8增加了红黑树部分)实现的。HashMap最多只允许一条记录的键为null,允许多条记录的值为null。HashMap非线程安全。ConcurrentHashMap线程安全。解决碰撞:当出现冲突时,运用拉链法,将关键词为同义词的结点链接在一个单链表中,散列表长m,则定义一个由m个头指针组成的指针数组T,地址为i的结点插入以T(i)为头指针的单链表中。Java8中,冲突的元素超过限制(8),用红黑树替换链表。 + +#### 6.解释Java 8-中间操作与终端操作? + +流操作可以分为两部分: + +中间操作 -返回另一个Stream的中间操作,允许操作以查询的形式连接。 + +终端操作 -产生非流,结果如原始值,集合或根本没有值。 + +#### 7.什么是Lambda表达式? + +Lambda Expression可以定义为允许用户将方法作为参数传递的匿名函数。这有助于删除大量的样板代码。Lambda函数没有访问修饰符(私有,公共或受保护),没有返回类型声明和没有名称。 + +Lambda表达式允许用户将“函数”传递给代码。所以,与以前需要一整套的接口/抽象类想必,我们可以更容易地编写代码。例如,假设我们的代码具有一些复杂的循环/条件逻辑或工作流程。使用lambda表达式,在那些有难度的地方,可以得到很好的解决。 + +#### 8.Lambda函数的优点: + +直到Java 8列表和集合通常由客户端代码从集合中获取迭代器来处理,然后使用它迭代其元素并依次处理每个元素。如果要并行处理不同的元素,那么客户代码而不是集合的责任就是组织它。 通过Java 8,可以更轻松地在多个线程上分发集合的处理。 集合现在可以在内部组织自己的迭代,将并行化的责任从客户端代码转移到库代码中。 + +更少的代码行。如上所述,用户必须仅以声明方式声明要执行的操作。 n > System.out.println(“Hello World”+ n); 所以用户必须键入减少的代码量。 + +使用Java 8 Lambda表达式可以实现更高的效率。通过使用具有多核的CPU,用户可以通过使用lambda并行处理集合来利用多核CPU。 + +#### 9.什么是Java8中的MetaSpace?它与PermGen Space有何不同? + +使用JDK8时,permGen空间已被删除。那么现在将元数据信息存储在哪里?此元数据现在存储在本机内存中,称为“MetaSpace”。该内存不是连续的Java堆内存。它允许通过垃圾收集,自动调整,元数据并发解除分配来改进PermGen空间。 + +#### 10.是什么使Java SE 8优于其他? + +Java SE 8具有以下功能,使其优于其他功能: + +它编写并行代码。它提供了更多可用的代码。它具有改进的性能应用程序。它具有更易读和简洁的代码。它支持编写包含促销的数据库。 + +#### 11.Lambda表达式的参数列表与Lambda箭头运算符有何不同? + +Lambda表达式可以一次携带零个,一个或甚至多个参数。另一方面,Lambda箭头运算符使用图标“->”将这些参数从列表和主体中分离出来。 + +#### 参考链接 + +https://blog.csdn.net/qq_37891300/article/details/82817900 + +https://blog.csdn.net/pzq915981048/article/details/89011881 + +https://www.cnblogs.com/jobbible/archive/2019/02/14/10374405.html \ No newline at end of file diff --git "a/\345\210\206\345\270\203\345\274\217.md" "b/\345\210\206\345\270\203\345\274\217.md" new file mode 100644 index 0000000..dca9148 --- /dev/null +++ "b/\345\210\206\345\270\203\345\274\217.md" @@ -0,0 +1,215 @@ +## 分布式 + + +* [1.分布式id如何生成?](#1分布式id如何生成) +* [2.雪花算法了解过吗?](#2雪花算法了解过吗) +* [3.什么是CAP定理?](#3什么是cap定理) +* [4.分布式事务了解过吗?](#4分布式事务了解过吗) +* [5.什么是二阶段提交(2PC)?什么是三阶段提交(3PC)?](#5什么是二阶段提交2pc什么是三阶段提交3pc) +* [6.TCC了解过吗?](#6tcc了解过吗) +* [7.Paxos算法了解过吗?](#7paxos算法了解过吗) +* [8.Zookeeper的Zab协议了解过吗?](#8zookeeper的zab协议了解过吗) +* [9.知道什么是Gossip协议吗?](#9知道什么是gossip协议吗) +* [10.了解过哪些负载均衡算法?](#10了解过哪些负载均衡算法) +* [11.负载均衡的实现方案有哪些?](#11负载均衡的实现方案有哪些) +* [12.正向代理和反向代理的区别](#12正向代理和反向代理的区别) +* [13.分布式 Session了解过吗?如何实现?](#13分布式-session了解过吗如何实现) +* [14.如何防止表单重复提交?](#14如何防止表单重复提交) +* [15.如何设计一个秒杀系统?](#15如何设计一个秒杀系统) +* [16.分布式系统的接口幂等性设计](#16分布式系统的接口幂等性设计) +* [17.如何保障请求执行顺序](#17如何保障请求执行顺序) +* [18.BASE理论了解过吗?](#18base理论了解过吗) +* [19.SOA和微服务架构有哪些区别?](#19soa和微服务架构有哪些区别) +* [参考资料](#参考资料) + + +#### 1.分布式id如何生成? + +详见:https://mp.weixin.qq.com/s/eakphQDWKrsUnIwTj8zMQA + +#### 2.雪花算法了解过吗? + +雪花算法生成的是Long类型的ID,一个Long类型占8个字节,每个字节占8比特,也就是说一个Long类型占64个比特。 雪花ID组成结构:正数位(占1比特)+ 时间戳(占41比特)+ 机器ID(占5比特)+ 数据中心(占5比特)+ 自增值(占12比特),总共64比特组成的一个Long类型。 第一个bit位(1bit):Java中long的最高位是符号位代表正负,正数是0,负数是1,一般生成ID都为正数,所以默认为0。 时间戳部分(41bit):毫秒级的时间,不建议存当前时间戳,而是用(当前时间戳 - 固定开始时间戳)的差值,可以使产生的ID从更小的值开始;41位的时间戳可以使用69年,(1L << 41) / (1000L * 60 * 60 * 24 * 365) = 69年 工作机器id(10bit):也被叫做workId,这个可以灵活配置,机房或者机器号组合都可以。 序列号部分(12bit),自增值支持同一毫秒内同一个节点可以生成4096个ID + +#### 3.什么是CAP定理? + +任何分布式系统都无法同时满足一致性(consistency),可用性(availibity),分区容错性(partition tolerance)这三项,最多只可同时满足其中的两项。 + +#### 4.分布式事务了解过吗? + +涉及到多个数据库操作的事务即为分布式事务,目的是为保证分布式系统中的数据一致性. + +#### 5.什么是二阶段提交(2PC)?什么是三阶段提交(3PC)? + +二阶段提交2PC:第一步请求阶段通过协调者来统计表决结果,第二步执行表决后的结果,如果表决的结果是提交,那就提交执行,否则不执行提交.缺点是同步阻塞,而且万一协调者挂了就无法保证ACID. + +三阶段提交3PC:在2PC的第一步拆分成了2步并且引入了超时机制,解决了2PC的痛点.第一步先向参与者发出一个信号,看看大家是否都能提交,如果可以就返回yes,否则返回no.第二步PreCommit阶段,预提交一下,如果参与者可以完成commit,就返回ack进确认,如果不能则放弃提交本次事务.第三步doCommit阶段,进行真正的事务提交. + +#### 6.TCC了解过吗? + +try,commit,cancel的缩写,try阶段进行检测,commit提交执行,只要try阶段成功了commit就一定会被执行,cancel业务出现错误时执行,回滚事务,释放资源. + +#### 7.Paxos算法了解过吗? + +详见:https://blog.csdn.net/westbrookliu/article/details/99713365 + +#### 8.Zookeeper的Zab协议了解过吗? + +详见:https://blog.csdn.net/liuchang19950703/article/details/111406622 + +#### 9.知道什么是Gossip协议吗? + +详见:https://mp.weixin.qq.com/s/dW0I29Sw86lU0qHpxyhdmw + +#### 10.了解过哪些负载均衡算法? + +轮询(Round Robin) +轮询算法把每个请求轮流发送到每个服务器上。 +该算法比较适合每个服务器的性能差不多的场景,如果有性能存在差异的情况下,那么性能较差的服务器可能无法承担多大的负载。 + +加权轮询(Weighted Round Robbin) +加权轮询是在轮询的基础上,根据服务器的性能差异,为服务器赋予一定的权值。 + +最少连接(least Connections) +由于每个请求的连接时间不一样,使用轮询或者加权轮询算法的话,可能会让一台服务器当前连接数过多,而另一台服务器的连接数过少,造成负载不均衡。最少连接算法就是将请求发送给当前最少连接数的服务器上。 + +加权最小连接(Weighted Least Connection) +在最小连接的基础上,根据服务器的性能为每台服务器分配权重,然后根据权重计算出每台服务器能处理的连接数。 + +随机算法(Random) +把请求随机发送到服务器上。和轮询算法类似,该算法比较适合服务器性能差不多的场景。 + +#### 11.负载均衡的实现方案有哪些? + +DNS 解析 +使用 DNS 作为负载均衡器,会根据负载情况返回不同服务器的 IP 地址。大型网站基本使用了这种方式最为第一级负载均衡手段,然后在内部在第二级负载均衡。 + +修改 MAC 地址 +使用 LVS(Linux Virtual Server)这种链路层负载均衡器,根据负载情况修改请求的 MAC 地址。 + +修改 IP 地址 +在网络层修改请求的目的 IP 地址。 + +HTTP 重定向 +HTTP 重定向负载均衡服务器收到 HTTP 请求之后会返回服务器的地址,并将该地址写入 HTTP 重定向响应中返回给浏览器,浏览器收到后再次发送请求。 + +#### 12.正向代理和反向代理的区别 + +正向代理:发生在客户端,是由用户主动发起的。比如翻墙,客户端通过主动访问代理服务器,让代理服务器获得需要的外网数据,然后转发回客户端。 +反向代理:发生在服务器端,用户不知道发生了代理。 + +#### 13.分布式 Session了解过吗?如何实现? + +如果不做任何处理的话,用户将出现频繁登录的现象,比如集群中存在 A、B 两台服务器,用户在第一次访问网站时,Nginx 通过其负载均衡机制将用户请求转发到 A 服务器,这时 A 服务器就会给用户创建一个 Session。当用户第二次发送请求时,Nginx 将其负载均衡到 B 服务器,而这时候 B 服务器并不存在 Session,所以就会将用户踢到登录页面。这将大大降低用户体验度,导致用户的流失,这种情况是项目绝不应该出现的。 + +1. 粘性 Session +原理 +粘性 Session 是指将用户锁定到某一个服务器上,比如上面说的例子,用户第一次请求时,负载均衡器将用户的请求转发到了 A 服务器上,如果负载均衡器设置了粘性 Session 的话,那么用户以后的每次请求都会转发到 A 服务器上,相当于把用户和 A 服务器粘到了一块,这就是粘性 Session 机制。 + +优点 +简单,不需要对 Session 做任何处理。 + +缺点 +缺乏容错性,如果当前访问的服务器发生故障,用户被转移到第二个服务器上时,他的 Session 信息都将失效。 + +适用场景 +发生故障对客户产生的影响较小; +服务器发生故障是低概率事件。 + +2. 服务器 Session 复制 + +原理 +任何一个服务器上的 Session 发生改变,该节点会把这个 Session 的所有内容序列化,然后广播给所有其它节点,不管其他服务器需不需要 Session,以此来保证 Session 同步。 + +优点 +可容错,各个服务器间 Session 能够实时响应。 + +缺点 +会对网络负荷造成一定压力,如果 Session 量大的话可能会造成网络堵塞,拖慢服务器性能。 + +实现方式 +设置 Tomcat 的 server.xml 开启 tomcat 集群功能。 +在应用里增加信息:通知应用当前处于集群环境中,支持分布式,即在 web.xml 中添加 选项。 + +3. Session 共享机制 + +使用分布式缓存方案比如 Memcached、Redis,但是要求 Memcached 或 Redis 必须是集群。 +使用 Session 共享也分两种机制,两种情况如下: + +3.1 粘性 Session 共享机制 +和粘性 Session 一样,一个用户的 Session 会绑定到一个 Tomcat 上。Memcached 只是起到备份作用。 + +3.2 非粘性 Session 共享机制 + +原理 +Tomcat 本身不存储 Session,而是存入 Memcached 中。Memcached 集群构建主从复制架构。 + +优点 +可容错,Session 实时响应。 +实现方式 +用开源的 msm 插件解决 Tomcat 之间的 Session 共享:Memcached_Session_Manager(MSM) + +4. Session 持久化到数据库 + +原理 +拿出一个数据库,专门用来存储 Session 信息。保证 Session 的持久化。 + +优点 +服务器出现问题,Session 不会丢失。 + +缺点 +如果网站的访问量很大,把 Session 存储到数据库中,会对数据库造成很大压力,还需要增加额外的开销维护数据库。 + +5. Terracotta 实现 Session 复制 + +原理 +Terracotta 的基本原理是对于集群间共享的数据,当在一个节点发生变化的时候,Terracotta 只把变化的部分发送给 Terracotta 服务器,然后由服务器把它转发给真正需要这个数据的节点。它是服务器 Session 复制的优化。 + +优点 +这样对网络的压力就非常小,各个节点也不必浪费 CPU 时间和内存进行大量的序列化操作。把这种集群间数据共享的机制应用在 Session 同步上,既避免了对数据库的依赖,又能达到负载均衡和灾难恢复的效果。 + +#### 14.如何防止表单重复提交? + +前端。每次点击后都要等X秒才能点击。 +数据库添加唯一索引 +服务器返回表单页面时,会先生成一个token保存于session或redis,当表单提交时候携带token,如果token一致,则执行后续,并将服务器中的token删除。 + +#### 15.如何设计一个秒杀系统? + +前端:在秒杀之前,按钮置灰,并且不给前端真正的请求地址。前端定时请求后端接口,如果到了秒杀时间,则返回给前端真正的地址,前端放开按钮,每次点击后都要等X秒才能点击。 +服务器:服务器用nginx做集群、redis也做集群 +限流:在秒杀之前,将秒杀数量的令牌存入到redis中,可以用list,每次来请求都去redis中取出令牌,如果获取到说明秒杀成功,然后去访问数据库下单,如果没有获取到,则说明商品卖完了。 +消息中间件:如果秒杀数量比较多,例如上万十万,则秒杀成功之后,将成功的请求放入到mq或者kafka中间件中,再从消息队列中获取请求。 +服务降级:为了以防万一,还是要做服务熔断降级。 + + +#### 16.分布式系统的接口幂等性设计 + +唯一id。每次操作,都根据操作和内容生成唯一的id,在执行之前先判断id是否存在,如果不存在则执行后续操作,并且保存到数据库或者redis等。 +服务端提供发送token的接口,业务调用接口前先获取token,然后调用业务接口请求时,把token携带过去,务器判断token是否存在redis中,存在表示第一次请求,可以继续执行业务,执行业务完成后,最后需要把redis中的token删除 +建去重表。将业务中有唯一标识的字段保存到去重表,如果表中存在,则表示已经处理过了 +版本控制。增加版本号,当版本号符合时,才能更新数据 +状态控制。例如订单有状态已支付 未支付 支付中 支付失败,当处于未支付的时候才允许修改为支付中等 + +#### 17.如何保障请求执行顺序 + +一般来说,从业务逻辑上最好设计系统不需要这种顺序的保证,因为一旦引入顺序性保障,会导致系统复杂度的上升,效率会降低,对于热点数据会压力过大等问题。 +首先使用一致性hash负载均衡策略,将同一个id的请求都分发到同一个机器上面去处理,比如订单可以根据订单id。如果处理的机器上面是多线程处理的,可以引入内存队列去处理,将相同id的请求通过hash到同一个队列当中,一个队列只对应一个处理线程。 +最好能将多个操作合并成一个操作。 + +#### 18.BASE理论了解过吗? + +BASE是 Basically Available (基本可用) Soft state(软状态) Eventually consistent(最终一致性)这几个单词的缩写,是从CAP理论发展而来的,其核心思想是:即使无法做到强一致性,但每个应用都可以根据自身特点,采取适当的方式来使系统达到最终一致性. + +#### 19.SOA和微服务架构有哪些区别? + +微服务是在SOA的基础上发展而来,从粒度上来说,微服务的粒度要比SOA更细. +微服务由于粒度更细,所以微服务架构的耦合度相对于SOA架构的耦合度更低. +微服务的服务规模相较于SOA一般要更大,所能承载的并发量也更高. + + + +### 参考资料 +https://www.cnblogs.com/workstation-nigoudongma/p/9546801.html +https://blog.csdn.net/zgsxhdzxl/article/details/104414475 +https://blog.csdn.net/lovexiaotaozi/article/details/89713937 diff --git "a/\345\244\232\347\272\277\347\250\213.md" "b/\345\244\232\347\272\277\347\250\213.md" new file mode 100644 index 0000000..97c5eff --- /dev/null +++ "b/\345\244\232\347\272\277\347\250\213.md" @@ -0,0 +1,437 @@ +## 多线程 + + +* [1.说说synchronized的实现原理](#1说说synchronized的实现原理) +* [2.ReentrantLock与synchronized的区别](#2reentrantlock与synchronized的区别) +* [3.ReentrantLock实现原理](#3reentrantlock实现原理) +* [4.Java原子类AtomicInteger实现原理](#4java原子类atomicinteger实现原理) +* [5.Java线程池实现原理](#5java线程池实现原理) +* [6.ThreadLocal实现原理](#6threadlocal实现原理) +* [7.InheritableThreadLocal原理知道吗?](#7inheritablethreadlocal原理知道吗) +* [8.说一下synchronized锁升级过程](#8说一下synchronized锁升级过程) +* [9.了解过什么是“伪共享”吗?](#9了解过什么是伪共享吗) +* [10.“伪共享”出现的原因是什么?](#10伪共享出现的原因是什么) +* [11.如何避免“伪共享”?](#11如何避免伪共享) +* [12.Java里的线程有哪些状态?](#12java里的线程有哪些状态) +* [13.什么是悲观锁?什么是乐观锁?](#13什么是悲观锁什么是乐观锁) +* [14.怎么停止一个运行中的线程?](#14怎么停止一个运行中的线程) +* [15.说一下你对volatile的理解?](#15说一下你对volatile的理解) +* [16.并发编程三要素?](#16并发编程三要素) +* [17.创建线程有哪些方式?](#17创建线程有哪些方式) +* [18.线程池的优点?](#18线程池的优点) +* [19.CyclicBarrier和CountDownLatch的区别](#19cyclicbarrier和countdownlatch的区别) +* [20.什么是CAS?](#20什么是cas) +* [21.CAS的问题](#21cas的问题) +* [22.什么是AQS?](#22什么是aqs) +* [23.AQS支持几种同步方式?](#23aqs支持几种同步方式) +* [24.什么是自旋锁?](#24什么是自旋锁) +* [25.什么是多线程的上下文切换?](#25什么是多线程的上下文切换) +* [26.什么是线程和进程?](#26什么是线程和进程) +* [27.程序计数器为什么是私有的?](#27程序计数器为什么是私有的) +* [28.虚拟机栈和本地方法栈为什么是私有的?](#28虚拟机栈和本地方法栈为什么是私有的) +* [29.并发与并行的区别?](#29并发与并行的区别) +* [30.什么是线程死锁?如何避免死锁?](#30什么是线程死锁如何避免死锁) +* [31.sleep() 方法和 wait() 方法的区别和共同点?](#31sleep-方法和-wait-方法的区别和共同点) +* [32.为什么我们调用 start() 方法时会执行 run() 方法,为什么我们不能直接调用 run() 方法?](#32为什么我们调用-start-方法时会执行-run-方法为什么我们不能直接调用-run-方法) +* [33.什么是线程安全问题?如何解决?](#33什么是线程安全问题如何解决) +* [34.什么是活锁?](#34什么是活锁) +* [35.什么是线程的饥饿问题?如何解决?](#35什么是线程的饥饿问题如何解决) +* [36.什么是线程的阻塞问题?如何解决?](#36什么是线程的阻塞问题如何解决) +* [37.synchronized 关键字和 volatile 关键字的区别](#37synchronized-关键字和-volatile-关键字的区别) +* [38.说一说几种常见的线程池及适用场景?](#38说一说几种常见的线程池及适用场景) +* [39.线程池都有哪几种工作队列?](#39线程池都有哪几种工作队列) +* [40.什么是线程安全?](#40什么是线程安全) +* [41.Java中如何获取到线程dump文件](#41java中如何获取到线程dump文件) +* [42.Java中用到的线程调度算法是什么?](#42java中用到的线程调度算法是什么) +* [43.Thread.sleep(0)的作用是什么?](#43threadsleep0的作用是什么) +* [44.单例模式的线程安全性](#44单例模式的线程安全性) +* [45.Semaphore有什么作用?](#45semaphore有什么作用) +* [46.Hashtable的size()方法中明明只有一条语句"return count",为什么还要做同步?](#46hashtable的size方法中明明只有一条语句return-count为什么还要做同步) +* [47.同步方法和同步块,哪个是更好的选择?](#47同步方法和同步块哪个是更好的选择) +* [48.高并发、任务执行时间短的业务怎样使用线程池?并发不高、任务执行时间长的业务怎样使用线程池?并发高、业务执行时间长的业务怎样使用线程池?](#48高并发任务执行时间短的业务怎样使用线程池并发不高任务执行时间长的业务怎样使用线程池并发高业务执行时间长的业务怎样使用线程池) +* [49.在Java中Lock接口比synchronized块的优势是什么?你需要实现一个高效的缓存,它允许多个用户读,但只允许一个用户写,以此来保持它的完整性,你会怎样去实现它?](#49在java中lock接口比synchronized块的优势是什么你需要实现一个高效的缓存它允许多个用户读但只允许一个用户写以此来保持它的完整性你会怎样去实现它) +* [50.你将如何使用thread dump?你将如何分析Thread dump?](#50你将如何使用thread-dump你将如何分析thread-dump) +* [参考资料](#参考资料) + + +#### 1.说说synchronized的实现原理 + +在 Java 中,每个对象都隐式包含一个 monitor(监视器)对象,加锁的过程其实就是竞争 monitor 的过程,当线程进入字节码 monitorenter 指令之后,线程将持有 monitor 对象,执行 monitorexit 时释放 monitor 对象,当其他线程没有拿到 monitor 对象时,则需要阻塞等待获取该对象。 + +#### 2.ReentrantLock与synchronized的区别 + +ReentrantLock 有如下特点: + +1. 可重入 + ReentrantLock 和 syncronized 关键字一样,都是可重入锁,不过两者实现原理稍有差别, RetrantLock 利用 AQS 的的 state 状态来判断资源是否已锁,同一线程重入加锁, state 的状态 +1 ; 同一线程重入解锁, state 状态 -1 (解锁必须为当前独占线程,否则异常); 当 state 为 0 时解锁成功。 +2. 需要手动加锁、解锁 + synchronized 关键字是自动进行加锁、解锁的,而 ReentrantLock 需要 lock() 和 unlock() 方法配合 try/finally 语句块来完成,来手动加锁、解锁。 +3. 支持设置锁的超时时间 + synchronized 关键字无法设置锁的超时时间,如果一个获得锁的线程内部发生死锁,那么其他线程就会一直进入阻塞状态,而 ReentrantLock 提供 tryLock 方法,允许设置线程获取锁的超时时间,如果超时,则跳过,不进行任何操作,避免死锁的发生。 +4. 支持公平/非公平锁 + synchronized 关键字是一种非公平锁,先抢到锁的线程先执行。而 ReentrantLock 的构造方法中允许设置 true/false 来实现公平、非公平锁,如果设置为 true ,则线程获取锁要遵循"先来后到"的规则,每次都会构造一个线程 Node ,然后到双向链表的"尾巴"后面排队,等待前面的 Node 释放锁资源。 +5. 可中断锁 + ReentrantLock 中的 lockInterruptibly() 方法使得线程可以在被阻塞时响应中断,比如一个线程 t1 通过 lockInterruptibly() 方法获取到一个可重入锁,并执行一个长时间的任务,另一个线程通过 interrupt() 方法就可以立刻打断 t1 线程的执行,来获取t1持有的那个可重入锁。而通过 ReentrantLock 的 lock() 方法或者 Synchronized 持有锁的线程是不会响应其他线程的 interrupt() 方法的,直到该方法主动释放锁之后才会响应 interrupt() 方法。 + +#### 3.ReentrantLock实现原理 + +详见:https://blog.csdn.net/yanbin0830/article/details/107542529 + +#### 4.Java原子类AtomicInteger实现原理 + +详见:https://www.cnblogs.com/scuwangjun/p/9098057.html + +#### 5.Java线程池实现原理 + +详见:https://www.cnblogs.com/dolphin0520/p/3932921.html + +#### 6.ThreadLocal实现原理 + +详见:https://www.cnblogs.com/fsmly/p/11020641.html + +#### 7.InheritableThreadLocal原理知道吗? + +详见:https://www.jianshu.com/p/94ba4a918ff5 + +#### 8.说一下synchronized锁升级过程 + +1. 偏向锁 + 在 JDK1.8 中,其实默认是轻量级锁,但如果设定了 -XX:BiasedLockingStartupDelay = 0 ,那在对一个 Object 做 syncronized 的时候,会立即上一把偏向锁。当处于偏向锁状态时, markwork 会记录当前线程 ID 。 + +2. 升级到轻量级锁 + 当下一个线程参与到偏向锁竞争时,会先判断 markword 中保存的线程 ID 是否与这个线程 ID 相等,如果不相等,会立即撤销偏向锁,升级为轻量级锁。每个线程在自己的线程栈中生成一个 LockRecord ( LR ),然后每个线程通过 CAS (自旋)的操作将锁对象头中的 markwork 设置为指向自己的 LR 的指针,哪个线程设置成功,就意味着获得锁。关于 synchronized 中此时执行的 CAS 操作是通过 native 的调用 HotSpot 中 bytecodeInterpreter.cpp 文件 C++ 代码实现的,有兴趣的可以继续深挖。 + +3. 升级到重量级锁 + 如果锁竞争加剧(如线程自旋次数或者自旋的线程数超过某阈值, JDK1.6 之后,由 JVM 自己控制该规则),就会升级为重量级锁。此时就会向操作系统申请资源,线程挂起,进入到操作系统内核态的等待队列中,等待操作系统调度,然后映射回用户态。在重量级锁中,由于需要做内核态到用户态的转换,而这个过程中需要消耗较多时间,也就是"重"的原因之一。 + +#### 9.了解过什么是“伪共享”吗? + +CPU缓存从内存读数据时,是按缓存行读取的,即使只用到一个变量,也要将整行数据进行读取,这行数据量可能包含其他变量。当多个线程同时修改同一个缓存行里的不同变量时,由于同时只能有一个线程在操作,所以相比将每个变量放到不同缓存行里,性能会有所下降。多个线程同时修改了同一个缓存行上的不同变量,由于不能并发修改,所以称为“伪共享”。 + +#### 10.“伪共享”出现的原因是什么? + +因为CPU缓存和内存交换数据的单位是缓存行,而同一个缓存行里的多个变量不能同时被多个线程修改。 + +#### 11.如何避免“伪共享”? + +1. 字节填充(创建变量时,使用字段对其进行填充,避免多个变量被分派到同一个缓存行里)。 +2. JDK8提供了一个Contended注解来解决伪共享。 + +#### 12.Java里的线程有哪些状态? + +1. 初始(NEW):新创建了一个线程对象,但还没有调用start()方法。 +2. 运行(RUNNABLE):Java线程中将就绪(ready)和运行中(running)两种状态笼统的称为“运行”。线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)。 +3. 阻塞(BLOCKED):表示线程阻塞于锁。 +4. 等待(WAITING):进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。 +5. 超时等待(TIMED_WAITING):该状态不同于WAITING,它可以在指定的时间后自行返回。 +6. 终止(TERMINATED):表示该线程已经执行完毕。 + +#### 13.什么是悲观锁?什么是乐观锁? + +当我们要对一个数据库中的一条数据进行修改的时候,为了避免同时被其他人修改,最好的办法就是直接对该数据进行加锁以防止并发。 +这种借助数据库锁机制在修改数据之前先锁定,再修改的方式被称之为悲观并发控制(又名“悲观锁”,Pessimistic Concurrency Control,缩写“PCC”)。 +之所以叫做悲观锁,是因为这是一种对数据的修改抱有悲观态度的并发控制方式。我们一般认为数据被并发修改的概率比较大,所以需要在修改之前先加锁。 + +乐观锁( Optimistic Locking ) 是相对悲观锁而言的,乐观锁假设数据一般情况下不会造成冲突,所以在数据进行提交更新的时候,才会正式对数据的冲突与否进行检测,如果发现冲突了,则让返回用户错误的信息,让用户决定如何去做。 +相对于悲观锁,在对数据库进行处理的时候,乐观锁并不会使用数据库提供的锁机制。一般的实现乐观锁的方式就是记录数据版本。 + +#### 14.怎么停止一个运行中的线程? + +详见:https://www.cnblogs.com/liyutian/p/10196044.html + +#### 15.说一下你对volatile的理解? + +详见:https://blog.csdn.net/yinbucheng/article/details/71305951/ + +#### 16.并发编程三要素? + +1)原子性 +原子性指的是一个或者多个操作,要么全部执行并且在执行的过程中不被其他操作打断,要么就全部都不执行。 + +2)可见性 +可见性指多个线程操作一个共享变量时,其中一个线程对变量进行修改后,其他线程可以立即看到修改的结果。 + +3)有序性 +有序性,即程序的执行顺序按照代码的先后顺序来执行。 + +#### 17.创建线程有哪些方式? + +1)继承Thread类创建线程类 + +2)通过Runnable接口创建线程类 + +3)通过Callable和Future创建线程 + +4)通过线程池创建 + +#### 18.线程池的优点? + +1)重用存在的线程,减少对象创建销毁的开销。 +2)可有效的控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。 +3)提供定时执行、定期执行、单线程、并发数控制等功能。 + +#### 19.CyclicBarrier和CountDownLatch的区别 + +1)CountDownLatch简单的说就是一个线程等待,直到他所等待的其他线程都执行完成并且调用countDown()方法发出通知后,当前线程才可以继续执行。 +2)cyclicBarrier是所有线程都进行等待,直到所有线程都准备好进入await()方法之后,所有线程同时开始执行! +3)CountDownLatch的计数器只能使用一次。而CyclicBarrier的计数器可以使用reset() 方法重置。所以CyclicBarrier能处理更为复杂的业务场景,比如如果计算发生错误,可以重置计数器,并让线程们重新执行一次。 +4)CyclicBarrier还提供其他有用的方法,比如getNumberWaiting方法可以获得CyclicBarrier阻塞的线程数量。isBroken方法用来知道阻塞的线程是否被中断。如果被中断返回true,否则返回false。 + +#### 20.什么是CAS? + +CAS是compare and swap的缩写,即我们所说的比较交换。 + +cas是一种基于锁的操作,而且是乐观锁。在java中锁分为乐观锁和悲观锁。悲观锁是将资源锁住,等一个之前获得锁的线程释放锁之后,下一个线程才可以访问。而乐观锁采取了一种宽泛的态度,通过某种方式不加锁来处理资源,比如通过给记录加version来获取数据,性能较悲观锁有很大的提高。 + +CAS 操作包含三个操作数 —— 内存位置(V)、预期原值(A)和新值(B)。如果内存地址里面的值和A的值是一样的,那么就将内存里面的值更新成B。CAS是通过无限循环来获取数据的,若果在第一轮循环中,a线程获取地址里面的值被b线程修改了,那么a线程需要自旋,到下次循环才有可能机会执行。 + +java.util.concurrent.atomic 包下的类大多是使用CAS操作来实现的( AtomicInteger,AtomicBoolean,AtomicLong)。 + +#### 21.CAS的问题 + +1)CAS容易造成ABA问题 + +一个线程a将数值改成了b,接着又改成了a,此时CAS认为是没有变化,其实是已经变化过了,而这个问题的解决方案可以使用版本号标识,每操作一次version加1。在java5中,已经提供了AtomicStampedReference来解决问题。 + +2) 不能保证代码块的原子性 + +CAS机制所保证的知识一个变量的原子性操作,而不能保证整个代码块的原子性。比如需要保证3个变量共同进行原子性的更新,就不得不使用synchronized了。 + +3)CAS造成CPU利用率增加 + +之前说过了CAS里面是一个循环判断的过程,如果线程一直没有获取到状态,cpu资源会一直被占用。 + +#### 22.什么是AQS? + +AQS是AbustactQueuedSynchronizer的简称,它是一个Java提高的底层同步工具类,用一个int类型的变量表示同步状态,并提供了一系列的CAS操作来管理这个同步状态。 + +AQS是一个用来构建锁和同步器的框架,使用AQS能简单且高效地构造出应用广泛的大量的同步器,比如我们提到的ReentrantLock,Semaphore,其他的诸如ReentrantReadWriteLock,SynchronousQueue,FutureTask等等皆是基于AQS的。 + +#### 23.AQS支持几种同步方式? + +1)独占式 + +2)共享式 + +这样方便使用者实现不同类型的同步组件,独占式如ReentrantLock,共享式如Semaphore,CountDownLatch,组合式的如ReentrantReadWriteLock。总之,AQS为使用提供了底层支撑,如何组装实现,使用者可以自由发挥。 + +#### 24.什么是自旋锁? + +自旋锁是SMP架构中的一种low-level的同步机制。 +当线程A想要获取一把自旋锁而该锁又被其它线程锁持有时,线程A会在一个循环中自旋以检测锁是不是已经可用了。 + +自旋锁需要注意: +由于自旋时不释放CPU,因而持有自旋锁的线程应该尽快释放自旋锁,否则等待该自旋锁的线程会一直在那里自旋,这就会浪费CPU时间。 +持有自旋锁的线程在sleep之前应该释放自旋锁以便其它线程可以获得自旋锁。 + +#### 25.什么是多线程的上下文切换? + +即使是单核CPU也支持多线程执行代码,CPU通过给每个线程分配CPU时间片来实现这个机制。时间片是CPU分配给各个线程的时间,因为时间片非常短,所以CPU通过不停地切换线程执行,让我们感觉多个线程时同时执行的,时间片一般是几十毫秒(ms) + +上下文切换过程中,CPU会停止处理当前运行的程序,并保存当前程序运行的具体位置以便之后继续运行 +CPU通过时间片分配算法来循环执行任务,当前任务执行一个时间片后会切换到下一个任务。但是,在切换前会保存上一个任务的状态,以便下次切换回这个任务时,可以再次加载这个任务的状态 +从任务保存到再加载的过程就是一次上下文切换 + +#### 26.什么是线程和进程? + +进程:在操作系统中能够独立运行,并且作为资源分配的基本单位。它表示运行中的程序。系统运行一个程序就是一个进程从创建、运行到消亡的过程。 + +线程:是一个比进程更小的执行单位,能够完成进程中的一个功能,也被称为轻量级进程。一个进程在其执行的过程中可以产生多个线程。 + +线程与进程不同的是:同类的多个线程共享进程的堆和方法区资源,但每个线程有自己的程序计数器、虚拟机栈和本地方法栈,所以系统在产生一个线程,或是在各个线程之间作切换工作时,负担要比进程小得多。 + +#### 27.程序计数器为什么是私有的? + +程序计数器主要有下面两个作用: + +字节码解释器通过改变程序计数器来依次读取指令,从而实现代码的流程控制,如:顺序执行、选择、循环、异常处理。 +在多线程的情况下,程序计数器用于记录当前线程执行的位置,从而当线程被切换回来的时候能够知道该线程上次运行到哪儿了。 +(需要注意的是,如果执行的是 native 方法,那么程序计数器记录的是 undefined 地址,只有执行的是 Java 代码时程序计数器记录的才是下一条指令的地址。) + +所以,程序计数器私有主要是为了线程切换后能恢复到正确的执行位置。 + +#### 28.虚拟机栈和本地方法栈为什么是私有的? + +虚拟机栈: 每个 Java 方法在执行的同时会创建一个栈帧用于存储局部变量表、操作数栈、常量池引用等信息。从方法调用直至执行完成的过程,就对应着一个栈帧在 Java 虚拟机栈中入栈和出栈的过程。 +本地方法栈: 和虚拟机栈所发挥的作用非常相似,区别是: 虚拟机栈为虚拟机执行 Java 方法 (也就是字节码)服务,而本地方法栈则为虚拟机使用到的 Native 方法服务。 在 HotSpot 虚拟机中和 Java 虚拟机栈合二为一。 +所以,为了保证线程中的局部变量不被别的线程访问到,虚拟机栈和本地方法栈是线程私有的。 + +#### 29.并发与并行的区别? + +并发指的是多个任务交替进行,并行则是指真正意义上的“同时进行”。 + +实际上,如果系统内只有一个CPU,使用多线程时,在真实系统环境下不能并行,只能通过切换时间片的方式交替进行,从而并发执行任务。真正的并行只能出现在拥有多个CPU的系统中。 + +#### 30.什么是线程死锁?如何避免死锁? + +多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。由于线程被无限期地阻塞,因此程序不可能正常终止。 + +假如线程 A 持有资源 2,线程 B 持有资源 1,他们同时都想申请对方的资源,所以这两个线程就会互相等待而进入死锁状态。 + +避免死锁的几个常见方法: +避免一个线程同时获取多个锁 +避免一个线程在锁内同时占用多个资源,尽量保证每个锁只占用一个资源。 +尝试使用定时锁,使用 lock.tryLock(timeout) 来代替使用内部锁机制。 +对于数据库锁,加锁和解锁必须在一个数据库连接里,否则会出现解锁失败的情况。 + +#### 31.sleep() 方法和 wait() 方法的区别和共同点? + +相同点: +两者都可以暂停线程的执行,都会让线程进入等待状态。 + +不同点: +sleep()方法没有释放锁,而 wait()方法释放了锁。 +sleep()方法属于Thread类的静态方法,作用于当前线程;而wait()方法是Object类的实例方法,作用于对象本身。 +执行sleep()方法后,可以通过超时或者调用interrupt()方法唤醒休眠中的线程;执行wait()方法后,通过调用notify()或notifyAll()方法唤醒等待线程。 + +#### 32.为什么我们调用 start() 方法时会执行 run() 方法,为什么我们不能直接调用 run() 方法? + +new 一个 Thread,线程进入初始状态;调用 start()方法,会启动一个线程并使线程进入了就绪状态,当分配到时间片后就可以开始运行了。 start() 会执行线程的相应准备工作,然后自动执行 run() 方法的内容,这是真正的多线程工作。 而直接执行 run() 方法,会把 run 方法当成一个 main 线程下的普通方法去执行,并不会在某个线程中执行它,所以这并不是多线程工作。 + +总结: 调用 start 方法可启动线程并使线程进入就绪状态,而 run 方法只是 thread 的一个普通方法调用,还是在主线程里执行。 + +#### 33.什么是线程安全问题?如何解决? + +线程安全问题指的是在某一线程从开始访问到结束访问某一数据期间,该数据被其他的线程所修改,那么对于当前线程而言,该线程就发生了线程安全问题,表现形式为数据的缺失,数据不一致等。 + +线程安全问题发生的条件: + +1)多线程环境下,即存在包括自己在内存在有多个线程。 +2)多线程环境下存在共享资源,且多线程操作该共享资源。 +3)多个线程必须对该共享资源有非原子性操作。 + +线程安全问题的解决思路: +1)尽量不使用共享变量,将不必要的共享变量变成局部变量来使用。 +2)使用synchronized关键字同步代码块,或者使用jdk包中提供的Lock为操作进行加锁。 +3)使用ThreadLocal为每一个线程建立一个变量的副本,各个线程间独立操作,互不影响。 + +#### 34.什么是活锁? + +活锁体现了一种谦让的美德,每个线程都想把资源让给对方,但是由于机器“智商”不够,可能会产生一直将资源让来让去,导致资源在两个线程间跳动而无法使某一线程真正的到资源并执行,这就是活锁的问题。 + +#### 35.什么是线程的饥饿问题?如何解决? + +饥饿指的是某一线程或多个线程因为某些原因一直获取不到资源,导致程序一直无法执行。如某一线程优先级太低导致一直分配不到资源,或者是某一线程一直占着某种资源不放,导致该线程无法执行等。 + +解决方法: +与死锁相比,饥饿现象还是有可能在一段时间之后恢复执行的。可以设置合适的线程优先级来尽量避免饥饿的产生。 + +#### 36.什么是线程的阻塞问题?如何解决? + +阻塞是用来形容多线程的问题,几个线程之间共享临界区资源,那么当一个线程占用了临界区资源后,所有需要使用该资源的线程都需要进入该临界区等待,等待会导致线程挂起,一直不能工作,这种情况就是阻塞,如果某一线程一直都不释放资源,将会导致其他所有等待在这个临界区的线程都不能工作。当我们使用synchronized或重入锁时,我们得到的就是阻塞线程,如论是synchronized或者重入锁,都会在试图执行代码前,得到临界区的锁,如果得不到锁,线程将会被挂起等待,知道其他线程执行完成并释放锁且拿到锁为止。 + +解决方法: +可以通过减少锁持有时间,读写锁分离,减小锁的粒度,锁分离,锁粗化等方式来优化锁的性能。 + +#### 37.synchronized 关键字和 volatile 关键字的区别 + +volatile关键字是线程同步的轻量级实现,所以volatile性能比synchronized关键字要好。但是volatile关键字只能用于变量而synchronized关键字可以修饰方法以及代码块。 +多线程访问volatile关键字不会发生阻塞,而synchronized关键字可能会发生阻塞。 +volatile关键字主要用于解决变量在多个线程之间的可见性,而 synchronized关键字解决的是多个线程之间访问资源的同步性。 +volatile关键字能保证数据的可见性,但不能保证数据的原子性。synchronized关键字两者都能保证。 + +#### 38.说一说几种常见的线程池及适用场景? + +FixedThreadPool:可重用固定线程数的线程池。(适用于负载比较重的服务器) +FixedThreadPool使用无界队列LinkedBlockingQueue作为线程池的工作队列 +该线程池中的线程数量始终不变。当有一个新的任务提交时,线程池中若有空闲线程,则立即执行。若没有,则新的任务会被暂存在一个任务队列中,待有线程空闲时,便处理在任务队列中的任务。 + +SingleThreadExecutor:只会创建一个线程执行任务。(适用于需要保证顺序执行各个任务;并且在任意时间点,没有多线程活动的场景。) +SingleThreadExecutorl也使用无界队列LinkedBlockingQueue作为工作队列 +若多余一个任务被提交到该线程池,任务会被保存在一个任务队列中,待线程空闲,按先入先出的顺序执行队列中的任务。 + +CachedThreadPool:是一个会根据需要调整线程数量的线程池。(大小无界,适用于执行很多的短期异步任务的小程序,或负载较轻的服务器) +CachedThreadPool使用没有容量的SynchronousQueue作为线程池的工作队列,但CachedThreadPool的maximumPool是无界的。 +线程池的线程数量不确定,但若有空闲线程可以复用,则会优先使用可复用的线程。若所有线程均在工作,又有新的任务提交,则会创建新的线程处理任务。所有线程在当前任务执行完毕后,将返回线程池进行复用。 + +ScheduledThreadPool:继承自ThreadPoolExecutor。它主要用来在给定的延迟之后运行任务,或者定期执行任务。使用DelayQueue作为任务队列。 + +#### 39.线程池都有哪几种工作队列? + +ArrayBlockingQueue:是一个基于数组结构的有界阻塞队列,此队列按FIFO(先进先出)原则对元素进行排序。 +LinkedBlockingQueue:是一个基于链表结构的阻塞队列,此队列按FIFO排序元素,吞吐量通常要高于ArrayBlockingQueue。静态工厂方法Executors.newFixedThreadPool()使用了这个队列。 +SynchronousQueue:是一个不存储元素的阻塞队列。每个插入操作必须等到另一个线程调用移除操作,否则插入操作一直处于阻塞状态,吞吐量通常要高于Linked-BlockingQueue,静态工厂方法Executors.newCachedThreadPool使用了这个队列。 +PriorityBlockingQueue:一个具有优先级的无限阻塞队列。 + +#### 40.什么是线程安全? + +如果你的代码在多线程下执行和在单线程下执行永远都能获得一样的结果,那么你的代码就是线程安全的。 + +这个问题有值得一提的地方,就是线程安全也是有几个级别的: + +1)不可变 +像String、Integer、Long这些,都是final类型的类,任何一个线程都改变不了它们的值,要改变除非新创建一个,因此这些不可变对象不需要任何同步手段就可以直接在多线程环境下使用 + +2)绝对线程安全 +不管运行时环境如何,调用者都不需要额外的同步措施。要做到这一点通常需要付出许多额外的代价,Java中标注自己是线程安全的类,实际上绝大多数都不是线程安全的,不过绝对线程安全的类,Java中也有,比方说CopyOnWriteArrayList、CopyOnWriteArraySet + +3)相对线程安全 +相对线程安全也就是我们通常意义上所说的线程安全,像Vector这种,add、remove方法都是原子操作,不会被打断,但也仅限于此,如果有个线程在遍历某个Vector、有个线程同时在add这个Vector,99%的情况下都会出现ConcurrentModificationException,也就是fail-fast机制。 + +4)线程非安全 +这个就没什么好说的了,ArrayList、LinkedList、HashMap等都是线程非安全的类,点击这里了解为什么不安全。 + +#### 41.Java中如何获取到线程dump文件 + +死循环、死锁、阻塞、页面打开慢等问题,打线程dump是最好的解决问题的途径。所谓线程dump也就是线程堆栈,获取到线程堆栈有两步: + +1)获取到线程的pid,可以通过使用jps命令,在Linux环境下还可以使用ps -ef | grep java +2)打印线程堆栈,可以通过使用jstack pid命令,在Linux环境下还可以使用kill -3 pid + +另外提一点,Thread类提供了一个getStackTrace()方法也可以用于获取线程堆栈。这是一个实例方法,因此此方法是和具体线程实例绑定的,每次获取获取到的是具体某个线程当前运行的堆栈。 + +#### 42.Java中用到的线程调度算法是什么? + +抢占式。一个线程用完CPU之后,操作系统会根据线程优先级、线程饥饿情况等数据算出一个总的优先级并分配下一个时间片给某个线程执行。 + +#### 43.Thread.sleep(0)的作用是什么? + +由于Java采用抢占式的线程调度算法,因此可能会出现某条线程常常获取到CPU控制权的情况,为了让某些优先级比较低的线程也能获取到CPU控制权,可以使用Thread.sleep(0)手动触发一次操作系统分配时间片的操作,这也是平衡CPU控制权的一种操作。 + +#### 44.单例模式的线程安全性 + +1)饿汉式单例模式的写法:线程安全 + +2)懒汉式单例模式的写法:非线程安全 + +3)双检锁单例模式的写法:线程安全 + +#### 45.Semaphore有什么作用? + +Semaphore就是一个信号量,它的作用是限制某段代码块的并发数。Semaphore有一个构造函数,可以传入一个int型整数n,表示某段代码最多只有n个线程可以访问,如果超出了n,那么请等待,等到某个线程执行完毕这段代码块,下一个线程再进入。由此可以看出如果Semaphore构造函数中传入的int型整数n=1,相当于变成了一个synchronized了。 + +#### 46.Hashtable的size()方法中明明只有一条语句"return count",为什么还要做同步? + +1)同一时间只能有一条线程执行固定类的同步方法,但是对于类的非同步方法,可以多条线程同时访问。所以,这样就有问题了,可能线程A在执行Hashtable的put方法添加数据,线程B则可以正常调用size()方法读取Hashtable中当前元素的个数,那读取到的值可能不是最新的,可能线程A添加了完了数据,但是没有对size++,线程B就已经读取size了,那么对于线程B来说读取到的size一定是不准确的。而给size()方法加了同步之后,意味着线程B调用size()方法只有在线程A调用put方法完毕之后才可以调用,这样就保证了线程安全性 + +2)CPU执行代码,执行的不是Java代码,这点很关键,一定得记住。Java代码最终是被翻译成机器码执行的,机器码才是真正可以和硬件电路交互的代码。即使你看到Java代码只有一行,甚至你看到Java代码编译之后生成的字节码也只有一行,也不意味着对于底层来说这句语句的操作只有一个。一句"return count"假设被翻译成了三句汇编语句执行,一句汇编语句和其机器码做对应,完全可能执行完第一句,线程就切换了。 + +#### 47.同步方法和同步块,哪个是更好的选择? + +同步块,这意味着同步块之外的代码是异步执行的,这比同步整个方法更提升代码的效率。请知道一条原则:同步的范围越小越好。 + +虽说同步的范围越少越好,但是在Java虚拟机中还是存在着一种叫做锁粗化的优化方法,这种方法就是把同步范围变大。这是有用的,比方说StringBuffer,它是一个线程安全的类,自然最常用的append()方法是一个同步方法,我们写代码的时候会反复append字符串,这意味着要进行反复的加锁->解锁,这对性能不利,因为这意味着Java虚拟机在这条线程上要反复地在内核态和用户态之间进行切换,因此Java虚拟机会将多次append方法调用的代码进行一个锁粗化的操作,将多次的append的操作扩展到append方法的头尾,变成一个大的同步块,这样就减少了加锁–>解锁的次数,有效地提升了代码执行的效率。 + +#### 48.高并发、任务执行时间短的业务怎样使用线程池?并发不高、任务执行时间长的业务怎样使用线程池?并发高、业务执行时间长的业务怎样使用线程池? +1)高并发、任务执行时间短的业务,线程池线程数可以设置为CPU核数+1,减少线程上下文的切换 + +2)并发不高、任务执行时间长的业务要区分开看: +a)假如是业务时间长集中在IO操作上,也就是IO密集型的任务,因为IO操作并不占用CPU,所以不要让所有的CPU闲下来,可以加大线程池中的线程数目,让CPU处理更多的业务 +b)假如是业务时间长集中在计算操作上,也就是计算密集型任务,这个就没办法了,和(1)一样吧,线程池中的线程数设置得少一些,减少线程上下文的切换 +c)并发高、业务执行时间长,解决这种类型任务的关键不在于线程池而在于整体架构的设计,看看这些业务里面某些数据是否能做缓存是第一步,增加服务器是第二步,至于线程池的设置,设置参考其他有关线程池的文章。最后,业务执行时间长的问题,也可能需要分析一下,看看能不能使用中间件对任务进行拆分和解耦。 + +#### 49.在Java中Lock接口比synchronized块的优势是什么?你需要实现一个高效的缓存,它允许多个用户读,但只允许一个用户写,以此来保持它的完整性,你会怎样去实现它? + +lock接口在多线程和并发编程中最大的优势是它们为读和写分别提供了锁,它能满足你写像ConcurrentHashMap这样的高性能数据结构和有条件的阻塞。Java线程面试的问题越来越会根据面试者的回答来提问。我强烈建议在你去参加多线程的面试之前认真读一下Locks,因为当前其大量用于构建电子交易终统的客户端缓存和交易连接空间。 + +#### 50.你将如何使用thread dump?你将如何分析Thread dump? + +在UNIX中你可以使用kill -3,然后thread dump将会打印日志,在windows中你可以使用”CTRL+Break”。非常简单和专业的线程面试问题,但是如果他问你怎样分析它,就会很棘手。 + +### 参考资料 + +https://blog.csdn.net/tanmomo/article/details/99671622 +https://blog.csdn.net/cmyperson/article/details/79610870 +https://www.cnblogs.com/toria/p/11234323.html +https://www.cnblogs.com/bors/p/dxc.html +http://ifeve.com/15-java-faq/ diff --git "a/\345\257\206\347\240\201\345\255\246.md" "b/\345\257\206\347\240\201\345\255\246.md" new file mode 100644 index 0000000..e09e945 --- /dev/null +++ "b/\345\257\206\347\240\201\345\255\246.md" @@ -0,0 +1,124 @@ +## 密码学 + +* [1.Java中常用的加密算法](#1java中常用的加密算法) +* [2.什么是base64](#2什么是base64) +* [3.MD5](#3md5) +* [4.SHA](#4sha) +* [5.HMAC](#5hmac) +* [6.密码的常用术语](#6密码的常用术语) +* [7.单向加密算法](#7单向加密算法) +* [8.复杂的对称加密(DES、PBE)、非对称加密算法](#8复杂的对称加密despbe非对称加密算法) +* [9.非对称加密](#9非对称加密) +* [10.DES](#10des) +* [参考链接](#参考链接) + +#### 1.Java中常用的加密算法 + +散列算法 + +- MD5 +- SHA + +对称加密 + +- DES +- 3DES +- AES + +非对称加密 + +- RSA +- ECC + +#### 2.什么是base64 + +Base64是网络上最常见的用于传输8Bit字节码的编码方式之一,Base64就是一种基于64个可打印字符来表示二进制数据的方法,不属于加密算法,只是是编码方式。 + +#### 3.MD5 + +MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一(又译摘要算法、哈希算法),主流编程语言普遍已有MD5实现。将数据(如汉字)运算为另一固定长度值,是杂凑算法的基础原理,MD5的前身有MD2、MD3和MD4。广泛用于加密和解密技术,常用于文件校验。校验?不管文件多大,经过MD5后都能生成唯一的MD5值。好比现在的ISO校验,都是MD5校验。怎么用?当然是把ISO经过MD5后产生MD5的值。一般下载linux-ISO的朋友都见过下载链接旁边放着MD5的串。就是用来验证文件是否一致的。 + +#### 4.SHA + +安全哈希算法(Secure Hash Algorithm)主要适用于数字签名标准(Digital Signature Standard DSS)里面定义的数字签名算法(Digital Signature Algorithm DSA)。对于长度小于2^64位的消息,SHA1会产生一个160位的消息摘要。该算法经过加密专家多年来的发展和改进已日益完善,并被广泛使用。该算法的思想是接收一段明文,然后以一种不可逆的方式将它转换成一段(通常更小)密文,也可以简单的理解为取一串输入码(称为预映射或信息),并把它们转化为长度较短、位数固定的输出序列即散列值(也称为信息摘要或信息认证代码)的过程。散列函数值可以说是对明文的一种"指纹"或是"摘要"所以对散列值的数字签名就可以视为对此明文的数字签名。 + +#### 5.HMAC + +HMAC(Hash Message Authentication Code,散列消息鉴别码,基于密钥的Hash算法的认证协议。消息鉴别码实现鉴别的原理是,用公开函数和密钥产生一个固定长度的值作为认证标识,用这个标识鉴别消息的完整性。使用一个密钥生成一个固定大小的小数据块,即MAC,并将其加入到消息中,然后传输。接收方利用与发送方共享的密钥进行鉴别认证等。 + +我们为什么要使用加密算法,分析用户登录时密码安全问题的演变过程: + +明文存储,这是一种最简单的存储方式,但是有着很大的安全隐患,首先密码暴露在网络传输的过程中,很容易被黑客拦截,其次如果服务器的数据库被脱库后,所有用户的密码一览无余,最后不称职的系统管理员可以很容易拿到用户登录密码,进行一些非法的交易,如果这个用户所有的密码都是一样的话,那么这个用户算是完蛋了。 + +所以后来演变为使用MD5来存储密码,但是这样也会出现问题,因为只要密码在网络中传输都有可能被黑客拦截,互联网上有着各种各样的MD5数据库,也是比较容易解密出用户原来的密码信息。对称加密算法,对称加密算法破解起来有一定的难度,但是关于这种加密算法有一个缺陷就是,客户端也需要进行加密,通过反编译或者查看网页源码等方式,也能够推算出加密算法,所以也存在着一定的风险性。基于以上出现的种种原因,采用非对称加密算法是一个非常不错的选择。 + +#### 6.密码的常用术语 + +1.密码体制:由明文空间、密文空间、密钥空间、加密算法和解密算法5部分组成。 + +2.密码协议:也称为安全协议,是指以密码学为基础的消息交换的通信协议,目的是在网络环境中提供安全的服务。 + +3.柯克霍夫原则:数据的安全基于密钥而不是算法的保密。即系统的安全取决于密钥,对密钥保密,对算法公开。——现代密码学设计的基本原则。 + +#### 7.单向加密算法 + +单向加密是非可逆加密,就是不可解密的加密方法。 +BASE64 严格地说,属于编码格式,而非加密算法 +MD5(Message Digest algorithm 5,信息摘要算法) +SHA(Secure Hash Algorithm,安全散列算法) +HMAC(Hash Message Authentication Code,散列消息鉴别码) + +#### 8.复杂的对称加密(DES、PBE)、非对称加密算法 + +DES(Data Encryption Standard,数据加密算法) +PBE(Password-based encryption,基于密码验证) +RSA(算法的名字以发明者的名字命名:Ron Rivest, AdiShamir 和Leonard Adleman) +DH(Diffie-Hellman算法,密钥一致协议) +DSA(Digital Signature Algorithm,数字签名) +ECC(Elliptic Curves Cryptography,椭圆曲线密码编码学) + +#### 9.非对称加密 + +示例 + +- 首先生成密钥对, 公钥为(5,14), 私钥为(11,14) +- 现在A希望将原文2发送给B +- A使用公钥加密数据. 2的5次方mod 14 = 4 , 将密文4发送给B +- B使用私钥解密数据. 4的11次方mod14 = 2, 得到原文2 + +特点 + +- 加密和解密使用不同的密钥 +- 如果使用私钥加密, 只能使用公钥解密 +- 如果使用公钥加密, 只能使用私钥解密 +- 处理数据的速度较慢, 因为安全级别高 + +常见算法 + +- RSA +- ECC + +#### 10.DES + +DES算法把64位的明文输入块变为64位的密文输出块,它所使用的密钥也是64位,其算法主要分为两步: + +**(1)初始置换** + +其功能是把输入的64位数据块按位重新组合,并把输出分为L0、R0两部分,每部分各长32位,其置换规则为将输入的第58位换到第一位,第50位换到第2位……依此类推,最后一位是原来的第7位。L0、R0则是换位输出后的两部分,L0是输出的左32位,R0是右32位,例:设置换前的输入值为D1D2D3……D64,则经过初始置换后的结果为:L0=D58D50……D8;R0=D57D49……D7。 + +**(2)逆置换** + +经过16次迭代运算后,得到L16、R16,将此作为输入,进行逆置换,逆置换正好是初始置换的逆运算,由此即得到密文输出。 + + +#### 参考链接 + +https://blog.csdn.net/qq_34988624/article/details/86691880 + +https://blog.csdn.net/java03_15/article/details/83927694 + +https://blog.csdn.net/ly20116/article/details/51025437 + +http://www.blogjava.net/amigoxie/archive/2014/07/06/415503.html + +https://www.jianshu.com/p/213d69ac27b3 diff --git "a/\345\276\256\346\234\215\345\212\241.md" "b/\345\276\256\346\234\215\345\212\241.md" new file mode 100644 index 0000000..ec05da5 --- /dev/null +++ "b/\345\276\256\346\234\215\345\212\241.md" @@ -0,0 +1,196 @@ +## 微服务 + + +* [1.微服务有哪些优缺点?](#1微服务有哪些优缺点) +* [2.作为注册中心,Zookeeper和Eureka有什么区别?](#2作为注册中心zookeeper和eureka有什么区别) +* [3.Service Mesh了解过吗?](#3service-mesh了解过吗) +* [4.微服务有哪些特点?](#4微服务有哪些特点) +* [5.单片,SOA 和微服务架构有什么区别?](#5单片soa-和微服务架构有什么区别) +* [6.Spring Cloud 解决了哪些问题?](#6spring-cloud-解决了哪些问题) +* [7.服务注册和发现是什么意思?Spring Cloud 如何实现?](#7服务注册和发现是什么意思spring-cloud-如何实现) +* [8.Spring Cloud 和dubbo的区别?](#8spring-cloud-和dubbo的区别) +* [9.什么是微服务?](#9什么是微服务) +* [10.微服务之间是如何通讯的?](#10微服务之间是如何通讯的) +* [11.请谈谈对SpringBoot 和SpringCloud的理解](#11请谈谈对springboot-和springcloud的理解) +* [12.什么是服务熔断,什么是服务降级](#12什么是服务熔断什么是服务降级) +* [13.你所知道的微服务技术栈有哪些?](#13你所知道的微服务技术栈有哪些) +* [14.什么是 Eureka服务注册与发现?](#14什么是-eureka服务注册与发现) +* [15.Eureka的基本架构是什么?](#15eureka的基本架构是什么) +* [16.作为服务注册中心,Eureka比Zookeeper好在哪里?](#16作为服务注册中心eureka比zookeeper好在哪里) +* [参考资料](#参考资料) + + +#### 1.微服务有哪些优缺点? + +优点: +独立的可扩展性,每个微服务都可以独立进行横向或纵向扩展,根据业务实际增长情况来进行快速扩展; +独立的可升级性,每个微服务都可以独立进行服务升级、更新,不用依赖于其它服务,结合持续集成工具可以进行持续发布,开发人员就可以独立快速完成服务升级发布流程; +易维护性,每个微服务的代码均只专注于完成该单个业务范畴的事情,因此微服务项目代码数量将减少至IDE可以快速加载的大小,这样可以提高了代码的可读性,进而可以提高研发人员的生产效率; +语言无关性,研发人员可以选用自己最为熟悉的语言和框架来完成他们的微服务项目(当然,一般根据每个公司的实际技术栈需要来了),这样在面对新技术或新框架的选用时,微服务能够更好地进行快速响应; +故障和资源的隔离性,在系统中出现不好的资源操作行为时,例如内存泄露、数据库连接未关闭等情况,将仅仅只会影响单个微服务; +优化跨团队沟通,如果要完全实践微服务架构设计风格,研发团队势必会按照新的原则来进行划分,由之前的按照技能、职能划分的方式变为按照业务(单个微服务)来进行划分,如此这般团队里将有各个方向技能的研发人员,沟通效率上来说要优于之前按照技能进行划分的组织架构; +原生基于“云”的系统架构设计,基于微服务架构设计风格,我们能构建出来原生对于“云”具备超高友好度的系统,与常用容器工具如Docker能够很方便地结合,构建持续发布系统与IaaS、PaaS平台对接,使其能够方便的部署于各类“云”上,如公用云、私有云以及混合云。 + +缺点: +增加了系统复杂性; +运维难度增加; +本地调用变成RPC调用,接口耗时增加; +可能会引入分布式事务。 + +#### 2.作为注册中心,Zookeeper和Eureka有什么区别? + +详见:https://mp.weixin.qq.com/s/B6F9Ea1GnDIou41Po3NMAQ + +#### 3.Service Mesh了解过吗? + +详见:https://www.jianshu.com/p/27a742e349f7 + +#### 4.微服务有哪些特点? + +· 解耦 – 系统内的服务很大程度上是分离的。因此,整个应用程序可以轻松构建,更改和扩展 +· 组件化 – 微服务被视为可以轻松更换和升级的独立组件 +· 业务能力 – 微服务非常简单,专注于单一功能 +· 自治 – 开发人员和团队可以彼此独立工作,从而提高速度 +· 持续交付 – 通过软件创建,测试和批准的系统自动化,允许频繁发布软件 +· 责任 – 微服务不关注应用程序作为项目。相反,他们将应用程序视为他们负责的产品 +· 分散治理 – 重点是使用正确的工具来做正确的工作。这意味着没有标准化模式或任何技术模式。开发人员可以自由选择最有用的工具来解决他们的问题 +· 敏捷 – 微服务支持敏捷开发。任何新功能都可以快速开发并再次丢弃 + +#### 5.单片,SOA 和微服务架构有什么区别? + +· 单片架构类似于大容器,其中应用程序的所有软件组件组装在一起并紧密封装。 +· 一个面向服务的架构(SOA)是一种相互通信服务的集合。通信可以涉及简单的数据传递,也可以涉及两个或多个协调某些活动的服务。 +· 微服务架构是一种架构风格,它将应用程序构建为以业务域为模型的小型自治服务集合。 + +#### 6.Spring Cloud 解决了哪些问题? + +· 与分布式系统相关的复杂性 – 包括网络问题,延迟开销,带宽问题,安全问题。 +· 处理服务发现的能力 – 服务发现允许集群中的进程和服务找到彼此并进行通信。 +· 解决冗余问题 – 冗余问题经常发生在分布式系统中。 +· 负载平衡 – 改进跨多个计算资源(例如计算机集群,网络链接,中央处理单元)的工作负载分布。 +· 减少性能问题 – 减少因各种操作开销导致的性能问题。 + +#### 7.服务注册和发现是什么意思?Spring Cloud 如何实现? + +当我们开始一个项目时,我们通常在属性文件中进行所有的配置。随着越来越多的服务开发和部署,添加和修改这些属性变得更加复杂。有些服务可能会下降,而某些位置可能会发生变化。手动更改属性可能会产生问题。 Eureka 服务注册和发现可以在这种情况下提供帮助。由于所有服务都在 Eureka 服务器上注册并通过调用 Eureka 服务器完成查找,因此无需处理服务地点的任何更改和处理。 + +#### 8.Spring Cloud 和dubbo的区别? + +(1)服务调用方式 dubbo是RPC springcloud Rest Api +(2)注册中心,dubbo 是zookeeper springcloud是eureka,也可以是zookeeper +(3)服务网关,dubbo本身没有实现,只能通过其他第三方技术整合,springcloud有Zuul路由网关,作为路由服务器,进行消费者的请求分发,springcloud支持断路器,与git完美集成配置文件支持版本控制,事物总线实现配置文件的更新与服务自动装配等等一系列的微服务架构要素。 + +#### 9.什么是微服务? + +微服务架构是一种架构模式或者说是一种架构风格,它提倡将单一应用程序划分成一组小的服务,每个服务运行在其独立的自己的进程中,服务之间互相协调、互相配合,为用户提供最终价值。 服务之间采用轻量级的通信机制互相沟通(通常是基于HTTP的RESTful API)。每个服务都围绕着具体业务进行构建,并且能够被独立地部署到生产环境、类生产环境等。另外,应尽量避免统一的、集中式的服务管理机制,对具体的一个服务而言,应根据业务上下文,选择合适的语言、工具对其进行构建,可以有一个非常轻量级的集中式管理来协调这些服务,可以使用不同的语言来编写服务,也可以使用不同的数据存储。 + +从技术维度来说: +微服务化的核心就是将传统的一站式应用,根据业务拆分成一个一个的服务,彻底地去耦合,每一个微服务提供单个业务功能的服务,一个服务做一件事,从技术角度看就是一种小而独立的处理过程,类似进程概念,能够自行单独启动或销毁,拥有自己独立的数据库。 + +#### 10.微服务之间是如何通讯的? + +第一种:远程过程调用(Remote Procedure Invocation) + +直接通过远程过程调用来访问别的service。 +示例:REST、gRPC、Apache、Thrift + +优点: +简单,常见。因为没有中间件代理,系统更简单 + +缺点: +只支持请求/响应的模式,不支持别的,比如通知、请求/异步响应、发布/订阅、发布/异步响应降低了可用性,因为客户端和服务端在请求过程中必须都是可用的 + +第二种:消息 + +使用异步消息来做服务间通信。服务间通过消息管道来交换消息,从而通信。 +示例:Apache Kafka、RabbitMQ + +优点: +把客户端和服务端解耦,更松耦合 提高可用性,因为消息中间件缓存了消息,直到消费者可以消费 +支持很多通信机制比如通知、请求/异步响应、发布/订阅、发布/异步响应 + +缺点: +消息中间件有额外的复杂性 + +#### 11.请谈谈对SpringBoot 和SpringCloud的理解 + +SpringBoot专注于快速方便的开发单个个体微服务。 +SpringCloud是关注全局的微服务协调整理治理框架,它将SpringBoot开发的一个个单体微服务整合并管理起来,为各个微服务之间提供,配置管理、服务发现、断路器、路由、微代理、事件总线、全局锁、决策竞选、分布式会话等等集成服务 +SpringBoot可以离开SpringCloud独立使用开发项目,但是SpringCloud离不开SpringBoot,属于依赖的关系。 +SpringBoot专注于快速、方便的开发单个微服务个体,SpringCloud关注全局的服务治理框架。 +Spring Boot可以离开Spring Cloud独立使用开发项目,但是Spring Cloud离不开Spring Boot,属于依赖的关系。 + +#### 12.什么是服务熔断,什么是服务降级 + +服务熔断 +熔断机制是应对雪崩效应的一种微服务链路保护机制。当扇出链路的某个微服务不可用或者响应时间太长时,会进行服务的降级,进而熔断该节点微服务的调用,快速返回”错误”的响应信息。当检测到该节点微服务调用响应正常后恢复调用链路。在SpringCloud框架里熔断机制通过Hystrix实现。Hystrix会监控微服务间调用的状况,当失败的调用到一定阈值,缺省是5秒内20次调用失败就会启动熔断机制。熔断机制的注解是@HystrixCommand。 + +服务降级 +其实就是线程池中单个线程障处理,防止单个线程请求时间太长,导致资源长期被占有而得不到释放,从而导致线程池被快速占用完,导致服务崩溃。 + +Hystrix能解决如下问题: +请求超时降级,线程资源不足降级,降级之后可以返回自定义数据 +线程池隔离降级,分布式服务可以针对不同的服务使用不同的线程池,从而互不影响 +自动触发降级与恢复 +实现请求缓存和请求合并 + +#### 13.你所知道的微服务技术栈有哪些? + +服务开发Springboot、Spring、SpringMVC +服务配置与管理Netflix公司的Archaius、阿里的Diamond等 +服务注册与发现Eureka、Consul、Zookeeper等 +服务调用Rest、RPC、gRPC +服务熔断器Hystrix、Envoy等 +负载均衡Ribbon、Nginx等 +服务接口调用(客户端调用服务的简化工具)Feign等 +消息队列Kafka、RabbitMQ、ActiveMQ等 +服务配置中心管理SpringCloudConfig、Chef等 +服务路由(API网关)Zuul等 +服务监控Zabbix、Nagios、Metrics、Spectator等 +全链路追踪Zipkin,Brave、Dapper等 +服务部署Docker、OpenStack、Kubernetes等 +数据流操作开发包SpringCloud Stream(封装与Redis,Rabbit、Kafka等发送接收消息) +事件消息总线Spring Cloud Bus + +#### 14.什么是 Eureka服务注册与发现? + +Eureka是Netflix的一个子模块,也是核心模块之一。Eureka是一个基于REST的服务,用于定位服务,以实现云端中间层服务发现和故障转移。服务注册与发现对于微服务架构来说是非常重要的,有了服务发现与注册,只需要使用服务的标识符,就可以访问到服务,而不需要修改服务调用的配置文件了。功能类似于dubbo的注册中心,比如Zookeeper。 + +#### 15.Eureka的基本架构是什么? + +Spring Cloud 封装了 Netflix 公司开发的 Eureka 模块来实现服务注册和发现(请对比Zookeeper)。 + +Eureka 采用了 C-S 的设计架构。Eureka Server 作为服务注册功能的服务器,它是服务注册中心。 + +而系统中的其他微服务,使用 Eureka 的客户端连接到 Eureka Server并维持心跳连接。这样系统的维护人员就可以通过 Eureka Server 来监控系统中各个微服务是否正常运行。SpringCloud 的一些其他模块(比如Zuul)就可以通过 Eureka Server 来发现系统中的其他微服务,并执行相关的逻辑。 + +Eureka包含两个组件: Eureka Server 和 Eureka Client + +Eureka Server提供服务注册服务各个节点启动后,会在EurekaServer中进行注册,这样EurekaServer中的服务注册表中将会存储所有可用服务节点的信息,服务节点的信息可以在界面中直观的看到 + +EurekaClient是一个Java客户端用于简化Eureka Server的交互,客户端同时也具备一个内置的、使用轮询(round-robin)负载算法的负载均衡器。在应用启动后,将会向Eureka Server发送心跳(默认周期为30秒)。如果Eureka Server在多个心跳周期内没有接收到某个节点的心跳,EurekaServer将会从服务注册表中把这个服务节点移除(默认90秒) + +#### 16.作为服务注册中心,Eureka比Zookeeper好在哪里? + +著名的CAP理论指出,一个分布式系统不可能同时满足C(一致性)、A(可用性)和P(分区容错性)。由于分区容错性P在是分布式系统中必须要保证的,因此我们只能在A和C之间进行权衡。 + +因此,Zookeeper 保证的是CP, Eureka 则是AP。 + +Zookeeper保证CP +当向注册中心查询服务列表时,我们可以容忍注册中心返回的是几分钟以前的注册信息,但不能接受服务直接down掉不可用。也就是说,服务注册功能对可用性的要求要高于一致性。但是zk会出现这样一种情况,当master节点因为网络故障与其他节点失去联系时,剩余节点会重新进行leader选举。问题在于,选举leader的时间太长,30~120s,且选举期间整个zk集群都是不可用的,这就导致在选举期间注册服务瘫痪。在云部署的环境下,因网络问题使得zk集群失去master节点是较大概率会发生的事,虽然服务能够最终恢复,但是漫长的选举时间导致的注册长期不可用是不能容忍的。 + +Eureka保证AP +Eureka看明白了这一点,因此在设计时就优先保证可用性。Eureka各个节点都是平等的,几个节点挂掉不会影响正常节点的工作,剩余的节点依然可以提供注册和查询服务。而Eureka的客户端在向某个Eureka注册或时如果发现连接失败,则会自动切换至其它节点,只要有一台Eureka还在,就能保证注册服务可用(保证可用性),只不过查到的信息可能不是最新的(不保证强一致性)。 + +除此之外,Eureka还有一种自我保护机制,如果在15分钟内超过85%的节点都没有正常的心跳,那么Eureka就认为客户端与注册中心出现了网络故障,此时会出现以下几种情况: + +Eureka不再从注册列表中移除因为长时间没收到心跳而应该过期的服务 +Eureka仍然能够接受新服务的注册和查询请求,但是不会被同步到其它节点上(即保证当前节点依然可用) +当网络稳定时,当前实例新的注册信息会被同步到其它节点中 +因此, Eureka可以很好的应对因网络故障导致部分节点失去联系的情况,而不会像zookeeper那样使整个注册服务瘫痪。 + + +### 参考资料 +https://www.cnblogs.com/zhuifeng523/p/12294904.html + +https://baijiahao.baidu.com/s?id=1655329799036379323 diff --git "a/\346\223\215\344\275\234\347\263\273\347\273\237.md" "b/\346\223\215\344\275\234\347\263\273\347\273\237.md" new file mode 100644 index 0000000..a208fdf --- /dev/null +++ "b/\346\223\215\344\275\234\347\263\273\347\273\237.md" @@ -0,0 +1,314 @@ +## 操作系统 + +* [1.说下进程的状态](#1说下进程的状态) +* [2.说下进程和线程的联系与区别](#2说下进程和线程的联系与区别) +* [3.为什么进程上下文切换比线程上下文切换代价高?](#3为什么进程上下文切换比线程上下文切换代价高) +* [4.说下你对进程同步的理解](#4说下你对进程同步的理解) +* [5.进程的通信方式有哪些](#5进程的通信方式有哪些) +* [6.进程调度的种类有哪些?](#6进程调度的种类有哪些) +* [7.非抢占式调度与抢占式调度的区别是什么?](#7非抢占式调度与抢占式调度的区别是什么) +* [8.说下你知道的调度算法](#8说下你知道的调度算法) +* [9.一个程序从开始运行到结束的完整过程(四个过程)](#9一个程序从开始运行到结束的完整过程四个过程) +* [10.死锁出现的条件?](#10死锁出现的条件) +* [11.如何处理死锁问题](#11如何处理死锁问题) +* [12.如何处理死锁问题](#12如何处理死锁问题) +* [13.什么是临界资源](#13什么是临界资源) +* [14.介绍一下内存池、进程池、线程池](#14介绍一下内存池进程池线程池) +* [15.动态链接库与静态链接库的区别](#15动态链接库与静态链接库的区别) +* [16.说下对虚拟内存的理解](#16说下对虚拟内存的理解) +* [17.页面置换算法了解多少?](#17页面置换算法了解多少) +* [18.中断与系统调用了解吗?](#18中断与系统调用了解吗) +* [19.用户态切换到内核态的方式有哪些?](#19用户态切换到内核态的方式有哪些) +* [20.用户态和核心态(内核态)之间的区别是什么呢?](#20用户态和核心态内核态之间的区别是什么呢) +* [21.内部碎片与外部碎片分别是什么?](#21内部碎片与外部碎片分别是什么) +* [22.系统调用与库函数的区别](#22系统调用与库函数的区别) +* [23.守护、僵尸、孤儿进程的概念](#23守护僵尸孤儿进程的概念) +* [参考资料](#参考资料) + +#### 1.说下进程的状态 + +就绪:进程已处于准备好运行的状态,即进程已分配到除CPU外的所有必要资源后,只要再获得CPU,便可立即执行 +执行:进程已经获得CPU,程序正在执行状态 +阻塞:正在执行的进程由于发生某事件(如I/O请求、申请缓冲区失败等)暂时无法继续执行的状态 + +#### 2.说下进程和线程的联系与区别 + +进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位 +线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位 + +进程和线程的关系 +一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。线程是操作系统可识别的最小执行和调度单位 +资源分配给进程,同一进程的所有线程共享该进程的所有资源。 同一进程中的多个线程共享代码段(代码和常量),数据段(全局变量和静态变量),扩展段(堆存储)。但是每个线程拥有自己的栈段,栈段又叫运行时段,用来存放所有局部变量和临时变量 +处理机分给线程,即真正在处理机上运行的是线程 +线程在执行过程中,需要协作同步。不同进程的线程间要利用消息通信的办法实现同步 + +进程与线程的区别 +进程有自己的独立地址空间,线程没有 +进程是资源分配的最小单位,线程是CPU调度的最小单位 +进程和线程通信方式不同(线程之间的通信比较方便。同一进程下的线程共享数据(比如全局变量,静态变量),通过这些数据来通信不仅快捷而且方便,当然如何处理好这些访问的同步与互斥正是编写多线程程序的难点。而进程之间的通信只能通过进程通信的方式进行。) +进程上下文切换开销大,线程开销小 +一个进程挂掉了不会影响其他进程,而线程挂掉了会影响其他线程 +对进程进程操作一般开销都比较大,对线程开销就小了 + +#### 3.为什么进程上下文切换比线程上下文切换代价高? + +进程切换分两步: +切换页目录以使用新的地址空间 +切换内核栈和硬件上下文 +对于linux来说,线程和进程的最大区别就在于地址空间,对于线程切换,第1步是不需要做的,第2是进程和线程切换都要做的 + +切换的性能消耗: +线程上下文切换和进程上下问切换一个最主要的区别是线程的切换虚拟内存空间依然是相同的,但是进程切换是不同的。这两种上下文切换的处理都是通过操作系统内核来完成的。内核的这种切换过程伴随的最显著的性能损耗是将寄存器中的内容切换出 +另外一个隐藏的损耗是上下文的切换会扰乱处理器的缓存机制。简单的说,一旦去切换上下文,处理器中所有已经缓存的内存地址一瞬间都作废了。还有一个显著的区别是当你改变虚拟内存空间的时候,处理的页表缓冲(processor's Translation Lookaside Buffer (TLB))或者相当的神马东西会被全部刷新,这将导致内存的访问在一段时间内相当的低效。但是在线程的切换中,不会出现这个问题 + +#### 4.说下你对进程同步的理解 + +进程同步的主要任务:是对多个相关进程在执行次序上进行协调,以使并发执行的诸进程之间能有效地共享资源和相互合作,从而使程序的执行具有可再现性 + +同步机制遵循的原则: +空闲让进; +忙则等待(保证对临界区的互斥访问); +有限等待(有限代表有限的时间,避免死等); +让权等待(当进程不能进入自己的临界区时,应该释放处理机,以免陷入忙等状态) + +#### 5.进程的通信方式有哪些 + +进程通信,是指进程之间的信息交换(信息量少则一个状态或数值,多者则是成千上万个字节)。因此,对于用信号量进行的进程间的互斥和同步,由于其所交换的信息量少而被归结为低级通信 + +所谓高级进程通信指:用户可以利用操作系统所提供的一组通信命令传送大量数据的一种通信方式。操作系统隐藏了进程通信的实现细节。或者说,通信过程对用户是透明的 + +高级通信机制可归结为三大类: +共享存储器系统(存储器中划分的共享存储区);实际操作中对应的是“剪贴板”(剪贴板实际上是系统维护管理的一块内存区域)的通信方式,比如举例如下:word进程按下ctrl+c,在ppt进程按下ctrl+v,即完成了word进程和ppt进程之间的通信,复制时将数据放入到剪贴板,粘贴时从剪贴板中取出数据,然后显示在ppt窗口上 +消息传递系统(进程间的数据交换以消息(message)为单位,当今最流行的微内核操作系统中,微内核与服务器之间的通信,无一例外地都采用了消息传递机制。应用举例:邮槽(MailSlot)是基于广播通信体系设计出来的,它采用无连接的不可靠的数据传输。邮槽是一种单向通信机制,创建邮槽的服务器进程读取数据,打开邮槽的客户机进程写入数据 +管道通信系统(管道即:连接读写进程以实现他们之间通信的共享文件(pipe文件,类似先进先出的队列,由一个进程写,另一进程读))。实际操作中,管道分为:匿名管道、命名管道。匿名管道是一个未命名的、单向管道,通过父进程和一个子进程之间传输数据。匿名管道只能实现本地机器上两个进程之间的通信,而不能实现跨网络的通信。命名管道不仅可以在本机上实现两个进程间的通信,还可以跨网络实现两个进程间的通信 +管道:管道是单向的、先进先出的、无结构的、固定大小的字节流,它把一个进程的标准输出和另一个进程的标准输入连接在一起。写进程在管道的尾端写入数据,读进程在管道的道端读出数据。数据读出后将从管道中移走,其它读进程都不能再读到这些数据。管道提供了简单的流控制机制。进程试图读空管道时,在有数据写入管道前,进程将一直阻塞。同样地,管道已经满时,进程再试图写管道,在其它进程从管道中移走数据之前,写进程将一直阻塞。 +信号量:信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其它进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段 +消息队列:是一个在系统内核中用来保存消 息的队列,它在系统内核中是以消息链表的形式出现的。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点 +共享内存:共享内存允许两个或多个进程访问同一个逻辑内存。这一段内存可以被两个或两个以上的进程映射至自身的地址空间中,一个进程写入共享内存的信息,可以被其他使用这个共享内存的进程,通过一个简单的内存读取读出,从而实现了进程间的通信。如果某个进程向共享内存写入数据,所做的改动将立即影响到可以访问同一段共享内存的任何其他进程。共享内存是最快的IPC方式,它是针对其它进程间通信方式运行效率低而专门设计的。它往往与其它通信机制(如信号量)配合使用,来实现进程间的同步和通信 +套接字:套接字也是一种进程间通信机制,与其它通信机制不同的是,它可用于不同机器间的进程通信 + +#### 6.进程调度的种类有哪些? + +高级调度:(High-Level Scheduling)又称为作业调度,它决定把后备作业调入内存运行 +低级调度:(Low-Level Scheduling)又称为进程调度,它决定把就绪队列的某进程获得CPU +中级调度:(Intermediate-Level Scheduling)又称为在虚拟存储器中引入,在内、外存对换区进行进程对换 + +#### 7.非抢占式调度与抢占式调度的区别是什么? + +非抢占式:分派程序一旦把处理机分配给某进程后便让它一直运行下去,直到进程完成或发生进程调度进程调度某事件而阻塞时,才把处理机分配给另一个进程 +抢占式:操作系统将正在运行的进程强行暂停,由调度程序将CPU分配给其他就绪进程的调度方式 + +#### 8.说下你知道的调度算法 + +FIFO或First Come, First Served (FCFS)先来先服务 +调度的顺序就是任务到达就绪队列的顺序 +公平、简单(FIFO队列)、非抢占、不适合交互式 +未考虑任务特性,平均等待时间可以缩短 + +Shortest Job First (SJF) +最短的作业(CPU区间长度最小)最先调度 +SJF可以保证最小的平均等待时间 + +Shortest Remaining Job First (SRJF) +SJF的可抢占版本,比SJF更有优势 +SJF(SRJF): 如何知道下一CPU区间大小?根据历史进行预测: 指数平均法 + +优先权调度 +每个任务关联一个优先权,调度优先权最高的任务 +注意:优先权太低的任务一直就绪,得不到运行,出现“饥饿”现象 + +Round-Robin(RR)轮转调度算法 +设置一个时间片,按时间片来轮转调度(“轮叫”算法) +优点: 定时有响应,等待时间较短;缺点: 上下文切换次数较多 +时间片太大,响应时间太长;吞吐量变小,周转时间变长;当时间片过长时,退化为FCFS + +多级队列调度 +按照一定的规则建立多个进程队列 +不同的队列有固定的优先级(高优先级有抢占权) +不同的队列可以给不同的时间片和采用不同的调度方法 +存在问题1:没法区分I/O bound和CPU bound +存在问题2:也存在一定程度的“饥饿”现象 + +多级反馈队列 +在多级队列的基础上,任务可以在队列之间移动,更细致的区分任务 +可以根据“享用”CPU时间多少来移动队列,阻止“饥饿” +最通用的调度算法,多数OS都使用该方法或其变形,如UNIX、Windows等 + +#### 9.一个程序从开始运行到结束的完整过程(四个过程) + +预处理:条件编译,头文件包含,宏替换的处理,生成.i文件。 + +编译:将预处理后的文件转换成汇编语言,生成.s文件 + +汇编:汇编变为目标代码(机器代码)生成.o的文件 + +链接:连接目标代码,生成可执行程序 + +#### 10.死锁出现的条件? + +定义:如果一组进程中的每一个进程都在等待仅由该组进程中的其他进程才能引发的事件,那么该组进程就是死锁的。或者在两个或多个并发进程中,如果每个进程持有某种资源而又都等待别的进程释放它或它们现在保持着的资源,在未改变这种状态之前都不能向前推进,称这一组进程产生了死锁。通俗地讲,就是两个或多个进程被无限期地阻塞、相互等待的一种状态。 + +产生死锁的必要条件: +互斥条件(Mutual exclusion):资源不能被共享,只能由一个进程使用。 +请求与保持条件(Hold and wait):已经得到资源的进程可以再次申请新的资源。 +非抢占条件(No pre-emption):已经分配的资源不能从相应的进程中被强制地剥夺。 +循环等待条件(Circular wait):系统中若干进程组成环路,该环路中每个进程都在等待相邻进程正占用的资源。 + +#### 11.如何处理死锁问题 + +忽略该问题。例如鸵鸟算法,该算法可以应用在极少发生死锁的的情况下。为什么叫鸵鸟算法呢,因为传说中鸵鸟看到危险就把头埋在地底下,可能鸵鸟觉得看不到危险也就没危险了吧。跟掩耳盗铃有点像。 +检测死锁并且恢复。 +仔细地对资源进行动态分配,使系统始终处于安全状态以避免死锁。 +通过破除死锁四个必要条件之一,来防止死锁产生。 + +#### 12.如何处理死锁问题 + +忽略该问题。例如鸵鸟算法,该算法可以应用在极少发生死锁的的情况下。为什么叫鸵鸟算法呢,因为传说中鸵鸟看到危险就把头埋在地底下,可能鸵鸟觉得看不到危险也就没危险了吧。跟掩耳盗铃有点像。 + +检测死锁并且恢复。 + +仔细地对资源进行动态分配,使系统始终处于安全状态以避免死锁。 + +通过破除死锁四个必要条件之一,来防止死锁产生。 + +#### 13.什么是临界资源 + +在操作系统中,进程是占有资源的最小单位(线程可以访问其所在进程内的所有资源,但线程本身并不占有资源或仅仅占有一点必须资源)。但对于某些资源来说,其在同一时间只能被一个进程所占用。这些一次只能被一个进程所占用的资源就是所谓的临界资源。典型的临界资源比如物理上的打印机,或是存在硬盘或内存中被多个进程所共享的一些变量和数据等(如果这类资源不被看成临界资源加以保护,那么很有可能造成丢数据的问题)。 + +对于临界资源的访问,必须是互斥进行。也就是当临界资源被占用时,另一个申请临界资源的进程会被阻塞,直到其所申请的临界资源被释放。而进程内访问临界资源的代码被成为临界区。 + +#### 14.介绍一下内存池、进程池、线程池 + +首先介绍一个概念“池化技术 ”。池化技术就是:提前保存大量的资源,以备不时之需以及重复使用。池化技术应用广泛,如内存池,线程池,连接池等等。内存池相关的内容,建议看看Apache、Nginx等开源web服务器的内存池实现。 +由于在实际应用当做,分配内存、创建进程、线程都会设计到一些系统调用,系统调用需要导致程序从用户态切换到内核态,是非常耗时的操作。因此,当程序中需要频繁的进行内存申请释放,进程、线程创建销毁等操作时,通常会使用内存池、进程池、线程池技术来提升程序的性能。 + +线程池:线程池的原理很简单,类似于操作系统中的缓冲区的概念,它的流程如下:先启动若干数量的线程,并让这些线程都处于睡眠状态,当需要一个开辟一个线程去做具体的工作时,就会唤醒线程池中的某一个睡眠线程,让它去做具体工作,当工作完成后,线程又处于睡眠状态,而不是将线程销毁。 + +进程池与线程池同理。 + +内存池:内存池是指程序预先从操作系统申请一块足够大内存,此后,当程序中需要申请内存的时候,不是直接向操作系统申请,而是直接从内存池中获取;同理,当程序释放内存的时候,并不真正将内存返回给操作系统,而是返回内存池。当程序退出(或者特定时间)时,内存池才将之前申请的内存真正释放。 + +#### 15.动态链接库与静态链接库的区别 + +静态库 +静态库是一个外部函数与变量的集合体。静态库的文件内容,通常包含一堆程序员自定的变量与函数,其内容不像动态链接库那么复杂,在编译期间由编译器与链接器将它集成至应用程序内,并制作成目标文件以及可以独立运作的可执行文件。而这个可执行文件与编译可执行文件的程序,都是一种程序的静态创建(static build)。 + +动态库 +静态库很方便,但是如果我们只是想用库中的某一个函数,却仍然得把所有的内容都链接进去。一个更现代的方法则是使用共享库,避免了在文件中静态库的大量重复。 +动态链接可以在首次载入的时候执行(load-time linking),这是 Linux 的标准做法,会由动态链接器ld-linux.so 完成,比方标准 C 库(libc.so) 通常就是动态链接的,这样所有的程序可以共享同一个库,而不用分别进行封装。 +动态链接也可以在程序开始执行的时候完成(run-time linking),在 Linux 中使用 dlopen()接口来完成(会使用函数指针),通常用于分布式软件,高性能服务器上。而且共享库也可以在多个进程间共享。 +链接使得我们可以用多个对象文件构造我们的程序。可以在程序的不同阶段进行(编译、载入、运行期间均可),理解链接可以帮助我们避免遇到奇怪的错误。 + +区别: +使用静态库的时候,静态链接库要参与编译,在生成执行文件之前的链接过程中,要将静态链接库的全部指令直接链接入可执行文件中。而动态库提供了一种方法,使进程可以调用不属于其可执行代码的函数。函数的可执行代码位于一个.dll文件中,该dll包含一个或多个已被编译,链接并与使用它们的进程分开储存的函数。 +静态库中不能再包含其他动态库或静态库,而在动态库中还可以再包含其他动态或者静态库。 +静态库在编译的时候,就将库函数装在到程序中去了,而动态库函数必须在运行的时候才被装载,所以使用静态库速度快一些。 + +#### 16.说下对虚拟内存的理解 + +定义:具有请求调入功能和置换功能,能从逻辑上对内存容量加以扩充得一种存储器系统。其逻辑容量由内存之和和外存之和决定。 + +与传统存储器比较虚拟存储器有以下三个主要特征: +多次性,是指无需在作业运行时一次性地全部装入内存,而是允许被分成多次调入内存运行。 +对换性,是指无需在作业运行时一直常驻内存,而是允许在作业的运行过程中,进行换进和换出。 +虚拟性,是指从逻辑上扩充内存的容量,使用户所看到的内存容量,远大于实际的内存容量。 + +虚拟内存的实现有以下两种方式: +请求分页存储管理。 +请求分段存储管理。 + +#### 17.页面置换算法了解多少? + +操作系统将内存按照页面进行管理,在需要的时候才把进程相应的部分调入内存。当产生缺页中断时,需要选择一个页面写入。如果要换出的页面在内存中被修改过,变成了“脏”页面,那就需要先写会到磁盘。页面置换算法,就是要选出最合适的一个页面,使得置换的效率最高。页面置换算法有很多,简单介绍几个,重点介绍比较重要的LRU及其实现算法。 + +一、最优页面置换算法 + +最理想的状态下,我们给页面做个标记,挑选一个最远才会被再次用到的页面调出。当然,这样的算法不可能实现,因为不确定一个页面在何时会被用到。 + +二、先进先出页面置换算法(FIFO)及其改进 + +这种算法的思想和队列是一样的,该算法总是淘汰最先进入内存的页面,即选择在内存中驻留时间最久的页面予淘汰。实现:把一个进程已调入内存的页面按先后次序链接成一个队列,并且设置一个指针总是指向最老的页面。缺点:对于有些经常被访问的页面如含有全局变量、常用函数、例程等的页面,不能保证这些不被淘汰。 + +三、最近最少使用页面置换算法LRU(Least Recently Used) + +根据页面调入内存后的使用情况做出决策。LRU置换算法是选择最近最久未使用的页面进行淘汰。 + +1.为每个在内存中的页面配置一个移位寄存器。(P165)定时信号将每隔一段时间将寄存器右移一位。最小数值的寄存器对应页面就是最久未使用页面。 + +2.利用一个特殊的栈保存当前使用的各个页面的页面号。每当进程访问某页面时,便将该页面的页面号从栈中移出,将它压入栈顶。因此,栈顶永远是最新被访问的页面号,栈底是最近最久未被访问的页面号。 + +#### 18.中断与系统调用了解吗? + +所谓的中断就是在计算机执行程序的过程中,由于出现了某些特殊事情,使得CPU暂停对程序的执行,转而去执行处理这一事件的程序。等这些特殊事情处理完之后再回去执行之前的程序。中断一般分为三类: + +由计算机硬件异常或故障引起的中断,称为内部异常中断; + +由程序中执行了引起中断的指令而造成的中断,称为软中断(这也是和我们将要说明的系统调用相关的中断); + +由外部设备请求引起的中断,称为外部中断。简单来说,对中断的理解就是对一些特殊事情的处理。 + +与中断紧密相连的一个概念就是中断处理程序了。当中断发生的时候,系统需要去对中断进行处理,对这些中断的处理是由操作系统内核中的特定函数进行的,这些处理中断的特定的函数就是我们所说的中断处理程序了。 + +另一个与中断紧密相连的概念就是中断的优先级。中断的优先级说明的是当一个中断正在被处理的时候,处理器能接受的中断的级别。中断的优先级也表明了中断需要被处理的紧急程度。每个中断都有一个对应的优先级,当处理器在处理某一中断的时候,只有比这个中断优先级高的中断可以被处理器接受并且被处理。优先级比这个当前正在被处理的中断优先级要低的中断将会被忽略。 + +典型的中断优先级如下所示: +机器错误 > 时钟 > 磁盘 > 网络设备 > 终端 > 软件中断 + + +在讲系统调用之前,先说下进程的执行在系统上的两个级别:用户级和核心级,也称为用户态和系统态(user mode and kernel mode)。 +用户空间就是用户进程所在的内存区域,相对的,系统空间就是操作系统占据的内存区域。用户进程和系统进程的所有数据都在内存中。处于用户态的程序只能访问用户空间,而处于内核态的程序可以访问用户空间和内核空间。 + +#### 19.用户态切换到内核态的方式有哪些? + +系统调用:程序的执行一般是在用户态下执行的,但当程序需要使用操作系统提供的服务时,比如说打开某一设备、创建文件、读写文件(这些均属于系统调用)等,就需要向操作系统发出调用服务的请求,这就是系统调用。 + +异常:当CPU在执行运行在用户态下的程序时,发生了某些事先不可知的异常,这时会触发由当前运行进程切换到处理此异常的内核相关程序中,也就转到了内核态,比如缺页异常。 + +外围设备的中断:当外围设备完成用户请求的操作后,会向CPU发出相应的中断信号,这时CPU会暂停执行下一条即将要执行的指令转而去执行与中断信号对应的处理程序,如果先前执行的指令是用户态下的程序,那么这个转换的过程自然也就发生了由用户态到内核态的切换。比如硬盘读写操作完成,系统会切换到硬盘读写的中断处理程序中执行后续操作等。 + +#### 20.用户态和核心态(内核态)之间的区别是什么呢? + +权限不一样。 + +用户态的进程能存取它们自己的指令和数据,但不能存取内核指令和数据(或其他进程的指令和数据)。 + +核心态下的进程能够存取内核和用户地址某些机器指令是特权指令,在用户态下执行特权指令会引起错误。在系统中内核并不是作为一个与用户进程平行的估计的进程的集合。 + +#### 21.内部碎片与外部碎片分别是什么? + +在内存管理中,内部碎片是已经被分配出去的的内存空间大于请求所需的内存空间。 + +外部碎片是指还没有分配出去,但是由于大小太小而无法分配给申请空间的新进程的内存空间空闲块。 + +固定分区存在内部碎片,可变式分区分配会存在外部碎片; + +页式虚拟存储系统存在内部碎片;段式虚拟存储系统,存在外部碎片 + +为了有效的利用内存,使内存产生更少的碎片,要对内存分页,内存以页为单位来使用,最后一页往往装不满,于是形成了内部碎片。 + +为了共享要分段,在段的换入换出时形成外部碎片,比如5K的段换出后,有一个4k的段进来放到原来5k的地方,于是形成1k的外部碎片。 + +#### 22.系统调用与库函数的区别 + +系统调用(System call)是程序向系统内核请求服务的方式。可以包括硬件相关的服务(例如,访问硬盘等),或者创建新进程,调度其他进程等。系统调用是程序和操作系统之间的重要接口。 + +库函数:把一些常用的函数编写完放到一个文件里,编写应用程序时调用,这是由第三方提供的,发生在用户地址空间。 + +在移植性方面,不同操作系统的系统调用一般是不同的,移植性差;而在所有的ANSI C编译器版本中,C库函数是相同的。 + +在调用开销方面,系统调用需要在用户空间和内核环境间切换,开销较大;而库函数调用属于“过程调用”,开销较小。 + +#### 23.守护、僵尸、孤儿进程的概念 + +守护进程:运行在后台的一种特殊进程,独立于控制终端并周期性地执行某些任务。 + +僵尸进程:一个进程 fork 子进程,子进程退出,而父进程没有wait/waitpid子进程,那么子进程的进程描述符仍保存在系统中,这样的进程称为僵尸进程。 + +孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,这些子进程称为孤儿进程。(孤儿进程将由 init 进程收养并对它们完成状态收集工作) + + +#### 参考资料 + +https://zhuanlan.zhihu.com/p/86629244 + +https://www.cnblogs.com/inception6-lxc/p/9073983.html diff --git "a/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225.md" "b/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225.md" new file mode 100644 index 0000000..e2aed00 --- /dev/null +++ "b/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225.md" @@ -0,0 +1,278 @@ +## 数据结构与算法 + + +* [1.什么是算法?](#1什么是算法) +* [2.TreeMap和TreeSet在排序时如何比较元素?Collections工具类中的sort()方法如何比较元素?](#2treemap和treeset在排序时如何比较元素collections工具类中的sort方法如何比较元素) +* [3.如何知道二叉树的深度?](#3如何知道二叉树的深度) +* [4.介绍一下,堆排序的原理是什么?](#4介绍一下堆排序的原理是什么) +* [5.数组和链表的区别](#5数组和链表的区别) +* [6.二分查找了解过吗?](#6二分查找了解过吗) +* [7.说下你熟悉的排序算法](#7说下你熟悉的排序算法) +* [8.布隆过滤器了解过吗?](#8布隆过滤器了解过吗) +* [9.一致性hash算法了解过吗?](#9一致性hash算法了解过吗) +* [10.如何在一个1到100的整数数组中找到丢失的数字?](#10如何在一个1到100的整数数组中找到丢失的数字) +* [11.请你讲讲LRU算法的实现原理?](#11请你讲讲lru算法的实现原理) +* [12.为什么要设计后缀表达式,有什么好处?](#12为什么要设计后缀表达式有什么好处) +* [13. 什么是B树?](#13-什么是b树) +* [14.什么是B+树?](#14什么是b树) +* [15.谈一谈,id全局唯一且自增,如何实现?](#15谈一谈id全局唯一且自增如何实现) +* [参考链接](#参考链接) + + +#### 1.什么是算法? + +算法简单来说就是解决问题的步骤。 + +在Java中,算法通常都是由类的方法来实现的。前面的数据结构,比如链表为啥插入、删除快,而查找慢,平衡的二叉树插入、删除、查找都快,这都是实现这些数据结构的算法所造成的。后面我们讲的各种排序实现也是算法范畴的重要领域。 + +一、算法的五个特征 + +①、`有穷性:对于任意一组合法输入值,在执行又穷步骤之后一定能结束,即:算法中的每个步骤都能在有限时间内完成。` + +②、确定性:在每种情况下所应执行的操作,在算法中都有确切的规定,使算法的执行者或阅读者都能明确其含义及如何执行。并且在任何条件下,算法都只有一条执行路径。 + +③、`可行性:算法中的所有操作都必须足够基本,都可以通过已经实现的基本操作运算有限次实现之。` + +④、有输入:作为算法加工对象的量值,通常体现在算法当中的一组变量。有些输入量需要在算法执行的过程中输入,而有的算法表面上可以没有输入,实际上已被嵌入算法之中。 + +⑤、`有输出:它是一组与“输入”有确定关系的量值,是算法进行信息加工后得到的结果,这种确定关系即为算法功能。` + +二、算法的设计原则 + +①、正确性:首先,算法应当满足以特定的“规则说明”方式给出的需求。其次,对算法是否“正确”的理解可以有以下四个层次: + +一、程序语法错误。 + +二、程序对于几组输入数据能够得出满足需要的结果。 + +三、程序对于精心选择的、典型、苛刻切带有刁难性的几组输入数据能够得出满足要求的结果。 + +四、程序对于一切合法的输入数据都能得到满足要求的结果。 + +PS:通常以第 三 层意义的正确性作为衡量一个算法是否合格的标准。 + +②、可读性:算法为了人的阅读与交流,其次才是计算机执行。因此算法应该易于人的理解;另一方面,晦涩难懂的程序易于隐藏较多的错误而难以调试。 + +③、健壮性:当输入的数据非法时,算法应当恰当的做出反应或进行相应处理,而不是产生莫名其妙的输出结果。并且,处理出错的方法不应是中断程序执行,而是应当返回一个表示错误或错误性质的值,以便在更高的抽象层次上进行处理。 + +④、高效率与低存储量需求:通常算法效率值得是算法执行时间;存储量是指算法执行过程中所需要的最大存储空间,两者都与问题的规模有关。 + +前面三点 正确性,可读性和健壮性相信都好理解。对于第四点算法的执行效率和存储量,我们知道比较算法的时候,可能会说“A算法比B算法快两倍”之类的话,但实际上这种说法没有任何意义。因为当数据项个数发生变化时,A算法和B算法的效率比例也会发生变化,比如数据项增加了50%,可能A算法比B算法快三倍,但是如果数据项减少了50%,可能A算法和B算法速度一样。所以描述算法的速度必须要和数据项的个数联系起来。也就是“大O”表示法,它是一种算法复杂度的相对表示方式,这里我简单介绍一下,后面会根据具体的算法来描述。 + +相对(relative):你只能比较相同的事物。你不能把一个做算数乘法的算法和排序整数列表的算法进行比较。但是,比较2个算法所做的算术操作(一个做乘法,一个做加法)将会告诉你一些有意义的东西; + +表示(representation):大O(用它最简单的形式)把算法间的比较简化为了一个单一变量。这个变量的选择基于观察或假设。例如,排序算法之间的对比通常是基于比较操作(比较2个结点来决定这2个结点的相对顺序)。这里面就假设了比较操作的计算开销很大。但是,如果比较操作的计算开销不大,而交换操作的计算开销很大,又会怎么样呢?这就改变了先前的比较方式; + +复杂度(complexity):如果排序10,000个元素花费了我1秒,那么排序1百万个元素会花多少时间?在这个例子里,复杂度就是相对其他东西的度量结果。 + +然后我们在说说算法的存储量,包括: + +程序本身所占空间; + +输入数据所占空间; + +辅助变量所占空间; + +一个算法的效率越高越好,而存储量是越低越好。 + +#### 2.TreeMap和TreeSet在排序时如何比较元素?Collections工具类中的sort()方法如何比较元素? + +TreeSet要求存放的对象所属的类必须实现Comparable接口,该接口提供了比较元素的compareTo()方法,当插入元素时会回调该方法比较元素的大小。TreeMap要求存放的键值对映射的键必须实现Comparable接口从而根据键对元素进行排序。Collections工具类的sort方法有两种重载的形式,第一种要求传入的待排序容器中存放的对象比较实现Comparable接口以实现元素的比较;第二种不强制性的要求容器中的元素必须可比较,但是要求传入第二个参数,参数是Comparator接口的子类型(需要重写compare方法实现元素的比较),相当于一个临时定义的排序规则,其实就是通过接口注入比较元素大小的算法,也是对回调模式的应用(Java中对函数式编程的支持)。 + +#### 3.如何知道二叉树的深度? + +实现二叉树的深度方式有两种,递归以及非递归。 + +①递归实现: + +为了求树的深度,可以先求其左子树的深度和右子树的深度,可以用递归实现,递归的出口就是节点为空。返回值为0; + +②非递归实现: + +利用层次遍历的算法,设置变量level记录当前节点所在的层数,设置变量last指向当前层的最后一个节点,当处理完当前层的最后一个节点,让level指向+1操作。设置变量cur记录当前层已经访问的节点的个数,当cur等于last时,表示该层访问结束。 + +层次遍历在求树的宽度、输出某一层节点,某一层节点个数,每一层节点个数都可以采取类似的算法。 + +树的宽度:在树的深度算法基础上,加一个记录访问过的层节点个数最多的变量max,在访问每层前max与last比较,如果max比较大,max不变,如果max小于last,把last赋值给max; + +#### 4.介绍一下,堆排序的原理是什么? + +堆排序就是把最大堆堆顶的最大数取出,将剩余的堆继续调整为最大堆,再次将堆顶的最大数取出,这个过程持续到剩余数只有一个时结束。在堆中定义以下几种操作: + +(1)最大堆调整(Max-Heapify):将堆的末端子节点作调整,使得子节点永远小于父节点。 + +(2)创建最大堆(Build-Max-Heap):将堆所有数据重新排序,使其成为最大堆。 + +(3)堆排序(Heap-Sort):移除位在第一个数据的根节点,并做最大堆调整的递归运算 + +#### 5.数组和链表的区别 + +1、数组是将元素在内存中连续存放,由于每个元素占用内存相同,可以通过下标迅速访问数组中任何元素。但是如果要在数组中增加一个元素,需要移动大量元素,在内存中空出一个元素的空间,然后将要增加的元素放在其中。同样的道理,如果想删除一个元素,同样需要移动大量元素去填掉被移动的元素。如果应用需要快速访问数据,很少或不插入和删除元素,就应该用数组。 + +2、链表恰好相反,链表中的元素在内存中不是顺序存储的,而是通过存在元素中的指针联系到一起。比如:上一个元素有个指针指到下一个元素,以此类推,直到最后一个元素。如果要访问链表中一个元素,需要从第一个元素开始,一直找到需要的元素位置。但是增加和删除一个元素对于链表数据结构就非常简单了,只要修改元素中的指针就可以了。如果应用需要经常插入和删除元素你就需要用链表数据结构了。 + +#### 6.二分查找了解过吗? + +##### 查找思路 +【a】待查找有序数组序列:1, 2, 3, 4, 5, 6, 7 + +起始: 定义start = 0 , end = 6, mid = (start + end ) / 2 = (0 + 6) / 2 = 3,arr[mid] = arr[3] = 4 + +【b】假设需要查找"2", 因为2 < arr[mid] = arr[3] = 4; 所以需要将end移动到mid左边一个位置,即end = mid - 1 = 3 - 1 = 2, + +此时重新计算mid = (start +end ) / 2 = (0 + 2) / 2 = 1; arr[mid] = arr[1] = 2 ,继续将2与arr[mid] = arr[1] = 2进行比较,发现相等,成功找到数字"2"所在的位置。 + +【c】假设需要查找"7",因为 7 > arr[mid] = arr[3] = 4,所以需要将start移动到mid右边一个位置,即start = mid + 1 = 4,此时重新计算mid = (start +end) / 2 = (4+ 6)/2 = 5, arr[mid] = arr[5] = 6, 因为7>arr[mid] = arr[5] = 6,所以还是需要将start移动到mid右边一个位置,即start = mid + 1 = 5 + 1 = 6, 此时重新计算mid = (start +end) / 2 = (6 + 6) / 2 = 6.arr[6] = 7, 此时arr[mid] = arr[6] = 7,刚好等于待查找数字7,说明成功找到数字"7"所在的位置. + + 【d】假设查找"0", 因为 0 < arr[mid] = arr[3] = 4, 所以需要将end移动到mid左边一个位置,即end = mid - 1 = 3 - 1 = 2,此时重新计算mid = (start +end) / 2 = (0 + 2) / 2 = 1,arr[mid] = arr[1] = 2, 因为0 < arr[mid] = arr[1] = 2,所以需要将end移动到mid左边一个位置,即end = mid - 1 = 1 - 1 = 0, 此时mid = (start +end) / 2 = (0 + 0) / 2 = 0,arr[mid] = arr[0] = 1,因为0 < arr[mid] = arr[0] = 1,所以需要将end移动到mid左边一个位置,即end = mid - 1 = 0 - 1 = -1 ,因为此时start = 0, end = -1,start >end,即start 已经大于end结束位置,说明没有找到相应的元素0。 + +##### 算法实现 + +```java +public class BinarySearchUtils { + + /** + * 根据指定值查找在数组中的位置 + * + * @param arr 待查找有序数组 + * @param value 指定值 + * @return 返回值在数组中对应的下标位置 + */ + public static int binarySearch(int[] arr, int value) { + //起始位置 + int start = 0; + //结束位置 + int end = arr.length - 1; + + while (true) { + //计算中间位置下标 + int mid = (start + end) / 2; + //中间值 + int midValue = arr[mid]; + + if (value == midValue) { + return mid; + } else { + //待查找数值比中间值小,需要将end = mid - 1 + if (midValue > value) { + end = mid - 1; + } else { + //待查找数值比中间值大,需要将start = mid + 1 + start = mid + 1; + } + } + + if (start > end) { + //start > end,说明未找到相应的元素,返回-1 + return -1; + } + } + } + +} +``` + +#### 7.说下你熟悉的排序算法 + +详见:https://www.cnblogs.com/onepixel/articles/7674659.html + +#### 8.布隆过滤器了解过吗? + +详见:https://www.cnblogs.com/liyulong1982/p/6013002.html + +#### 9.一致性hash算法了解过吗? + +详见:https://mp.weixin.qq.com/s/bCH-aU8cKS3uT6PwRYNJtA + +#### 10.如何在一个1到100的整数数组中找到丢失的数字? + +如果是丢了一个数字,用个遍历把这些数字累加求和, + +然后用 (1 + 100)*100/2 减去这个累加的总和,就是少的那一个数. + +如果是丢了一些数字, + +方法一: + +先 1-100 遍历 创建一个字典,key为1-100,值默认都为NO。 + +然后把那一些数字作为一个数组,判断是否包含每一个key,包含那key,则那key的值改为YES, + +最后值为NO的数则为缺失的数字 + +方法二: + +先排序,并创建一个用来装缺失数的空数组,排好序后遍历,最大的数用101减,其余用后一个值减去前一个值如果差值不是1而是为n,就把被减数分别加1到(n-1)得出的数保存下来就是缺少的数字 + +#### 11.请你讲讲LRU算法的实现原理? + +①LRU(Least recently used,最近最少使用)算法根据数据的历史访问记录来进行淘汰数据,其核心思想是“如果数据最近被访问过,那么将来被访问的几率也很高”,反过来说“如果数据最近这段时间一直都没有访问,那么将来被访问的概率也会很低”,两种理解是一样的;常用于页面置换算法,为虚拟页式存储管理服务。 + +②达到这样一种情形的算法是最理想的:每次调换出的页面是所有内存页面中最迟将被使用的;这可以最大限度的推迟页面调换,这种算法,被称为理想页面置换算法。可惜的是,这种算法是无法实现的。 为了尽量减少与理想算法的差距,产生了各种精妙的算法,最近最少使用页面置换算法便是其中一个。LRU 算法的提出,是基于这样一个事实:在前面几条指令中使用频繁的页面很可能在后面的几条指令中频繁使用。反过来说,已经很久没有使用的页面很可能在未来较长的一段时间内不会被用到 。这个,就是著名的局部性原理——比内存速度还要快的cache,也是基于同样的原理运行的。因此,我们只需要在每次调换时,找到最近最少使用的那个页面调出内存。 + +#### 12.为什么要设计后缀表达式,有什么好处? + +后缀表达式又叫逆波兰表达式,逆波兰记法不需要括号来标识操作符的优先级。 + +#### 13. 什么是B树? + +B树是一种多叉树,也叫多路搜索树,适合用于文件索引上,减少磁盘IO次数,子节点存储最大数成为B树的阶,图中为2-3树。 + +m阶B树特点: + +非叶节点最多有m棵子树。 +根节点最少有两棵子树,非根非叶节点最少有m/2棵子树。 +非叶节点保存的关键字个数等于该节点子树个数-1。 +非叶节点保存的关键字大小有序。 +节点中每个关键字左子树的关键字都小于该该关键字,右子树的关键字都大于该该关键字。 +所有叶节点都在同一层。 +查找: + +对节点关键字进行二分查找。 +如果找不到,进入对应的子树进行二分查找,如此循环。 + +#### 14.什么是B+树? + +B树的变种,拥有B树的特点 + +独有特点: + +节点中的关键字与子树数目相同。 +关键字对应的子树节点都大于等于该关键字,子树包含该关键字自身。 +所有关键字都出现在叶节点之中。 +所有叶节点都有指向下一个叶节点的指针。 +搜索:只在叶节点搜索。 + +叶子节点保存关键字和对应的数据,非叶节点只保存关键字和指向叶节点的指针,同等关键字数量的B树和B+树,B+树更小。 + +更适合做索引系统,原因: + +由于叶节点有指针项链,B+树更适合做范围检索。 +由于非叶节点只保存关键字和指向叶节点的指针,B+树可以容纳更多的关键字,树层数变小,磁盘查询次数更低。 +B+树的查询效率比较稳定,查询所有关键字的路径相同。(MySQL索引就提供了B+树的实现方式) + +#### 15.谈一谈,id全局唯一且自增,如何实现? + +SnowFlake雪花算法 + +雪花ID生成的是一个64位的二进制正整数,然后转换成10进制的数。64位二进制数由如下部分组成: + +snowflake id生成规则 + +1位标识符:始终是0,由于long基本类型在Java中是带符号的,最高位是符号位,正数是0,负数是1,所以id一般是正数,最高位是0。 + +41位时间戳:41位时间截不是存储当前时间的时间截,而是存储时间截的差值(当前时间截 - 开始时间截 )得到的值,这里的的开始时间截,一般是我们的id生成器开始使用的时间,由我们程序来指定的。 + +10位机器标识码:可以部署在1024个节点,如果机器分机房(IDC)部署,这10位可以由 5位机房ID + 5位机器ID 组成。 + +12位序列:毫秒内的计数,12位的计数顺序号支持每个节点每毫秒(同一机器,同一时间截)产生4096个ID序号 + +#### 参考链接 + +https://zhuanlan.zhihu.com/p/150340528?from_voters_page=true + +https://blog.csdn.net/Mr_BJL/article/details/88073694 + +https://blog.csdn.net/chenshiyang0806/article/details/90744039 + +https://blog.csdn.net/Weixiaohuai/article/details/83188174 diff --git "a/\346\266\210\346\201\257\351\230\237\345\210\227.md" "b/\346\266\210\346\201\257\351\230\237\345\210\227.md" new file mode 100644 index 0000000..5da2330 --- /dev/null +++ "b/\346\266\210\346\201\257\351\230\237\345\210\227.md" @@ -0,0 +1,228 @@ +## 消息队列 + + +* [1.消息队列有哪些应用场景?](#1消息队列有哪些应用场景) +* [2.消息队列的弊端有哪些?](#2消息队列的弊端有哪些) +* [3.使用消息队列,怎么确保消息不丢失?](#3使用消息队列怎么确保消息不丢失) +* [4.使用消息队列,如果处理重复消息?](#4使用消息队列如果处理重复消息) +* [5.Kafka的消息是有序的吗?如果保证Kafka消息的顺序性?](#5kafka的消息是有序的吗如果保证kafka消息的顺序性) +* [6.消息如何保证幂等性](#6消息如何保证幂等性) +* [7.消息队列积压怎么办](#7消息队列积压怎么办) +* [8.各种MQ的比较](#8各种mq的比较) +* [9.如何解决消息队列的延时以及过期失效问题?消息队列满了以后该怎么处理?有几百万消息持续积压几小时怎么解决?](#9如何解决消息队列的延时以及过期失效问题消息队列满了以后该怎么处理有几百万消息持续积压几小时怎么解决) +* [10.为什么使用消息队列?](#10为什么使用消息队列) +* [参考链接](#参考链接) + + +#### 1.消息队列有哪些应用场景? + +异步处理、流量控制、服务解耦、消息广播 + +#### 2.消息队列的弊端有哪些? + +数据延迟;增加系统复杂度;可能产生数据不一致的问题。 + +#### 3.使用消息队列,怎么确保消息不丢失? + +在生产阶段,你需要捕获消息发送的错误,并重发消息。 在存储阶段,你可以通过配置刷盘和复制相关的参数,让消息写入到多个副本的磁盘上,来确保消息不会因为某个 Broker 宕机或者磁盘损坏而丢失。 在消费阶段,你需要在处理完全部消费业务逻辑之后,再发送消费确认。 + +#### 4.使用消息队列,如果处理重复消息? + +1)利用数据库的唯一约束实现幂等 2)为更新的数据设置前置条件(CAS) 3)记录并检查操作(在发送消息时,给每条消息指定一个全局唯一的 ID,消费时,先根据这个 ID 检查这条消息是否有被消费过,如果没有消费过,才更新数据,然后将消费状态置为已消费。) + +#### 5.Kafka的消息是有序的吗?如果保证Kafka消息的顺序性? + +Kafka只能保证局部有序,即只能保证一个分区里的消息有序。而其具体实现是通过生产者为每个分区的消息维护一个发送队列,我们需要将保证顺序的消息都发送到同一个分区中。并且由于Kafka会同时发送多个消息,所以还需指定max.in.flight.requests.per.connection为1,保证前一个消息发送成功,后一个消息才开始发送。 + +#### 6.消息如何保证幂等性 + +例如kafka的offset可能是消费者批量处理后才提交到zk,重启后再消费时就可能会收到重复消息,需要消费者在处理消息时做幂等性设计,即先判断是否消费过,把已消费的放到本地缓存或者redis中,每次消费时先做个判断即可。 + +#### 7.消息队列积压怎么办 + +当消费者出现异常,很容易引起队列积压,如果一秒钟1000个消息,那么一个小时就是几千万的消息积压,是非常可怕的事情,但是生产线上又有可能会出现; + +当消息积压来不及处理,rabbitMQ如果设置了消息过期时间,那么就有可能由于积压无法及时处理而过期,这消息就被丢失了; + +解决方法如下: + +> - 不建议在生产环境使用数据过期策略,一是数据是否丢失无法控制,二是一旦积压就很有可能丢失;建议数据的处理都有代码来控制; +> - 当出现消息积压时,做法就是临时扩大consumer个数,让消息快速消费,一般都是通过业务逻辑的手段来完成:如下: + +【rabbitmq解决积压范例】 + +> > 1. 修复consumer代码故障,确保consumer逻辑正确可以消费; +> > 2. 停止consumer,开启10倍20倍的queue个数; +> > \* 创建一个临时的consumer程序,消费积压的queue,并把消息写入到扩建的10倍queue中; +> > \* 再开启10倍20倍的consumer对新的扩充后队列进行消费; +> > \* 这种做法相当于通过物理资源扩充了10倍来快速消费; + +> > 1. 当消费完成后,需要恢复原有架构,开启原来的consumer进行正常消费; + +【kafka解决范例】 + +> > 1. 修复consumer代码故障,确保consumer逻辑正确可以消费; +> > 2. 停止consumer,新建topic,新建10倍20倍的partition个数; +> > \* 创建对应原topic的partition个数的临时的consumer程序,消费原来的topic,并把消息写入到扩建的新topic中; +> > \* 再开启对应新partition个数的consumer对新的topic进行消费; +> > \* 这种做法相当于通过物理资源扩充了10倍来快速消费; + +> > 1. 当消费完成后,需要恢复原有架构,开启原来的consumer进行正常消费; + +#### 8.各种MQ的比较 + +| 特性 | activeMQ | rabbitMQ | rocketMQ | kafka | +| ------------------- | ------------------------ | ------------------------------------ | ------------------------------------------------------------ | ------------------------------------------------------------ | +| 单机吞吐量 | 万/秒 | 万/秒 | 10万/秒 | 10万/秒 | +| topic对吞吐量的影响 | 无 | 无 | topic达到几百/几千个级别,吞吐量会有小幅下降; 这是rocket的最大优势 所以非常适用于支撑大批量topic场景 | topic可以达到几十/几百个级别,吞吐量会有大幅下降 kafka不适用大批量topic场景,除非加机器 | +| 时效性 | 毫秒 | 微秒 这是rabbit 最大优势,延迟低 | 毫秒 | 毫秒 | +| 可用性 | 高。主从架构 | 高。主从架构 | 非常高。分布式。 | 非常高。分布式。数据多副本,不会丢数据,不会不可用。 | +| 可靠性 | 有较低概率丢失数据 | ---- | 经配置优化可达到0丢失 | 经配置优化可达到0丢失 | +| 功能特性 | 功能齐全,但已不怎么维护 | erlang开发,并发强,性能极好,延迟低 | MQ功能较为齐全,扩展好 | 功能简单,主要用于大数据实时计算和日志采集,事实标准 | + +综上,总结如下: + +------ + +【activeMQ】 + +> - 优点:技术成熟,功能齐全,历史悠久,有大量公司在使用 +> - 缺点:偶尔会有较低概率丢失数据,而且社区已经不怎么维护5.15.X版本 +> - 使用场景:主要用于系统解耦和异步处理,不适用与大数据量吞吐情况。互联网公司很少适用 + +------ + +【rabitMQ】 + +> - 优点:吞吐量高,功能齐全,管理界面易用,社区活跃,性能极好,; +> - 缺点:吞吐量只是万级,erlang难以二次开发和掌控;集群动态扩展非常麻烦; +> - 使用场景:吞吐量不高而要求低延迟,并且不会频繁调整和扩展的场景。非常适合国内中小型互联网公司适用,因为管理界面非常友好,可以在界面进行配置和优化/集群监控。 + +------ + +【rocketMQ】 + +> - 优点:支持百千级大规模topic。吞吐量高(十万级,日处理上百亿)。接口易用。,分布式易扩展,阿里支持。java开发易于掌控。 +> - 缺点:与阿里(社区)存在绑定。不兼容JMS规范。 +> - 使用场景:高吞吐量 + +------ + +【kafka】 + +> - 优点:超高吞吐量,超高可用性和可靠性,分布式易扩展 +> - 缺点:topic支持少,MQ功能简单,消息可能会重复消费影响数据精确度 +> - 使用场景:超高吞吐量场景而数据精确度没那么高,天然适合大数据实时计算和日志采集场景 + +#### 9.如何解决消息队列的延时以及过期失效问题?消息队列满了以后该怎么处理?有几百万消息持续积压几小时怎么解决? + +(一)、大量消息在mq里积压了几个小时了还没解决 + +几千万条数据在MQ里积压了七八个小时,从下午4点多,积压到了晚上很晚,10点多,11点多 +这个是我们真实遇到过的一个场景,确实是线上故障了,这个时候要不然就是修复consumer的问题,让他恢复消费速度,然后傻傻的等待几个小时消费完毕。这个肯定不能在面试的时候说吧。 + +一个消费者一秒是1000条,一秒3个消费者是3000条,一分钟是18万条,1000多万条,所以如果你积压了几百万到上千万的数据,即使消费者恢复了,也需要大概1小时的时间才能恢复过来。 + +一般这个时候,只能操作临时紧急扩容了,具体操作步骤和思路如下: + +先修复consumer的问题,确保其恢复消费速度,然后将现有cnosumer都停掉。 +新建一个topic,partition是原来的10倍,临时建立好原先10倍或者20倍的queue数量。 +然后写一个临时的分发数据的consumer程序,这个程序部署上去消费积压的数据,消费之后不做耗时的处理,直接均匀轮询写入临时建立好的10倍数量的queue。 +接着临时征用10倍的机器来部署consumer,每一批consumer消费一个临时queue的数据。 +这种做法相当于是临时将queue资源和consumer资源扩大10倍,以正常的10倍速度来消费数据。 +等快速消费完积压数据之后,得恢复原先部署架构,重新用原先的consumer机器来消费消息。 +(二)、消息队列过期失效问题 + +假设你用的是rabbitmq,rabbitmq是可以设置过期时间的,就是TTL,如果消息在queue中积压超过一定的时间就会被rabbitmq给清理掉,这个数据就没了。那这就是第二个坑了。这就不是说数据会大量积压在mq里,而是大量的数据会直接搞丢。 + +这个情况下,就不是说要增加consumer消费积压的消息,因为实际上没啥积压,而是丢了大量的消息。我们可以采取一个方案,就是批量重导,这个我们之前线上也有类似的场景干过。就是大量积压的时候,我们当时就直接丢弃数据了,然后等过了高峰期以后,比如大家一起喝咖啡熬夜到晚上12点以后,用户都睡觉了。 + +这个时候我们就开始写程序,将丢失的那批数据,写个临时程序,一点一点的查出来,然后重新灌入mq里面去,把白天丢的数据给他补回来。也只能是这样了。 + +假设1万个订单积压在mq里面,没有处理,其中1000个订单都丢了,你只能手动写程序把那1000个订单给查出来,手动发到mq里去再补一次。 + +(三)、消息队列满了怎么搞? + +如果走的方式是消息积压在mq里,那么如果你很长时间都没处理掉,此时导致mq都快写满了,咋办?这个还有别的办法吗?没有,谁让你第一个方案执行的太慢了,你临时写程序,接入数据来消费,消费一个丢弃一个,都不要了,快速消费掉所有的消息。然后走第二个方案,到了晚上再补数据吧。 + +#### 10.为什么使用消息队列? + +##### 面试官心理分析 + +其实面试官主要是想看看: + +- 第一,你知不知道你们系统里为什么要用消息队列这个东西? + + 不少候选人,说自己项目里用了 Redis、MQ,但是其实他并不知道自己为什么要用这个东西。其实说白了,就是为了用而用,或者是别人设计的架构,他从头到尾都没思考过。 + + 没有对自己的架构问过为什么的人,一定是平时没有思考的人,面试官对这类候选人印象通常很不好。因为面试官担心你进了团队之后只会木头木脑的干呆活儿,不会自己思考。 + +- 第二,你既然用了消息队列这个东西,你知不知道用了有什么好处&坏处? + + 你要是没考虑过这个,那你盲目弄个 MQ 进系统里,后面出了问题你是不是就自己溜了给公司留坑?你要是没考虑过引入一个技术可能存在的弊端和风险,面试官把这类候选人招进来了,基本可能就是挖坑型选手。就怕你干 1 年挖一堆坑,自己跳槽了,给公司留下无穷后患。 + +- 第三,既然你用了 MQ,可能是某一种 MQ,那么你当时做没做过调研? + + 你别傻乎乎的自己拍脑袋看个人喜好就瞎用了一个 MQ,比如 Kafka,甚至都从没调研过业界流行的 MQ 到底有哪几种。每一个 MQ 的优点和缺点是什么。每一个 MQ 没有绝对的好坏,但是就是看用在哪个场景可以扬长避短,利用其优势,规避其劣势。 + + 如果是一个不考虑技术选型的候选人招进了团队,leader 交给他一个任务,去设计个什么系统,他在里面用一些技术,可能都没考虑过选型,最后选的技术可能并不一定合适,一样是留坑。 + +##### 面试题剖析 + +其实就是问问你消息队列都有哪些使用场景,然后你项目里具体是什么场景,说说你在这个场景里用消息队列是什么? + +面试官问你这个问题,期望的一个回答是说,你们公司有个什么业务场景,这个业务场景有个什么技术挑战,如果不用 MQ 可能会很麻烦,但是你现在用了 MQ 之后带给了你很多的好处。 + +先说一下消息队列常见的使用场景吧,其实场景有很多,但是比较核心的有 3 个:解耦、异步、削峰。 + +##### 解耦 + +看这么个场景。A 系统发送数据到 BCD 三个系统,通过接口调用发送。如果 E 系统也要这个数据呢?那如果 C 系统现在不需要了呢?A 系统负责人几乎崩溃...... + +![file](https://img2018.cnblogs.com/blog/1756639/201909/1756639-20190908223436765-607649977.jpg) + + + +在这个场景中,A 系统跟其它各种乱七八糟的系统严重耦合,A 系统产生一条比较关键的数据,很多系统都需要 A 系统将这个数据发送过来。A 系统要时时刻刻考虑 BCDE 四个系统如果挂了该咋办?要不要重发,要不要把消息存起来?头发都白了啊! + +如果使用 MQ,A 系统产生一条数据,发送到 MQ 里面去,哪个系统需要数据自己去 MQ 里面消费。如果新系统需要数据,直接从 MQ 里消费即可;如果某个系统不需要这条数据了,就取消对 MQ 消息的消费即可。这样下来,A 系统压根儿不需要去考虑要给谁发送数据,不需要维护这个代码,也不需要考虑人家是否调用成功、失败超时等情况。 + +![file](https://img2018.cnblogs.com/blog/1756639/201909/1756639-20190908223437000-220196142.jpg) + +总结:通过一个 MQ,Pub/Sub 发布订阅消息这么一个模型,A 系统就跟其它系统彻底解耦了。 + +面试技巧:你需要去考虑一下你负责的系统中是否有类似的场景,就是一个系统或者一个模块,调用了多个系统或者模块,互相之间的调用很复杂,维护起来很麻烦。但是其实这个调用是不需要直接同步调用接口的,如果用 MQ 给它异步化解耦,也是可以的,你就需要去考虑在你的项目里,是不是可以运用这个 MQ 去进行系统的解耦。在简历中体现出来这块东西,用 MQ 作解耦。 + +##### 异步 + +再来看一个场景,A 系统接收一个请求,需要在自己本地写库,还需要在 BCD 三个系统写库,自己本地写库要 3ms,BCD 三个系统分别写库要 300ms、450ms、200ms。最终请求总延时是 3 + 300 + 450 + 200 = 953ms,接近 1s,用户感觉搞个什么东西,慢死了慢死了。用户通过浏览器发起请求,等待个 1s,这几乎是不可接受的。 + +![file](https://img2018.cnblogs.com/blog/1756639/201909/1756639-20190908223437240-841013337.jpg) + +一般互联网类的企业,对于用户直接的操作,一般要求是每个请求都必须在 200 ms 以内完成,对用户几乎是无感知的。 + +如果使用 MQ,那么 A 系统连续发送 3 条消息到 MQ 队列中,假如耗时 5ms,A 系统从接受一个请求到返回响应给用户,总时长是 3 + 5 = 8ms,对于用户而言,其实感觉上就是点个按钮,8ms 以后就直接返回了,爽!网站做得真好,真快 + +![file](https://img2018.cnblogs.com/blog/1756639/201909/1756639-20190908223437468-1330530320.jpg) + +##### 削峰 + +每天 0:00 到 12:00,A 系统风平浪静,每秒并发请求数量就 50 个。结果每次一到 12:00 ~ 13:00 ,每秒并发请求数量突然会暴增到 5k+ 条。但是系统是直接基于 MySQL 的,大量的请求涌入 MySQL,每秒钟对 MySQL 执行约 5k 条 SQL。 + +一般的 MySQL,扛到每秒 2k 个请求就差不多了,如果每秒请求到 5k 的话,可能就直接把 MySQL 给打死了,导致系统崩溃,用户也就没法再使用系统了。 + +但是高峰期一过,到了下午的时候,就成了低峰期,可能也就 1w 的用户同时在网站上操作,每秒中的请求数量可能也就 50 个请求,对整个系统几乎没有任何的压力。 + +![file](https://img2018.cnblogs.com/blog/1756639/201909/1756639-20190908223437702-1402821528.jpg) + +如果使用 MQ,每秒 5k 个请求写入 MQ,A 系统每秒钟最多处理 2k 个请求,因为 MySQL 每秒钟最多处理 2k 个。A 系统从 MQ 中慢慢拉取请求,每秒钟就拉取 2k 个请求,不要超过自己每秒能处理的最大请求数量就 ok,这样下来,哪怕是高峰期的时候,A 系统也绝对不会挂掉。而 MQ 每秒钟 5k 个请求进来,就 2k 个请求出去,结果就导致在中午高峰期(1 个小时),可能有几十万甚至几百万的请求积压在 MQ 中。 + +![file](https://img2018.cnblogs.com/blog/1756639/201909/1756639-20190908223437928-344432831.jpg) + +这个短暂的高峰期积压是 ok 的,因为高峰期过了之后,每秒钟就 50 个请求进 MQ,但是 A 系统依然会按照每秒 2k 个请求的速度在处理。所以说,只要高峰期一过,A 系统就会快速将积压的消息给解决掉。 + +### 参考链接 + +https://www.jianshu.com/p/88a4da652e23 + +https://blog.csdn.net/qq_41701956/article/details/103276267 diff --git "a/\347\274\226\350\257\221\345\216\237\347\220\206.md" "b/\347\274\226\350\257\221\345\216\237\347\220\206.md" new file mode 100644 index 0000000..f0336c1 --- /dev/null +++ "b/\347\274\226\350\257\221\345\216\237\347\220\206.md" @@ -0,0 +1,91 @@ +## 编译原理 + +* [1.词法分析](#1词法分析) +* [2.语法分析](#2语法分析) +* [3.语义分析](#3语义分析) +* [4.中间代码生成](#4中间代码生成) +* [5.目标代码生成](#5目标代码生成) +* [6.表格管理程序](#6表格管理程序) +* [7.出错处理](#7出错处理) +* [8.句型、句子、语言](#8句型句子语言) +* [9.有穷自动机(有限自动机)](#9有穷自动机有限自动机) +* [10.全局优化](#10全局优化) +* [参考链接](#参考链接) + + + +#### 1.词法分析 + +即对构成源程序的字符流进行扫描然后根据构词规则识别单词(也称单词符号或符号)。所以当单词不符合构词规则时词法分析会报错。 +**读入一个一个的字符(输入)**,对这些字符进行扫描和分解,从而识别出**一个个单词**(输出)。 + + + +#### 2.语法分析 + +语法分析是编译过程的一个逻辑阶段。语法分析的任务是在词法分析的基础上将单词序列组合成各类语法短语,如“程序”,“语句”,“表达式”等等.语法分析程序判断源程序在结构上是否正确. + +在词法分析的基础上,将单词序列(输出)分解成各类语法短语。(赋值语句等语句) +语法分析依据语言的语法规则,确定整个输入串是否在语法上正确。 +If else是否匹配,无论是LL(1)文法分析,自顶向下还是自底向上都是要按照给定的语法,判断词法分析的词语是不是满足语法要求(标识符定义是否正确,括号是否匹配,关键字是否正确,标识符,函数定义是否正确,使用的函数或者标识符是否定义等等) + +#### 3.语义分析 + +审查源程序有无语义错误,为代码生成阶段收集类型信息(如类型转化,类型匹配,上下文相关性等)。 +主要是类型相容检查,有以下几种: +各种条件表达式的类型是不是boolean型? +运算符的分量类型是否相容? +赋值语句的左右部的类型是否相容? +形参和实参的类型是否相容? +下标表达式的类型是否为所允许的类型? +函数说明中的函数类型和返回值的类型是否一致? +V[E]中的V是不是变量,而且是数组类型? +V.i中的V是不是变量,而且是记录类型?i是不是该记录的域名? +x+f(…)中的f是不是函数名?形参个数和实参个数是否一致? +每个使用性标识符是否都有声明?有无标识符的重复声明? +在语义分析同时产生中间代码,在这种模式下,语义分析的主要功能如下: +语义审查 +在扫描声明部分时构造标识符的符号表 +在扫描语句部分时产生中间代码 + +#### 4.中间代码生成 + +中间代码是一种结构简单,含义明确的记号系统。 +将源程序生成一种内部表示形式,这种内部表示形式叫中间代码。(四元式就是一种中间代码形式) + +#### 5.目标代码生成 + +把中间代码变换成特定机器上的绝对指令代码或可重定位的指令代码或汇编指令代码,它的工作与硬件系统和指令含义有关. + +#### 6.表格管理程序 + +编译过程中源程序的各种信息被保留在种种不同的表格里,编译各阶段的工作涉及到构造、查找或更新有关的表格,因此需要有表格管理工作。 + +#### 7.出错处理 + +出错处理:编译过程中,发现源程序有错误(词法错误、语法错误、语义错误),编译程序应报告错误的性质和出错的地点,并将错误所造成的影响限制在尽可能小的范围内,使得源程序的其余部分继续被编译下去。这些工作称为出错处理(error handling)。目的是使得编译程序能够继续向下进行分析和处理。 + +#### 8.句型、句子、语言 + +(1)句型和句子 +句型:若符号串x是从开始符推导出来的,即S =>*x,则称x是文法G的句型 +如果此时x只由终结符组成那么也称x为句子。 +(2)语言 +定义:由文法G生成的语言记为L(G),它是文法G的一切句子的集合。 +文法和语言的关系:文法G生成的每个串都在L(G)中且L(G)中的每个串确实能被G生成。 +(3)等价文法 +若L(G1)=L(G2),则称文法G1和G2是等价的。 + +#### 9.有穷自动机(有限自动机) + +为什么是有穷?:状态和输入字母表有穷。 +作用:是一种识别装置,识别正规文法所定义的语言和正规式所表示的集合。 +分类:(i)确定的有穷自动机(DFA)(ii)不确定的有穷自动机(NFA) + +#### 10.全局优化 + +过程内的全局优化是在一个程序过程(C语言内称为函数)范围内进行的优化,前面提到的所有方法也都可用到全局优化当中。 + +#### 参考链接 + +https://blog.csdn.net/csyifanZhang/article/details/107521129 diff --git "a/\350\256\241\347\256\227\346\234\272\347\273\204\346\210\220\345\216\237\347\220\206.md" "b/\350\256\241\347\256\227\346\234\272\347\273\204\346\210\220\345\216\237\347\220\206.md" new file mode 100644 index 0000000..ff8f49e --- /dev/null +++ "b/\350\256\241\347\256\227\346\234\272\347\273\204\346\210\220\345\216\237\347\220\206.md" @@ -0,0 +1,172 @@ +## 计算机组成原理 + +* [1.计算机系统由哪两部分组成?计算机系统性能取决于什么?](#1计算机系统由哪两部分组成计算机系统性能取决于什么) +* [2.计算机系统5层层次结构从下到上由哪五层组成?哪些是物理机,哪些是虚拟机?](#2计算机系统5层层次结构从下到上由哪五层组成哪些是物理机哪些是虚拟机) +* [3.在计算机系统结构中,什么是翻译?什么是解释?](#3在计算机系统结构中什么是翻译什么是解释) +* [4.什么是计算机体系结构?什么是计算机组成?以乘法指令为例说明二者区别。](#4什么是计算机体系结构什么是计算机组成以乘法指令为例说明二者区别) +* [5.冯诺依曼机器的主要特点?](#5冯诺依曼机器的主要特点) +* [6.程序访问的局部性](#6程序访问的局部性) +* [7.字长](#7字长) +* [8.Cache的基本工作原理](#8cache的基本工作原理) +* [9.Cache和主存之间的映射方式](#9cache和主存之间的映射方式) +* [10. Cache中主存块的替换算法](#10-cache中主存块的替换算法) +* [11.二进制一般使用什么方法转换成十进制?](#11二进制一般使用什么方法转换成十进制) +* [12.计算机直接使用原码计算有什么缺点?](#12计算机直接使用原码计算有什么缺点) +* [13.请计算12、124、1023、-1、-127的二进制原码。](#13请计算121241023-1-127的二进制原码) +* [14.计算机的补码解决了什么问题?](#14计算机的补码解决了什么问题) +* [15.什么是溢出?什么是上溢?什么是下溢?](#15什么是溢出什么是上溢什么是下溢) +* [16.浮点数之间做加减法运算需要几个步骤?每个步骤都是必须的吗?为什么?](#16浮点数之间做加减法运算需要几个步骤每个步骤都是必须的吗为什么) +* [17.虚拟存储器的基本概念](#17虚拟存储器的基本概念) +* [18.页式虚拟存储器](#18页式虚拟存储器) +* [19.段式虚拟存储器](#19段式虚拟存储器) +* [20.段页式虚拟存储器](#20段页式虚拟存储器) +* [参考链接](#参考链接) + +#### 1.计算机系统由哪两部分组成?计算机系统性能取决于什么? + +计算机系统是由“硬件”和“软件”组成。衡量一台计算机性能的优劣是根据多项技术指标综合确定的,既包括硬件的各种性能指标,又包括软件的各种功能。 + +1)计算机系统由硬件和软件两部分组成。 +2)计算机系统性能由硬件和软件共同决定。 + +#### 2.计算机系统5层层次结构从下到上由哪五层组成?哪些是物理机,哪些是虚拟机? + +1)微程序机器、传统机器、操作系统机器、汇编语言机器、高级语言机器 +2)微程序机器和传统机器是物理机,其他是虚拟机。 + +#### 3.在计算机系统结构中,什么是翻译?什么是解释? + +1)翻译:将一种语言编写的程序全部翻译成另一种语言,然后再执行; +2)解释:将一种语言编写的程序的一条语句翻译成另一种语言的一条或多条语句,然后执行,执行完这条语言后,再解释下一条。 + +#### 4.什么是计算机体系结构?什么是计算机组成?以乘法指令为例说明二者区别。 + +1)计算机体系结构是指那些能够被程序员看到的计算机的属性。如指令集、数据类型等; +2)计算机组成是指如何实现计算机体系结构所体现出来的属性; +3)以乘法指令为例,计算机是否有乘法指令,属于体系结构的问题。乘法指令是采用专用的乘法器,还是使用加法器和移位器构成,属于计算机组成的问题。 + +#### 5.冯诺依曼机器的主要特点? + +1)计算机由运算器、存储器、控制器、输入设备和输出设备五大部分组成; +2)指令和数据存储在存储器中,并可以按地址访问; +3)指令和数据均以二进制表示; +4)指令由操作码和地址码构成,操作码指明操作的性质,地址码表示操作数在存储器中的位置; +5)指令在存储器内按顺序存放,通常按自动的顺序取出执行; +6)机器以运算器为中心,I/O设备与存储器交换数据也要通过运算器。(因此,后来有了以存储器为中心的计算机结构) + +#### 6.程序访问的局部性 + +l 时间局部性:如果一个存储项被访问,则可能该项会很快被再次访问. + +l 空间局部性:如果一个存储项被访问,则该项及其邻近的项也可能很快被访问. + +**解释** + +计算机不能直接理解高级语言,只能直接理解机器语言,所以必须要把高级语言翻译成机器语言,计算机才能执行高级语言编写的程序。 + +翻译的方式有两种,一个是编译,一个是解释。 + +l 编译型语言写的程序在执行之前,需要一个专门的编译过程,把程序编译成为机器语言的文件,比如exe文件,如果源程序不变以后要运行的话就不用重新翻译。 + +l 解释则不同,解释性语言的程序不需要编译,在运行程序的时候才翻译,翻译一句执行一句,不生成目标程序,这样解释性语言每执行一次就要翻译一次,效率比较低。 + +l .java文件->编译->.class文件,编译成.class字节码,.class需要jvm解释,然后解释执行。Java很特殊,Java程序需要编译但是没有直接编译成机器语言,即二进制语言,而是编译成字节码(.class)再用解释方式执行。java程序编译以后的class属于中间代码,并不是可执行程序exe,不是二进制文件,所以在执行的时候需要一个中介来解释中间代码,这就是所谓的java虚拟机(JVM),也叫JDK。 + +l C语言编译过程分成四个步骤: + +1, 由.c文件到.i文件,这个过程叫预处理 + +将#include包含的头文件直接拷贝到hell.c当中;将#define定义的宏进行替换,同时将代码中没用的注释部分删除等 + +2, 由.i文件到.s文件,这个过程叫编译 + +3, 由.s文件到.o文件,这个过程叫汇编 + +高级语言->汇编语言->机器语言 + +4, 由.o文件到可执行文件,这个过程叫链接 + +将翻译成的二进制与需要用到库绑定在一块 + +#### 7.字长 + +l 机器字长:计算机能直接处理的二进制位数 + +l 指令字长:一个指令字中包含的二进制代码位数 + +l 存储字长:一个存储单元存储二进制代码长度 + +l CPI:执行一条指令需要的时钟周期数 + +#### 8.Cache的基本工作原理 + +Cache通常由两部分组成,块表和快速存储器.其工作原理是:处理机按主存地址访问存储器,存储器地址的高段通过主存-Cache地址映射机构借助查块表判定该地址的存储单元是否在Cache中,如果在,则Cache命中,按Cache地址访问Cache.否则,Cache不命中,则需要访问主存,并从主存中调入相应数据块到Cache中,若Cache中已写满,则要按某种算法将Cache中的某一块替换出去,并修改有关的地址映射关系. + +#### 9.Cache和主存之间的映射方式 + +l 直接映射就是将主存地址映射到Cache中的一个指定地址.任何时候,主存中存储单元的数据只能调入到Cache中的一个位置,这是固定的,若这个位置已有数据,则产生冲突,原来的块将无条件地被替换出去. + +l 全相联映射就是任何主存地址可映射到任何Cache地址的方式.在这种方式下,主存中存储单元的数据可调入到Cache中的任意位置.只有在Cache中的块全部装满后才会出现块冲突. + +l 组相联映射指的是将存储空间的页面分成若干组,各组之间的直接映射,而组内各块之间则是全相联映射. + +#### 10. Cache中主存块的替换算法 + +| | 思想 | 优点 | 缺点 | +| ----------------- | ------------------------------------------------ | ---------------------------------------------------- | ------------------------------------------------------------ | +| 随机算法RAND | 用软的或硬的随机数产生器产生上层中要被替换的页号 | 简单,易于实现 | 没有利用上层存储器使用的"历史信息",没有反映等程序局部性,命中率低. | +| 先进先出FIFO | 选择最早装入上层的页作为被替换的页 | 实现方便,利用了主存历史的信息 | 不能正确反映程序局部性原理,命中率不高,可能出现一种异常现象. | +| 近期最少使用法LRU | 选择近期最少访问的页作为被替换的页 | 比较正确反映程序局部性,利用访存的历史信息,命中率较高 | 实现较复杂 | +| 优化替换算法OPT | 将未来近期不用的页换出去 | 命中率最高,可作为衡量其他替换算法的标准 | 不现实,只是一种理想算法 | + +#### 11.二进制一般使用什么方法转换成十进制? + +整数:按权展开法。 + +#### 12.计算机直接使用原码计算有什么缺点? + +0有两种表示方法,减法运算复杂。 + +#### 13.请计算12、124、1023、-1、-127的二进制原码。 + +12(0b1100)、124(0b1111100)、1023(0b1111111111)、-1(-0b1)、-127(-0b1111111) + +#### 14.计算机的补码解决了什么问题? + +计算机的补码解决了什么问题? + +#### 15.什么是溢出?什么是上溢?什么是下溢? + +溢出即计算机无法表示数值。上溢是指数值绝对值大于表示范围,下溢是指计算机无法提供有效精度表示数值。 + +#### 16.浮点数之间做加减法运算需要几个步骤?每个步骤都是必须的吗?为什么? + +浮点数加减法需要经过以下几个步骤:对阶、尾数求和、尾数规格化、舍入、溢出判断。对阶是为了使得尾数可以进行运算,阶码不一致尾数运算无效,尾数规格化、舍入是为了正确存储结果,溢出判断是为了判断运算过程是否有误,如果溢出将会发出信号进行溢出处理。 + +#### 17.虚拟存储器的基本概念 + +虚拟存储器是指具有请求调入和置换功能,能从逻辑上对内存容量加以扩存的一种存储器系统 + +#### 18.页式虚拟存储器 + +页式管理:是把虚拟存储空间和实际空间等分成固定大小的页,各虚拟页可装入主存中的不同实际页面位置.页式存储中,处理机逻辑地址由虚页号和页内地址两部分组成,实际地址也分为页号和页内地址两部分,由地址映射机构将虚页号转换成主存的实际页号. + +页式管理用一个页表,包括页号,每页在主存中起始位置,装入位等.页表是虚拟页号与物理页号的映射表.页式管理由操作系统进行,对应用程序员的透明的. + +#### 19.段式虚拟存储器 + +段式管理: 把主存按段分配的存储管理方式.它是一种模块化的存储管理方式,每个用户程序模块可分到一个段,该程序模块只能访问分配给该模块的段所对应的主存空间.段长可以任意设定,并可放大和缩小. + +系统中通过一个段表指明各段在主存中的位置.段表中包括段名(段号),段起点,装入位和段长等.段表本身也是一个段.段一般是按程序模块分的. + +#### 20.段页式虚拟存储器 + +段页式管理:是上述两种方法的结合,它将存储空间按逻辑模块分成段,每段又分成若干个页,访存通过一个段表和若干个页表进行.段的长度必须是页长的整数倍,段的起点必须是某一页的起点. + +#### 参考链接 + +https://blog.csdn.net/weixin_41798450/article/details/88831860 + +https://blog.csdn.net/weixin_34054931/article/details/93843108 + +https://huanglei.blog.csdn.net/article/details/106071160 diff --git "a/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234.md" "b/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234.md" new file mode 100644 index 0000000..48d98aa --- /dev/null +++ "b/\350\256\241\347\256\227\346\234\272\347\275\221\347\273\234.md" @@ -0,0 +1,240 @@ +## 计算机网络 + + +* [1.请简述TCP/UDP的区别](#1请简述tcpudp的区别) +* [2.TCP对应的协议和UDP对应的协议](#2tcp对应的协议和udp对应的协议) +* [3.有哪些私有(保留)地址?](#3有哪些私有保留地址) +* [4.你能说一说OSI七层模型?](#4你能说一说osi七层模型) +* [5.说一说TCP/IP四层模型](#5说一说tcpip四层模型) +* [6. 简述IP地址的分类?](#6-简述ip地址的分类) +* [7.简述ARP地址解析协议工作原理](#7简述arp地址解析协议工作原理) +* [8.简述ICMP、TFTP、HTTP、NAT、DHCP协议](#8简述icmptftphttpnatdhcp协议) +* [9.说一说TCP的三次握手](#9说一说tcp的三次握手) +* [10.为什么TCP要三次握手](#10为什么tcp要三次握手) +* [11.TCP建立连接时为什么要传回 SYN](#11tcp建立连接时为什么要传回-syn) +* [12.TCP为什么要四次挥手](#12tcp为什么要四次挥手) +* [13.滑动窗口和流量控制](#13滑动窗口和流量控制) +* [14.拥塞控制](#14拥塞控制) +* [15.在浏览器中输入url地址到显示主页的过程](#15在浏览器中输入url地址到显示主页的过程) +* [16.HTTP协议包括哪些请求?](#16http协议包括哪些请求) +* [参考链接](#参考链接) + + +#### 1.请简述TCP/UDP的区别 + +TCP和UDP是OSI模型中的运输层中的协议。TCP提供可靠的通信传输,而UDP则常被用于让广播和细节控制交给应用的通信传输。 +两者的区别大致如下: + +- TCP面向连接,UDP面向非连接即发送数据前不需要建立链接 +- TCP提供可靠的服务(数据传输),UDP无法保证 +- TCP面向字节流,UDP面向报文 +- TCP数据传输慢,UDP数据传输快 +- TCP提供一种面向连接的、可靠的字节流服务 +- 在一个TCP连接中,仅有两方进行彼此通信,因此广播和多播不能用于TCP +- TCP使用校验和,确认和重传机制来保证可靠传输 +- TCP使用累积确认 +- TCP使用滑动窗口机制来实现流量控制,通过动态改变窗口的大小进行拥塞控制 + + + +#### 2.TCP对应的协议和UDP对应的协议 + +TCP对应的协议: + +- FTP:定义了文件传输协议,使用21端口。 +- Telnet:一种用于远程登陆的端口,使用23端口,用户可以以自己的身份远程连接到计算机上,可提供基于DOS模式下的通信服务。 +- SMTP:邮件传送协议,用于发送邮件。服务器开放的是25号端口。 +- POP3:它是和SMTP对应,POP3用于接收邮件。POP3协议所用的是110端口。 +- HTTP:是从Web服务器传输超文本到本地浏览器的传送协议。 + +UDP对应的协议: + +- DNS:用于域名解析服务,将域名地址转换为IP地址。DNS用的是53号端口。 +- SNMP:简单网络管理协议,使用161号端口,是用来管理网络设备的。由于网络设备很多,无连接的服务就体现出其优势。 +- TFTP(Trival File TransferProtocal),简单文件传输协议,该协议在熟知端口69上使用UDP服务。 + +#### 3.有哪些私有(保留)地址? + +A类:10.0.0.0 - 10.255.255.255 + +B类:172.16.0.0 - 172.31.255.255 + +C类:192.168.0.0 - 192.168.255.255 + +#### 4.你能说一说OSI七层模型? + +![img](https://pic3.zhimg.com/80/v2-2af488004591cbc12cd82c44518523de_720w.jpg) + +#### 5.说一说TCP/IP四层模型 + +如果你不了解,请直接点击阅读:[TCP/IP四层模型](https://link.zhihu.com/?target=http%3A//www.cnblogs.com/BlueTzar/articles/811160.html) + + +#### 6. 简述IP地址的分类? + +IP地址分为网络号和主机号, A类地址的前8位是网络地址,B类地址的前16位是网络地址,C类地址的前24位是网络地址。 + +A类地址: 1.0.0.0~126.0.0.0 + +B类地址:128.0.0.0 ~ 191.255.255.255 + +C类地址:192.0.0.0 ~ 223.255.255.255 + +D类地址:224.0.0.0 ~ 239.255.255.255 (作为多播使用) + +E类地址:保留 + +A,B,C是基本类,D、E类作为多播和保留使用。主机号,全0的是网络号,主机号全1的是广播地址。 + +#### 7.简述ARP地址解析协议工作原理 + +首先, 每个主机会在自己的ARP缓冲区简历一个ARP列表,以表示IP地址和MAC地址之间的对应关系。 + +当源主机要发送数据时,首先检查自己的ARP列表中是否有对应的目的主机的MAC地址,如果有就直接发送数据,如果没有,就向本网段的所有的主机发送ARP数据包, 该数据包括的内容由:源主机IP地址,源主机的MAC地址,目的主机的IP地址 + +当本网络的所有主机收到ARP数据包时,首先检查数据包中的IP地址是否是自己的IP地址,如果不是,则忽略该数据包,如果是,则首先从数据包中取出源主机的IP和MAC地址写入到ARP列表中,如果已经存在,则覆盖,然后将自己的MAC地址中放入到ARP响应包中,告诉源主机自己是它想找的MAC地址。 + +源主机接收到ARP响应包后,将目的主机的IP和MAC地址写入到ARP列表,并利用此消息发送数据。如果源主机一直没有收到ARP响应数据包,表示ARP查询失败。 + +广播发送ARP请求,单播发送ARP响应。 + +#### 8.简述ICMP、TFTP、HTTP、NAT、DHCP协议 + +ICMP : 因特网控制报文协议。它是TCP/IP协议族的一个子协议,用于在IP主机、路由器之间传递控制消息 + +TFTP:是TCP/IP协议族中的一个用来在客户机和服务器之间进行简单的文件传输的协议,提供不复杂、开销不大的文件传输服务 + +HTTP:超文本传输层协议,是一个属于应用层的面向对象的协议 + +NAT协议:网络地址转换接入广域网(WAN)技术,是一种将私有地址转换为合法IP地址的转换技术 + +DHCP协议:动态主机配置协议,使用UDP协议工作。给内部的网络和网络服务供应商自动的分配IP地址。 + +RARP是逆地址解析协议,作用是完成从硬件地址到IP地址的映射,RARP只能用于具有广播能力的网络。封装一个RARP的数据包里面有MAC地址, 然后广播到网络上,当服务器收到请求包后,就查找对应的MAC地址的IP地址装入到响应报文中发送给请求者。 + +一些常见的端口号及其用途: + +TCP 21端口 : FTP 文件传输服务 + +TCP 23 端口:TELNET 终端仿真服务 + +TCP 25端口:SMTP简单邮件传输服务 + +UDP 53端口:DNS域名解析服务 + +TCP 80端口:HTTP超文本传输服务 + +TCP 109端口:POP2邮局协议2 + +TCP 110端口 : POP3邮局协议版本3使用的端口 + +UDP 69 端口:TFTP 简单文件传输协议 + +3306:Mysql端口号 + +#### 9.说一说TCP的三次握手 + +在TCP/IP协议中,TCP协议提供可靠的连接服务,连接是通过三次握手进行初始化的。三次握手的目的是同步连接双方的序列号和确认号并交换TCP窗口大小信息 + +![图片描述](https://segmentfault.com/img/bVTyxj?w=600&h=669) + +- 核心思想:让双方都证实对方能发收。知道对方能收是因为收到对方的因为收到信息之后发的回应(ACK)。 +- 客户端–发送带有 SYN 标志的数据包–一次握手–服务端 +- 服务端–发送带有 SYN/ACK 标志的数据包–二次握手–客户端 +- 客户端–发送带有带有 ACK 标志的数据包–三次握手–服务端 + +#### 10.为什么TCP要三次握手 + +三次握手的目的是建立可靠的通信信道,说到通讯,简单来说就是数据的发送与接收,而三次握手最主要的目的就是双方确认自己与对方的发送与接收是正常的。 + +第一次握手:Client 什么都不能确认;Server 确认了对方发送正常,自己接收正常 + +第二次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:对方发送正常,自己接收正常 + +第三次握手:Client 确认了:自己发送、接收正常,对方发送、接收正常;Server 确认了:自己发送、接收正常,对方发送、接收正常 + +所以三次握手就能确认双发收发功能都正常,缺一不可。 + +#### 11.TCP建立连接时为什么要传回 SYN + +接收端传回发送端所发送的 SYN 是为了告诉发送端,我接收到的信息确实就是你所发送的信号了。 + +> SYN 是 TCP/IP 建立连接时使用的握手信号。在客户机和服务器之间建立正常的 TCP 网络连接时,客户机首先发出一个 SYN 消息,服务器使用 SYN-ACK 应答表示接收到了这个消息,最后客户机再以 ACK(Acknowledgement[汉译:确认字符 ,在数据通信传输中,接收站发给发送站的一种传输控制字符。它表示确认发来的数据已经接受无误。 ])消息响应。这样在客户机和服务器之间才能建立起可靠的TCP连接,数据才可以在客户机和服务器之间传递。 + + +#### 12.TCP为什么要四次挥手 + +任何一方都可以在数据传送结束后发出连接释放的通知,待对方确认后进入半关闭状态。当另一方也没有数据再发送的时候,则发出连接释放通知,对方确认后就完全关闭了TCP连接。 + +举个例子:A 和 B 打电话,通话即将结束后,A 说“我没啥要说的了”,B回答“我知道了”,但是 B 可能还会有要说的话,A 不能要求 B 跟着自己的节奏结束通话,于是 B 可能又巴拉巴拉说了一通,最后 B 说“我说完了”,A 回答“知道了”,这样通话才算结束。 + +上面讲的比较概括,推荐一篇讲的比较细致的文章:https://blog.csdn.net/qzcsu/article/details/72861891 + + + +#### 13.滑动窗口和流量控制 + +TCP 利用滑动窗口实现流量控制。流量控制是为了控制发送方发送速率,保证接收方来得及接收。 接收方发送的确认报文中的窗口字段可以用来控制发送方窗口大小,从而影响发送方的发送速率。将窗口字段设置为 0,则发送方不能发送数据。 + + + +#### 14.拥塞控制 + +在某段时间,若对网络中某一资源的需求超过了该资源所能提供的可用部分,网络的性能就要变坏。这种情况就叫拥塞。拥塞控制就是为了防止过多的数据注入到网络中,这样就可以使网络中的路由器或链路不致过载。拥塞控制所要做的都有一个前提,就是网络能够承受现有的网络负荷。拥塞控制是一个全局性的过程,涉及到所有的主机,所有的路由器,以及与降低网络传输性能有关的所有因素。相反,流量控制往往是点对点通信量的控制,是个端到端的问题。流量控制所要做到的就是抑制发送端发送数据的速率,以便使接收端来得及接收。 + +为了进行拥塞控制,TCP 发送方要维持一个 拥塞窗口(cwnd) 的状态变量。拥塞控制窗口的大小取决于网络的拥塞程度,并且动态变化。发送方让自己的发送窗口取为拥塞窗口和接收方的接受窗口中较小的一个。 + +TCP的拥塞控制采用了四种算法,即 慢开始 、 拥塞避免 、快重传 和 快恢复。在网络层也可以使路由器采用适当的分组丢弃策略(如主动队列管理 AQM),以减少网络拥塞的发生。 + +- 慢开始: 慢开始算法的思路是当主机开始发送数据时,如果立即把大量数据字节注入到网络,那么可能会引起网络阻塞,因为现在还不知道网络的符合情况。经验表明,较好的方法是先探测一下,即由小到大逐渐增大发送窗口,也就是由小到大逐渐增大拥塞窗口数值。cwnd初始值为1,每经过一个传播轮次,cwnd加倍。 +- 拥塞避免: 拥塞避免算法的思路是让拥塞窗口cwnd缓慢增大,即每经过一个往返时间RTT就把发送放的cwnd加1. +- 快重传与快恢复: 在 TCP/IP 中,快速重传和恢复(fast retransmit and recovery,FRR)是一种拥塞控制算法,它能快速恢复丢失的数据包。没有 FRR,如果数据包丢失了,TCP 将会使用定时器来要求传输暂停。在暂停的这段时间内,没有新的或复制的数据包被发送。有了 FRR,如果接收机接收到一个不按顺序的数据段,它会立即给发送机发送一个重复确认。如果发送机接收到三个重复确认,它会假定确认件指出的数据段丢失了,并立即重传这些丢失的数据段。有了 FRR,就不会因为重传时要求的暂停被耽误。  当有单独的数据包丢失时,快速重传和恢复(FRR)能最有效地工作。当有多个数据信息包在某一段很短的时间内丢失时,它则不能很有效地工作。 + +#### 15.在浏览器中输入url地址到显示主页的过程 + +百度好像最喜欢问这个问题。 + +> 打开一个网页,整个过程会使用哪些协议 + +图解(图片来源:《图解HTTP》): + +![img](https://my-blog-to-use.oss-cn-beijing.aliyuncs.com/2019-11/url%E8%BE%93%E5%85%A5%E5%88%B0%E5%B1%95%E7%A4%BA%E5%87%BA%E6%9D%A5%E7%9A%84%E8%BF%87%E7%A8%8B.jpg) + +总体来说分为以下几个过程: + +1. DNS解析 +2. TCP连接 +3. 发送HTTP请求 +4. 服务器处理请求并返回HTTP报文 +5. 浏览器解析渲染页面 +6. 连接结束 + +具体可以参考下面这篇文章: + +- https://segmentfault.com/a/1190000006879700 + + +#### 16.HTTP协议包括哪些请求? + +- GET:对服务器资源的简单请求 +- POST:用于发送包含用户提交数据的请求 +- HEAD:类似于GET请求,不过返回的响应中没有具体内容,用于获取报头 +- PUT:传说中请求文档的一个版本 +- DELETE:发出一个删除指定文档的请求 +- TRACE:发送一个请求副本,以跟踪其处理进程 +- OPTIONS:返回所有可用的方法,检查服务器支持哪些方法 +- CONNECT:用于ssl隧道的基于代理的请求 + + + +### 参考链接 + +https://blog.csdn.net/sdgihshdv/article/details/79503274 + +https://segmentfault.com/a/1190000010819141 + +https://blog.csdn.net/qq_29869043/article/details/82812986 + +https://zhuanlan.zhihu.com/p/24001696 + +https://www.cnblogs.com/wuwuyong/p/12198928.html diff --git "a/\350\256\276\350\256\241\346\250\241\345\274\217.md" "b/\350\256\276\350\256\241\346\250\241\345\274\217.md" new file mode 100644 index 0000000..0f868c3 --- /dev/null +++ "b/\350\256\276\350\256\241\346\250\241\345\274\217.md" @@ -0,0 +1,378 @@ +## 设计模式 + + +* [1.接口是什么?为什么要使用接口而不是直接使用具体类?](#1接口是什么为什么要使用接口而不是直接使用具体类) +* [2.设计模式六大原则?](#2设计模式六大原则) +* [3.Java怎么实现单例模式?](#3java怎么实现单例模式) +* [4.什么是代理模式?什么是动态代理?Java中动态代理有哪些实现方式?](#4什么是代理模式什么是动态代理java中动态代理有哪些实现方式) +* [5.设计模式的类型](#5设计模式的类型) +* [6.说说你所熟悉或听说过的 j2ee 中的几种常用模式?](#6说说你所熟悉或听说过的-j2ee-中的几种常用模式) +* [7.简述一下你了解的 Java 设计模式(总结)](#7简述一下你了解的-java-设计模式总结) +* [8.适配器模式是什么?什么时候使用?](#8适配器模式是什么什么时候使用) +* [9.适配器模式与装饰器模式有什么区别?](#9适配器模式与装饰器模式有什么区别) +* [10.适配器模式和代理模式之间有什么不同?](#10适配器模式和代理模式之间有什么不同) +* [11.什么是模板方法模式?试举例说明。](#11什么是模板方法模式试举例说明) +* [12.OOP中的组合、聚合和关联有什么区别?](#12oop中的组合聚合和关联有什么区别) +* [13.给我一个符合开闭原则的设计模式的例子?](#13给我一个符合开闭原则的设计模式的例子) +* [14.工厂模式与抽象工厂模式的区别?](#14工厂模式与抽象工厂模式的区别) +* [15.举出一个例子,在这种情况你会更倾向于使用抽象类,而不是接口?](#15举出一个例子在这种情况你会更倾向于使用抽象类而不是接口) +* [16.Dubbo 源码使用了哪些设计模式?](#16dubbo-源码使用了哪些设计模式) +* [17.Spring 当中用到了哪些设计模式?](#17spring-当中用到了哪些设计模式) +* [参考链接](#参考链接) + + +#### 1.接口是什么?为什么要使用接口而不是直接使用具体类? + +接口用于定义 API。它定义了类必须得遵循的规则。同时,它提供了一种抽象,因为客户端只使用接口,这样可以有多重实现,如 List 接口,你可以使用可随机访问的 ArrayList,也可以使用方便插入和删除的 LinkedList。接口中不允许写代码,以此来保证抽象,但是 Java 8 中你可以在接口声明静态的默认方法,这种方法是具体的。 + +#### 2.设计模式六大原则? + +1、开闭原则(Open Close Principle) + +开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。 + +2、里氏代换原则(Liskov Substitution Principle) + +里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。—— From Baidu 百科 + +3、依赖倒转原则(Dependence Inversion Principle) + +这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。 + +4、接口隔离原则(Interface Segregation Principle) + +这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。 + +5、迪米特法则(最少知道原则)(Demeter Principle) + +为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。 + +6、合成复用原则(Composite Reuse Principle) + +原则是尽量使用合成/聚合的方式,而不是使用继承 + +#### 3.Java怎么实现单例模式? + +- 懒汉式:懒加载,线程不安全 + +```java +public class Singleton +{ + private static Singleton singleton; + + private Singleton() + { + } + + public static Singleton getInstance() + { + if (singleton == null) + singleton = new Singleton(); + return singleton; + } +} + +``` + +- 懒汉式线程安全版:同步效率低 + +```java +public class Singleton +{ + private static Singleton singleton; + + private Singleton() + { + } + + public synchronized static Singleton getInstance() + { + if (singleton == null) + singleton = new Singleton(); + return singleton; + } +} + +``` + +- 饿汉式: + +```java +public class Singleton +{ + private static Singleton singleton = new Singleton(); + + private Singleton() + { + } + + public static Singleton getInstance() + { + return singleton; + } +} + +``` + +- 饿汉式变种: + +```java +public class Singleton +{ + private static Singleton singleton; + static + { + singleton = new Singleton(); + } + + private Singleton() + { + } + + public static Singleton getInstance() + { + return singleton; + } +} + +``` + +- 静态内部类方式:利用 JVM 的加载机制,当使用到 SingletonHolder 才会进行初始化。 + +```java +public class Singleton +{ + private Singleton() + { + } + + private static class SingletonHolder + { + private static final Singleton singleton = new Singleton(); + } + + public static Singleton getInstance() + { + return SingletonHolder.singleton; + } +} + +``` + +- 枚举: + +```java +public enum Singletons +{ + INSTANCE; + // 此处表示单例对象里面的各种方法 + public void Method() + { + } +} +``` + +- 双重校验锁: + +```java +public class Singleton +{ + private volatile static Singleton singleton; + + private Singleton() + { + } + + public static Singleton getInstance() + { + if (singleton == null) + { + synchronized (Singleton.class) + { + if (singleton == null) + { + singleton = new Singleton(); + } + } + } + return singleton; + } +} + +``` + +#### 4.什么是代理模式?什么是动态代理?Java中动态代理有哪些实现方式? + +详见:https://www.cnblogs.com/qlqwjy/p/7550609.html + +#### 5.设计模式的类型 + +根据设计模式的参考书 Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素) 中所提到的,总共有 23 种设计模式。这些模式可以分为三大类:创建型模式(Creational Patterns)、结构型模式(Structural Patterns)、行为型模式(Behavioral Patterns)。当然,我们还会讨论另一类设计模式:J2EE 设计模式。 + +| 序号 | 模式 & 描述 | 包括 | +| :--- | :----------------------------------------------------------- | :----------------------------------------------------------- | +| 1 | 创建型模式 这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。 | 工厂模式(Factory Pattern)抽象工厂模式(Abstract Factory Pattern)单例模式(Singleton Pattern)建造者模式(Builder Pattern)原型模式(Prototype Pattern) | +| 2 | 结构型模式 这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。 | 适配器模式(Adapter Pattern)桥接模式(Bridge Pattern)过滤器模式(Filter、Criteria Pattern)组合模式(Composite Pattern)装饰器模式(Decorator Pattern)外观模式(Facade Pattern)享元模式(Flyweight Pattern)代理模式(Proxy Pattern) | +| 3 | 行为型模式 这些设计模式特别关注对象之间的通信。 | 责任链模式(Chain of Responsibility Pattern)命令模式(Command Pattern)解释器模式(Interpreter Pattern)迭代器模式(Iterator Pattern)中介者模式(Mediator Pattern)备忘录模式(Memento Pattern)观察者模式(Observer Pattern)状态模式(State Pattern)空对象模式(Null Object Pattern)策略模式(Strategy Pattern)模板模式(Template Pattern)访问者模式(Visitor Pattern) | +| 4 | J2EE 模式 这些设计模式特别关注表示层。这些模式是由 Sun Java Center 鉴定的。 | MVC 模式(MVC Pattern)业务代表模式(Business Delegate Pattern)组合实体模式(Composite Entity Pattern)数据访问对象模式(Data Access Object Pattern)前端控制器模式(Front Controller Pattern)拦截过滤器模式(Intercepting Filter Pattern)服务定位器模式(Service Locator Pattern)传输对象模式(Transfer Object Pattern) | + +#### 6.说说你所熟悉或听说过的 j2ee 中的几种常用模式? + +IO 流的装饰器模式,Web 过滤器的责任链模式,Spring 的单例模式和工厂模式, +Spring 中根据不同配置方式进行初始化的策略模式 + +#### 7.简述一下你了解的 Java 设计模式(总结) + +标星号的为常用设计模式 + +``` +★单例模式:保证某个类只能有一个唯一实例,并提供一个全局的访问点。 +★简单工厂:一个工厂类根据传入的参数决定创建出那一种产品类的实例。 +工厂方法:定义一个创建对象的接口,让子类决定实例化那个类。 +抽象工厂:创建一组相关或依赖对象族,比如创建一组配套的汉堡可乐鸡翅。 +★建造者模式:封装一个复杂对象的构建过程,并可以按步骤构造,最后再build。 +★原型模式:通过复制现有的实例来创建新的实例,减少创建对象成本(字段需要复杂计算或者创建成本高)。 + +★适配器模式:将一个类的方法接口转换成我们希望的另外一个接口。 +★组合模式:将对象组合成树形结构以表示“部分-整体”的层次结构。(无限层级的知识点树) +★装饰模式:动态的给对象添加新的功能。 +★代理模式:为对象提供一个代理以增强对象内的方法。 +亨元(蝇量)模式:通过共享技术来有效的支持大量细粒度的对象(Integer中的少量缓存)。 +★外观模式:对外提供一个统一的方法,来访问子系统中的一群接口。 +桥接模式:将抽象部分和它的实现部分分离,使它们都可以独立的变化(比如插座和充电器,他们之间相插是固定的, +但是至于插座是插在220V还是110V,充电器是充手机还是pad可以自主选择)。 + +★模板方法模式:定义一个算法步骤,每个小步骤由子类各自实现。 +解释器模式:给定一个语言,定义它的文法的一种表示,并定义一个解释器。 +★策略模式:定义一系列算法,把他们封装起来,并且使它们可以相互替换。 +★状态模式:允许一个对象根据其内部状态改变而改变它的行为。 +★观察者模式:被观测的对象发生改变时通知它的所有观察者。 +备忘录模式:保存一个对象的某个状态,以便在适当的时候恢复对象。 +中介者模式:许多对象利用中介者来进行交互,将网状的对象关系变为星状的(最少知识原则)。 +命令模式:将命令请求封装为一个对象,可用于操作的撤销或重做。 +访问者模式:某种物体的使用方式是不一样的,将不同的使用方式交给访问者,而不是给这个物体。(例如对铜的使用,造币厂 +造硬币。雕刻厂造铜像,不应该把造硬币和造铜像的功能交给铜自己实现,这样才能解耦) +★责任链模式:避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链, +并且沿着这条链传递请求,直到有对象处理它为止。 +迭代器模式:一种遍历访问聚合对象中各个元素的方法,不暴露该对象的内部结构。 +``` + +#### 8.适配器模式是什么?什么时候使用? + +适配器模式(Adapter Pattern)是作为两个不兼容的接口之间的桥梁。这种类型的设计模式属于结构型模式,它结合了两个独立接口的功能。适配器模式提供对接口的转换。如果你的客户端使用某些接口,但是你有另外一些接口,你就可以写一个适配去来连接这些接口。 + +#### 9.适配器模式与装饰器模式有什么区别? + +虽然适配器模式和装饰器模式的结构类似,但是每种模式的出现意图不同。适配器模式被用于桥接两个接口,而装饰模式的目的是在不修改类的情况下给类增加新的功能。 + +装饰者模式:动态地将责任附加到对象上,若要扩展功能,装饰者模提供了比继承更有弹性的替代方案。 +通俗的解释:装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例。 + +适配器模式:将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。 +适配器模式有三种:类的适配器模式、对象的适配器模式、接口的适配器模式。 +通俗的说法:适配器模式将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题。 + +举例如下: + +1、适配器模式 + +```java +//file 为已定义好的文件流 +FileInputStream fileInput = new FileInputStream(file); +InputStreamReader inputStreamReader = new InputStreamReader(fileInput); +``` + +以上就是适配器模式的体现,FileInputStream是字节流,而并没有字符流读取字符的一些api,因此通过InputStreamReader将其转为Reader子类,因此有了可以操作文本的文件方法。 + +2、装饰者模式 + +BufferedReader bufferedReader=new BufferedReader(inputStreamReader);构造了缓冲字符流,将FileInputStream字节流包装为BufferedReader过程就是装饰的过程,刚开始的字节流FileInputStream只有read一个字节的方法,包装为inputStreamReader后,就有了读取一个字符的功能,在包装为BufferedReader后,就拥有了read一行字符的功能。 + +#### 10.适配器模式和代理模式之间有什么不同? + +这个问题与前面的类似,适配器模式和代理模式的区别在于他们的意图不同。由于适配器模式和代理模式都是封装真正执行动作的类,因此结构是一致的,但是适配器模式用于接口之间的转换,而代理模式则是增加一个额外的中间层,以便支持分配、控制或智能访问。 + +#### 11.什么是模板方法模式?试举例说明。 + +详见:https://www.cnblogs.com/adamjwh/p/10919149.html + +#### 12.OOP中的组合、聚合和关联有什么区别? + +如果两个对象彼此有关系,就说他们是彼此相关联的。组合和聚合是面向对象中的两种形式的关联。组合是一种比聚合更强力的关联。组合中,一个对象是另一个的拥有者,而聚合则是指一个对象使用另一个对象。如果对象 A 是由对象 B 组合的,则 A 不存在的话,B一定不存在,但是如果 A 对象聚合了一个对象 B,则即使 A 不存在了,B 也可以单独存在。 + +#### 13.给我一个符合开闭原则的设计模式的例子? + +开闭原则要求你的代码对扩展开放,对修改关闭。这个意思就是说,如果你想增加一个新的功能,你可以很容易的在不改变已测试过的代码的前提下增加新的代码。有好几个设计模式是基于开闭原则的,如策略模式,如果你需要一个新的策略,只需要实现接口,增加配置,不需要改变核心逻辑。一个正在工作的例子是 Collections.sort() 方法,这就是基于策略模式,遵循开闭原则的,你不需为新的对象修改 sort() 方法,你需要做的仅仅是实现你自己的 Comparator 接口。 + + + +#### 14.工厂模式与抽象工厂模式的区别? + +首先来看看这两者的定义区别: + +工厂模式:定义一个用于创建对象的借口,让子类决定实例化哪一个类 + +抽象工厂模式:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类 + +​ 个人觉得这个区别在于产品,如果产品单一,最合适用工厂模式,但是如果有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。再通俗深化理解下:工厂模式针对的是一个产品等级结构 ,抽象工厂模式针对的是面向多个产品等级结构的。 + +再来看看工厂方法模式与抽象工厂模式对比: + +| 工厂方法模式 | 抽象工厂模式 | +| ------------------------------------------ | ------------------------------------------ | +| 针对的是一个产品等级结构 | 针对的是面向多个产品等级结构 | +| 一个抽象产品类 | 多个抽象产品类 | +| 可以派生出多个具体产品类 | 每个抽象产品类可以派生出多个具体产品类 | +| 一个抽象工厂类,可以派生出多个具体工厂类 | 一个抽象工厂类,可以派生出多个具体工厂类 | +| 每个具体工厂类只能创建一个具体产品类的实例 | 每个具体工厂类可以创建多个具体产品类的实例 | + + #### 15.举出一个例子,在这种情况你会更倾向于使用抽象类,而不是接口? + +这是很常用但又是很难回答的设计面试问题。接口和抽象类都遵循”面向接口而不是实现编码”设计原则,它可以增加代码的灵活性,可以适应不断变化的需求。下面有几个点可以帮助你回答这个问题: + +1. 在一些对时间要求比较高的应用中,倾向于使用抽象类,它会比接口稍快一点。 +2. 如果希望把一系列行为都规范在类继承层次内,并且可以更好地在同一个地方进行编码,那么抽象类是一个更好的选择。有时,接口和抽象类可以一起使用,接口中定义函数,而在抽象类中定义默认的实现。 + +#### 16.Dubbo 源码使用了哪些设计模式? + +责任链模式:责任链中的每个节点实现 Filter 接口,然后由 ProtocolFilterWrapper,将所有 Filter 串连起来。 + Dubbo 的许多功能都是通过 Filter 扩展实现的,比如监控、日志、缓存、安全、telnet 以及 RPC 本身都是。 + +观察者模式:消费者在初始化的时候回调用 subscribe 方法,注册一个观察者,如果观察者引用的服务地址列表发生改变, + 就会通过 NotifyListener 通知消费者。 + +装饰器模式:比如 ProtocolFilterWrapper 类是对 Protocol 类的修饰。 + +工厂模式:如 ExtenstionLoader.getExtenstionLoader(Protocol.class).getAdaptiveExtenstion()。 + +#### 17.Spring 当中用到了哪些设计模式? + +模板方法模式:例如 jdbcTemplate,通过封装固定的数据库访问比如获取 connection、获取 statement,关闭 connection、关闭 statement 等 + 然后将特殊的 sql 操作交给用户自己实现。 + +策略模式:Spring 在初始化对象的时候,可以选择单例或者原型模式。 + +简单工厂:Spring 中的 BeanFactory 就是简单工厂模式的体现,根据传入一个唯一的标识来获得 bean 对象。 + +工厂方法模式:一般情况下,应用程序有自己的工厂对象来创建 bean.如果将应用程序自己的工厂对象交给 Spring 管理, 那么 Spring 管理的就不是普通的 bean,而是工厂 Bean。 + +单例模式:保证全局只有唯一一个对象。 + +适配器模式:SpringAOP 的 Advice 有如下:BeforeAdvice、AfterAdvice、AfterAdvice,而需要将这些增强转为 aop 框架所需的 + 对应的拦截器 MethodBeforeAdviceInterceptor、AfterReturningAdviceInterceptor、ThrowsAdviceInterceptor。 + +代理模式:Spring 的 Proxy 模式在 aop 中有体现,比如 JdkDynamicAopProxy 和 Cglib2AopProxy。 + +装饰者模式:如 HttpServletRequestWrapper,自定义请求包装器包装请求,将字符编码转换的工作添加到 getParameter()方法中。 + +观察者模式:如启动初始化 Spring 时的 ApplicationListener 监听器。 + +#### 参考链接 + +https://www.cnblogs.com/study-makes-me-happy/p/7839052.html + +https://ld246.com/article/1583476977456 + +https://www.runoob.com/design-pattern/design-pattern-tutorial.html + +https://creativecommons.org/licenses/by-sa/4.0/