关于java:java-web项目中BigDecimal返回值的序列化问题解决方案

在java web我的项目中返回一个费用,费用的类型应用了BigDecimal,而后就间接依照公司框架封装了返回值,后果就报错了。我的项目应用的框架是SpringBoot + swagger + lombok,代码如下:申请接口: @ApiOperation(value = "查问费用测试2")@PostMapping(path = "/getFee2/{fee}")public ResultVo<BigDecimal> getFee2(@PathVariable String fee) { BigDecimal f = StringUtils.isEmpty(fee) ? null : new BigDecimal(fee); return ResultVo.ok(f);}返回后果的封装类 @ApiModel("返回信息包装类")@Datapublic class ResultVo<T> { public static final int OK_CODE = 0; public static final int ERROR_CODE = 1; private static final String DEFAULT_MESSAGE = "OK"; private static final ResultVo<Void> OK_VO; private String code; private String errorMsg; private T content; static { OK_VO = new ResultVo<>(OK_CODE, DEFAULT_MESSAGE); } public ResultVo(String code, String errorMsg, T content) { this.code = code; this.errorMsg = errorMsg; this.content = content; } public static <T> ResultVo<T> ok(T content) { return new ResultVo<>(OK_CODE, null, content); } public static <T> ResultVo<T> error(T content) { return new ResultVo<>(ERROR_CODE, null, content); } public static ResultVo<Void> ok() { return OK_VO; } public ResultVo() { }}接口申请链接: ...

January 13, 2023 · 2 min · jiezi

关于java:如何构建基于-DDD-领域驱动的微服务

只管微服务中的“微”一词示意服务的规模,但它并不是应用微服务的唯一标准。当团队转向基于微服务的架构时,他们旨在进步敏捷性以及自主且频繁地部署性能。很难确定这种架构格调的简略定义。我喜爱Adrian Cockcroft的对于微服务的简短定义: “ 面向服务的体系结构,它由涣散耦合的、具备上下文边界的元素组成。” 只管这定义了高级设计启发式技术,但微服务架构具备一些独特的个性,使其有别于以往的面向服务的架构。以下是其中一些特色。这些以及其余一些文档都有据可查-Martin Fowler的文章和Sam Newman的Building Microservices,仅举几例。 服务具备围绕业务上下文而不是任意技术上形象的明确定义的边界通过用意公开界面暗藏实现细节并公开性能服务不会共享超出其边界的内部结构。例如,不共享数据库。服务能够抵制故障。团队独立领有职能,并可能自主公布变更团队拥戴自动化文化。例如,自动化测试,继续集成和继续交付简而言之,咱们能够将这种体系结构款式总结如下: 松耦合的面向服务的体系结构,其中每个服务都蕴含在定义明确的有界上下文中,从而能够疾速,频繁且牢靠地交付应用程序。 畛域驱动设计和有界上下文 微服务的力量来自明确定义其职责并划分它们之间的边界。此处的目标是在边界内建设高凝聚力,并在边界外建设低耦合(banq注:高凝聚低耦合)。也就是说,趋于一起扭转的事物应该属于同一事物。就像在许多现实生活中的问题一样,这说起来容易做起来难,业务在一直倒退,逻辑的假如前提也会随之扭转。因而,重构的能力是设计零碎时要思考的另一关键问题。 畛域驱动设计(DDD)是要害,在咱们看来,这是设计微服务时必不可少的工具,无论是突破整体还是施行未开发我的项目。畛域驱动的设计(Eric Evans在他的书中提出)是一组思维、原理和模式,可帮忙基于业务畛域的根底模型设计软件系统。开发人员和领域专家独特单干,以通用的通用语言创立业务模型。而后,他们将这些模型绑定到有意义的零碎,并在这些零碎与从事这些服务的团队之间建设合作协定。更重要的是,他们设计了零碎之间的概念轮廓或边界。 微服务设计从这些概念中吸取了灵感,因为所有这些原理都有助于构建能够互相独立变动和倒退的模块化零碎。 在持续进行之前,让咱们疾速理解一下DDD的一些根本术语。域驱动设计的残缺概述超出了本博客的范畴。咱们强烈建议任何尝试构建微服务的人举荐Eric Evans的书籍。 畛域:代表组织的工作。例如它是批发或电子商务。 子域:组织或组织内的业务部门。域由多个子域组成。 无所不在的语言:这是用于表白模型的语言。在上面的示例中,Item是一个模型,属于这些子域中每个子域的通用语言。开发人员,产品经理,领域专家和业务涉众都批准应用雷同的语言,并在其工件(代码,产品文档等)中应用该语言。 有界上下文:域驱动的设计将有界上下文定义为“单词或语句能确定其含意的设置”。简而言之,这意味着模型是有意义的边界。在下面的示例中,“我的项目”在每种上下文中的含意不同。在目录上下文中,我的项目示意可售产品,而在购物车上下文中,则示意客户已将其增加到购物车中的我的项目。在“运输”上下文中,它示意将要运送给客户的仓库物料。这些模型中的每一个都是不同的,并且每个都有不同的含意,并且可能蕴含不同的属性。通过将这些模型拆散并隔离在它们各自的边界内,咱们能够自在地表白模型而没有歧义。 留神:必须理解子域和有界上下文之间的区别。子域属于问题空间,即您的企业如何对待问题,而受限上下文属于解决方案空间,即咱们将如何施行问题的解决方案。从实践上讲,每个子域可能具备多个有界上下文,只管咱们致力为每个子域提供一个有界上下文。 微服务与无限上下文如何相干 当初,微服务在哪里适宜?能够说每个有界上下文都映射到微服务吗?是的,咱们将明确为什么。在某些状况下,有界上下文的边界或轮廓可能很大。 思考下面的例子。定价绑定上下文具备三个不同的模型-价格,定价我的项目和折扣,每个模型负责目录我的项目的价格,计算我的项目列表的总价格并别离利用折扣。咱们能够创立一个蕴含以上所有模型的零碎,然而它可能会成为一个不合理的大型应用程序。如前所述,每个数据模型都有其不变性和业务规定。随着工夫的流逝,如果咱们不小心的话,零碎可能会变成一个泥泞的大球,边界含糊,职责重叠,甚至可能回到咱们开始的中央—一个整体。 对系统进行建模的另一种办法是将相干模型拆散或分组为独自的微服务。在DDD中,这些模型(价格,定价我的项目和折扣)被称为聚合Aggregates。聚合是组成相干模型的独立模型。您只能通过已公布的界面更改聚合的状态,并且聚合可确保一致性,并且不变量保持良好状态。 聚合是关联对象的集群,被视为数据更改的单元。内部援用仅限于AGGREGATE的一个成员,称为根。一组一致性规定实用于AGGREGATE的边界。 同样,没有必要肯定要将每个聚合建模为一个独特的微服务。图中的服务(聚合)是一对一关系,但这不肯定是规定。在某些状况下,在单个服务中托管多个聚合可能是有意义的,尤其是当咱们不齐全理解业务畛域时。须要留神的重要一点是,只能在单个聚合中保障一致性,并且只能通过已公布的界面批改聚合。任何违反这些规定的行为都有变成大泥球的危险。 上下文映射—准确划分微服务边界的一种办法 整体构造通常由不同的模型组成,大多数模型是严密耦合的-模型可能晓得彼此的密切细节,更改一个模型可能会对另一个模型产生副作用,依此类推。合成整体时,确定这些模型(在这种状况下为汇合)及其关系至关重要。上下文映射能够帮忙咱们做到这一点。它们用于标识和定义各种有界上下文和聚合之间的关系。在下面的示例中,有界上下文定义了模型的边界(价格,折扣等),而上下文映射定义了这些模型之间以及不同有界上下文之间的关系。 上下文映射的残缺摸索不在本博客的探讨范畴之内,但咱们将通过一个示例进行阐明。下图显示了解决电子商务订单付款的各种应用程序。 购物车上下文负责订单的在线受权;订单上下文流程过帐付款后的付款流程;联系核心会解决所有例外情况,例如重试付款和更改用于订单的付款形式为了简略起见,让咱们假如所有这些上下文都是作为独自的服务实现的所有这些上下文封装了雷同的模型。请留神,这些模型在逻辑上是雷同的。也就是说,它们都遵循雷同的通用域语言-付款形式,受权和结算。只是它们是不同上下文的一部分。从新定义服务边界—将聚合映射到正确的上下文 谬误案例如下图: 电子商务中所有模型都间接与单个领取聚合的网关上下文(payment gateway context)集成,领取须要保障事务性,然而因为与多个服务集成,领取的事务性就不能通过在各种服务之间强制执行不变性和一致性来实现,(banq注:当然有人就提出分布式事务的概念来在这些不同服务之间实现领取过程的事务性,这其实是在谬误设计根底上的伪概念)。 请留神,领取网关中的任何更改都将迫使更改多个服务,并可能更改多个团队,因为不同的组能够领有这些上下文。 进行一些调整并使聚合与正确的上下文对齐,咱们能够更好地示意这些子域如下图。产生了很多变动。让咱们回顾一下更改: 通常,整体(单体)或遗留应用程序具备许多聚合,通常具备重叠的边界。创立这些聚合及其依赖关系的上下文地图有助于咱们理解将要从这些整体中解脱进去的任何新微服务的轮廓。请记住,微服务架构的胜利或失败取决于聚合之间的低耦合以及这些聚合之间的高内聚性。 同样重要的是要留神,有界上下文自身就是适合的内聚单元。即便上下文具备多个聚合,整个上下文及其聚合也能够组成一个微服务。咱们发现这种启发式办法对于有些艰涩的畛域特地有用-思考组织正在涉足的新业务畛域。您可能对拆散的正确边界没有足够的理解,并且聚集体的任何过早合成都可能导致低廉的重构。设想一下,因为数据迁徙,不得不将两个数据库合并为一个,因为咱们偶尔发现两个聚合属于同一类。然而请确保通过接口将这些聚合充沛隔离,以使它们不晓得彼此的简单细节。 事件风暴-辨认服务边界的另一种技术 事件风暴是识别系统中的聚合(以及微服务)的另一种必不可少的技术。这对于毁坏整体构造以及设计简单的微服务生态系统都是有用的工具。咱们曾经应用这种技术合成了一个简单的应用程序,并且打算在独自的博客中介绍Event Storming的教训。对于此博客的范畴,咱们想给出一个疾速的高级概述。如果您有趣味进一步摸索,请观看Alberto Brandelloni的视频。 简而言之,事件风暴是在应用程序团队(在咱们的状况下为整体)中进行的头脑风暴,以识别系统中产生的各种畛域事件和流程。团队还确定这些事件影响及其后续影响的汇总或模型。在团队进行此练习时,他们会确定不同的重叠概念,不置可否的畛域语言以及互相抵触的业务流程。他们将相干模型分组,从新定义聚合并确定反复的过程。随着这些工作的进行,这些汇合所属的无限上下文变得清晰起来。如果所有团队都在同一个房间(物理或虚构)中,并开始在Scrum格调的白板上绘制事件,命令和过程的映射,那么Event Storming研讨会将十分有用。在本练习完结时, 从新定义的聚合列表。这些可能成为新的微服务这些微服务之间须要流动的域事件间接从其余应用程序或用户调用的命令咱们在一场Event Storming研讨会完结时展现了一个示例板。对于团队来说,这是一次很棒的合作流动,以就正确的聚合和无限的上下文达成统一。除了进行杰出的团队建设流动外,团队在本次会议中怀才不遇,对畛域,通用语言和准确的服务边界有着独特的了解。 微服务之间的通信 一个整体在一个流程边界内托管了多个聚合体。因而,在此边界内能够治理聚合体的事务一致性,例如,如果客户下订单,咱们能够缩小我的项目的库存,并向客户发送电子邮件,全副都在一次交易事务中。所有操作都会胜利,或者全副都会失败。然而,当咱们突破整体并将聚合分布到不同的环境中时,咱们将领有数十甚至数百个微服务。迄今为止,在整体构造的单个边界内存在的流程当初散布在多个分布式系统中。要在所有这些分布式系统上实现事务的完整性和一致性十分艰难,而且要付出代价-零碎的可用性。 微服务也是分布式系统。因而,CAP定理也实用于它们- “分布式系统只能提供三个所需特色中的两个:一致性,可用性和分区容限(CAP中的“ C”,“ A”和“ P”)。” 在事实世界的零碎中,分区容忍度是无奈商议的- 网络不牢靠,虚拟机可能宕机,区域之间的提早会变得更糟,等等。 因而,咱们能够抉择“可用性”或“一致性”。当初,咱们晓得在任何古代应用程序中,就义可用性也不是一个好主见。 围绕最终一致性设计应用程序 如果您尝试跨多个分布式系统构建事务,那么您将再次陷入困境。变成最蹩脚的一种分布式整体事务。如果任何一个零碎点不可用,则整个流程将不可用,通常会导致令人丧气的客户体验、失去保障失败的承诺等。 此外,对一项服务的更改通常可能须要对另一项服务进行更改,从而导致简单而低廉的部署。因而,咱们最好依据本人的用例来设计应用程序,以容忍一点点的不一致性,以进步可用性。对于下面的示例,咱们能够使所有过程异步,从而最终保持一致。咱们能够异步发送电子邮件,而与其余流程无关。 如果承诺的物品当前在仓库中不可用,该我的项目可能被延期订购,或者咱们能够进行承受超过某个阈值的我的项目的订单。 有时,您可能会遇到一个场景,该场景可能须要逾越不同流程边界的两个聚合中的强ACID款式事务。这是从新查看这些聚合并将它们合并为一个极好的标记。在咱们开始在不同过程边界中合成这些聚合之前,事件风暴和上下文映射将有助于及早辨认这些依赖性。将两个微服务合并为一个老本很高,这是咱们应该致力防止的事件。 反对事件驱动的架构 微服务可能会在其聚合上收回实质上的变动。这些称为畛域事件,并且对这些更改感兴趣的任何服务都能够侦听这些事件并在其域内采取相应的操作。这种办法防止了任何行为上的耦合:一个域不规定其余域应该做什么,以及工夫耦合-一个过程的胜利实现不依赖于同时可用的所有零碎。当然,这将意味着零碎最终将保持一致。 ...

January 13, 2023 · 1 min · jiezi

关于java:在GCP上创建GCE的三种方式ConsolegcloudTerraform

1 简介如果要抉择GCP为云平台,则常常须要创立GCE(Google Compute Engine),有以下几种形式: (1) 在浏览器创立 (2) 命令 gcloud (3) Terraform 在开始之前,能够查看:《初始化一个GCP我的项目并用gcloud拜访操作》。 2 GCP Console登陆操作界面,点击创立按钮,而后抉择好参数即可: 会显示出对应的价格。 3 gcloud命令在操作界面创立时,能够间接查看对应的gcould命令: 咱们间接运行就能够创立了: $ gcloud compute instances create pkslow-vm \--project=pkslow \--zone=us-west1-a \--machine-type=e2-micro \--network-interface=network-tier=PREMIUM,subnet=default \--maintenance-policy=MIGRATE \--service-account=admin-for-all@pkslow.iam.gserviceaccount.com \--scopes=https://www.googleapis.com/auth/cloud-platform \--tags=http-server,https-server \--create-disk=auto-delete=yes,boot=yes,device-name=instance-1,image=projects/centos-cloud/global/images/centos-8-v20211105,mode=rw,size=20,type=projects/pkslow/zones/us-west1-a/diskTypes/pd-standard \--no-shielded-secure-boot \--shielded-vtpm \--shielded-integrity-monitoring \--reservation-affinity=anyCreated [https://www.googleapis.com/compute/v1/projects/pkslow/zones/us-west1-a/instances/pkslow-vm].NAME ZONE MACHINE_TYPE PREEMPTIBLE INTERNAL_IP EXTERNAL_IP STATUSpkslow-vm us-west1-a e2-micro 10.138.0.5 34.145.124.xxx RUNNING 10.138.0.5 34.145.124.xxx RUNNING查看是否创立胜利: $ gcloud compute instances listNAME ZONE MACHINE_TYPE PREEMPTIBLE INTERNAL_IP EXTERNAL_IP STATUSpkslow-vm us-west1-a e2-micro 4 Terraform当然,最佳实际是应用Terraform来治理,代码简略易懂,具体如下: ...

January 13, 2023 · 1 min · jiezi

关于java:排查+解决-Java-内存泄漏最基本的方法你必须学会

起源:zhenbianshu.github.io/ 前些日子小组内安顿值班,轮流看顾咱们的服务,次要做一些报警邮件解决、Bug 排查、经营 issue 解决的事。工作日还好,无论干什么都要下班的,若是轮到周末,那这一天算是毁了。 不晓得是公司网络广了就这样还是网络运维组不给力,网络总有问题,不是这边交换机脱网了就是那边路由器坏了,还偶发地各种超时,而咱们灵活地服务探测服务总能精确地抓住偶现的小问题,给美妙的工作加点料。好几次值班组的小伙伴们一起吐槽,磋商着怎么避过服务保活机制,偷偷停了探测服务而不让人发现(尽管也并不敢)。 前些天我就在周末解决了一次探测服务的锅。 问题网络问题?早晨七点多开始,我就开始不停地收到报警邮件,邮件显示探测的几个接口有超时状况。少数执行栈都在: java.io.BufferedReader.readLine(BufferedReader.java:371)java.io.BufferedReader.readLine(BufferReader.java:389)java_io_BufferedReader$readLine.call(Unknown Source)com.domain.detect.http.HttpClient.getResponse(HttpClient.groovy:122)com.domain.detect.http.HttpClient.this$2$getResponse(HttpClient.groovy)这个线程栈的报错我见得多了,咱们设置的 HTTP DNS 超时是 1s, connect 超时是 2s, read 超时是 3s,这种报错都是探测服务失常发送了 HTTP 申请,服务器也在收到申请失常解决后失常响应了,但数据包在网络层层转发中失落了,所以申请线程的执行栈会停留在获取接口响应的中央。这种状况的典型特色就是能在服务器上查找到对应的日志记录。而且日志会显示服务器响应齐全失常。与它绝对的还有线程栈停留在 Socket connect 处的,这是在建连时就失败了,服务端齐全无感知。 我留神到其中一个接口报错更频繁一些,这个接口须要上传一个 4M 的文件到服务器,而后通过一连串的业务逻辑解决,再返回 2M 的文本数据,而其余的接口则是简略的业务逻辑,我猜想可能是须要上传下载的数据太多,所以超时导致丢包的概率也更大吧。 依据这个猜测,群登上服务器,应用申请的 request_id 在近期服务日志中搜寻一下,果不其然,就是网络丢包问题导致的接口超时了。 当然这样 leader 是不会称心的,这个论断还得有人接锅才行。于是连忙分割运维和网络组,向他们确认一下过后的网络状态。网络组同学回复说是咱们探测服务所在机房的交换机老旧,存在未知的转发瓶颈,正在优化,这让我更释怀了,于是在部门群里简略交待一下,算是实现工作。 问题暴发本认为这次值班就起这么一个小波浪,后果在早晨八点多,各种接口的报警邮件一拥而上,打得筹备拾掇货色过周日单休的我措手不及。 这次简直所有的接口都在超时,而咱们那个大量网络 I/O 的接口则是每次探测必超时,难道是整个机房故障了么。 我再次通过服务器和监控看到各个接口的指标都很失常,本人测试了下接口也齐全 OK,既然不影响线上服务,我筹备先通过探测服务的接口把探测工作停掉再缓缓排查。 后果给暂停探测工作的接口发申请良久也没有响应,这时候我才晓得没这么简略。 解决内存透露于是赶快登陆探测服务器,首先是 top free df 三连,后果还真发现了些异样。 咱们的探测过程 CPU 占用率特地高,达到了 900%。另外,JVM 系列面试题和答案全副整顿好了,微信搜寻Java技术栈,在后盾发送:面试,能够在线浏览。 咱们的 Java 过程,并不做大量 CPU 运算,失常状况下,CPU 应该在 100~200% 之间,呈现这种 CPU 飙升的状况,要么走到了死循环,要么就是在做大量的 GC。 应用 jstat -gc pid [interval] 命令查看了 java 过程的 GC 状态,果然,FULL GC 达到了每秒一次。 ...

January 13, 2023 · 2 min · jiezi

关于java:通过Google-Cloud-StorageGCS管理Terraform的状态State

治理Terraform状态文件的最佳形式是通过云端的对立的存储,如谷歌云就用GCS。 首先要创立一个Bucket: $ gsutil mb -p pkslow -l us-west1 -b on gs://pkslow-terraformCreating gs://pkslow-terraform/...$ gsutil ls gs://gs://pkslow-terraform/而后在Terraform文件中配置对应的信息: terraform { backend "gcs" { bucket = "pkslow-terraform" prefix = "state/gcp/pubsub" }}初始化后,就会在Bucket上创立对应的目录: $ terraform init -plugin-dir=${TERRAFORM_PLUGIN}变更失效: $ terraform apply -auto-approve咱们在浏览器查看一下,发现曾经胜利状态了对应的状态文件: 通过近程的云端,不仅能够存入状态文件,也能够从状态文件读取数据,如一些输入变量。比方模块A创立了一个VM,而咱们可能通过这种形式获取它的IP,以便在其它模块应用。大抵的配置如下: data "terraform_remote_state" "foo" { backend = "gcs" config = { bucket = "terraform-state" prefix = "prod" }}resource "template_file" "bar" { template = "${greeting}" vars { greeting = "${data.terraform_remote_state.foo.greeting}" }}代码代码请查看GitHub: https://github.com/LarryDpk/p... Reference: ...

January 12, 2023 · 1 min · jiezi

关于java:通过gcloud创建Google-Kubernetes-EngineGKE并通过kubectl访问

1 简介GKE(Google Kubernetes Engine)是一个K8s平台, 咱们能够应用gcloud来创立GKE集群。在开始之前,能够查看:《初始化一个GCP我的项目并用gcloud拜访操作》。 2 创立GKE集群2.1 关上API在创立集群之前,须要关上Google API,不然无奈操作: $ gcloud services enable compute.googleapis.com$ gcloud services enable container.googleapis.com2.2 创立K8s集群的节点机器类型多种多样,能够查看一下某个区都有哪些机器类型: $ gcloud compute machine-types list | grep us-west这里我抉择一个便宜的:n1-standard-1。 应用 gcloud container clusters create 来创立: $ gcloud container clusters create pkslow-k8s \--zone us-west1-a \--cluster-version 1.20.10-gke.1600 \--machine-type n1-standard-1WARNING: Currently VPC-native is not the default mode during cluster creation. In the future, this will become the default mode and can be disabled using `--no-enable-ip-alias` flag. Use `--[no-]enable-ip-alias` flag to suppress this warning.WARNING: Starting with version 1.18, clusters will have shielded GKE nodes by default.WARNING: Your Pod address range (`--cluster-ipv4-cidr`) can accommodate at most 1008 node(s). WARNING: Starting with version 1.19, newly created clusters and node-pools will have COS_CONTAINERD as the default node image when no image type is specified.Creating cluster pkslow-k8s in us-west1-a...done. Created [https://container.googleapis.com/v1/projects/pkslow/zones/us-west1-a/clusters/pkslow-k8s].To inspect the contents of your cluster, go to: https://console.cloud.google.com/kubernetes/workload_/gcloud/us-west1-a/pkslow-k8s?project=pkslowkubeconfig entry generated for pkslow-k8s.NAME LOCATION MASTER_VERSION MASTER_IP MACHINE_TYPE NODE_VERSION NUM_NODES STATUSpkslow-k8s us-west1-a 1.20.10-gke.1600 34.82.42.67 n1-standard-1 1.20.10-gke.1600 3 RUNNING看日志,提醒创立胜利。 ...

January 12, 2023 · 2 min · jiezi

关于java:通过Terraform创建GCP-Pubsub

1 简介Terraform是治理许多平台的基础设施的工具,如AWS、GCP和Azure。这篇文章将解说如何通过Terraform来治理GCP Pub/Sub。 创立GCP我的项目请参考:初始化一个GCP我的项目并用gcloud拜访操作 2 Terraform创立Pub/Sub2.1 下载Terraform插件咱们须要装置GCP的Terraform插件来治理GCP资源: # 设置插件目录$ export TERRAFORM_PLUGIN=/Users/larry/Software/terraform/plugins# 创立目录$ mkdir -p ${TERRAFORM_PLUGIN}/registry.terraform.io/hashicorp/google/4.0.0/darwin_amd64$ cd ${TERRAFORM_PLUGIN}/registry.terraform.io/hashicorp/google/4.0.0/darwin_amd64# 下载$ wget https://releases.hashicorp.com/terraform-provider-google/4.0.0/terraform-provider-google_4.0.0_darwin_amd64.zip# 解压$ unzip terraform-provider-google_4.0.0_darwin_amd64.zip2.2 筹备Terraform代码须要提供Terraform代码理治理Pub/Sub,更多细节请参考: Terrafrom GCP. 版本文件version.tf: terraform { required_version = "= 1.0.11" required_providers { google = { source = "hashicorp/google" version = "= 4.0.0" } }}主文件main.tf: provider "google" { project = "pkslow"}resource "google_pubsub_topic" "pkslow-poc" { name = "pkslow-poc"}resource "google_pubsub_subscription" "pkslow-poc" { name = "pkslow-poc" topic = google_pubsub_topic.pkslow-poc.name labels = { foo = "bar" } # 20 minutes message_retention_duration = "1200s" retain_acked_messages = true ack_deadline_seconds = 20 expiration_policy { ttl = "300000.5s" } retry_policy { minimum_backoff = "10s" } enable_message_ordering = true}2.3 初始化和变更指定插件目录初始化: ...

January 12, 2023 · 1 min · jiezi

关于java:初始化一个GCP项目并用gcloud访问操作

1 简介谷歌云GCP(Google Cloud Platform)是由Google提供的云平台,还是为用户提供了许多收费的产品,还是能够尝试一下的。对于学习或者小我的项目,都能够应用。 2 创立一个新我的项目要应用GCP,咱们须要创立一个我的项目,它所有的资源都是在我的项目之下治理的: 3 创立Service Account在理论开发中,咱们不能应用本人的账号在做操作,最好的形式是创立一个服务账号(Service Account),这应该也是所有云平台都举荐的形式。创立地位如下: 输出账号名字: 抉择角色,为了不便,我间接抉择Owner,会领有所有权限,但理论利用必定不能这样,要做好隔离: 4 创立密钥文件对于Service Account,不是通过用户名明码来受权的,而是通过密钥文件,创立如下: 抉择新建一个密钥,并格局为json。创立后,会主动下载key文件。 5 设置gcloud SDKKey文件拿到后,咱们能够设置环境变量:GOOGLE_APPLICATION_CREDENTIALS: $ export GOOGLE_APPLICATION_CREDENTIALS=/Users/larry/Software/google-cloud-sdk/pkslow-admin-for-all.json激活Service Account: $ gcloud auth activate-service-account admin-for-all@pkslow.iam.gserviceaccount.com --key-file=${GOOGLE_APPLICATION_CREDENTIALS}设置SDK的我的项目ID: $ gcloud config set project pkslow检查一下设置是否正确: $ gcloud auth list Credentialed AccountsACTIVE ACCOUNT* admin-for-all@pkslow.iam.gserviceaccount.comTo set the active account, run: $ gcloud config set account `ACCOUNT`$ gcloud config list[core]account = admin-for-all@pkslow.iam.gserviceaccount.comdisable_usage_reporting = Trueproject = pkslowYour active configuration is: [default]6 应用gcloud创立Pub/SubSDK设置好后,就能够应用了,咱们应用它来创立Pub/Sub试试。创立主题和订阅: ...

January 12, 2023 · 1 min · jiezi

关于java:Spring-Boot通过Actuator显示git和build的信息

1 简介为了更好的版本控制和问题定位,咱们须要晓得正在运行的利用是什么版本,什么时候打包的,Git的相干信息等。通过/actuator/info能够帮忙咱们获取这些信息。 2 配置首先要有actuator的依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId></dependency>而后关上对应的端口: management: endpoints: web: exposure: include: "*"这时就能够拜访/actuator/info了,不过返回是空的。 要返回git和build的信息,咱们须要减少插件: <plugins> <plugin> <groupId>pl.project13.maven</groupId> <artifactId>git-commit-id-plugin</artifactId> <version>4.0.0</version> <executions> <execution> <id>get-the-git-infos</id> <goals> <goal>revision</goal> </goals> <phase>initialize</phase> </execution> </executions> <configuration> <dotGitDirectory>${project.basedir}/.git</dotGitDirectory> <generateGitPropertiesFile>true</generateGitPropertiesFile> </configuration> </plugin> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <version>${spring-boot-dependencies.version}</version> <executions> <execution> <goals> <goal>build-info</goal> </goals> </execution> </executions> </plugin></plugins>这两个插件会为咱们生成两个文件,一个是build-info.properties,专门放一些build的信息;另一个是git.properties,放一些版本控制的信息: 当咱们再拜访/actuator/info时,Spring Boot就会读取并显示对应的信息了: 3 总结代码请查看:https://github.com/LarryDpk/p...

January 12, 2023 · 1 min · jiezi

关于java:别催了别催了这篇文章我一次性把Shell的内容说完

Shell 搜寻与匹配1、在文件中查找字符串grep 命令能够搜寻文件,查找指定的字符串。 $ grep myvar *.c在这个例子中,咱们搜寻的文件全都位于当前目录下。因而,咱们只应用了简略的 shell 模式 *.c 来匹配以 .c 完结的文件,并没有在文件名前再增加门路。 但并非所有待搜寻的文件都老老实实地待在当前目录下。但因为shell 并不在意你输出多少路径名,所以咱们也能够这么写: $ grep myvar ../lib/*.c ../server/*.c ../cmd/*.c */*.c如果待搜寻的文件不止一个,grep 会在输入前加上文件名以及冒号,而后是该文件中蕴含 grep 搜寻内容的文本。 grep 的第一个(非选项)参数能够是一个简略的字符串,也能够是更简单的正则表达式(regexp)。正则表达式不同于 shell 的模式匹配,只管两者有时看起来差不多。 常见谬误 遗记指定 grep 的输出,例如 grep myvar。这种状况下,grep 会认为你要从 STDIN 提供输出,而你认为它会读取文件,于是 grep 就干等着,鸿鹄之志。 2、只显示蕴含搜寻后果的文件名你须要找出蕴含特定字符串的文件,然而不想看到其所在的文本行,只用输入文件名即可,常常在线上为了搜寻配置文件。 用 grep 的 -l 选项仅显示文件名即可,如下: $ grep -l myvar *.cboth.cgood.csomio.c$如果在一个文件中找到了屡次匹配,grep 依然只输入该文件名一次。如果没有找到匹配,则什么都不输入。 因为这些文件蕴含了你要查找的字符串,如果想据此构建一个待处理 文件的列表,选项 -l 就能派上用场了。将 grep 命令放进 $(),而后就能够在命令行上应用这些文件名了,如下: rm -i $(grep -l 'This file is obsolete' * ) 删除蕴含字符串“This file is obsolete”的文件,咱们给 rm 加上了 -i 选项,以便在删除每个文件前都先询问你。 ...

January 12, 2023 · 3 min · jiezi

关于java:Redis-发布订阅模式原理拆解并实现一个消息队列

“65 哥,如果你交了个丑陋小姐姐做女朋友,你会通过什么形式将这个音讯广而告之给你的微信好友?“ “那不得拍点女朋友的美照 + 密切照弄一个九宫格图文音讯在朋友圈公布大肆宣传,暴击独身狗。”像这种 65 哥通过朋友圈公布音讯,关注 65 哥的好友能收到告诉的场景叫做「公布/订阅机制」。 明天不聊小姐姐,深刻理解下 「Redis 公布/订阅机制」。的原理与实战使用。 Redis 通过 SUBSCRIBE,UNSUBSCRIBE和PUBLISH 实现公布订阅消息传递模式,Redis 提供了两种模式实现,别离是「公布/订阅到频道」和「公布\订阅到模式」。 Redis 公布订阅简介Redis 公布订阅(Pus/Sub)是一种音讯通信模式:发送者通过 PUBLISH公布音讯,订阅者通过 SUBSCRIBE 订阅接管音讯或通过UNSUBSCRIBE 勾销订阅。 次要蕴含三个局部组成:「发布者」、「订阅者」、「Channel」。 发布者和订阅者属于客户端,Channel 是 Redis 服务端,发布者将音讯公布到频道,订阅这个频道的订阅者则收到音讯。 如下图所示,三个「订阅者」订阅「ChannelA」频道: 这时候,小组长往「ChannelA」公布音讯,这个音讯的订阅者就会收到音讯「关注码哥字节,晋升技术」: Pub/Sub 实战废话不多说,晓得基本概念当前,学习一个技术第一步先把它跑起来,接着才是摸索原理,从而达到「知其然,知其所以然」的境界 。 一共有两种模式实现「公布\订阅」: 应用频道(Channel)的公布订阅;应用模式(Pattern)的公布订阅。须要留神的是,公布订阅机制与 db 空间无关,比方在 db 10 公布, db0 的订阅者也会收到音讯。 通过频道(Channel)实现三步走: 订阅者订阅频道;发布者向「频道」公布音讯;所有订阅「频道」的订阅者收到音讯。订阅者订阅频道 应用 SUBSCRIBE channel [channel ...]订阅一个或者多个频道,O(n) 工夫复杂度,n = 订阅的 Channel 数量。 SUBSCRIBE developReading messages... (press Ctrl-C to quit)1) "subscribe" // 音讯类型2) "develop" // 频道3) (integer) 1 // 音讯内容执行该指令后,客户端进入订阅状态,订阅者只能应用subscribe、unsubscribe、psubscribe和punsubscribe这四个属于"公布/订阅" 的指令。 ...

January 12, 2023 · 3 min · jiezi

关于java:成员变量java循环机构

1.概念所谓的成员变量,是指在类中(不是办法或其余代码块)间接定义的变量。依据是否带有static关键字,成员变量又分为动态变量(类变量)、实例变量(对象变量)。成员变量在整个类的外部都无效,能够在以后类的任何办法中应用。另外如果成员变量不是被private润饰的,还能够在其余的类中援用。 2.实例变量实例变量也被成为对象变量,是指在类中定义的非static变量。 实例变量具备如下特点: ● 实例变量申明在一个类中,但在办法、构造方法和语句块的里面; ● 当一个对象被实例化之后,每个实例变量的值也就跟着确定了; ● 实例变量在对象创立时创立,在对象被销毁时销毁; ● 实例变量对于类中的办法、构造方法或者语句块都是可见的。个别状况下咱们应该把实例变量设为公有,通过拜访修饰符能够使实例变量对子类也可见; ● 实例变量具备默认值。数值型变量的默认值是0,布尔型变量的默认值是false,援用类型变量的默认值是null。变量的值能够在申明时指定,也能够在构造方法中指定; ● 实例变量能够间接通过变量名拜访。 但在静态方法以及其余类中,应该应用齐全限定名:ObjectReference.VariableName。 3.动态变量动态变量又被称为类变量,是被static润饰的、间接定义在类中(办法之外)的变量,它具备如下特点: ● 动态变量能够被public、private、final和static润饰; ● 动态变量在办法里面定义,但能够在动态语句块中初始化,且初始化后不可被扭转; ● 动态变量与实例变量具备类似的可见性。但为了对类的使用者可见,大多数动态变量都申明为public类型; ● 动态变量的默认值和实例变量类似; ● 动态变量通过ClassName.VariableName的模式进行拜访; ● 动态变量存储在动态存储区; ● 动态变量在第一次被拜访时创立,在程序完结时销毁; ● 无论在一个类中创立了多少个对象,一个类都只领有类变量的一份拷贝; ● 动态变量被申明为public static final类型时,变量名称个别倡议应用大写字母。 4.权限修饰符大家要留神,成员变量的作用域,是能够通过权限修饰符来进行批改的。也就是说,咱们能够给一个成员变量不同的修饰符,赋予该变量不同的权限。比方,咱们能够给一个人身上赋予不同的”角色标签“,就能够扭转这个人的”势力大小“。 在Java中,有如下4个权限修饰符: 1、private公有的修饰符:能够润饰成员变量、成员办法、构造方法,但不能润饰类(外部类除外)。被private润饰的成员只能在被润饰的本类中拜访,在其余类中不能调用。个别被private润饰的成员变量,是通过公开的set和get办法向外界提供拜访形式。 2.defalut默认的修饰符:不必写任何关键字,它能够润饰类、成员变量、成员办法、构造方法。变量被默认权限润饰后,只能被本类以及同一个包下的其余类拜访。 3.protected受爱护的修饰符:能够润饰成员变量、成员办法、构造方法,但不能润饰类(外部类除外)。成员变量被protected润饰后,能够在同一类外部,和同一包中的其余类拜访。如果不同包中的类想要拜访被protected润饰的成员,这个类必须是其子类。 4.public公开的修饰符:是权限最大的修饰符,能够润饰类、成员变量、成员办法、构造方法。成员变量被public润饰后,能够在任何一个类中任意应用,不论是否是同一个包。 5.案例在上面的案例中,壹哥定义了2个成员变量供大家参考: public class Demo01 { private int age = 18;//实例变量、对象变量,在以后的Demo01类外部无效 public static String msg = "Hello,一一哥";//动态变量、类变量,因为是public公开的,在以后Demo01类外部,及其他类中都能够应用 public static void main(String[] args) { //留神:在static静态方法中不能引用非动态变量 //System.out.println("age=" + age); System.out.println("msg=" + msg); }}

January 12, 2023 · 1 min · jiezi

关于java:IoTLink-v121-最新公告

IoTLinkv1.2.1版本更新 更新内容新增 对外接口模块 yunze-iotapi部署教程 文档阐明新增 微信端部署教程新增电信DCP查问激活工夫接口优化 所属卡 已到缄默期 无激活工夫 无发货日期 sql

January 12, 2023 · 1 min · jiezi

关于java:Shell-命令奇淫技巧就是有点短

1、在任意目录之间疾速挪动你发现自己要在两个或更多目录之间频繁挪动,一会切换到这里,一会切换到那里,来回跳转。这些目录之间隔得还挺远,重复输出简短的门路让人疲惫不堪。 应用内建命令 pushd 和 popd 来治理目录栈,轻松地在目录之间切换。上面是一个简略的示例: $ cd /tmp/tank$ pwd/tmp/tank$ pushd /var/log/cups/var/log/cups /tmp/tank$ pwd/var/log/cups$ lsaccess_log error_log page_log$ popd/tmp/tank$ lsempty full$ pushd /var/log/cups/var/log/cups /tmp/tank$ pushd/tmp/tank /var/log/cups$ pushd/var/log/cups /tmp/tank$ pushd/tmp/tank /var/log/cups$ dirs/tmp/tank /var/log/cups栈是一种后进先出的构造,这两个命令也正是这么做的。如果对一个新目录应用 pushd,那么它会将前一个目录压入栈中。当应用 popd时,它会弹出栈顶保留的以后地位,切换到新的栈顶目录。应用这些命令更改地位时,会从左到右输入目录栈中的值,对应于栈中自顶向下的程序。 如果应用 pushd 时没有指定目录,那么它会替换栈顶的两个目录的地位,这样就能够重复使用 pushd 命令来实现两者之间的切换。cd命令也可能达到雷同成果。 如果不记得目录栈中都有哪些目录,能够应用内建命令 dirs 依照从左到右的程序显示。加上 -v 选项后,显示模式更形象。 $ dirs -v 0 /opt/yongheng 1 /opt/yongheng/Shell$数字可用来调整栈内目录的地位。pushd +1 会将编号为 1 的目录置为栈顶(并切换到该目录)并将其余目录下压。 $ pushd +1/opt/yongheng/Shell /opt/yongheng$ dirs -v 0 /opt/yongheng/Shell1 /opt/yongheng 要想看到相似于栈的目录列表,但又不心愿呈现编号,能够应用 -p选项。 # dirs -p /opt/yongheng/Shell /opt/yongheng 2、反复上一个命令你刚刚输出了一个又长又麻烦的命令,其中蕴含了简短的路径名和一堆简单的参数。当初须要从新执行该命令。难道还得再输出一次? ...

January 11, 2023 · 1 min · jiezi

关于java:JVM参数调优

jvm参数:-Xms:初始堆大小-Xmx:最大堆大小当最小堆占满后,会尝试进行GC,如果GC之后还不能失去足够的内存(GC未必会收集到所有以后可用内存),调配新的对象,那么就会扩大堆,如果-Xmx设置的太小,扩大堆就会失败,导致OutOfMemoryError谬误提醒。-Xms能够设置与-Xmx雷同,以防止每次垃圾回收实现后JVM从新分配内存。-Xss:设置每个线程的堆栈大小。JDK5.0当前每个线程堆栈大小为1M,以前每个线程堆栈大小为256K。更具利用的线程所需内存大小进行调整。在雷同物理内 存下,减小这个值能生成更多的线程。然而操作系统对一个过程内的线程数还是有限度的,不能有限生成,经验值在3000~5000左右。-XX:NewSize=n:设置年老代大小-XX:NewRatio=n:设置年老代和年轻代的比值。如:为3,示意年老代与年轻代比值为1:3,年老代占整个年老代年轻代和的1/4-XX:SurvivorRatio=n:年老代中Eden区与两个Survivor区的比值。留神Survivor区有两个。如:3,示意Eden:Survivor=3:2,一个Survivor区占整个年老代的1/5-XX:MaxPermSize=n:设置长久代大小收集器设置-XX:+UseSerialGC:设置串行收集器-XX:+UseParallelGC:设置并行收集器-XX:+UseParalledlOldGC:设置并行年轻代收集器-XX:+UseConcMarkSweepGC:设置并发收集器垃圾回收统计信息-XX:+PrintGC-XX:+PrintGCDetails-XX:+PrintGCTimeStamps-Xloggc:filename并行收集器设置-XX:ParallelGCThreads=n:设置并行收集器收集时应用的CPU数。并行收集线程数。-XX:MaxGCPauseMillis=n:设置并行收集最大暂停工夫-XX:GCTimeRatio=n:设置垃圾回收工夫占程序运行工夫的百分比。公式为1/(1+n)并发收集器设置-XX:+CMSIncrementalMode:设置为增量模式。实用于单CPU状况。-XX:ParallelGCThreads=n:设置并发收集器年老代收集形式为并行收集时,应用的CPU数。并行收集线程数。 回收器抉择JVM给了三种抉择:串行收集器、并行收集器、并发收集器,然而串行收集器只实用于小数据量的状况,所以这里的抉择次要针对并行收集器和并发收集器。默认状况下,JDK5.0以前都是应用串行收集器,如果想应用其余收集器须要在启动时退出相应参数。JDK5.0当前,JVM会依据以后系统配置进行判断。 调优总结对JVM内存的零碎级的调优次要的目标是缩小GC的频率和Full GC的次数。1.Full GC 会对整个堆进行整顿,包含Young、Tenured和Perm。Full GC因为须要对整个堆进行回收,所以比较慢,因而应该尽可能减少Full GC的次数。 2.导致Full GC的起因 1)年轻代(Tenured)被写满 调优时尽量让对象在新生代GC时被回收、让对象在新生代多存活一段时间和不要创立过大的对象及数组防止间接在旧生代创建对象 。 2)长久代Pemanet Generation空间有余 增大Perm Gen空间,防止太多动态对象 , 管制好新生代和旧生代的比例 3)System.gc()被显示调用 垃圾回收不要手动触发,尽量依附JVM本身的机制 调优步骤 剖析内存透露、剖析Dump文件、监控GC状态、调整JVM参数 1.剖析内存透露查看零碎产生cpu高和内存透露的过程,线程,找到具体产生问题的利用,定位到代码,通过优化代码来解决问题,比方,流没敞开,死循环,死锁等。 2.剖析dump文件用jmap 生成dump文件,显然个别的Window零碎没有这么大的内存,必须借助高配置的Linux,几种工具关上该文件: Visual VMIBM HeapAnalyzerJDK 自带的Hprof工具Mat(Eclipse专门的动态内存剖析工具)举荐应用备注:文件太大,倡议应用Eclipse专门的动态内存剖析工具Mat关上剖析。通过剖析dump 内存快照文件,更加具体的全面的理解利用的jvm参数配置,gc过程,oom等。 3.监控GC的状态应用各种JVM工具,查看以后日志,剖析以后JVM参数设置,并且剖析以后堆内存快照和gc日志,依据理论的各区域内存划分和GC执行工夫,感觉是否进行优化。 举一个例子: 零碎解体前的一些景象: 每次垃圾回收的工夫越来越长,由之前的10ms缩短到50ms左右,FullGC的工夫也有之前的0.5s缩短到4、5sFullGC的次数越来越多,最频繁时隔不到1分钟就进行一次FullGC年轻代的内存越来越大并且每次FullGC后年轻代没有内存被开释之后零碎会无奈响应新的申请,逐步达到OutOfMemoryError的临界值,这个时候就须要剖析JVM内存快照dump。剖析后果,判断是否须要优化如果各项参数设置正当,零碎没有超时日志呈现,GC频率不高,GC耗时不高,那么没有必要进行GC优化,如果GC工夫超过1-3秒,或者频繁GC,则必须优化。 注:如果满足上面的指标,则个别不须要进行GC优化: Minor GC执行工夫不到50ms;Minor GC执行不频繁,约10秒一次;Full GC执行工夫不到1s;Full GC执行频率不算频繁,不低于10分钟1次; 4.调整参数如果内存调配过大或过小,或者采纳的GC收集器比较慢,则应该优先调整这些参数,并且先找1台或几台机器进行beta,而后比拟优化过的机器和没有优化的机器的性能比照,并有针对性的做出最初抉择。 一直的剖析和调整 通过一直的试验和试错,剖析并找到最合适的参数,如果找到了最合适的参数,则将这些参数利用到所有服务器。 JVM调优参数参考1.针对JVM堆的设置,个别能够通过-Xms -Xmx限定其最小、最大值,为了避免垃圾收集器在最小、最大之间膨胀堆而产生额定的工夫,通常把最大、最小设置为雷同的值; 2.年老代和年轻代将依据默认的比例(1:2)调配堆内存, 能够通过调整二者之间的比率NewRadio来调整二者之间的大小,也能够针对回收代。 比方年老代,通过 -XX:newSize -XX:MaxNewSize来设置其相对大小。同样,为了避免年老代的堆膨胀,咱们通常会把-XX:newSize -XX:MaxNewSize设置为同样大小。 3.年老代和年轻代设置多大才算正当 更大的年老代必然导致更小的年轻代,大的年老代会缩短一般GC的周期,但会减少每次GC的工夫;小的年轻代会导致更频繁的Full GC 更小的年老代必然导致更大年轻代,小的年老代会导致一般GC很频繁,但每次的GC工夫会更短;大的年轻代会缩小Full GC的频率 如何抉择应该依赖应用程序对象生命周期的散布状况: 如果利用存在大量的长期对象,比方高并发利用,应该抉择更大的年老代;如果存在绝对较多的长久对象,比方传输数量量大的利用,年轻代应该适当增大。但很多利用都没有这样显著的个性。 在抉择时应该依据以下两点: (1)本着Full GC尽量少的准则,让年轻代尽量缓存罕用对象,JVM的默认比例1:2也是这个情理 。 (2)通过观察利用一段时间,看其余在峰值时年轻代会占多少内存,在不影响Full GC的前提下,依据理论状况加大年老代,比方能够把比例控制在1:1。但应该给年轻代至多预留1/3的增长空间。 4.在配置较好的机器上(比方多核、大内存),能够为年轻代抉择并行收集算法:-XX:+UseParallelOldGC**。 5.线程堆栈的设置:每个线程默认会开启1M的堆栈,用于寄存栈帧、调用参数、局部变量等,对大多数利用而言这个默认值太了,个别256K就足用。实践上,在内存不变的状况下,缩小每个线程的堆栈,能够产生更多的线程,但这实际上还受限于操作系统,并不能无限大。

January 11, 2023 · 1 min · jiezi

关于java:jvm-cpu和内存问题常见分析方法

Java程序在运行中常常遇到CPU或内存使用率高的问题,那么应该如何排查问题的起因呢,本文大略形容一下剖析排查办法。 形式一、命令形式剖析1.排查占用CPU的过程应用top命令,查找CPU和内存使用率最高的过程获取过程PID。(在大写关上的状况下按P键或者在大写没有关上的状况下按 shift+P键,会依照CPU使用率的高下进行排序,在大写关上的状况下按M键或者在大写没有关上的状况下按 shift+M键,会依照内存使用率的高下进行排序) 2.查找理论占用最高的线程应用命令top -H -p PID,此处PID就是上一步获取的过程PID,通过此命令能够查看理论占用CPU最高的的线程的ID,此处会有几个TID。 3.获取对应线程的线程栈信息应用命令printf "%x\n" tid,将线程ID转换为16进制应用命令jstack PID(过程pid) |grep tid(线程pid16进制) -A 50,此处tid为上一步转换后的16进制,应用此命令能够查看到对应线程的线程栈信息,从对依据线程栈对对应的代码进行剖析。 形式二、dump文件剖析1.dump文件输入jmap -dump:live,format=b,file=20170307.dump 9729file前面的是自定义的文件名,最初的数字是过程的pid 2.应用jvisualvm来剖析dump文件:jvisualvm是JDK自带的Java性能剖析工具,在JDK的bin目录下,文件名就叫jvisualvm.exe。jvisualvm能够监控本地、近程的java过程,实时查看过程的cpu、堆、线程等参数,对java过程生成dump文件,并对dump文件进行剖析。应用形式:间接双击关上jvisualvm.exe,点击文件->装入,在文件类型那一栏抉择堆,抉择要剖析的dump文件,关上。装入之后在界面右侧的概要、类等选项卡能够看到生成dump文件过后的堆信息能够看到,dump文件里记录的堆中的实例,总大小大略300M左右,(用第一行的实例大小除以百分比就能算进去),和JVM默认的新生代的大小差不多,远小于JVM中设置的最大堆内存,也就是说,dump文件里记录的并不是实例大小达到最大堆内存时的状态。为了验证一下,我本人在本地模仿了一下堆内存溢出的情景,并用jvisualvm监控.剖析:红框框出的局部是产生堆内存溢出时的情景,已应用的堆大小(蓝色局部)并没有增长特地显著,然而申请的堆的大小(黄色局部)从默认的400多兆急速上涨,涨到800M,而后内存溢出,然而应用的堆大小仍然没怎么增长。 所以,dump文件中的实例列表其实是反映了应用的堆的状况,而应用的堆内存并没有达到事后设置的最大堆内存,只是在申请堆内存的过程中超出了事后设置的最大堆内存,而后内存溢出。通过剖析Dump文件就能够发现程序哪里有死锁。 OOM(Out Of Memory)为什么会呈现 OOM,个别由这些问题引起调配过少:JVM 初始化内存小,业务应用了大量内存;或者不同 JVM 区域分配内存不合理代码破绽:某一个对象被频繁申请,不必了之后却没有被开释,导致内存耗尽内存透露:申请应用完的内存没有开释,导致虚拟机不能再次应用该内存,此时这段内存就泄露了。因为申请者不必了,而又不能被虚拟机调配给他人用内存溢出:申请的内存超出了 JVM 能提供的内存大小,此时称之为溢出内存透露继续存在,最初肯定会溢出,两者是因果关系 比拟常见的 OOM 类型有以下几种:java.lang.OutOfMemoryError: PermGen spaceJava7 永恒代(办法区)溢出,它用于存储已被虚拟机加载的类信息、常量、动态变量、即时编译器编译后的代码等数据。每当一个类首次加载的时候,元数据都会寄存到永恒代个别呈现于大量 Class 对象或者 JSP 页面,或者采纳 CgLib 动静代理技术导致。Java8 将永恒代变更为元空间,报错:java.lang.OutOfMemoryError: Metadata space,元空间内存不足默认进行动静扩大。咱们能够通过 -XX:PermSize 和 -XX:MaxPermSize 批改办法区大小 java.lang.StackOverflowError栈溢出,个别是因为程序中存在 死循环或者深度递归调用 造成的。如果栈大小设置过小也会呈现溢出,能够通过 -Xss 设置栈的大小虚拟机抛出栈溢出谬误,能够在日志中定位到谬误的类、办法。 java.lang.OutOfMemoryError: Java heap space堆内存溢出,溢出的起因个别因为 JVM 堆内存设置不合理或者内存透露导致如果是内存透露,能够通过工具查看透露对象到 GC Roots 的援用链。把握了透露对象的类型信息以及 GC Roots 援用链信息,就能够精准地定位出透露代码的地位。如果不存在内存透露,就是内存中的对象的确都还必须存活着,那就应该查看虚拟机的堆参数(-Xmx 与 -Xms),查看是否能够将虚拟机的内存调大些。 线上如遇到 JVM 内存溢出,能够分以下几步排查1、jmap -heap PID 查看是否内存调配过小。2、jmap -histo:live PID | more 查看是否有显著的对象调配过多且没有开释状况。3、jmap -dump:file=./jvmdump.hprof PID导出 JVM 以后内存快照,应用 JDK 自带或 MAT 等工具剖析快照。如果下面还不能定位问题,那么须要排查利用是否在一直创立资源,比方网络连接或者线程,都可能会导致系统资源耗尽。 ...

January 10, 2023 · 1 min · jiezi

关于java:Prometheus的使用

Prometheus 是一个开放性的监控解决方案,用户能够十分不便的装置和应用 Prometheus 并且可能十分不便的对其进行扩大。 在Prometheus的架构设计中,Prometheus Server 并不间接服务监控特定的指标,其次要工作负责数据的收集,存储并且对外提供数据查问反对。因而为了可能可能监控到某些货色,如主机的CPU使用率,咱们须要应用到Exporter。Prometheus周期性的从Exporter裸露的HTTP服务地址(通常是/metrics)拉取监控样本数据。 Exporter能够是一个绝对凋谢的概念,其能够是一个独立运行的程序独立于监控指标以外,也能够是间接内置在监控指标中。只有可能向Prometheus提供规范格局的监控样本数据即可。 1 环境配置咱们在 Windows 下装置 Prometheus。 1.1 装置 Prometheus下载地址:https://prometheus.io/download/ 抉择 Windows 安装包,我抉择的是prometheus-2.41.0.windows-amd64, 下载实现后解压,间接运行 prometheus.exe 即可。 prometheus默认端口是9090,在浏览器拜访:http://localhost:9090,即可看到我的项目曾经在运行。 Prometheus 的相干配置能够在 prometheus.yaml 中批改。 1.2 装置 NodeExporterNodeExporter 是 Prometheus 提供的一个能够采集到主机信息的应用程序,它能采集到机器的 CPU、内存、磁盘等信息。 下载地址: https://prometheus.io/download/ 抉择 Windows 版本,我抉择的是windows_exporter-0.20.0-amd64,下载实现后间接运行 windows_exporter-0.20.0-amd64.exe 文件即可。 windows_exporter默认端口是9182,通过浏览器拜访:http://localhost:9182/metrics, 能够看到以后 node exporter 获取到的以后主机的所有监控数据。 其中 HELP 用于解释以后指标的含意,TYPE 则阐明以后指标的数据类型。 2 增加数据源编辑 prometheus 的配置文件 prometheus.yml,将scrape_configs批改为如下内容: scrape_configs: - job_name: "prometheus" static_configs: - targets: ["localhost:9090"] # node exporter 监控源 - job_name: 'prometheus2' static_configs: - targets: ['localhost:8080']即配置了两个工作。一个名为 prometheus,其从「localhost:9090」地址读取数据。另一个名为 prometheus2,其从「localhost:8080」地址读取数据。 而后重启 Prometheus。 ...

January 10, 2023 · 2 min · jiezi

关于java:Java循环运行时暂停一段时间

GitHub我的项目地址 Gitee我的项目地址 Java 在运行 for 循环时,心愿能够每个循环暂停一段时间。 应用 sleep 办法即可: for (int i = 0; i < 10; i++) { try { System.out.println("i:" + i + " time:" + getTme()); Thread.sleep(10 * 1000); // 暂停10秒 } catch (InterruptedException e) { e.printStackTrace(); }}运行后,能够看到输入: i:0 time:15:35:06i:1 time:15:35:16i:2 time:15:35:26i:3 time:15:35:36i:4 time:15:35:46暂停10秒胜利。    学习更多编程常识,请关注我的公众号: 代码的路

January 10, 2023 · 1 min · jiezi

关于java:局部变量的特点以及成员变量的区别

1.概念 在下面的章节中,其实曾经跟大家介绍了局部变量的概念。 即:局部变量是在定义形参、办法或代码块外部的变量,该变量只在以后办法、代码块中无效。 2.特点 局部变量具备如下特点: ● 局部变量申明在办法、构造方法或者代码块、形参中; ● 局部变量在办法、构造方法、或者语句块被执行时创立,当它们执行实现后,局部变量就会被销毁; ● 拜访修饰符不能增加在局部变量上; ● 局部变量只在申明它的办法、构造方法或者代码块、形参中可见; ● 局部变量是在栈上调配的; ● 局部变量没有默认值,所以局部变量被申明后,必须通过初始化,才能够应用。 3.案例 在上面的案例中,给大家定义了几个局部变量供大家参考。 <code class="language-plaintext hljs">public class Demo01 { //args也是一种局部变量,在main(){}办法的{}范畴内无效 public static void main(String[] args) { int a = 10;//局部变量,在main(){}办法的{}范畴内无效 System.out.println("a=" + a); } public void showAge() { //i也是一种局部变量,只在for(){}这对{}范畴内 for(int i=0;i<100;i++) { System.out.println("age=" + age); } }}</code>至此,就把局部变量相干的内容给大家介绍完了,当初你晓得什么是局部变量及其特点了吗?另外咱们要搞清楚局部变量和成员变量的区别: 相同点: 定义变量的格局雷同;先申明后应用;变量都有对应的作用域。不同点: 两者申明的地位及作用范畴不同,如下表所示: 如果你还有什么别的问题,能够在评论区留言~

January 10, 2023 · 1 min · jiezi

关于java:java循环结构的概述

1.概念 所谓的成员变量,是指在类中(不是办法或其余代码块)间接定义的变量。依据是否带有static关键字,成员变量又分为动态变量(类变量)、实例变量(对象变量)。成员变量在整个类的外部都无效,能够在以后类的任何办法中应用。另外如果成员变量不是被private润饰的,还能够在其余的类中援用。 2.实例变量 实例变量也被成为对象变量,是指在类中定义的非static变量。实例变量具备如下特点: ● 实例变量申明在一个类中,但在办法、构造方法和语句块的里面; ● 当一个对象被实例化之后,每个实例变量的值也就跟着确定了; ● 实例变量在对象创立时创立,在对象被销毁时销毁; ● 实例变量对于类中的办法、构造方法或者语句块都是可见的。个别状况下咱们应该把实例变量设为公有,通过拜访修饰符能够使实例变量对子类也可见; ● 实例变量具备默认值。数值型变量的默认值是0,布尔型变量的默认值是false,援用类型变量的默认值是null。变量的值能够在申明时指定,也能够在构造方法中指定; ● 实例变量能够间接通过变量名拜访。但在静态方法以及其余类中,应该应用齐全限定名:ObjectReference.VariableName。 3.动态变量 动态变量又被称为类变量,是被static润饰的、间接定义在类中(办法之外)的变量,它具备如下特点: ● 动态变量能够被public、private、final和static润饰; ● 动态变量在办法里面定义,但能够在动态语句块中初始化,且初始化后不可被扭转; ● 动态变量与实例变量具备类似的可见性。但为了对类的使用者可见,大多数动态变量都申明为public类型; ● 动态变量的默认值和实例变量类似; ● 动态变量通过ClassName.VariableName的模式进行拜访; ● 动态变量存储在动态存储区; ● 动态变量在第一次被拜访时创立,在程序完结时销毁; ● 无论在一个类中创立了多少个对象,一个类都只领有类变量的一份拷贝; ● 动态变量被申明为public static final类型时,变量名称个别倡议应用大写字母。 4.权限修饰符 大家要留神,成员变量的作用域,是能够通过权限修饰符来进行批改的。也就是说,咱们能够给一个成员变量不同的修饰符,赋予该变量不同的权限。比方,咱们能够给一个人身上赋予不同的”角色标签“,就能够扭转这个人的”势力大小“。在Java中,有如下4个权限修饰符: private公有的修饰符:能够润饰成员变量、成员办法、构造方法,但不能润饰类(外部类除外)。被private润饰的成员只能在被润饰的本类中拜访,在其余类中不能调用。个别被private润饰的成员变量,是通过公开的set和get办法向外界提供拜访形式。defalut默认的修饰符:不必写任何关键字,它能够润饰类、成员变量、成员办法、构造方法。变量被默认权限润饰后,只能被本类以及同一个包下的其余类拜访。protected受爱护的修饰符:能够润饰成员变量、成员办法、构造方法,但不能润饰类(外部类除外)。成员变量被protected润饰后,能够在同一类外部,和同一包中的其余类拜访。如果不同包中的类想要拜访被protected润饰的成员,这个类必须是其子类。public公开的修饰符:是权限最大的修饰符,能够润饰类、成员变量、成员办法、构造方法。成员变量被public润饰后,能够在任何一个类中任意应用,不论是否是同一个包。案例在上面的案例中,壹哥定义了2个成员变量供大家参考: <code class="language-plaintext hljs">public class Demo01 { private int age = 18;//实例变量、对象变量,在以后的Demo01类外部无效 public static String msg = "Hello,一一哥";//动态变量、类变量,因为是public公开的,在以后Demo01类外部,及其他类中都能够应用 public static void main(String[] args) { //留神:在static静态方法中不能引用非动态变量 //System.out.println("age=" + age); System.out.println("msg=" + msg); }}</code>

January 10, 2023 · 1 min · jiezi

关于java:ShardingSphere分库分表schema名称导致NPE问题排查记录

前段时间把 ShardingSphere 降级到了 5.1.1 版本,奈何官网版本升级太快跟不上速度,这不最近又发现了一个 BUG。 问题景象数据库做了分库分表,在须要查问多表数据进行 merge 的时候产生了一个 NPE 的异样。 Caused by: java.lang.NullPointerException    at org.apache.shardingsphere.sharding.merge.dql.orderby.OrderByValue.getOrderValuesCaseSensitiveFromTables(OrderByValue.java:73) ~[shardingsphere-sharding-core-5.1.1.jar:5.1.1]    at org.apache.shardingsphere.sharding.merge.dql.orderby.OrderByValue.getOrderValuesCaseSensitive(OrderByValue.java:64) ~[shardingsphere-sharding-core-5.1.1.jar:5.1.1]    at org.apache.shardingsphere.sharding.merge.dql.orderby.OrderByValue.<init>(OrderByValue.java:58) ~[shardingsphere-sharding-core-5.1.1.jar:5.1.1]    at org.apache.shardingsphere.sharding.merge.dql.orderby.OrderByStreamMergedResult.orderResultSetsToQueue(OrderByStreamMergedResult.java:56) ~[shardingsphere-sharding-core-5.1.1.jar:5.1.1]    at org.apache.shardingsphere.sharding.merge.dql.orderby.OrderByStreamMergedResult.<init>(OrderByStreamMergedResult.java:50) ~[shardingsphere-sharding-core-5.1.1.jar:5.1.1]    at org.apache.shardingsphere.sharding.merge.dql.ShardingDQLResultMerger.build(ShardingDQLResultMerger.java:89) ~[shardingsphere-sharding-core-5.1.1.jar:5.1.1]    at org.apache.shardingsphere.sharding.merge.dql.ShardingDQLResultMerger.merge(ShardingDQLResultMerger.java:63) ~[shardingsphere-sharding-core-5.1.1.jar:5.1.1]    at org.apache.shardingsphere.infra.merge.MergeEngine.executeMerge(MergeEngine.java:90) ~[shardingsphere-infra-merge-5.1.1.jar:5.1.1]    at org.apache.shardingsphere.infra.merge.MergeEngine.merge(MergeEngine.java:80) ~[shardingsphere-infra-merge-5.1.1.jar:5.1.1]    at org.apache.shardingsphere.driver.jdbc.core.statement.ShardingSpherePreparedStatement.mergeQuery(ShardingSpherePreparedStatement.java:487) ~[shardingsphere-jdbc-core-5.1.1.jar:5.1.1]    at org.apache.shardingsphere.driver.jdbc.core.statement.ShardingSpherePreparedStatement.getResultSet(ShardingSpherePreparedStatement.java:435) ~[shardingsphere-jdbc-core-5.1.1.jar:5.1.1]    at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getFirstResultSet(DefaultResultSetHandler.java:237) ~[mybatis-3.5.3.jar:3.5.3]    at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.handleResultSets(DefaultResultSetHandler.java:187) ~[mybatis-3.5.3.jar:3.5.3]    at org.apache.ibatis.executor.statement.PreparedStatementHandler.query(PreparedStatementHandler.java:65) ~[mybatis-3.5.3.jar:3.5.3]    at org.apache.ibatis.executor.statement.RoutingStatementHandler.query(RoutingStatementHandler.java:79) ~[mybatis-3.5.3.jar:3.5.3]    at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:63) ~[mybatis-3.5.3.jar:3.5.3]    at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:324) ~[mybatis-3.5.3.jar:3.5.3]    at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156) ~[mybatis-3.5.3.jar:3.5.3]    at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109) ~[mybatis-3.5.3.jar:3.5.3]    at jdk.internal.reflect.GeneratedMethodAccessor346.invoke(Unknown Source) ~[?:?]    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]    at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]    at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:63) ~[mybatis-3.5.3.jar:3.5.3]    at com.sun.proxy.$Proxy410.query(Unknown Source) ~[?:?]    at com.github.pagehelper.PageInterceptor.intercept(PageInterceptor.java:108) ~[pagehelper-5.1.11.jar:?]    at org.apache.ibatis.plugin.Plugin.invoke(Plugin.java:61) ~[mybatis-3.5.3.jar:3.5.3]    at com.sun.proxy.$Proxy410.query(Unknown Source) ~[?:?]    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:147) ~[mybatis-3.5.3.jar:3.5.3]    at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140) ~[mybatis-3.5.3.jar:3.5.3]    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:?]    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:?]    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:?]    at java.lang.reflect.Method.invoke(Method.java:566) ~[?:?]    at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427) ~[mybatis-spring-2.0.6.jar:2.0.6]    ... 95 more问题排查跟踪到报错的中央,发现是这个中央的schema是个null,从而引发了 NPE。 一路往上看代码,最终定位到了这个获取schema的中央,也就是元数据去getDefaultSchema获取默认的schema名称改的时候拿到了一个空值。 进入这个办法后发现通过schema去schemas这个map里获取名称的时候是个空值,debug到这个中央其实发现了问题。 咱们的schemaName配置的是orderTrade蕴含有大写字符的,所以name传进来的是orderTrade,然而问题是这个schemas确是ordertrade。 所以很显然,这里获取不到正确的schema名称,导致了这个 NPE 的异样,那么问题是这个schemas是怎么加载进来的呢? 咱们发现schemas是在创立元数据的时候,通过构造函数赋值的,那么只有找到这个赋值的中央应该就能发现问题了。 通过一番查找,找到了调用的中央,这个schemas值就是databaseMap中的value,那么咱们要持续看这个databaseMap是如何初始化来的。 持续看源码,找到了databaseMap进行初始化的中央,原来是通过DatabaseLoader去加载元数据的时候初始化的,那么这个load办法是怎么解决的呢? 从代码来看他蕴含了两局部的信息,第一个是咱们本人通过schema配置的一些分库分表的配置信息,另外一部分则是数据库默认的一些表的元数据,比方mysql、information_schema这些,那咱们只有看本人配置的那局部就能够了,也就是SchemaLoader.load(dataSourceMap, rules, props)办法。 看他实际上就是获取数据库是什么类型,比方mysql,而后去加载表的元数据,最初new进去ShardingSphereSchema,间接看最初的new局部代码就行了。 进入这个办法,霎时就水落石出了,原来在put的时候对所有的schemaName进行了小写解决,所以在最下面咱们去get的时候必定会拿到一个空值,最终导致merge的时候产生了 NPE 异样。 解决方案当初问题起因曾经发现了,那么该如何解决呢?总不能不让他人配置的时候不让写大写吧,本着能不能白嫖一个 PR 的想法,又去给 Sharding 提了一个 Issue。 就我点了根烟的功夫,回头就给我回复说新版本曾经修复了,心愿落空了,修复计划就是查问的时候也做小写解决了,好吧,那就这样吧。

January 10, 2023 · 1 min · jiezi

关于java:日志瘦身骚操作从-5G-优化到-1G牛逼

作者:明明如月学长\链接:https://juejin.cn/post/711704... 一、背景在日常开发中,通常为了不便调试、不便查问题,会打印很多 INFO 级别的日志。 随着访问量越来越大,一不小心,某个日志文件一天的 size 就大于了某个阈值(如 5G),于是,收到了优化日志大小的告警,肯定工夫内不优化反馈给你主管,囧... 日志过大容易导致一些运维操作耗费机器性能,如日志文件检索、数据采集、磁盘清理等。 那么,日志瘦身哪些常见的思路呢? 本文联合某个具体案例谈谈我的认识。 举荐一个开源收费的 Spring Boot 最全教程: https://github.com/javastacks/spring-boot-best-practice二、日志瘦身方法论 2.1 只打印必要的日志有时候为了不便测试,长期打印很多 INFO 级别日志。对于这种日志,等我的项目上线前,能够将非必要的日志删除或者调整为 DEBUG 级别。 但有些场景下有些日志可打印为 DEBUG 也可打印为 INFO,打印成 INFO 级别占空间,打印成 DEBUG 级别线上查问题的时候又须要用到,肿么办? 咱们能够对日志工具类进行革新,反对上下文传递某个开关时(失常调用没有这个开关,通过公司的 Tracer 或者 RPC上下文传递),能够长期将 DEBUG日志晋升为 INFO级别。 伪代码如下: if(log.isDebugEnable()){ log.debug(xxx);}else if(TracerUtils.openDebug2Info()){ log.info("【debug2info】"+xxx);}这样,能够将一些纠结是否要打印成 INFO 日志的 log 打印成 DEBUG 级别,查问题时主动晋升为INFO 日志。 为了防止误会,辨别 DEBUG 晋升 INFO 的日志和一般 INFO 日志,加上 相似【debug2info】 日志前缀。 当然,你也能够搞一些其余骚操作,这里只是举个例子,请自行触类旁通。 2.2 合并打印有些能够合并的日志,能够思考合并。 如在同一个办法前后都打印了 INFO 日志: INFO [64 位traceId] XXXService 执行前 size =10 INFO [64 位traceId] XXXService 执行后 size =4能够合并成一条: ...

January 10, 2023 · 2 min · jiezi

关于java:全网最全的权限系统设计方案

本文曾经收录到Github仓库,该仓库蕴含计算机根底、Java根底、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构、校招社招分享等外围知识点,欢送star~ Github地址:https://github.com/Tyson0314/... 明天和大家聊聊权限零碎设计常见的计划。 1、为什么须要权限治理日常工作中权限的问题时时刻刻随同着咱们,程序员新入职一家公司须要找人开明各种权限,比方网络连接的权限、编码下载提交的权限、监控平台登录的权限、经营平台查数据的权限等等。 在很多时候咱们会感觉这么多繁冗的申请给工作带来不便,并且如果忽然想要查一些数据,发现没有申请过权限,须要再走审批流程,工夫拉得会很长。那为什么还须要这么严格的权限治理呢? 举个例子,一家领取公司有经营后盾,经营后盾能够查到所有的商户信息,法人代表信息,交易信息以及费率配置信息,如果咱们把这些信息不加筛选都给到公司的每一个小伙伴,那么跑市场的都能够操作商家的费率信息,如果一个不小心把费率改了会造成微小的损失。 又比方商户的信息都是十分隐秘的,有些居心不良的小伙伴把这些信息拿进去卖给商家的竞争对手,会给商家造成重大的不良后果。尽管这么做都是个别人人为的过错,然而制度上如果自身这些信息不凋谢进去就能在很大水平上防止违法乱纪的事件产生了。 总体来讲权限治理是公司数据安全的重要保障,针对不同的岗位,不同的级别看到的数据是不一样的,操作数据的限度也是不一样的。比方波及到资金的信息只凋谢给财务的相干岗位,波及到配置的信息只凋谢给经营的相干岗位,这样各司其职能防止很多不必要的平安问题。 如何让各个岗位的人在零碎上各司其职,就是权限治理要解决的问题。2、权限模型2.1 权限设计从业务分类上来讲权限能够分为数据查看权限,数据批改权限等,对应到零碎设计中有页面权限、菜单权限、按钮权限等。菜单也分一级菜单、二级菜单甚至三级菜单,以csdn文章编辑页面左侧菜单栏为例是分了两级菜单。菜单对应的页面里又有很多按钮,咱们在设计的时候最好把权限设计成树形构造,这样在申请权限的时候就能够高深莫测的看到菜单的构造,须要哪些权限就十分的明了了。 如下图所示: 依照这个架构,按钮的父级是二级菜单,二级菜单的父级是一级菜单,这样用户申请权限的时候十分清晰的看到本人须要哪些权限。 2.2 为什么须要角色权限构造梳理清晰之后,须要思考怎么把权限调配给用户,用户少的状况下,能够间接调配,一个用户能够有多个权限,对立一个权限能够被多个用户领有,用户-权限的模型构造如下所示: 这种模型可能满足权限的根本调配能力,然而随着用户数量的增长,这种模型的弊病就凸显进去了,每一个用户都须要去调配权限,十分的节约管理员的工夫和精力,并且用户和权限芜杂的对应关系会给前期带来微小的保护老本。用户-权限对应关系图: 这种对应关系在用户多的状况下根本无奈保护了。其实很多用户负责同一个业务模块所须要的权限是一样的,这样的话咱们是不是能够借助第三个媒介,把须要雷同的权限都调配给这个媒介,而后用户和媒介关联起来,用户就领有了媒介的权限了。这就是经典的RBAC模型,其中媒介就是咱们通常所说的角色。 2.3 权限模型的演进2.3.1 RBAC模型有了角色之后能够把权限调配给角色,须要雷同权限的用户和角色对应起来就能够了,一个权限能够调配给多个角色,一个角色能够领有多个权限,同样一个用户能够调配多个角色,一个角色也能够对应多个用户,对应模型如下所示: 这就是经典的RBAC模型了(role-based-access-control),在这外面角色起到了桥梁左右,连贯了用户和权限的关系,每个角色能够领有多个权限,每个用户能够调配多个角色,这样用户就领有了多个角色的多个权限。 同时因为有角色作为媒介,大大降低了盘根错节的交互关系,比方一家有上万人的公司,角色可能只须要几百个就搞定了,因为很多用户须要的权限是一样的,调配一样的角色就能够了。这种模型的对应关系图如下所示: 用户和角色,角色和权限都是多对多的关系,这种模型是最通用的权限治理模型,节俭了很大的权限保护老本, 然而理论的业务变幻无穷,权限治理的模型也须要依据不同的业务模型适当的调整,比方一个公司外部的组织架构是分层级的,层级越高权限越大,因为层级高的人不仅要领有本人上司领有的权限,二期还要有一些额定的权限。 RBAC模型能够给不同层级的人调配不同的角色,层级高的对应角色的权限就多,这样的解决形式能够解决问题,然而有没有更好的解决办法呢,答案必定是有的,这就引出角色继承的RBAC模型。 2.3.2 角色继承的RBAC模型角色继承的RBAC模型又称RBAC1模型。每个公司都有本人的组织架构,比方公司里治理财务的人员有财务总监、财务主管、出纳员等,财务主管须要领有但不限于出纳员的权限,财务总监须要领有但不限于财务主管的权限,像这种治理关系向下兼容的模式就须要用到角色继承的RBAC模型。角色继承的RBAC模型的思路是下层角色继承上层角色的所有权限,并且能够额定领有其余权限。 模型如下所示: 从模型图中能够看出上级角色领有的权限,下级角色都领有,并且下级角色能够领有其余的权限。角色的层级关系能够分为两种,一种是上级角色只能领有一个下级角色,然而下级角色能够领有多个上级角色,这种构造用图形示意是一个树形构造,如下图所示: 还有一种关系是上级角色能够领有多个下级角色,下级角色也能够领有多个上级角色,这种构造用图形示意是一个有向无环图,如下图所示: 树形图是咱们比拟罕用的,因为一个用户个别状况下不会同时有多个直属下级,比方财务部只能有一个财务总监,然而能够有多个财务主管和收纳员。 2.3.3 带束缚的RBAC模型带束缚的RBAC模型又成RBAC2模型。在理论工作中,为了平安的思考会有很多约束条件,比方财务部里同一个人不能即是会计又是审核员,跟一个人同一时间不能即是运动员又是裁判员是一个情理的,又比方财务部的审核员不能超过2个,不能1个也没有。因为角色和权限是关联的,所以咱们做好角色的束缚就能够了。 常见的约束条件有:角色互斥、基数束缚、先决条件束缚等。角色互斥: 如果角色A和角色B是互斥关系的话,那么一个用户同一时间不能即领有角色A,又领有角色B,只能领有其中的一个角色。 比方咱们给一个用户赋予了会计的角色就不能同时再赋予审核员的角色,如果想领有审核员的角色就必须先去掉会计的角色。假如提交角色和审核角色是互质的,咱们能够用图形示意: 基数束缚: 同一个角色被调配的用户数量能够被限度,比方规定领有超级管理员角色的用户有且只有1个;用户被调配的角色数量也须要被限度,角色被调配的权限数量也能够被限度。 先决条件束缚:用户想被赋予下级角色,首先须要领有上级角色,比方技术负责人的角色和一般技术员工角色是上下级关系,那么用户想要用户技术负责人的角色就要先领有一般技术员工的角色。 2.4 用户划分2.4.1 用户组咱们创立角色是为了解决用户数量大的状况下,用户调配权限繁琐以及用户-权限关系保护老本高的问题。形象出一个角色,把须要一起操作的权限调配给这个角色,把角色赋予用户,用户就领有了角色上的权限,这样防止了一个个的给用户调配权限,节俭了大量的资源。 同样的如果有一批用户须要雷同的角色,咱们也须要一个个的给用户调配角色,比方一个公司的客服部门有500多集体,有一天研发部研发了一套查问后盾数据的产品,客服的小伙伴都须要应用,然而客服因为之前并没有对立的一个角色给到所有的客服小伙伴,这时候须要新加一个角色,把权限调配给该角色,而后再把角色一个个调配给客服人员,这时候会发现给500个用户一个个增加角色十分的麻烦。然而客服人员又有独特的属性,所以咱们能够创立一个用户组,所有的客服人员都属于客服用户组,把角色调配给客服用户组,这个用户组上面的所有用户就领有了须要的权限。 RBAC模型增加用户组之后的模型图如下所示: 很多敌人会问,用户组和角色有什么区别呢?简略的来说,用户组是一群用户的组合,而角色是用户和权限之间的桥梁。 用户组把雷同属性的用户组合起来,比方同一个我的项目的开发、产品、测试能够是一个用户组,同一个部门的雷同职位的员工能够是一个用户组, 一个用户组能够是一个职级,能够是一个部门,能够是一起做事件的来自不同岗位的人。 用户能够分组,权限也能够分组,权限特地多的状况下,能够把一个模块的权限组合起来成为一个权限组,权限组也是解决权限和角色对应关系简单的问题。 比方咱们定义权限的时候一级菜单、二级菜单、按钮都能够是权限,一个一级菜单上面有几十个二级菜单,每个二级菜单上面又有几十个按钮,这时候咱们把权限一个个调配给角色也是十分麻烦的,能够采纳分组的办法把权限分组,而后把分好的组赋予角色就能够了。 给权限分组也是个技术活,须要理分明权限之间的关系,比方领取的经营后盾咱们须要查各种信息,账务的数据、订单的数据、商户的数据等等,这些查问的数据并不在一个页面,每个页面也有很多按钮,咱们能够把这几个页面以及按钮对应的权限组合成一个权限组赋予角色。退出权限组之后的RBAC模型如下所示: 理论工作中咱们很少给权限分组,给用户分组的场景会多一些,有的时候用户组也能够间接和权限关联,这个看理论的业务场景是否须要,权限模型没有对立的,业务越简单业务模型会约多样化。 2.4.2 组织每个公司都有本人的组织架构,很多时候权限的调配能够依据组织架构来划分。因为同一个组织内的小伙伴应用的大部分权限是一样的。如下所示一个公司的组织架构图: 依照这个组织架构,每一个组织里的成员应用的根底权限很可能是一样的,比方人力资源都须要看到人才招聘的相干信息,市场推广都须要看到行业剖析的相干信息,依照组织来调配角色会有很多劣势: 实现权限调配的自动化: 和组织关系买通之后,依照组织来调配角色,如果有新入职的用户,被划分在某个组织上面之后,会主动获取该组织下所有的权限,无需人工调配。又比方有用户调岗,只须要把组织关系调整就能够了,权限会跟着组织关系主动调整,也无需人工干预。这么做首先须要把权限和组织关系买通。 控制数据权限: 把角色关联到组织,组织里的成员只能看到本组织下的数据,比方市场推广和大客定制,市场推广针对的是零散的客户,大可定制针对的是有肯定体量的客户,互相的数据尽管在一个平台,然而只能看本人组织下的数据。 退出组织之后的RBAC模型如下所示: ...

January 9, 2023 · 1 min · jiezi

关于java:12月更新2022亮点总结-Java-on-Visual-Studio-Code

大家好,一年的工夫过得很快,咱们曾经来到了2023年。回顾2022年,咱们的产品也经验了很多的迭代,在此之中,咱们有几个亮点想与大家分享! 2022年的亮点Spring Boot 插件的重大可视化体验降级从今年年初开始,咱们开始对 Spring Boot 插件进行一系列改良,旨在进步 Spring 开发者在 Visual Studio Code 上的工作效率。这包含 Bean 和 Endpoint Mapping 视图、Spring 应用程序的更多实时信息显示以及内存的可视化展现。咱们心愿这些改良能够让开发 Spring 应用程序变得更加容易,以及察看利用程序运行时的状态变得更加不便。 根底编码体验改良编码教训对开发者的日常效率至关重要。2022年,咱们进行了一系列重要改良,使 Java 开发者的编码生存比以往任何时候都更加轻松。这包含相似 IntelliJ IDEA 的后缀补全,更多生成代码片段的快捷方式,签名帮忙优化等等。根底体验将持续成为咱们将来的重点。 内置 Lombok 反对Project Lombok 是一个风行且宽泛应用的 Java 库,用于最小化或删除样板代码。从7月开始,咱们的 Java 插件能够间接反对应用 Lombok 的我的项目,而无需装置任何额定的插件。咱们还要感激@GabrielBB,他启动了最后的 Lombok 插件。您能够在这篇博文中找到如何启用 Lombok 反对。 200万 Java 开发者应用 Visual Studio Code11 月,咱们分享了 Visual Studio Code 上有 200 万 Java 开发者的音讯,这是一个重要的里程碑,咱们要感激社区的所有反对,谢谢! 除了2022的亮点之外,让咱们看看最新版本的新性能! 2022年12月更新Spring Boot – 实时内存视图作为本月更新的亮点,咱们引入了一个新的图形内存视图,作为 Spring Boot Dashboard 的最新成员。内存视图能够可视化正在运行的 Spring Boot 应用程序的内存和垃圾回收流动,与 Spring Boot Dashboard 的形式十分类似,它曾经为您提供了对运行 Spring Boot 应用程序(如 Bean 和 Endpoint Mapping)的观察力。 ...

January 9, 2023 · 1 min · jiezi

关于java:Apollo实现cron语句的热配置

GitHub我的项目地址 Gitee我的项目地址 Apollo(阿波罗)是携程框架部门研发的分布式配置核心,可能集中化治理利用不同环境、不同集群的配置,配置批改后可能实时推送到利用端,并且具备标准的权限、流程治理等个性,实用于微服务配置管理场景。 Apollo 与 properties 配置文件的性能雷同,都能够设置参数。Apollo 的长处在于,能够实时批改参数的值,而不须要重启我的项目。 1 配置 Apollo本地配置 Apollo 的形式参考: 2 增加 Apollo 参数在Apollo中增加参数: param.cron_test1=0/5 * * * * ?param.cron_test2=0/5 * * * * ?要实现 Apollo 对定时工作 cron 语句的热配置,须要应用ScheduledTaskRegistrar。 具体形式如下: @Override public void configureTasks(ScheduledTaskRegistrar taskRegistrar) { Runnable runnable = () -> { System.out.println("cron_test:" + cron_test); }; Trigger trigger = triggerContext -> { CronTrigger cronTrigger = new CronTrigger(cron_test); return cronTrigger.nextExecutionTime(triggerContext); }; taskRegistrar.addTriggerTask(runnable , trigger ); } @Override public int getOrder() { return 0; }残缺我的项目地址: ...

January 9, 2023 · 1 min · jiezi

关于java:Apollo本地快速部署

GitHub我的项目地址 Gitee我的项目地址 Apollo(阿波罗)是携程框架部门研发的分布式配置核心,可能集中化治理利用不同环境、不同集群的配置,配置批改后可能实时推送到利用端,并且具备标准的权限、流程治理等个性,实用于微服务配置管理场景。 Apollo 与 properties 配置文件的性能雷同,都能够设置参数。Apollo 的长处在于,能够实时批改参数的值,而不须要重启我的项目。 1 环境筹备须要 Java 1.8 及以上,MySQL 5.6 及以上的版本。 MySQL装置配置形式:https://mp.weixin.qq.com/s/IS... 如果只是本地测试的话,举荐应用 GitHub 上的开源我的项目 Apollo Quick Start; 安装包下载地址:https://pan.baidu.com/s/11dYV... 提取码:6666 2 SQL 导入下载并解压安装包 apollo-quick-start-2.0.1.zip,能够看到目录下有 sql 文件夹,外面有 apolloconfigdb.sql 和 apolloportaldb.sql 两个文件,须要将这两个文件导入 MySQL中。 关上 win 菜单中的 MySQL 8.0 Command Line Client - Unicode 命令, 运行: source D:\Apollo\apollo-quick-start-2.0.1\sql\apolloconfigdb.sqlsource D:\Apollo\apollo-quick-start-2.0.1\sql\apolloportaldb.sqlD:\Apollo 是我寄存 apollo-quick-start-2.0.1 文件夹的门路。 即可实现导入。 导入胜利后,能够通过执行以下sql语句来验证: select `NamespaceId`, `Key`, `Value`, `Comment` from ApolloConfigDB.Item;有以下输入,示意导入胜利。 3 启动 Apollo编辑 apollo-quick-start-2.0.1文件夹下的 demo.sh,批改 ApolloPortalDB 和 ApolloConfigDB 相干的数据库连贯配置信息。 ...

January 9, 2023 · 1 min · jiezi

关于java:到底什么样的-REST-才是最佳-REST

说起 REST API,小伙伴们多多少少都有据说过,然而如果让你具体介绍一下什么是 REST,预计会有很多人讲不进去,或者只讲进去其中一部分。 明天松哥就来和大家一起来聊一聊到底什么是 REST,顺便再来看下 Spring HATEOAS 的用法。 1. REST 成熟模型首先对于 REST,有一个大佬 Leonard Richardson 为 REST 定义了一个成熟度模型,他一共定义了四个不同的档次,别离如下: Level0:Web 服务单纯的应用 HTTP 作为数据传输方式,实质上就是近程办法调用,常见的 SOAP 和 RPC 基本上都属于这一类。Level1:在这一级别上,引入了资源的概念,服务端的每一个资源,都有一个对应的操作地址。Level2:在这一级别上,咱们引入了不同的 HTTP 申请办法来形容不同的操作,例如 GET 示意查问、POST 示意插入、PUT 示意更新、DELETE 示意删除,并且应用 HTTP 的状态码来示意不同的响应后果。一般来说,大家在日常的接口开发中,基本上都能做到这一层级。然而这还不是最佳后果。Level3:依照 Leonard Richardson 的意思,这一层级的 REST 基于 HATEOAS(Hypertext As The Engine Of Application State),在这一级别上,除了返回资源的 JSON 之外,还会额定返回一组 Link,这组 Link 形容了对于该资源能够做哪些操作,以及具体的该怎么做。在日常的开发中,咱们个别都是只实现到 Level2 这一层级,真正做到 Level3 的预计很少,不过尽管在工作中个别不会做到 Level3 这一层级,然而,我置信很多小伙伴应该是见过 Level3 层级的 REST 是啥样子的,特地是看过 vhr 视频的小伙伴,松哥在其中讲过,通过 Spring Data Jpa+Spring Rest Repositories 实现的 CURD 接口,其实就是一个达到了 Level3 层级的 REST。 ...

January 9, 2023 · 3 min · jiezi

关于java:dubbo-SPI-实现详解

咱们晓得 dubbo 的扩展性十分强,扩大点十分多,这些扩大都是靠 SPI 来加载的,然而dubbo并没有应用规范的SPI而是抉择了本人实现,这又是为什么呢? JDK SPI机制jdk的SPI设计是为了能够面向接口编程,使第三方能够更好的对接口进行扩大实现,而应用方无需指定实现类,合乎软件设计的可插拔准则,典型的应用场景如 jdbc,咱们晓得在应用数据库时咱们只须要将对应数据库的驱动包引入即可,无需额定编码,用过 SLF4J 的同学必定也晓得我的项目中放一个实现了 SLF4J 的对应接口的实现就能够间接应用了,无需编码指定具体实现类,这就是 SPI 的功绩。但很多组件都没有基于原始的 SPI 做扩大而是抉择在 SPI 的原理根底上本人实现,起因是 JDK 原生的 SPI 有一些局限性。 JDK的SPI实现有以下问题: 会默认实例化所有扩大,不能按需加载,如果扩大多而且大多数又用不到甚至某些还比拟消耗资源或者加载比较慢就会白白浪费资源浪费时间获取扩大时只能通过iterator的形式获取扩大,不能用key获取,查找时不太不便扩大加载失败时提示信息不敌对,甚至找不到是哪个扩大加载失败了dubbo SPI机制dubbo官网也写了其 SPI的实现机制,总结下能够失去如下信息: dubbo 的 SPI 是按需加载,不会初始化所有扩大类每个扩大能够有一个名字,加载失败时能够依据名字找到具体的加载失败扩展名,获取扩大时也能依据名称获取,方便使用减少了对扩大点 IoC 和 AOP 的反对,一个扩大实现能够通过setter注入到其余扩大实现,还有 Wrapper 实现会主动包装最终实现类,且会主动通过结构器注入理论实现类,ExtensionLoader 在加载扩大点时,如果加载到的扩大点有拷贝构造函数,则断定为扩大点 Wrapper 类。动静扩大自适应、主动激活机制,即被注解 @Adaptive 的办法会依据注解中的key运行时适配其实现类,主动激活是指被 @Activate 标记的实现类反对自定义加载条件dubbo 的许多模块都和 SPI 密切相关,了解 dubbo 的 SPI 实现机制对浏览 dubbo 源码会有很大助益;上面从一些外围注解和类逐个进行解说。 注解 @SPI这个注解用在接口类上,示意其是一个可扩大类,dubbo 的 SPI 实现会在获取扩大实现是查看接口类是否带有该注解,否则报错;该注解反对设定默认扩大名称,如 dubbo 的 Protocol 接口指定了 dubbo 为其默认实现类,那 dubbo 这个 key又是怎么来的呢,咱们来看看 dubbo 扩大的配置格局,在 DubboProtocol 类的模块下 META-INF/dubbo/internal 目录中有一个 com.alibaba.dubbo.rpc.Protocol 文件,他是以扩大实现的接口名命名的 ,文件中的内容为 dubbo=com.alibaba.dubbo.rpc.protocol.dubbo.DubboProtocol,能够看到它是一个 key=value 的格局,dubbo 这个key即代表了value这个实现类。 ...

January 9, 2023 · 5 min · jiezi

关于java:Spring-Boot-30横空出世快来看看是不是该升级了

简介Spring boot 3.0于2022年11月正式公布了,这次的公布对于咱们一般程序员的影响有多少呢?咱们是不是须要思考立马降级到Spring Boot3.0呢? 别急,看完这篇文章再来做决定也不迟。 对JAVA17和JAVA19的反对置信很多小伙伴到当初还是应用得是JDK8,然而JDK8曾经公布很多年了,随着oracle减速JDK版本的公布,当初每半年公布一次,目前最新的JDK版本曾经到了19了。其中JDK11和JDK17是LTS版本,也就是说咱们常说的稳固版本。 鉴于JDK17带来的很多新个性,Spring boot的最低JDK版本反对曾经晋升到了JDK17,如果你还在应用JDK8或者JDK11的话,那么首先须要把JDK版本升级到17才可能应用Spring Boot 3.0。 很多小伙伴可能不是很分明JDK17到底有些什么新的个性或者性能,这里再给大家具体介绍一下。 record首先是在JDK14的时候引入了record这个关键词,Record是一种轻量级的class,能够看做是数据结构体。和scala中的case有点类似。 举个自定义User的例子看一下Record是怎么用的: public record Address( String addressName, String city) {}public record CustUser( String firstName, String lastName, Address address, int age) {}下面咱们定义了两个类,CustUser和Address。CustUser中援用了Address。 Record和一般的类的区别就在于Record多了一个括号括起来的定义的字段。 Record类默认是final的,外面的字段默认是private final的。 要想晓得Record到底是怎么工作的,咱们能够应用javap来对编译好的class文件反编译,运行javap CustUser,能够失去上面的后果: 正告: 二进制文件CustUser蕴含com.flydean.records.CustUserCompiled from "CustUser.java"public final class com.flydean.records.CustUser extends java.lang.Record { public com.flydean.records.CustUser(java.lang.String, java.lang.String, com.flydean.records.Address, int); public java.lang.String toString(); public final int hashCode(); public final boolean equals(java.lang.Object); public java.lang.String firstName(); public java.lang.String lastName(); public com.flydean.records.Address address(); public int age();}下面能够看到final class CustUser继承自java.lang.Record。 ...

January 9, 2023 · 4 min · jiezi

关于java:成功上岸字节全靠这份Redis技术笔记深入浅出值得一看

前言正如题目所说,我当初曾经如愿以偿地进了字节!之前本人始终待在一个不大不小的外包公司,每天做着反复的层删改查工作。直到22年年底,本人通过敌人的介绍拿到了字节的面试机会,本人在家温习了3个月,胜利地拿到了字节的offer,其中复习资料对我最要害的就是这份Redis技术笔记,让我举一反三,对我的技术出息十分大的帮忙!当初我怀着帮忙别人的想法将这份笔记收费分享给大家! 下文内容波及到:面试题(含答案)+学习笔记+电子书籍+学习视频,收费打包分享,【间接点击此处】即可获取。Redis笔记介绍Redis作为同时具备高性能、高牢靠和高可扩展性的典型键值数据库,Redis不仅功能强大,而且稳固,天经地义地成为了大型互联网公司的首选。 泛滥大厂在招聘的时候,不仅会要求面试者能简略地应用Redis,还要能深刻地了解底层实现原理,并且具备解决常见问题的能力。能够说,熟练掌握Redis曾经成为了技术人的一个必备技能。 然而,在学习和应用Redis的过程中,总不可避免地遇见一些辣手的问题,比方: Redis的key和数据结构应该怎么设计?有什么最佳实际办法? Redis集群如何平衡数据?又如何横向扩大? 怎么保证数据的一致性?热点数据的问题怎么解决? RDB长久化生成的数据快照,每次更新是全量更新还是增量更新? 缓存雪崩、缓存穿透、缓存预热、缓存更新、缓存降级等问题怎么解决?* 如何高效浏览Redis源代码?这份笔记梳理了一套零碎的Redis学习办法。将纷繁复杂的Redis常识和问题演绎在“两大维度,三大主线”这个框架之中,心愿帮你建设起零碎观和全局观,从而带你彻底搞懂底层实现原理。除此之外,笔记还会具体解说常见的问题以及应答计划,解说Redis在典型场景(比方缓存、秒杀)中的利用,让你可能疾速把握卓有成效的实战经验,并利用在本人的Redis实战我的项目当中,全方位晋升你的技术! Redis笔记模块本份笔记深入浅出地介绍了 Redis 的 5 种数据类型,并通过多个实用示例展现了 Redis 的用法。除此之外,笔记中还讲述了 Redis 的优化办法以及扩大办法,是一份对于学习和应用 Redis 来说不可多得的参考书籍。 笔记一共由三个局部组成。第一局部对 Redis 迚行了介绍,阐明了 Redis 的根本应用办法、它领有的 5 种数据结构以及操作这 5 种数据结构的命令,并解说了如何应用 Redis 去构建文章聚合网站、cookie、购物车、网页缓存、数据库行缓存等一系列程序。 第二局部对 Redis 命令迚行了更具体的介绍,并展现了如何应用 Redis 去构建更为简单的辅助工具和应用程序,并在最初展现了如何应用 Redis 去构建一个简略的社交网站。 第三局部对 Redis 用户常常会遇到的一些问题迚行了介绍,解说了升高 Redis 内存占用的办法、扩大 Redis 性能的办法以及应用 Lua 语言迚行脚本编程的办法。 笔记既涵盖了命令用法等入门主题,也蕴含了复制、集群、性能扩大等深刻主题,所以无论是 Redis 老手还是有肯定教训的 Redis 使用者,应该都能从笔记获益。 笔记内容过长,不能一一展现进去,当初筛选重要局部展现!下文内容波及到:面试题(含答案)+学习笔记+电子书籍+学习视频,收费打包分享,【间接点击此处】即可获取。 笔记第一局部:意识Redis 笔记第二局部:Redis外围概念 笔记第三局部:Redis命令手册 笔记第四局部:Redis应用Redis构建反对程序 笔记第五局部:Redis进阶实战教程 笔记第六局部:应用Redis搭建应用程序组件 笔记第七局部:利用Redis搭建社交网站 笔记内容详解笔记大略总结会是从构建一个键值数据库的要害架构动手,不仅带你建设起全局观,还帮你迅速抓住外围主线。除此之外,还会具体解说数据结构、线程模型、网络框架、长久化、主从同步和切片集群等,帮你搞懂底层原理。 重点从典型案例和罕用场景两个维度介绍Redis的实战经验。在“案例”层面,会具体解说数据结构的正当应用、防止申请阻塞和抖动、晋升内存应用效率的要害技巧;在“场景”层面,会针对缓存和集群两大场景,透彻解说缓存的基本原理,以及雪崩、穿透、净化等异常情况的应答计划,还会围绕集群计划优化、数据一致性、高并发拜访等问题,分享具体可行的解决方案。 如何取得这份优质的笔记在此作者在此郑重承诺,此笔记100%收费赠送给大家,倡议大家利用碎片工夫进行系统性的学习。拿到此份笔记不论是用来突击面试,还是查漏补缺,置信对大家的工作都是极大的助力! 情谊分享:文章码字不容易,心愿多多点赞+转发+评论反对一波。 须要文章中提到的面试题、笔记、电子书、学习视频,能够关注我,而后【间接点击此处】即可收费获取哦。

January 9, 2023 · 1 min · jiezi

关于java:虽然是我遇到的一个棘手的生产问题但是我写出来之后就是你的了

你好呀,是歪歪。 前几天,就在大家还沉迷在期待春节到来的喜悦气氛的时候,在一个外围链路上的外围零碎中,我踩到一个坑的一比的坑,要不是我从容沉着,解决思路忙中有序,解决伎俩雷厉风行,把它给扼杀在萌芽阶段了,那这玩意必定得引发一个比较严重的生产问题。 从问题呈现到定位到这个问题的根本原因,我大略是花了两天半的工夫。 所以写篇文章给大家复盘一下啊,这个案例就是一个纯技术的问题导致的,和业务的相关度其实并不大,所以你拿过来间接添枝加叶,略微改改,往本人的服务上套一下,那就是你的了。 我再说一次:尽管当初不是你的,然而你看完之后就是你的了,你明确我意思吧? 表象事件是这样的,我这边有一个服务,你能够把这个服务粗犷的了解为是一个商城一样的服务。有商城必定就有下单嘛。 而后接到上游服务反馈,说调用下单接口偶然有调用超时的状况呈现,断断续续的呈现好几次了,给了几笔流水号,让我看一下啥状况。过后我的第一反馈是不可能是我这边服务的问题,因为这个服务上次上线都至多是一个多月前的事件了,所以不可能是因为近期服务投产导致的。 然而下单接口,你听名字就晓得了,外围链接上的外围性能,不能有一点麻痹大意。 每一个申请都很重要,客户下单体验不好,可能就不买了,造成交易损失。 交易上不去营业额就上不去,营业额上不去利润就上不去,利润上不去年初就上不去。 想到这一层关系之后,我立马就登陆到服务器上,开始定位问题。 一看日志,的确是我这边接口申请解决慢了,导致的调用方超时。 为什么会慢呢? 于是依照惯例思路先依据日志判断了一下下单接口中调用其余服务的接口相应是否失常,从数据库获取数据的工夫是否失常。 这些判断没问题之后,我转而把眼光放到了 gc 上,通过监控发现那个工夫点触发了一次耗时靠近 1s 的 full gc,导致响应慢了。 因为咱们监控只采集服务近一周的 gc 数据,所以我把工夫拉长后发现 full gc 在这一周的工夫内呈现的频率还有点高,尽管我还没定位到问题的根本原因,然而我定位到了问题的外表起因,就是触发了 full gc。 因为是外围链路,外围流程,所以此时不应该急着去定位根本原因,而是先缓解问题。 好在咱们提前准备了各种起因的应急预案,其中就蕴含这个场景。预案的内容就是扩充利用堆内存,延缓 full gc 的呈现。 所以我当即进行操作报备并分割运维,依照紧急预案执行,把服务的堆内存由 8G 扩充一倍,晋升到 16G。 尽管这个办法简略粗犷,然而既解决了以后的调用超时的问题,也给了我足够的排查问题的工夫。 定位起因过后我其实一点都不慌的,因为问题在萌芽阶段的时候我就把它给干掉了。 不就是 full gc 吗,哦,我的老朋友。 先大胆假如一波:程序外面某个逻辑不小心搞出了大对象,触发了 full gc。 所以我先是双手插兜,带着监控图和日志申请,闲庭信步的走进我的项目代码外面,想要凭借肉眼找出一点蛛丝马迹...... 没有任何播种,因为下单服务波及到的逻辑真的是太多了,服务外面 List 和 Map 随处可见,我很难找到到底哪里是大对象。 然而我还是一点都不慌,因为这半天都没有再次发生 Full GC,阐明此时留给我的工夫还是比拟短缺的, 所以我申请了场外支援,让 DBA 帮我导出一下服务的慢查问 SQL,因为我想可能是从数据库外面一次性取的数据太多了,而程序外面也没有做管制导致的。 我之前就踩过相似的坑。 一个依据客户号查问客户有多少订单的外部应用接口,接口的返回是 List<订单>,看起来没啥故障,对不对? 一般来说一个集体客户就几十上百,多一点的上千,顶天了的上万个订单,一次性拿进去也不是不能够。 ...

January 9, 2023 · 4 min · jiezi

关于java:面试官数据库日期类型字段需要兼容不同数据库应该如何选择

作者:sp42a\起源:https://zhangxin.blog.csdn.ne... 当设计一个产品,其中很多中央要把日期类型保留到数据库中,如果产品有兼容不同数据库产品的需要,那么,该当怎么设计呢? 当然,首先想到的是,应用数据库的 Date 或 DateTime 类型,可是看看不同数据库这些类型间的区别吧,真让人望而止步。 MySQL 数据库: 它们别离是 date、datetime、time、timestamp 和 year。 date :“yyyy-mm-dd”格局示意的日期值time :“hh:mm:ss”格局示意的工夫值datetime:“yyyy-mm-dd hh:mm:ss”格局timestamp:“yyyymmddhhmmss”格局示意的工夫戳值year:“yyyy”格局的年份值。范畴: date “1000-01-01” 到 “9999-12-31” 3字节time “-838:59:59” 到 “838:59:59” 3字节datetime “1000-01-01 00:00:00” 到 “9999-12-31 23:59:59” 8字节timestamp 19700101000000 到 2037 年的某个时刻 4字节year 1901 到 2155 1 字节Oracle 数据库: Date 类型的外部编码为12 长度:占用7个字节 数据存储的每一位到第七位别离为:世纪,年,月,日,时,分,秒 TIMESTAMP是反对小数秒和时区的日期/工夫类型。对秒的精确度更高 TIMESTAMP WITH TIME ZONE 类型是 TIMESTAMP 的子类型,减少了时区反对,占用13字节的存储空间,最初两位用于保留时区信息 INTERVAL 用于示意一段时间或一个工夫距离的办法。在后面有屡次提过。INTERVAL有两种类型. YEAR TO MONTH 能存储年或月指定的一个时间段.DATE TO SECOND 存储天,小时,分钟,秒指定的时间段.sql server: datetime 和 smalldatetime datetime数据类型所占用的存储空间为8个字节,其中前4个字节用于存储1900年1月1日以前或当前的天数,数值分正负,负数示意在此日期之后的日期,正数示意在此日期之前的日期;后4个字节用于存储从此日零时起所指定的工夫通过的毫秒数。smalldatetime数据类型应用4个字节存储数据。其中前2个字节存储从根底日期1900年1月1日以来的天数,后两个字节存储此日零时起所指定的工夫通过的分钟数。smalldatetime数据类型与datetime数据类型类似,但其日期工夫范畴较小,从1900年1月1日到2079年6月6日。此数据类型精度较低,只能准确到分钟,其分钟个位为依据秒数四舍五入的值,即以30秒为界四舍五入。如果没有兼容多种数据库这个要求,我会毫不犹豫的应用数据库的 Date 类型。因为如果应用 Java 框架产生代码,对数据库中定义为 Date 类型的字段,甚至能在页面上产生出JS的工夫抉择框,确实能节俭很多开发工夫。而兼容不同数据库,就心愿产品在由一种数据库,迁徙到另外一种数据库时,尽可能小的代价,应用了 Date,看来就很艰难了。 ...

January 9, 2023 · 1 min · jiezi

关于java:Mybatis自动生成增删改查代码

GitHub我的项目地址 Gitee我的项目地址 应用 mybatis generator 主动生成代码,实现数据库的增删改查。 1 配置Mybatis插件在pom文件增加依赖: <plugins><plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.3.4</version> <configuration> <configurationFile>${basedir}/src/main/resources/mybatis-generator.xml</configurationFile> <overwrite>true</overwrite> <verbose>true</verbose> </configuration> <dependencies> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.46</version> </dependency> </dependencies></plugin></plugins>更新依赖胜利后,能够在maven中看到曾经有了mybatis插件 2 创立库表在数据库创建表格,具体形式见:https://mp.weixin.qq.com/s/IS... 3 配置参数src/main/resources/mybatis-generator.xml : <?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd" ><generatorConfiguration> <context id="context" targetRuntime="MyBatis3"> <!-- 去除主动生成正文 --> <commentGenerator> <property name="suppressAllComments" value="true"/> <property name="suppressDate" value="true"/> </commentGenerator> <!-- 数据库的相干配置 --> <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://localhost:3306/sys" userId="root" password="root"/> <javaTypeResolver> <property name="forceBigDecimals" value="false"/> </javaTypeResolver> <!-- 实体类生成的地位 --> <javaModelGenerator targetPackage="com.spring.boot.dao.model" targetProject="src/main/java"> <property name="enableSubPackages" value="false"/> <property name="trimStrings" value="true"/> </javaModelGenerator> <!-- *Mapper.xml 文件的地位 --> <sqlMapGenerator targetPackage="mapper" targetProject=".\src\main\resources"> <property name="enableSubPackages" value="false"/> </sqlMapGenerator> <!-- Mapper 接口文件的地位 --> <javaClientGenerator targetPackage="com.spring.boot.dao" targetProject="src/main/java" type="XMLMAPPER"> <property name="enableSubPackages" value="false"/> </javaClientGenerator> <!-- 相干表的配置 --> <table tableName="user_data" domainObjectName="UserDataPo" enableCountByExample="false" enableDeleteByExample="false" enableSelectByExample="false" enableUpdateByExample="false"/> </context></generatorConfiguration>4 运行插件双击 mybatis-generator:generate,运行插件。 ...

January 9, 2023 · 1 min · jiezi

关于java:POI-中-getPhysicalNumberOfCells-与-getLastCellNum-有什么区别

POI是Apache的开源Java库,它用于读写Microsoft Office文件格式。它蕴含一个类叫做Sheet,用于示意Excel工作表中的数据。 getPhysicalNumberOfCells办法返回工作表中理论蕴含数据的单元格数量。这意味着,如果有空单元格,则它们不计入内。getLastCellNum办法返回工作表中最初一个单元格的编号。这包含所有单元格,包含空单元格。例如,假如你有一个工作表,其中有5列,其中列2和列4没有数据。 在这种状况下,getPhysicalNumberOfCells办法将返回3,因为只有3个单元格蕴含数据。getLastCellNum办法将返回5,因为工作表中最初一个单元格的编号是5。 总之,getPhysicalNumberOfCells办法次要用于获取工作表中理论蕴含数据的单元格数量,而getLastCellNum办法用于获取工作表中最初一个单元格的编号。

January 9, 2023 · 1 min · jiezi

关于java:单体的-TienChin-和微服务的-TienChin-有何异同

有不少小伙伴心愿松哥能整一个微服务的实战我的项目,微服务这块技术点其实松哥是讲过很多了,图文版的教程视频版的教程都有,不过的确不足一个我的项目,所以我在想等 TienChin 我的项目搞完之后,和小伙伴们也来一起搞一个微服务的我的项目。 明天我想从架构的角度来和小伙伴们聊一聊微服务。不聊具体的技术点,就单纯来看看一个微服务项目该怎么设计。 1. 单体版 TienChin松哥目前在录的 TienChin 我的项目就是一个前后端拆散的单体我的项目,采纳了 Spring Boot + Vue3。那么单体版的 TienChin 具备什么样的特色呢?我从长处和毛病两个方面来和大家剖析。 先来看一张简略的架构图: 能够看到,尽管是单体我的项目,然而为了开发不便,我的项目也细分为许多不同的模块,我的项目中的适配器能够分为两大类: 入站适配器:就是内部零碎来调用咱们的零碎,REST API 和 Vue 网页都算是入站适配器,内部零碎通过这两个接口来调用咱们的零碎。出站适配器:这个次要是咱们零碎外部调用内部零碎的形式,例如咱们的我的项目中须要用到 MySQL、Redis等,那么就通过出站适配器来实现。1.1 长处开发简略:轻易一个 IDE,撸起袖子就能够开写了。测试简略:我的项目启动之后,间接利用 POSTMAN 等工具就能够测试项目接口了。部署简略:我的项目开发实现之后,打包成一个 jar 或者一个 war,间接部署就行了。横向扩大简略:当我的项目并发能力有余的时候,能够不便的联合 Nginx 等负载平衡工具进行横向扩大。能够看到,单体我的项目的劣势整体上来说还是非常明显的。 1.2 毛病然而毛病也是非常明显的。 我的项目越来越简单首先就是我的项目不可能始终这么简略,咱们这个我的项目中还是细分了很多不同的模块。随着工夫的推移,这些模块会变得越来愈简单。批改每一个 BUG 都要小心翼翼,牵一发而动全身。并且随着项目组中人员的到职/入职,新接手的人会让这个我的项目更加简单,每一次 BUG 的修复或者新性能的增加,都会让这个我的项目变得更加“不可捉摸”。 开发进度越来越不可控因为零碎越来越简单,咱们不得不增派人手参加到这个我的项目的开发中,以期推动我的项目进度。这么多人的协调又是一个问题。并且,随着我的项目越来越大,每一次编译运行都得数分钟、十几分钟甚至更久,这也会重大拖慢咱们的我的项目进度。 发版周期过长单体我的项目发版很多小伙伴可能都刻骨铭心,发版当天如临大敌,所有人都加班,等我的项目上线运行都没问题,各项数据都 OK,此时可能曾经凌晨三四点了,所有人拖着疲乏的身材上班。正是因为每一次发版都是一个小事,所以个别单体我的项目不太会频繁发版(我说的频繁是指如一天一版这种),发版周期广泛比拟长。 难以扩大当零碎不同模块对资源的需要不同的时候,咱们想做针对性的硬件扩大也并不不便。 举个简略例子,有一个模块须要进行大量的运算,咱们心愿能为之提供更好的 CPU;有一个模块须要更大的内存,咱们须要扩大更大的内存。 然而因为所有的模块都打包在一起,咱们只能针对以后服务器做各种硬件降级,无奈针对某一个模块做专门的硬件降级。 过期的技术栈不易更新我置信很多小伙伴见到的单体我的项目还有一个特点就是技术栈广泛比拟老旧。这也是因为单体我的项目工夫久了之后,积重难返,想要对根底框架做版本升级往往牵一发而动全身,更别提从传统的 SSM 切换到 Spring Boot 上这种超级繁琐的工作了。因而大部分的单体我的项目,在立项的那一刻选用了什么技术栈、选用了技术的哪个版本,基本上这个我的项目将来都是这个版本了。 从下面的介绍中小伙伴们能够看到,单体我的项目长处很显著,然而毛病也是非常明显的。而这些毛病,都能够通过微服务来解决。 2. 微服务版 TienChin如果 TienChin 我的项目是微服务版呢?咱们来看一张简略的架构图。 简略画了张图,我来解释下: 首先咱们基本上是依照业务来划分服务的。每一个服务都有本人独立的数据库,本人操作本人的库。假如在线索治理中,须要调用商机治理,那不能间接操作商机的数据库,必须去调用商机治理服务中提供的 REST API,通过这个 REST API 来操作库。所有的服务有一个对立的入口 Gateway,如果前端是手机 App 或者小程序之类的,通过 Gateway 来拜访到零碎。有一个后盾治理的 Web UI 我的项目,提供相应的网页操作。大抵上就是这个样子。 ...

January 8, 2023 · 1 min · jiezi

关于java:分布式高并发系统防御限流

分布式高并发零碎常见的用来爱护零碎的三把利器:缓存、降级、限流。有天深夜发现公司的点评后盾零碎数据库cpu打到96%以上,排查发现是有人应用脚本歹意拜访咱们的零碎。失常状况下,调用量每秒1次左右,然而依据监控零碎发现歹意申请拜访的接口每秒调用20次左右,并且调用的接口是慢接口,导致cpu应用飙升。 为了爱护零碎,除了缓存和降级外,咱们采纳限流来针对这种歹意申请做限度,保障失常用户的应用,抵挡歹意申请。 限流什么是限流呢?限流是限度达到零碎的并发申请数量,保证系统可能失常响应局部用户申请,而对于超过限度的流量,则通过拒绝服务的形式保障整体零碎的可用性。依据限流作用范畴,能够分为单机限流和分布式限流;依据限流形式,又分为计数器、滑动窗口、漏桶限令牌桶限流计数器计数器是一种最简略限流算法,其原理就是:在一段时间距离内,对申请进行计数,与阀值进行比拟判断是否须要限流,一旦到了工夫临界点,将计数器清零。比方在1秒钟内对申请限度为50次限流逻辑:1.在程序中设置一个变量 count,当来一个申请我就将这个数 +1,同时记录申请工夫。2.当下一个申请来的时候判断 count 的计数值是否超过设定的频次50,以及以后申请的工夫和第一次申请工夫是否在 1 秒钟内。3.如果在 1 秒钟内并且超过设定的频次则证实申请过多,前面的申请就回绝掉。4.如果该申请与第一个申请的间隔时间大于计数周期,且 count 值还在限流范畴内,就重置 count。有余:边界状况解决,假如有个用户在第 1秒内的最初几毫秒霎时发送 40 个申请,当 1 秒完结后 counter 清零了,他在下一秒的前几毫秒时候又发送 40个申请。相当于在间断的1秒内不止发送了50个申请,然而咱们的限流没限制住。滑动窗口滑动窗口是针对计数器存在的临界点缺点,所谓滑动窗口(Sliding window)是一种流量控制技术,这个词呈现在 TCP 协定中。滑动窗口把固定工夫片进行划分,并且随着工夫的流逝,进行挪动,固定数量的能够挪动的格子,进行计数并判断阀值。限流逻辑:1.其实计数器就是滑动窗口,只不过只有一个窗格而已。2.想让限流做的更准确只须要划分更多的窗格就能够了,为了更准确咱们也不晓得到底该设置多少个格子。3.格子的数量影响着滑动窗口算法的精度,仍然有工夫片的概念,无奈基本解决临界点问题。有余:无奈基本解决临界点问题。漏桶漏桶算法(Leaky Bucket),原理就是一个固定容量的漏桶,依照固定速率流出水滴。用过水龙头都晓得,关上龙头开关水就会流下滴到水桶里,而漏桶指的是水桶上面有个破绽能够出水,如果水龙头开的特地大那么水流速就会过大,这样就可能导致水桶的水满了而后溢出。 漏桶算法有以下特点::1.漏桶具备固定容量,出水速率是固定常量(流出申请)2.如果桶是空的,则不需流出水滴3.能够以任意速率流入水滴到漏桶(流入申请)4.如果流入水滴超出了桶的容量,则流入的水滴溢出(新申请被回绝)有余:漏桶限度的是常量流出速率(即流出速率是一个固定常量值),所以最大的速率就是出水的速率,不能呈现突发流量。令牌桶令牌桶算法(Token Bucket)是网络流量整形(Traffic Shaping)和速率限度(Rate Limiting)中最常应用的一种算法。典型状况下,令牌桶算法用来管制发送到网络上的数据的数目,并容许突发数据的发送。漏桶算法有以下特点::1.令牌按固定的速率被放入令牌桶中2.桶中最多寄存 B 个令牌,当桶满时,新增加的令牌被抛弃或回绝3.如果桶中的令牌有余 N 个,则不会删除令牌,且申请将被限流(抛弃或阻塞期待)咱们有一个固定的桶,桶里寄存着令牌(token)。一开始桶是空的,零碎按固定的工夫(rate)往桶里增加令牌,直到桶里的令牌数满,多余的申请会被抛弃。当申请来的时候,从桶里移除一个令牌,如果桶是空的则拒绝请求或者阻塞。容许肯定水平突发流量,是比拟好的限流算法实现下面介绍了限流算法,上面介绍几种常见限流算法的应用基于redis的计数器限流定义限流注解@Inherited@Documented@Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface AccessLimit { /** * 指定工夫范畴 申请次数 */ int maxCount() default 50; /** * 申请次数的指定工夫范畴 秒数(redis数据过期工夫) */ int second() default 1;}限流切面@Slf4j@Aspect@Componentpublic class AccessLimitAspect { @ApolloJsonValue("${app.service.limit.teacherId:[]}") private List<String> teacherIds; @Autowired private RedissonClient redissonClient; @Autowired private HttpServletRequest httpServletRequest; @SneakyThrows @Around("@annotation(accessLimit)") public Object doLimit(ProceedingJoinPoint proceedingJoinPoint, AccessLimit accessLimit) { String employeeId = httpServletRequest.getHeader("employeeId"); log.info("employeeId:{}", employeeId); Assert.notNull(employeeId, "employeeId must not be null!"); if (teacherIds.contains(employeeId)) { log.info("request limit start, employeeId {}", employeeId); // 获取注解内容信息 int seconds = accessLimit.second(); int maxCount = accessLimit.maxCount(); // 存储key String key = employeeId; // 曾经拜访的次数 Integer count = redissonClient.get(key); log.info("曾经拜访的次数:{}", count); if (null == count || -1 == count) { redissonClient.set(key, 1, seconds, TimeUnit.SECONDS); } if (count < maxCount) { redissonClient.increment(key); } if (count >= maxCount) { log.warn("申请过于频繁请稍后再试"); return null; } log.info("request limit end, employeeId {}", employeeId); } return proceedingJoinPoint.proceed(); }}基于redis的令牌桶限流定义限流注解@Inherited@Documented@Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})@Retention(RetentionPolicy.RUNTIME)public @interface AccessLimit {}限流切面@Slf4j@Aspect@Componentpublic class AccessLimitAspect { @ApolloJsonValue("${app.service.limit.teacherId:[]}") private List<String> teacherIds; @Autowired private RedissonClient redissonClient; @Autowired private HttpServletRequest httpServletRequest; @SneakyThrows @Around("@annotation(accessLimit)") public Object doLimit(ProceedingJoinPoint proceedingJoinPoint, AccessLimit accessLimit) { String employeeId = httpServletRequest.getHeader("employeeId"); log.info("employeeId:{}", employeeId); Assert.notNull(employeeId, "employeeId must not be null!"); if (teacherIds.contains(employeeId)) { log.info("request limit start, employeeId {}", employeeId); //应用redisson限流器,每秒限度50次申请 RRateLimiter limiter = redissonClient.getRateLimiter("limit_teacher"); limiter.trySetRate(RateType.OVERALL, 50, 1, RateIntervalUnit.SECONDS); limiter.acquire(); log.info("request limit end, employeeId {}", employeeId); } return proceedingJoinPoint.proceed(); } @Around("@within(cn.tinman.clouds.jojoread.admin.limit.AccessLimit)") public Object limit(ProceedingJoinPoint joinPoint) { MethodSignature signature = (MethodSignature) joinPoint.getSignature(); //办法上的降级注解优先于类上的 AccessLimit limit = AnnotationUtils.findAnnotation(signature.getMethod(), AccessLimit.class); if (Objects.isNull(limit)) { limit = AnnotationUtils.findAnnotation(joinPoint.getTarget().getClass(), AccessLimit.class); } Assert.notNull(limit, "@AccessLimit must not be null!"); return doLimit(joinPoint, limit); }}基于Guava 的令牌桶限流(单机)限度 QPS 为 2,也就是每隔 500ms 生成一个令牌RateLimiter rateLimiter = RateLimiter.create(2);for (int i = 0; i < 10; i++) { String time = LocalDateTime.now().format(DateTimeFormatter.ISO_LOCAL_TIME); System.out.println(time + ":" + rateLimiter.tryAcquire()); Thread.sleep(250);}程序每隔 250ms 获取一次令牌,所以两次获取中只有一次会胜利。18:19:06.797557:true18:19:07.061419:false18:19:07.316283:true18:19:07.566746:false18:19:07.817035:true18:19:08.072483:false总结限流次要利用场景有:电商零碎(特地是6.18、双11、双12等)中的秒杀流动,应用限流避免应用软件歹意刷单;根底api接口限流:例如天气信息获取,IP对应城市接口,百度、腾讯等对外提供的根底接口,都是通过限流来实现收费与付费间接的转换。零碎宽泛调用的api接口,重大耗费网络、内存等资源,须要正当限流。除了针对服务器进行限流,咱们也能够对容器进行限流,比方 Tomcat、Nginx 等限流伎俩。Tomcat 能够设置最大线程数(maxThreads),当并发超过最大线程数会排队期待执行;Nginx 提供了两种限流伎俩:一是管制速率,二是管制并发连接数。限流算法redis实现限流guava的令牌桶限流

January 7, 2023 · 2 min · jiezi

关于java:公司的这种打包启动方式我简直惊呆了

大家好,我是不才陈某~ 大家都晓得,SpringBoot利用最终会打出一个Fat Jar, 外面蕴含了用到的全副依赖,启动也非常简单,java -jar xxx.jar即可。 然而咱们公司打出的最终包,将依赖包挪到了内部,而后启动的时候通过loader.path指定依赖包的地位,如java -Dloader.path=libs -jar xxxx的形式启动,也可能启动胜利。 这样做最大的一个益处就是如果发现某个依赖呈现问题,那么我只须要在libs替换其中某个依赖,影响范畴能够减小很多。 那大家是不是很好奇是怎么做到的呢? 关注公众号:码猿技术专栏,回复关键词:1111 获取阿里外部java性能调优手册打包形式详解次要是通过两个maven插件打出这样的构造的包。 1. spring-boot-maven-plugin该插件是spring boot官网提供的一个打包插件,次要用来打出fat jar,并且提供了反对java -jar xxx.jar形式启动。官网地址:https://docs.spring.io/spring...。 咱们须要用这个插件,因为只有它能够打出反对启动的jar,然而打出的包中又不能有依赖,该怎么做呢?如下图: layout: 布局形式,这里要抉择ZIP,前面阐明起因。includes: 抉择蕴含哪些依赖,这里写了一个不存在的jar,那么也间接实现了不打入其余的依赖。这种形式比拟ugly,然而目前没有找到更加适合的计划。2. maven-assembly-pluginmaven-assembly-plugin插件能够灵便定制打包内容,官网地址:https://maven.apache.org/plug...。 咱们当初就是想方法利用该插件抽出咱们用到的依赖包,该怎么做呢? 咱们当初看下assembly.xml中的要害配置: 能够依据include、exclude属性通过正则灵便的抽取相干依赖到指定的目录下 最终执行mvn clean package在target目录下失去最终的安装包: 解压该安装包: 关上libs目录: 启动形式解析当初咱们曾经依照本人想要的构造打出包了,那如何在启动的时候加载libs目录中的依赖呢? 后面提到了springboot插件打出的包是启动的入口,实际上在这个包外面springboot会主动打入一个疏导类org.springframework.boot.loader.Launcher,它是 Spring Boot 可执行 jar 的次要入口点,它是 Spring Boot jar 文件中的理论 Main-Class,用于设置适当的 URLClassLoader 并最终调用Spring Boot我的项目中定义的 main()办法。 Launcher有三个子类(JarLauncher、WarLauncher 和 PropertiesLauncher),如果咱们打包插件的layout配置的是ZIP的形式,它会应用PropertiesLauncher。 PropertiesLauncher机制阐明: 默认状况下,PropertiesLauncher 在 BOOT-INF/lib/ 中加载,咱们能够通过设置loader.properties中的loader.path 或 LOADER_PATH 环境变量来减少其它的加载地位。 loader.path:配置逗号分隔的 Classpath 类门路,例如 lib,${HOME}/app/lib,后面的门路优先,相似于 javac 命令中的 -classpath。loader.home:用于解析 loader.path 配置的相对路径,默认是${user.dir}。所以,打包胜利后,咱们能够通过java -jar -Dloader.path=xx1,xx2,public <jarName>.jar 命令来启动程序,这样对应目录下的依赖均会被加载。 ...

January 6, 2023 · 1 min · jiezi

关于java:秒杀系统设计的5个要点

本文曾经收录到Github仓库,该仓库蕴含计算机根底、Java根底、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构等外围知识点,欢送star~ Github地址:https://github.com/Tyson0314/... 秒杀零碎波及到的知识点高并发,cache,锁机制基于缓存架构redis,Memcached的先进先出队列。略微大一点的秒杀,必定是分布式的集群的,并发来自于多个节点的JVM,synchronized所有在JVM上加锁是不行了数据库压力秒杀超卖问题如何避免用户来刷, 黑名单?IP限度?利用memcached的带原子性个性的操作做并发管制秒杀简略设计方案比方有10件商品要秒杀,能够放到缓存中,读写时不要加锁。 当并发量大的时候,可能有25集体秒杀胜利,这样前面的就能够间接抛秒杀完结的动态页面。进去的25集体中有15集体是不可能取得商品的。所以能够依据进入的先后顺序只能前10集体购买胜利。前面15集体就抛商品已秒杀完。 比方某商品10件物品待秒。假如有100台web服务器(假如web服务器是Nginx + Tomcat),n台app服务器,n个数据库 第一步 如果Java层做过滤,能够在每台web服务器的业务解决模块里做个计数器AtomicInteger(10)=待秒商品总数,decreaseAndGet()>=0的持续做后续解决,<0的间接返回秒杀完结页面,这样通过第一步的解决只剩下100台*10个=1000个申请。 第二步,memcached 里以商品id作为key的value放个10,每个web服务器在接到每个申请的同时,向memcached服务器发动申请,利用memcached的decr(key,1)操作返回值>=0的持续解决,其余的返回秒杀失败页面,这样通过第二步的解决只剩下100台中最疾速达到的10个申请。 第三步,向App服务器发动下单操作事务。 第四步,App服务器向商品所在的数据库申请减库存操作(操作数据库时能够 "update table set count=count-1 where id=商品id and count>0;" update 胜利记录数为1,再向订单数据库增加订单记录,都胜利后提交整个事务,否则的话提醒秒杀失败,用户进入领取流程。 看看淘宝的秒杀一、前端 面对高并发的抢购流动,前端罕用的三板斧是【扩容】【动态化】【限流】 扩容:加机器,这是最简略的办法,通过减少前端池的整体承载量来抗峰值。 动态化:将流动页面上的所有能够动态的元素全副动态化,并尽量减少动静元素。通过CDN来抗峰值。 限流:个别都会采纳IP级别的限流,即针对某一个IP,限度单位工夫内发动申请数量。或者流动入口的时候减少游戏或者问题环节进行消峰操作。 有损服务:最初一招,在靠近前端池承载能力的水位下限的时候,随机回绝局部申请来爱护流动整体的可用性。 二、那么后端的数据库在高并发和超卖下会遇到什么问题呢 首先MySQL本身对于高并发的解决性能就会呈现问题,一般来说,MySQL的解决性能会随着并发thread回升而回升,然而到了肯定的并发度之后会呈现显著的拐点,之后一路降落,最终甚至会比单thread的性能还要差。其次,超卖的根结在于减库存操作是一个事务操作,须要先select,而后insert,最初update -1。最初这个-1操作是不能呈现正数的,然而当多用户在有库存的状况下并发操作,呈现正数这是无奈防止的。最初,当减库存和高并发碰到一起的时候,因为操作的库存数目在同一行,就会呈现争抢InnoDB行锁的问题,导致呈现相互期待甚至死锁,从而大大降低MySQL的解决性能,最终导致前端页面呈现超时异样。针对上述问题,如何解决呢? 淘宝的高大上解决方案: I:敞开死锁检测,进步并发解决性能。 II:批改源代码,将排队提到进入引擎层前,升高引擎层面的并发度。 III:组提交,升高server和引擎的交互次数,升高IO耗费。 解决方案1:将存库从MySQL前移到Redis中,所有的写操作放到内存中,因为Redis中不存在锁故不会呈现相互期待,并且因为Redis的写性能和读性能都远高于MySQL,这就解决了高并发下的性能问题。而后通过队列等异步伎俩,将变动的数据异步写入到DB中。 长处:解决性能问题 毛病:没有解决超卖问题,同时因为异步写入DB,存在某一时刻DB和Redis中数据不统一的危险。 解决方案2:引入队列,而后将所有写DB操作在单队列中排队,齐全串行解决。当达到库存阀值的时候就不在生产队列,并敞开购买性能。这就解决了超卖问题。 长处:解决超卖问题,稍微晋升性能。 毛病:性能受限于队列处理机解决性能和DB的写入性能中最短的那个,另外多商品同时抢购的时候须要筹备多条队列。 解决方案3:将写操作前移到MC中,同时利用MC的轻量级的锁机制CAS来实现减库存操作。 长处:读写在内存中,操作性能快,引入轻量级锁之后能够保障同一时刻只有一个写入胜利,解决减库存问题。 毛病:没有实测,基于CAS的个性不晓得高并发下是否会呈现大量更新失败?不过加锁之后必定对并发性能会有影响。 解决方案4:将提交操作变成两段式,先申请后确认。而后利用Redis的原子自增操作,同时利用Redis的事务个性来发号,保障拿到小于等于库存阀值的号的人都能够胜利提交订单。而后数据异步更新到DB中。 长处:解决超卖问题,库存读写都在内存中,故同时解决性能问题。 毛病:因为异步写入DB,可能存在数据不统一。另可能存在少买,也就是如果拿到号的人不真正下订单,可能库存减为0,然而订单数并没有达到库存阀值。 总结 1、前端三板斧【扩容】【限流】【动态化】 2、后端两条路【内存】+【排队】 最初给大家分享一个Github仓库,下面有大彬整顿的300多本经典的计算机书籍PDF,包含C语言、C++、Java、Python、前端、数据库、操作系统、计算机网络、数据结构和算法、机器学习、编程人生等,能够star一下,下次找书间接在下面搜寻,仓库继续更新中~ Github地址:https://github.com/Tyson0314/...

January 6, 2023 · 1 min · jiezi

关于java:基于云基础设施快速部署-RocketMQ-50-集群

本文作者:蔡低垂,Apache RocketMQ Committer, 阿里云智能技术专家。 背景 上图左侧为 RocketMQ 4.x版本集群,属于非切换架构。NameServer 作为无状态节点能够部署多份,broker 集群能够部署多组 broker ,每一组有一个 Broker Master 和多个 Broker Slave 。运行过程中如果某一组 master 故障,音讯发送会路由到失常的 master 上,一般音讯能够从原 Broker Slave 持续生产。 但非切换架构存在若干问题,比方定时音讯或事务音讯须要由 Master 进行二次投递,如果 Master 故障,则须要人工染指将 Master 从新复原。因而, RocketMQ 5.0 提出了自主切换架构。 自主切换架构新增了一个 Controller 模块,负责选主。当某个 Broker Master 故障,会抉择适合的 Broker Slave 晋升为 Master,无需人工染指。 如果要在生产环境中部署一套集群,须要布局整个集群的机器资源(比方哪些模块部署在哪些机器、哪些机器须要什么样的资源规格等),而后装置 JDK 等依赖软件。每个组件还须要筹备有其配置文件、启动脚本,再启动各个组件。整个过程非常消耗人力,而且存在误操作可能。 而在云基础设施上部署 RocketMQ 面临更多挑战: 首先,在云基础设施上创立不同规格的虚拟机更为不便,因而在云基础设施上部署时,一个虚拟机上往往只会部署一个模块,以实现资源隔离。然而,多节点部署也带了更高的操作老本。而零碎外部组件的宕机、复原、迁徙等行为也须要进行反对。 从社区角度看,因为社区面向不同用户,不同用户往往会在不同云根底服务提供商上进行部署。然而从 IaaS 层设施看,不同云厂商提供的接口并不对立。 为了解决上述问题,社区借鉴了面向接口编程的思路:不间接操作基础设施,而是通过标准接口。而 Kubernetes 正是这样一个容器编排的“标准接口”。于是,社区在解决 RocketMQ 在云基础设施的部署问题时,抉择基于 Kubernetes 进行部署,不同云厂商负责从 Kubernetes 到具体云 IaaS 层的调度:将有状态 RocketMQ 集群托管到 Kubernetes 集群,充分利用 Kubernetes 提供的部署、降级、自愈相干能力,同时也能享受到 Kubernetes 社区的生态红利。 ...

January 5, 2023 · 3 min · jiezi

关于java:程序员面试中一面二面三面有什么区别

很多公司面试都分一面、二面、三面甚至更多,大家可能会好奇,为什么要面这么多面,每一面又有啥区别呢? 首先我来答复下为什么要这么多面,最外围的是最初3点: 如果光是一个人面,放心会看走眼;面试通过最初的后果就是退出团队,那么要退出团长,怎么都得团队一些重要角色都批准吧,这些角色就对应1面、2面、3面。每一面侧重点不一样,这样考查也更为聚焦和全面。上面我依据腾讯、字节的教训,具体说一下每一面到底是怎么的。文末有福利记得查收 一面一面是组长面,组长也就是你入职之后的顶头上司,入职了你就跟着他混。所以组长面通常是最为认真的一面,一方便是好好把关之后再推给下面领导,避免浪费领导工夫,一方面是如果招募的人不适合,最终坑得是本人啊。 一面次要考查你的编程能力,通常会依据你简历上的技术栈,方方面面地询问技术细节,当然,有时候也会问一些团队中比拟重要的技能。 二面二面是总监面,总监个别耿直壮年、技术犹在,也会问技术细节,但不会像一面那么多,压力面通常就出在总监面。 二面的重点是我的项目和场景设计。 我的项目的话通常会让你先介绍,在介绍地过程中会发散出一些问题,问你为什么这样设计,如果有某种异样,你这个零碎是否能失常运做等; 场景设计的话个别就是让你设计某个场景,比方我就被要求设计过账单零碎、任务调度零碎等。 一般而言的话我的项目细节和场景设计只会有一个深刻考查,毕竟工夫也无限,但也的确遇到过面试官聊兴奋了,都具体探讨,这除了累一点不是好事,至多证实面试官对你是感兴趣的。 三面GM面,也就是部门负责人,这种级别的大佬通常很忙,字节的话还好,个别一周内就会进行,腾讯就离谱了,有时候约个GM要约1个月。 GM级别都是业界大佬,可能多年也没写过代码,喜怒不形于色,个别也是温和示人,所以这一面在面试过程中承当的压力可能是最小的。 好了,话说回来,GM面试通常有两类: 次要和你聊聊天,比方怎么学习的,对将来的布局等,其实是在这个过程中考查软实力,面试过程尽管没啥压力,然而很多时候会挂得莫名其妙。还有些GM也会聊一些技术畛域,比方我在字节GM面的时候被问到对后盾平安的思考,也就是说一个话题,让你本人论述,不会扣你细节,然而这种级别的大佬其实聊几句就大略能摸清楚你的掌握情况。嗯,讲到这里,大家可能get到了三面别离是做什么的,上面咱们来看一些常见的疑难。 二面肯定比一面难?不是的,难度其实很随缘,有些组长十分执着于技术,这种状况一面就会很难。 而二面通常是我的项目相干的,可能毕业前几年还会感觉很艰难,前面我的项目做多了,也晓得哪些地方可能是考查重点,哪些地方是本人的亮点,通常来说反而施展应该比一面稳固。 为什么我面了4,5面?几种状况啊。 1.后面两轮面试官一致比拟大,一个极好,一个极差; 2.感觉你还能够,但差点意思,项目组又切实缺人,找集体再给你一次机会; 3.还有一种可能是部门调整了,总监换了,有些公司,比方腾讯,面试体系是不买通的,也就是说互不赖账,所以新总监要从新面一次,新GM个别倒是不会有这个闲心。 4.最有可能的,还是组长面拆分了,因为组长太忙,底下又有能力很强的骨干,所以有时候会让骨干先面一次,通过的再进行组长面把关,有时候甚至一面齐全是骨干代劳,也是失常的,所以很可能你遇到的是1.1,1.2面,而后才是真正的1面。 GM面挂人吗?难说,只能说绝对少一些,之前呆过的一个部门,据说GM面有30%的几率挂掉,其实不太能了解,只能说集体爱好吧,GM这层势力曾经很大了。 是否所有的一面、二面、三面,都如此分工明确当然不是了,面试官自身也具备很大的灵活性,其实多面的实质是拜山头,而因为自身曾经分面,才逐渐演变为侧重点不同,这不是肯定的,有些团队就是每一面都freestyle也不奇怪。 哪一面最重要一面二面都相当重要,三面的话,说实话,重要性要低些,自身一二面大佬曾经认可了,而GM工作中可能简直不会有交加,甚至很多时候我都感觉GM面意义不大。 总结本次给大家分享了面试为什么这么多面,每面做什么,能够看到要找个工作还真是挺不容易的,须要付出很多汗水和心力。 但小编感觉面试自身也是双向选择的过程,只有你继续致力、放弃平常心,最初肯定能播种不错的Offer。小编也筹备了一些Java面试材料给大家,蕴含大厂面试真题、java外围知识点、java视频面试题解析等一系列材料有须要的小伙伴——【间接点击此处】——即可获取~

January 5, 2023 · 1 min · jiezi

关于java:透过现象看本质我找到了Netty粘包与半包的这几种解决方案

1、粘包与半包啥也不说了,间接上代码是不是有点不太敌对,我所谓了,都快过年了,还要啥自行车 我上来就是一段代码猛如虎 1.1 服务器代码public class StudyServer { static final Logger log = LoggerFactory.getLogger(StudyServer.class); void start() { NioEventLoopGroup boss = new NioEventLoopGroup(1); NioEventLoopGroup worker = new NioEventLoopGroup(); try { ServerBootstrap serverBootstrap = new ServerBootstrap(); serverBootstrap.channel(NioServerSocketChannel.class); serverBootstrap.group(boss, worker); serverBootstrap.childHandler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) { ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG)); ch.pipeline().addLast(new ChannelInboundHandlerAdapter() { @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { // 连贯建设时会执行该办法 log.debug("connected {}", ctx.channel()); super.channelActive(ctx); } @Override public void channelInactive(ChannelHandlerContext ctx) throws Exception { // 连贯断开时会执行该办法 log.debug("disconnect {}", ctx.channel()); super.channelInactive(ctx); } }); } }); ChannelFuture channelFuture = serverBootstrap.bind(8080); log.debug("{} binding...", channelFuture.channel()); channelFuture.sync(); log.debug("{} bound...", channelFuture.channel()); // 敞开channel channelFuture.channel().closeFuture().sync(); } catch (InterruptedException e) { log.error("server error", e); } finally { boss.shutdownGracefully(); worker.shutdownGracefully(); log.debug("stopped"); } } public static void main(String[] args) { new StudyServer().start(); }}1.2 粘包景象客户端代码 ...

January 5, 2023 · 10 min · jiezi

关于java:完爆90的性能毛病数据库优化八大通用绝招

大家好,我是不才陈某~ 毫不夸大的说咱们后端工程师,无论在哪家公司,呆在哪个团队,做哪个零碎,遇到的第一个让人头疼的问题相对是数据库性能问题。如果咱们有一套成熟的方法论,能让大家疾速、精确的去抉择出适合的优化计划,我置信可能疾速筹备解决咱么日常遇到的80%甚至90%的性能问题。 从解决问题的角度登程,咱们得先理解到问题的起因;其次咱们得有一套思考、判断问题的流程形式,让咱们正当的站在哪个层面抉择计划;最初从泛滥的计划外面抉择一个适宜的计划进行解决问题,找到一个适合的计划的前提是咱们本人对各种计划之间的优缺点、场景有足够的理解,没有一个计划是齐全能够通吃通用的,软件工程没有银弹。 下文的我工作多年以来,已经应用过的八大计划,联合了平时本人学习收集的一些材料,以零碎、全面的形式整顿成了这篇博文,也心愿能让一些有须要的同行在工作上、成长上提供肯定的帮忙。 关注公众号:码猿技术专栏,回复关键词:1111 获取阿里外部Java性能调优手册为什么数据库会慢?慢的实质: 慢的实质 查找的工夫复杂度查找算法存储数据结构存储数据结构数据总量数据拆分高负载CPU、磁盘忙碌无论是关系型数据库还是NoSQL,任何存储系统决定于其查问性能的次要有三种: 查找的工夫复杂度数据总量高负载而决定于查找时间复杂度次要有两个因素: 查找算法存储数据结构无论是哪种存储,数据量越少,天然查问性能就越高,随着数据量增多,资源的耗费(CPU、磁盘读写忙碌)、耗时也会越来越高。 从关系型数据库角度登程,索引构造根本固定是B+Tree,工夫复杂度是O(log n),存储构造是行式存储。因而咱们对于关系数据库能优化的个别只有数据量。 而高负载造成起因有高并发申请、简单查问等,导致CPU、磁盘忙碌等,而服务器资源有余则会导致慢查问等问题。该类型问题个别会抉择集群、数据冗余的形式分担压力。 应该站在哪个层面思考优化? 从上图可见,自顶向下的一共有四层,别离是硬件、存储系统、存储构造、具体实现。层与层之间是紧密联系的,每一层的下层是该层的载体;因而越往顶层越能决定性能的下限,同时优化的老本也绝对会比拟高,性价比也随之越低。以最底层的具体实现为例,那么索引的优化的老本应该是最小的,能够说加了索引后无论是CPU耗费还是响应工夫都是空谷传声升高;然而一个简略的语句,无论如何优化加索引也是有局限的,当在具体实现这层没有任何优化空间的时候就得往上一层【存储构造】思考,思考是否从物理表设计的层面登程优化(如分库分表、压缩数据量等),如果是文档型数据库得思考下文档聚合的后果;如果在存储构造这层优化得没成果,得持续往再上一次进行思考,是否关系型数据库应该不适宜用在当初得业务场景?如果要换存储,那么得换怎么得NoSQL? 所以咱们优化的思路,出于性价比的优先思考具体实现,切实没有优化空间了再往上一层思考。当然如果公司有钱,间接应用钞能力,绕过了后面三层,这也是一种便捷的应急解决形式。 该篇文章不探讨顶与底的两个层面的优化,次要从存储构造、存储系统两头两层的角度登程进行探讨。 关注公众号:码猿技术专栏,回复关键词:1111 获取阿里外部Java性能调优手册八大计划总结 数据库的优化计划外围实质有三种:缩小数据量、用空间换性能、抉择适合的存储系统,这也对应了开篇解说的慢的三个起因:数据总量、高负载、*查找的工夫复杂度。* 这里大略解释下收益类型:短期收益,解决成本低,能紧急应答,久了则会有技术债权;长期收益则跟短期收益相同,短期内解决老本高,然而成果能短暂应用,扩展性会更好。 静态数据意思是,绝对改变频率比拟低的,也无需过多联表的,where过滤比拟少。动态数据与之相同,更新频率高,通过动静条件筛选过滤。 缩小数据量缩小数据量类型共有四种计划:数据序列化存储、数据归档、两头表生成、分库分表。 就如下面所说的,无论是哪种存储,数据量越少,天然查问性能就越高,随着数据量增多,资源的耗费(CPU、磁盘读写忙碌)、耗时也会越来越高。目前市面上的NoSQL基本上都反对分片存储,所以其人造分布式写的能力从数据量上能失去十分的解决方案。而关系型数据库,查找算法与存储构造是能够优化的空间比拟少,因而咱们个别思考出发点只有从如何缩小数据量的这个角度进行抉择优化,因而本类型的优化计划次要针对关系型数据库进行解决。 数据归档 留神点:别一次性迁徙数量过多,倡议低频率屡次限量迁徙。像MySQL因为删除数据后是不会开释空间的,能够执行命令OPTIMIZE TABLE开释存储空间,然而会锁表,如果存储空间还满足,能够不执行。 倡议优先思考该计划,次要通过数据库作业把非热点数据迁徙到历史表,如果须要查历史数据,可新增业务入口路由到对应的历史表(库)。 两头表(后果表) 两头表(后果表)其实就是利用调度工作把简单查问的后果跑进去存储到一张额定的物理表,因为这张物理表寄存的是通过跑批汇总后的数据,因而能够了解成依据原有的业务进行了高度的数据压缩。以报表为例,如果一个月的源数据有数十万,咱们通过调度工作以月的维度生成,那么等于把原有的数据压缩了几十万分之一;接下来的季报和年报能够依据月报*N来进行统计,以这种形式解决的数据,就算三年、五年甚至十年数据量都能够在承受范畴之内,而且能够准确计算失去。 那么数据的压缩比率是否越低越好?上面有一段口诀: 字段越多,粒度越细,灵活性越高,能够以两头表进行不同业务联表处理。字段越少,粒度越粗,灵活性越低,个别作为后果表查问进去。数据序列化存储 在数据库以序列化存储的形式,对于一些不须要结构化存储的业务来说是一种很好缩小数据量的形式,特地是对于一些M*N的数据量的业务场景,如果以M作为主表优化,那么就能够把数据量维持最多是M的量级。另外像订单的地址信息,这种业务个别是不须要依据外面的字段检索进去,也比拟适宜。 这种计划我认为属于一种临时性的优化计划,无论是从序列化后失落了部份字段的查问能力,还是这计划的可优化性都是无限的。 关注公众号:码猿技术专栏,回复关键词:1111 获取阿里外部Java性能调优手册分库分表分库分表作为数据库优化的一种十分经典的优化计划,特地是在以前NoSQL还不是很成熟的年代,这个计划就如救命草个别的存在。 现在也有不少同行也会抉择这种优化形式,然而从我角度来看,分库分表是一种优化老本很大的计划。这里我有几个倡议: 分库分表是切实没有方法的方法,应放到最初抉择。优先选择NoSQL代替,因为NoSQL诞生基本上为了扩展性与高性能。到底分库还是分表?量大则分表,并发高则分库不思考扩容,一部做到位。因为技术更新太快了,每3-5年一大变。拆分形式 只有波及到这个拆,那么无论是微服务也好,分库分表也好,拆分的形式次要分两种:垂直拆分、程度拆分。 垂直拆分更多是从业务角度进行拆分,次要是为了升高业务耦合度;此外以SQL Server为例,一页是8KB存储,如果在一张表里字段越多,一行数据天然占的空间就越大,那么一页数据所存储的行数就天然越少,那么每次查问所须要IO则越高因而性能天然也越慢;因而反之,缩小字段也能很好进步性能。之前我据说某些同行的表有80个字段,几百万的数据就开始慢了。 程度拆分更多是从技术角度进行拆分,拆分后每张表的构造是截然不同的,简而言之就是把原有一张表的数据,通过技术手段进行分片到多张表存储,从根本上解决了数据量的问题。 路由形式 进行程度拆分后,依据分区键(sharding key)原来应该在同一张表的数据拆解写到不同的物理表里,那么查问也得依据分区键进行定位到对应的物理表从而把数据给查问进去。 路由形式个别有三种区间范畴、Hash、分片映射表,每种路由形式都有本人的长处和毛病,能够依据对应的业务场景进行抉择。 区间范畴依据某个元素的区间的进行拆分,以工夫为例子,如果有个业务咱们心愿以月为单位拆分那么表就会拆分像 table_2022-04,这种对于文档型、ElasticSearch这类型的NoSQL也实用,无论是定位查问,还是日后清理保护都是十分的不便的。那么毛病也显著,会因为业务独特性导致数据不均匀,甚至不同区间范畴之间的数据量差别很大。 Hash也是一种罕用的路由形式,依据Hash算法取模以数据量平均别离存储在物理表里,毛病是对于带分区键的查问依赖特地强,如果不带分区键就无奈定位到具体的物理表导致相干所有表都查问一次,而且在分库的状况下对于Join、聚合计算、分页等一些RDBMS的个性性能还无奈应用。 个别分区键就一个,如果有时候业务场景得用不是分区键的字段进行查问,那么难道就必须得全副扫描一遍?其实能够应用分片映射表的形式,简略来说就是额定有一张表记录额定字段与分区键的映射关系。举个例子,有张订单表,本来是以UserID作为分区键拆分的,当初心愿用OrderID进行查问,那么得有额定得一张物理表记录了OrderID与UserID的映射关系。因而得先查问一次映射表拿到分区键,再依据分区键的值路由到对应的物理表查问进去。可能有些敌人会问,那这映射表是否多一个映射关系就多一张表,还是多个映射关系在同一张表。我优先倡议独自解决,如果说映射表字段过多,那跟不进行程度拆分时的状态其实就是统一的,这又跑回去的老问题。 用空间换性能该类型的两个计划都是用来应答高负载的场景,计划有以下两种:分布式缓存、一主多从。 与其说这个计划叫用空间换性能,我认为用空间换资源更加贴切一些。因而两个计划的实质次要通数据冗余、集群等形式分担负载压力。 对于关系型数据库而言,因为他的ACID个性让它天生不反对写的分布式存储,然而它仍然人造的反对分布式读。 分布式缓存 缓存层级能够分好几种:客户端缓存、API服务本地缓存和分布式缓存,咱们这次只聊分布式缓存。个别咱们抉择分布式缓存零碎都会优先选择NoSQL的键值型数据库,例如Memcached、Redis,现在Redis的数据结构多样性,高性能,易扩展性也逐步占据了分布式缓存的主导地位。 缓存策略也次要有很多种:Cache-Aside、Read/Wirte-Through、Write-Back,咱们用得比拟多的形式次要Cache-Aside,具体流程可看下图: 我置信大家对分布式缓存绝对都比拟相熟了,然而我在这里还是有几个留神点心愿揭示一下大家: ...

January 5, 2023 · 1 min · jiezi

关于java:实时订阅推送设计与实现

本文曾经收录到Github仓库,该仓库蕴含计算机根底、Java根底、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构等外围知识点,欢送star~ Github地址:https://github.com/Tyson0314/... 什么是领劵的订阅推送?就是用户订阅了该劵的推送,在可支付前的一分钟就要把揭示信息推送到用户的app中。具体计划就是到具体的推送工夫点了,coupon零碎调用音讯核心的推送接口,把信息推送进来。 上面咱们剖析一下这个性能的业务情景。公司目前注册用户6000W+,比方有一张无门槛的优惠劵下单立减20元,那么抢这张劵的人就会比拟多,咱们激进预计10W+,百万级别不好说。咱们初定为20W万人,那么这20W条推送信息要在一分钟推送实现!并且一个用户是能够订阅多张劵的。所以咱们晓得了这个订阅性能的有两个突出的难点: 1、推送的实效性:推送慢了,用户会埋怨没有及时告诉他们错过了开抢机会。 2、推送的体量大:爆款的神劵,人人都想抢! 然而推送体量又会影响到推送的实效性。这真是一个让人头疼的问题! 那就让咱们把问题一个个解决掉吧! 推送的实效性的问题:当用户在领劵核心订阅了某个劵的支付揭示后,在后盾就会生成一条用户的订阅揭示记录,外面记录了在哪个工夫点给用户发送推送信息。所以问题就变成了零碎如何疾速实时选出哪些要推送的记录! 计划1:MQ的提早投递。MQ尽管反对音讯的提早投递,然而不适宜用来做准确工夫点投递!并且用户执行订阅之后又勾销订阅的话,要把收回去的MQ音讯delete掉这个操作有拍板大,短时间内难以落地!并且用户能够勾销之后再订阅,这又波及到去重的问题。所以MQ的计划否掉。计划2:传统定时工作。这个相对来说就简略一点,用定时工作是去db外面load用户的订阅揭示记录,从中选出以后能够推送的记录。但有句话说得好任何脱离实际业务的设计都是耍流氓。上面咱们就剖析一下传统的定时工作到底适不适宜咱们的这个业务!是否反对多机同时跑个别不能,同一时刻只能单机跑。存储数据源个别是mysql或者其它传统数据库,并且是单表存储频率反对秒、分、时、天,个别不能太快如上表格所示,能够看到个别传统的定时工作存在以下毛病: 1、性能瓶颈。只有一台机在解决,在大体量数据背后力不从心! 2、实效性差。定时工作的频率不能太高,太高会业务数据库造成很大的压力! 3、单点故障。万一跑的那台机挂了,那整个业务不可用了。这是一个很可怕的事件! 所以传统定时工作也不太适宜这个业务。 那有其余解决方案吗?其实能够对传统的定时工作做一个简略的革新即可!把它变成能够同时多机跑,并且实效性能够准确到秒级,并且回绝单点故障的定时工作集群!这其中就要借助咱们的弱小的redis了。 计划3:定时工作集群首先咱们要定义定时工作集群要解决的三个问题! 1、实效性要高 2、吞吐量要大 3、服务要稳固,不能有单点故障 上面是整个定时工作集群的架构图。 架构很简略:咱们把用户的订阅推送记录存储到redis集群的sortedSet队列外面,且以揭示用户揭示工夫戳作为score值,而后在咱们个每业务server外面起一个定时器频率是秒级,我的设定就是1s,而后通过负载平衡之后从某个队列外面获取要推送的用户记录进行推送。上面咱们剖析以下这个架构。 1、性能:除去带宽等其它因素,根本与机器数成线性相关。机器数量越多吞吐量越大,机器数量少时绝对的吞吐量就缩小。 2、实效性:进步到了秒级,成果还能够承受。 3、单点故障?不存在的!除非redis集群或者所有server全挂了。 这里解释一下为什么用redis? redis 能够作为一个高性能的存储db,性能要比MySQL好很多,并且反对长久化,稳定性好。redis SortedSet队列人造反对以工夫作为条件排序,完满满足咱们选出要推送的记录。既然计划曾经有了,怎么实现呢? 首先咱们以user_id作为key,而后mod队列数hash到redis SortedSet队列外面。为什么要这样呢,因为如果用户同时订阅了两张劵并且推送工夫很近,这样的两条推送就能够合并成一条,并且这样hash也绝对平均。上面是局部代码的截图: 而后要决定队列的数量,个别失常来说咱们有多少台解决的服务器就定义多少条队列。因为队列太少,会造成队列竞争,太多可能会导致记录得不到及时处理。 然而最佳实际是队列数量应该是可动静配置化的,因为线上的集群机器数是会常常变的。大促的时候咱们会加机器是不是,并且业务量增长了,机器数也是会减少是不是~。所以我是借用了淘宝的diamond进行队列数的动静配置。 咱们每次从队列外面取多少条记录也是能够动静配置的 这样就能够随时依据理论的生产状况调整整个集群的吞吐量。 所以咱们的定时工作集群还是具备一个个性就是反对动静调整。 最初一个要害组件就是负载平衡了。这个是十分重要的!因为这个做得不好就会可能导致多台机竞争同时解决一个队列,影响整个集群的效率!在工夫很紧的状况下我就用了一个简略的计划,利用redis一个自增key,而后 mod 队列数量算法。这样就很大水平上就保障不会有两台机器同时去竞争一条队列。 最初咱们算一下整个集群的吞吐量 10(机器数) * 2000(一次拉取数) = 20000。而后以MQ的模式把音讯推送到音讯核心,发MQ是异步的,算上其它解决0.5s。 其实发送20W的推送也就是10几s的事件。 到这里咱们整个定时工作集群就差不多根本落地好了。反过来认真思考了一下,有以下能够优化的点: 1、加监控, 集群怎么能够木有监控呢,万一出问题有工作沉积怎么办。 2、加上可视化界面。 3、最好有智能调度,减少工作优先级。确保优先级高的工作先运行。 4、资源调度,万一机器数量不够,力不从心,优先保障重要工作执行。 目前我的项目已上线,运行稳固。 最初给大家分享一个Github仓库,下面有大彬整顿的300多本经典的计算机书籍PDF,包含C语言、C++、Java、Python、前端、数据库、操作系统、计算机网络、数据结构和算法、机器学习、编程人生等,能够star一下,下次找书间接在下面搜寻,仓库继续更新中~ Github地址:https://github.com/Tyson0314/...

January 4, 2023 · 1 min · jiezi

关于java:Mybatis的SqlSession初始化及调用过程

咱们晓得Mybatis最终是通过SqlSession对象去执行sql语句的,通过后面几篇文章咱们也晓得Mybatis是怎么解析mapper.xml文件、怎么把sql语句读入到Mybatis的Congifuration对象中、最初Mapper接口的代理对象是怎么匹配到sql语句、并最终通过SqlSession对象去执行sql语句的。 上述整个过程咱们都曾经理解过了,惟一一个尚未剖析过的问题是:SqlSession是怎么初始化的?以及他具体是怎么执行sql语句的? 明天的次要指标就是要搞清楚以上两个问题: SqlSession对象的创立或者初始化过程。SqlSession执行sql语句的具体过程。SqlSession对象的创立不同的我的项目,SqlSession会有不同的创立过程,但根本都大同小异。咱们明天次要剖析Springboot+Mybatis我的项目中SqlSession的创立过程。 Springboot我的项目中次要通过配置类MybatisAutoConfiguration来实现Mybatis的初始化。 MybatisAutoConfiguration次要实现: 创立并初始化Configuration对象通过SqlSessionFactoryBean初始化SqlSessionFactory(初始化为DefaultSqlSessionFactory)初始化SqlSession,Spring我的项目SqlSession初始化为SqlSessionTemplate对象MybatisAutoConfiguration#sqlSessionFactorysqlSessionFactory办法次要实现Configuration对象的创立,以及SqlSessionFactory对象的创立。办法比拟长,最初通过SqlSessionFactoryBean的build办法创立DefaultSqlSessionFactory对象返回,并交给Spring Ioc容器治理。 @Bean @ConditionalOnMissingBean public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {SqlSessionFactoryBean factory = new SqlSessionFactoryBean(); factory.setDataSource(dataSource); factory.setVfs(SpringBootVFS.class); if (StringUtils.hasText(this.properties.getConfigLocation())) { factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation())); } applyConfiguration(factory);//省略return factory.getObject();MybatisAutoConfiguration#sqlSessionTemplatesqlSessionTemplate对象是Spring+Mybatis我的项目的SqlSession落地对象,通过sqlSessionTemplate能够实现Spring和Mybatis的无缝对接。通过下面SqlSession的类构造,咱们晓得SqlSessionTemplate理论是SqlSession的一个实现类,所以,通过@Bean注解的最终返回SqlSessionTemplate对象的办法sqlSessionTemplate(SqlSessionFactory sqlSessionFactory)的目标就是创立SqlSession对象,并最终交给Spring的Ioc容器来治理。其中参数SqlSessionFactory是通过Spring Ioc依赖注入的DefaultSqlSessionFactory对象: @Bean @ConditionalOnMissingBean public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) { ExecutorType executorType = this.properties.getExecutorType(); if (executorType != null) { return new SqlSessionTemplate(sqlSessionFactory, executorType); } else { return new SqlSessionTemplate(sqlSessionFactory); } }最终会调用到SqlSessionTemplate的SqlSessionTemplate办法: public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) { notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required"); notNull(executorType, "Property 'executorType' is required"); this.sqlSessionFactory = sqlSessionFactory; this.executorType = executorType; this.exceptionTranslator = exceptionTranslator; this.sqlSessionProxy = (SqlSession) newProxyInstance(SqlSessionFactory.class.getClassLoader(), new Class[] { SqlSession.class }, new SqlSessionInterceptor()); }咱们须要把关注点放在代码最初一句话,创立了一个动静代理对象(又是动静代理)赋值给SqlSessionTelmplate对象的sqlSessionProxy,这个代理对象的回调对象为SqlSessionInterceptor,咱们对JDK动静代理曾经十分相熟了,咱们晓得所有的对于代理对象sqlSessionProxy的办法调用,最终都会调用到回调对象SqlSessionInterceptor的invoke办法。 ...

January 4, 2023 · 2 min · jiezi

关于java:为什么说IO密集型业务线程数是CPU数的2倍

I/O密集型业务,线程数量要设置成 CPU 的 2 倍! 也不晓得这是哪本书的坑爹实践,当初总有一些小青年老拿着这样的定理来说教。说的山盟海誓,毋庸置疑,好像是权威的化身。探讨时把这样的实践当作前提,真的是受益不浅。 但惋惜的是,这样的实践站不住脚。我只须要一个简略的反诘,它就不攻自破: Tomcat的默认线程数是多少呢? 它既不是 CPU 的 2 倍,也不是什么其余数值。在某些高并发的服务中,它的外围线程数,可能达到数千甚至上万。对于一个Tomcat来说,它解决的大多数都是I/O密集型的业务,能够说是最好的实际场景。 要明确这个线程数设置的玄机,就必须理解I/O申请的特点。I/O申请不仅仅指的是磁盘读写,在互联网服务中更多指的是网络I/O申请。 I/O申请的速度,要远低于CPU运行的速度。大部分I/O申请,在发动之后,就进入期待状态,这个期待状态不会节约CPU,所以一台机器在同一时刻反对的I/O申请,能够很多。 如果I/O申请的速度比拟快,和CPU的耗时对等的时候,咱们把解决I/O的线程数,设置成 CPU 的 2倍,是正当的。但事实中并没有这么多如果,咱们要解决秒成千上万的I/O申请,注定了它的耗时要比CPU多的多。 像RPC组件,比方Dubbo服务端,也会设置一个比拟大的线程数(比方600);Feign这种就更不必多说了,短连贯意味着更多线程数的反对。这都是些最佳实际。 尽管I/O线程数量增多,会造成十分频繁的上下文切换,进而影响效率。但在互联网利用中,它却是一个优良的解决方案。 更优良的解决形式也有,那就是应用协程。协程是用户态的线程,是对一般线程更细粒度的划分。它是在用户态运行的,由用户自行调度,所以也就防止了频繁的上下文切换问题。 但协程在Java中还不成熟,它仍然是Golang语言的迷人个性。应用Golang开发的Web服务,能够采纳更少的线程来反对大量I/O密集型的申请。 综上所述,题目的表述并不正确,而且错的离谱。

January 4, 2023 · 1 min · jiezi

关于java:RocketMQ-50-多语言客户端的设计与实现

本文作者:古崟佑,阿里云中间件开发。 RocketMQ 5.0 版本领有十分多新个性,比方存储计算拆散、 batch 能力的晋升等,它是具备里程碑意义的版本。 提到新版本,咱们往往会首先想到服务端架构的设计变动,很容易疏忽客户端的设计理念。客户端也是音讯产品的必要组成部分,许多个性须要 client 与 server 两端相互合作,能力更好地实现。 轻量化、云原生以及对立模型是 RocketMQ 5.0 客户端的三个设计理念。 01 轻量化 轻量化的重点在于轻逻辑、轻流程,化繁为简,缩小多语言生态倒退的妨碍。 上图列举了 RocketMQ 4.x 版本和 RocketMQ 5.0 版本的差别。 ①4.x 版本的序列化应用 JsonCodecs 和 RocketMQCodecs,5.0 版本应用的则是规范的 Protobuf 协定。多语言倒退的妨碍包含许多不标准,比方 RocketMQ 自定义序列化对于其余的语言须要本人实现一套协定以实现正反序列化解析。而 Json 作为规范序列化协定,根本能够实现所有语言的正反序列化,但毛病也非常明显,冗余信息过多,体积占用太大,因而更多用于 restful 架构等前后端交互的场景。此外,消息中间件场景无需关怀传输数据时是否可读。因而, Protobuf 成为了抉择,它原生反对多语言,且传输时体积占用十分小,成熟且规范。 ②此前客户端应用 consumer 生产信息时,会存在计算逻辑比方重均衡 以及零碎级 topic 解决。然而 RocketMQ 5.0 版本将所有计算逻辑上移到了服务端,客户端只需简略地调用 Receive 接口,也无需额定解决零碎级 topic ,整体逻辑变得十分轻量。 ③4.x版本的实现和保护老本十分高,因而5.0版本并没有基于4.x进行迭代和更新。设计之初有一种思路为间接在4.x客户端上减少 gRPC 协定,迭代降级成为5.0,但这相当于扛着历史包袱往前走,也违反了轻量化准则,因而被否定。 02 云原生 云的弹性、高可用性以及交互运维能力在 RocketMQ 5.0 客户端中均有体现,别离对应极致弹性伸缩、低耦合以及云端一体。 上图为 4.x版本和5.0版本的客户端。在4.x版本中, 一个 Queue 最多对应一个 consumer,减少 consumer 不肯定能晋升生产并发,其弹性有下限。但在 RocketMQ 5.0,每一个 consumer 能够向所有 broker 发动 Pop 申请。此前为 push 模式,当初改为 pop 申请。晋升 consumer 数量可能晋升生产并发,即便只有一个队列,也能够生成数百数千个消费者对立拉取队列音讯。 ...

January 4, 2023 · 2 min · jiezi

关于java:RocketMQ-Compaction-Topic的设计与实现

本文作者:刘涛,阿里云智能技术专家。 01 Compaction Topic介绍 一般来说,音讯队列提供的数据过期机制有如下几种,比方有基于工夫的过期机制——数据保留多长时间后即进行清理,也有基于数据总量的过期机制——数据分区数据量达到肯定值后进行清理。 而 Compaction Topic 是一种基于 key 的数据过期机制,即对于雷同 key 的数据只保留最新值。 该个性的利用场景次要为保护状态信息,或者在须要用到 KV 构造时,能够通过 Compaction Topic 将 key-value 信息间接保留到 MQ,从而解除对外部数据库的依赖。比方保护生产位点,能够将生产组加分区作为 key ,将生产位点做 offset ,以音讯模式发送到 MQ ,压缩之后,生产时获取最新 offset 信息即可。另外,像 connect 里的 source 信息比方 Binlog 解析位点或其余 source 解决的位点信息均可存到 Compaction Topic。同时 Compaction Topic 也反对 存储 RSQLDB 与 RStreams 的 checkpoint 信息。 02 须要解决的问题 Compaction 过程中,须要解决如下几个问题: 第一,数据写入过程中,数据如何从生产者发送到 broker 并且最终落盘,数据主备之间的 HA 如何保障? 第二,整个 compaction 的流程包含哪几个步骤?如果数据量太大,如何优化? 第三,数据生产时如何索引音讯?如果找不到音讯指定的 offset 音讯,如何解决? 第四,如果有机器故障,如何复原老数据? 03 方案设计与实现 第一,数据如何写入。 ...

January 4, 2023 · 2 min · jiezi

关于java:面试官Docker-有几种网络模式5-年工作经验都表示答不上来

本文作者:知知行行 \本文链接:https://www.cnblogs.com/loron... docker容器网络Docker在装置后主动提供3种网络,能够应用docker network ls命令查看 [root@localhost ~]# docker network lsNETWORK ID NAME DRIVER SCOPEcd97bb997b84 bridge bridge local0a04824fc9b6 host host local4dcb8fbdb599 none null localDocker应用Linux桥接,在宿主机虚构一个Docker容器网桥(docker0),Docker启动一个容器时会依据Docker网桥的网段调配给容器一个IP地址,称为Container-IP,同时Docker网桥是每个容器的默认网关。因为在同一宿主机内的容器都接入同一个网桥,这样容器之间就可能通过容器的Container-IP间接通信。 docker的4种网络模式网络模式配置阐明host--network host容器和宿主机共享Network namespacecontainer--network container:NAME_OR_ID容器和另外一个容器共享Network namespacenone--network none容器有独立的Network namespace,但并没有对其进行任何网络设置,如调配veth pair 和网桥连贯,配置IP等bridge--networkbridge 默认模式 bridge模式当Docker过程启动时,会在主机上创立一个名为docker0的虚构网桥,此主机上启动的Docker容器会连贯到这个虚构网桥上。虚构网桥的工作形式和物理交换机相似,这样主机上的所有容器就通过交换机连在了一个二层网络中。 从docker0子网中调配一个IP给容器应用,并设置docker0的IP地址为容器的默认网关。在主机上创立一对虚构网卡veth pair设施,Docker将veth pair设施的一端放在新创建的容器中,并命名为eth0(容器的网卡),另一端放在主机中,以vethxxx这样相似的名字命名,并将这个网络设备退出到docker0网桥中。能够通过brctl show命令查看。 bridge模式是docker的默认网络模式,不写--network参数,就是bridge模式。应用docker run -p时,docker理论是在iptables做了DNAT规定,实现端口转发性能。能够应用iptables -t nat -vnL查看。 bridge模式如下图所示: 假如上图的docker2中运行了一个nginx,大家来想几个问题: 同主机间两个容器间是否能够间接通信?比方在docker1上能不能间接拜访到docker2的nginx站点?在宿主机上是否间接拜访到docker2的nginx站点?在另一台主机上如何拜访node1上的这个nginx站点呢?DNAT公布?Docker网桥是宿主机虚构进去的,并不是实在存在的网络设备,内部网络是无奈寻址到的,这也意味着内部网络无奈通过间接Container-IP拜访到容器。如果容器心愿内部拜访可能拜访到,能够通过映射容器端口到宿主主机(端口映射),即docker run创立容器时候通过 -p 或 -P 参数来启用,拜访容器的时候就通过[宿主机IP]:[容器端口]拜访容器。 container模式这个模式指定新创建的容器和曾经存在的一个容器共享一个 Network Namespace,而不是和宿主机共享。新创建的容器不会创立本人的网卡,配置本人的 IP,而是和一个指定的容器共享 IP、端口范畴等。同样,两个容器除了网络方面,其余的如文件系统、过程列表等还是隔离的。两个容器的过程能够通过 lo 网卡设施通信。container模式如下图所示: host模式如果启动容器的时候应用host模式,那么这个容器将不会取得一个独立的Network Namespace,而是和宿主机共用一个Network Namespace。容器将不会虚构出本人的网卡,配置本人的IP等,而是应用宿主机的IP和端口。然而,容器的其余方面,如文件系统、过程列表等还是和宿主机隔离的。 应用host模式的容器能够间接应用宿主机的IP地址与外界通信,容器外部的服务端口也能够应用宿主机的端口,不须要进行NAT,host最大的劣势就是网络性能比拟好,然而docker host上曾经应用的端口就不能再用了,网络的隔离性不好。 Host模式如下图所示: none模式应用none模式,Docker容器领有本人的Network Namespace,然而,并不为Docker容器进行任何网络配置。也就是说,这个Docker容器没有网卡、IP、路由等信息。须要咱们本人为Docker容器增加网卡、配置IP等。 ...

January 4, 2023 · 9 min · jiezi

关于java:阿里排查神器太强了

本文曾经收录到Github仓库,该仓库蕴含计算机根底、Java根底、多线程、JVM、数据库、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服务、设计模式、架构等外围知识点,欢送star~ Github地址:https://github.com/Tyson0314/... Gitee地址:https://gitee.com/tysondai/Ja... 简介Arthas 是Alibaba开源的Java诊断工具,动静跟踪Java代码;实时监控JVM状态,能够在不中断程序执行的状况下轻松实现JVM相干问题排查工作 。反对JDK 6+,反对Linux/Mac/Windows。这个工具真的很好用,而且入门超简略,非常举荐。 应用场景这个类从哪个 jar 包加载的?为什么会报各种类相干的 Exception?我改的代码为什么没有执行到?难道是我没 commit?分支搞错了?遇到问题无奈在线上 debug,难道只能通过加日志再从新公布吗?线上遇到某个用户的数据处理有问题,但线上同样无奈 debug,线下无奈重现!是否有一个全局视角来查看零碎的运行状况?有什么方法能够监控到JVM的实时运行状态?接下来,围绕这6个问题,学习下Arthas的根本用法。装置执行上面命令下载 wget https://alibaba.github.io/arthas/arthas-boot.jar用java -jar的形式启动 java -jar arthas-boot.jar[INFO] Found existing java process, please choose one and hit RETURN.* [1]: 79952 cn.test.MobileApplication [2]: 93872 org.jetbrains.jps.cmdline.Launcher而后输出数字,抉择你想要监听的利用,回车即可 常用命令查问arthas版本 [arthas@79952]$ version3.1.41、stack输入以后办法被调用的调用门路 很多时候咱们都晓得一个办法被执行,然而有很多中央调用了它,你并不知道是谁调用了它,此时你须要的是 stack 命令。 参数名称参数阐明class-pattern类名表达式匹配method-pattern办法名表达式匹配[arthas@79952]$ stack com.baomidou.mybatisplus.extension.service.IService getOnePress Q or Ctrl+C to abort.Affect(class-cnt:202 , method-cnt:209) cost in 10761 ms.ts=2019-11-13 11:49:13;thread_name=http-nio-8801-exec-6;id=2d;is_daemon=true;priority=5;TCCL=org.springframework.boot.web.embedded.tomcat.TomcatEmbeddedWebappClassLoader@a6c54c3 @com.baomidou.mybatisplus.extension.service.impl.ServiceImpl.getOne() at com.baomidou.mybatisplus.extension.service.IService.getOne(IService.java:230) ...... ...... at cn.test.mobile.controller.order.OrderController.getOrderInfo(OrderController.java:500)能够看到OrderController.java的第500行调用了这个getOne接口。 留神这个命令须要调用后才会触发日志,类似的还有watch、trace等 2、jad反编译指定已加载类的源码 有时候,版本公布后,代码居然没有执行,代码是最新的吗,这时能够应用jad反编译相应的class。 jad cn.test.mobile.controller.order.OrderController仅编译指定的办法 ...

January 3, 2023 · 4 min · jiezi

关于java:面试官为什么-waitnotify-必须与-synchronized-一起使用

起源:blog.csdn.net/randompeople/article/details/114917087 为什么 java wait/notify 必须与 synchronized 一起应用这个问题就是书本上没怎么解说,就是通知咱们这样解决,但没有解释为什么这么解决?我也是基于这样的困惑去理解起因。 synchronized是什么Java中提供了两种实现同步的根底语义:synchronized办法和synchronized块, 看个demo: public class SyncTest { \\ 1、synchronized办法 public synchronized void syncMethod(){ System.out.println("hello method"); } \\ 2、synchronized块 public void syncBlock(){ synchronized (this){ System.out.println("hello block"); } }}具体还要辨别: 润饰实例办法,作用于以后实例加锁,进入同步代码前要取得以后实例的锁。不同实例对象的拜访,是不会造成锁的。润饰静态方法,作用于以后类对象加锁,进入同步代码前要取得以后类对象的锁润饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要取得给定对象的锁。它具备的个性: 原子性可见性有序性可重入性synchronized如何实现锁这样看来synchronized实现的锁是基于class对象来实现的,咱们来看看如何实现的,它其实是跟class对象的对象头一起起作用的,对象在内存中的布局分为三块区域:对象头、实例数据和对齐填充。 其中对象头中有一个Mark Word,这里次要存储对象的hashCode、锁信息或分代年龄或GC标记等信息,把可能的状况列出来大略如下: 其中synchronized就与锁标记位一起作用实现锁。次要剖析一下重量级锁也就是通常说synchronized的对象锁,锁标识位为10,其中指针指向的是monitor对象(也称为管程或监视器锁)的起始地址。 每个对象都存在着一个 monitor 与之关联,对象与其 monitor 之间的关系有存在多种实现形式,如monitor能够与对象一起创立销毁或当线程试图获取对象锁时主动生成,但当一个 monitor 被某个线程持有后,它便处于锁定状态。 在Java虚拟机(HotSpot)中,monitor是由ObjectMonitor实现的,其次要数据结构如下(位于HotSpot虚拟机源码ObjectMonitor.hpp文件,C++实现的): ObjectMonitor() { _header = NULL; _count = 0; //记录个数 _waiters = 0, _recursions = 0; _object = NULL; _owner = NULL; _WaitSet = NULL; //处于wait状态的线程,会被退出到_WaitSet _WaitSetLock = 0 ; _Responsible = NULL ; _succ = NULL ; _cxq = NULL ; FreeNext = NULL ; _EntryList = NULL ; //处于期待锁block状态的线程,会被退出到该列表 _SpinFreq = 0 ; _SpinClock = 0 ; OwnerIsThread = 0 ; }下面有2个字段很重要: ...

January 3, 2023 · 2 min · jiezi

关于java:从RedisHTTP协议看Nett协议设计我发现了个惊天大秘密

1. 协定的作用TCP/IP 中音讯传输基于流的形式,没有边界 协定的目标就是划定音讯的边界,制订通信单方要独特恪守的通信规定 2. Redis 协定如果咱们要向 Redis 服务器发送一条 set name Nyima 的指令,须要恪守如下协定 // 该指令一共有3局部,每条指令之后都要增加回车与换行符*3\r\n// 第一个指令的长度是3$3\r\n// 第一个指令是set指令set\r\n// 上面的指令以此类推$4\r\nname\r\n$5\r\nNyima\r\n客户端代码如下 public class RedisClient { static final Logger log = LoggerFactory.getLogger(StudyServer.class); public static void main(String[] args) { NioEventLoopGroup group = new NioEventLoopGroup(); try { ChannelFuture channelFuture = new Bootstrap() .group(group) .channel(NioSocketChannel.class) .handler(new ChannelInitializer<SocketChannel>() { @Override protected void initChannel(SocketChannel ch) { // 打印日志 ch.pipeline().addLast(new LoggingHandler(LogLevel.DEBUG)); ch.pipeline().addLast(new ChannelInboundHandlerAdapter() { @Override public void channelActive(ChannelHandlerContext ctx) throws Exception { // 回车与换行符 final byte[] LINE = {'\r','\n'}; // 取得ByteBuf ByteBuf buffer = ctx.alloc().buffer(); // 连贯建设后,向Redis中发送一条指令,留神增加回车与换行 // set name Nyima buffer.writeBytes("*3".getBytes()); buffer.writeBytes(LINE); buffer.writeBytes("$3".getBytes()); buffer.writeBytes(LINE); buffer.writeBytes("set".getBytes()); buffer.writeBytes(LINE); buffer.writeBytes("$4".getBytes()); buffer.writeBytes(LINE); buffer.writeBytes("name".getBytes()); buffer.writeBytes(LINE); buffer.writeBytes("$5".getBytes()); buffer.writeBytes(LINE); buffer.writeBytes("Nyima".getBytes()); buffer.writeBytes(LINE); ctx.writeAndFlush(buffer); } }); } }) .connect(new InetSocketAddress("localhost", 6379)); channelFuture.sync(); // 敞开channel channelFuture.channel().close().sync(); } catch (InterruptedException e) { e.printStackTrace(); } finally { // 敞开group group.shutdownGracefully(); } }}控制台打印后果 ...

January 3, 2023 · 5 min · jiezi

关于java:含文档PPT源码等微信小程序旅游服务平台后台管理前后分离VUE包运行成功

   博主介绍:✌退职Java研发工程师、专一于程序设计、源码分享、技术交换、专一于Java技术畛域和毕业设计✌ 项目名称 [[含文档+PPT+源码等]微信小程序游览服务平台+后盾治理前后拆散VUE包运行胜利 视频演示 视频去哪了呢?_哔哩哔哩_bilibili 零碎介绍 《微信小程序游览服务平台+后盾管理系统|前后拆散VUE》该我的项目含有源码、文档等材料、配套开发软件、软件装置教程、我的项目公布教程等 本零碎蕴含微信小程序前台和Java做的后盾管理系统,该后盾采纳前后台前后拆散的模式应用Java+VUE 微信小程序——前台波及技术:WXML 和 WXSS、JavaScript、uniapp Java——商城后盾波及技术: 前端应用技术:HTML5,CSS3、JavaScript、VUE等 后端应用技术:Spring、SpringMvc、Mybatis(SSM)等 数据库:Mysql数据库 小程序框架:uniapp 小程序开发软件:HBuilder X 小程序运行软件:微信开发者 随着互联网的趋势的到来,各行各业都在思考利用互联网将本人的信息推广进来, 最好形式就是建设本人的平台信息,并对其进行治理,随着当初智能手机的遍及, 人们对于智能手机外面的利用游览服务软件也在一直的应用,本文首先剖析了游览服务软件应用程序的需要, 从零碎开发环境、零碎指标、设计流程、功能设计等几个方面对系统进行了零碎设计。 开发出本游览服务软件,次要实现了管理员后端;首页、集体核心、游览攻略治理、游览资讯治理、 景点信息管理、门票预约治理、用户治理、酒店信息管理、酒店预约治理、举荐路线治理、论坛治理、系统管理,用户前端;首页、景点信息、酒店信息、论坛核心、我的等。 总体设计次要包含零碎功能设计、该零碎里充沛综合利用Mysql数据库、JAVA等相干常识。网页界面的形成,具备简略易懂、便捷等特色。 设计过程中,第一,动态页面的制作须要利用语言,以及APP的美工,在这些方面均播种了较好的问题。第二,针对HBuilder X等技术动静编程以及数据库进行努力学习和大量实际,并使用到了APP的建设中。 系统结构设计是把一个大工作细分为多个小工作的过程。实现这些小工作后,它们就组合成一个残缺的工作。其具体的工作步骤是: (1)将零碎分解成多个子模块。 (2)预设计各子模块的性能。 (3)设计各子模块之间的逻辑关系。 (4)设计各个模块的接口和模块间的信息传递。 在整个设计过程中,要确定可能的具体解决方案,以实现每一个小的最终目标,对于每一个小指标,咱们首先必须理解一些相干的需要剖析信息。而后对系统进行初步设计,逐渐优化,设计出具体的、可实现的系统结构。 环境须要 1.运行环境:最好是java jdk 1.8,咱们在这个平台上运行的。其余版本实践上也能够。2.IDE环境:IDEA,Eclipse,Myeclipse都能够。举荐IDEA;3.tomcat环境:Tomcat 7.x,8.x,9.x版本均可4.硬件环境:windows 7/8/10 1G内存以上;或者 Mac OS; 5.数据库:MySql 5.7版本;6.是否Maven我的项目:否; 技术栈 后端:Spring+SpringMVC+Mybatis前端:JSP+CSS+JavaScript+jQuery应用阐明 应用Navicat或者其它工具,在mysql中创立对应名称的数据库,并导入我的项目的sql文件;应用IDEA/Eclipse/MyEclipse导入我的项目,Eclipse/MyEclipse导入时,若为maven我的项目请抉择maven;若为maven我的项目,导入胜利后请执行maven clean;maven install命令,而后运行;将我的项目中springmvc-servlet.xml配置文件中的数据库配置改为本人的配置;运行我的项目,在浏览器中输出http://localhost:8080/ 登录运行截图 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑  用户管理控制层: package com.houserss.controller; ...

January 2, 2023 · 5 min · jiezi

关于java:Mybatis的Mapper代理对象生成及调用过程

你在mapper.xml文件中写的sql语句最终是怎么被执行的?咱们编写的mapper接口最终是怎么生成代理对象并被调用执行的? 这部分内容应该是Mybatis框架中最要害、也是最简单的局部,明天文章的次要指标是要搞清楚: mapper.xml文件是怎么初始化到Mybatis框架中的?mapper接口生成动静代理对象的过程。mapper接口动静代理对象的执行过程。把握了以上3个问题,咱们就把握了Mybatis的外围。 Mapper初始化过程指的是mapper.xml文件的解析过程。 这个动作是在SqlSessionFactory创立的过程中同步实现的,或者说是在SqlSessionFactory被build进去之前实现。 XMLMapperBuilder负责对mapper.xml文件做解析,SqlSessionFactorBean的buildSqlSessionFactory()办法中会针对不同配置状况进行解析。其中咱们最罕用的是在配置文件中指定mapper.xml文件的门路(就是源码中的这个mapperLocations): if (this.mapperLocations != null) { if (this.mapperLocations.length == 0) { LOGGER.warn(() -> "Property 'mapperLocations' was specified but matching resources are not found."); } else { for (Resource mapperLocation : this.mapperLocations) { if (mapperLocation == null) { continue; } try { XMLMapperBuilder xmlMapperBuilder = new XMLMapperBuilder(mapperLocation.getInputStream(), targetConfiguration, mapperLocation.toString(), targetConfiguration.getSqlFragments()); xmlMapperBuilder.parse(); } catch (Exception e) { throw new NestedIOException("Failed to parse mapping resource: '" + mapperLocation + "'", e); } finally { ErrorContext.instance().reset(); } LOGGER.debug(() -> "Parsed mapper file: '" + mapperLocation + "'"); } } } else { LOGGER.debug(() -> "Property 'mapperLocations' was not specified."); } return this.sqlSessionFactoryBuilder.build(targetConfiguration);创立XMLMapperBuilder对象并调用parse()办法实现解析。 ...

January 2, 2023 · 2 min · jiezi

关于java:技术阿里云实现ocr实现批量图片和pdf文件表格图片转换excel文档支持票据图片提取普通图片文字提取处理

反对pdf/图片/表格等格式文件装换成excel文件或其余格式文件首先,图片辨认过程 @Test void request_002() throws FileNotFoundException { //读取文件夹 String fileSource = "C:\\Users\\Administrator\\Desktop\\work\\20221217\\invoice\\pageFiles"; String fileName = fileSource + "\\excelFile\\" + "票据_" + DateUtil.format(DateUtil.date(), DatePattern.PURE_DATETIME_PATTERN) + ".xlsx"; long beginTime = System.currentTimeMillis(); List<File> files = FileUtil.loopFiles(fileSource); List<InvoiceVO> getList = new ArrayList<>(); for (File file : files) { Console.log("开始辨认文件 : {}", file.getName()); //申请参数 RecognizeInvoiceRequest request = new RecognizeInvoiceRequest(); RuntimeOptions runtime = new RuntimeOptions(); request.body = new FileInputStream(file.getPath()); try { RecognizeInvoiceResponse response = client().recognizeInvoiceWithOptions(request, runtime); Console.log("文件 :{} 辨认胜利", file.getName()); JSONObject jsonObject = JSONObject.parseObject(response.body.data); String data = jsonObject.getString("data"); Console.log("data : => {}", data); InvoiceVO invoiceData = JSONUtil.toBean(data, InvoiceVO.class); getList.add(invoiceData); } catch (TeaException error) { Console.log(error.message); } catch (Exception _error) { TeaException error = new TeaException(_error.getMessage(), _error); Console.log(error.message); } } //执行写出 if (getList.size() > 0) { Console.log("开始写出excel文件~"); toExcel(getList, fileName); Console.log("文件 : {} 写出胜利! 总耗时 : {} 秒", fileName, (System.currentTimeMillis() - beginTime) / 1000); } }接着,写出excel文件private void toExcel(List<InvoiceVO> getList, String filePathName) { //合并单元格 (开始列,完结列) TreeMap<Integer, Integer> treeMap = new TreeMap<>(); int beforeRow = 1; //不进行合并的列 List<Integer> unMergeList = new ArrayList<>(); //写出的文件列表 List<InvoiceVO> dataList = new ArrayList<>(); for (int i = 0; i < getList.size(); i++) { InvoiceVO invoiceVO = getList.get(i); List<InvoiceDetails> details = invoiceVO.getInvoiceDetails(); for (InvoiceDetails detail : details) { InvoiceVO vo = new InvoiceVO(); BeanUtil.copyProperties(invoiceVO, vo); BeanUtil.copyProperties(detail, vo); dataList.add(vo); } //避免越过合并解决 int detailSize = details.size(); int afterRowSize = beforeRow + detailSize; treeMap.put(beforeRow, afterRowSize - 1); if(detailSize <= 1){ unMergeList.add(beforeRow); } beforeRow = afterRowSize; } //写出文件 ExcelWriter writer = ExcelUtil.getWriter(filePathName); //题目 addHeader(writer); //主动列宽 writer.autoSizeColumnAll(); treeMap.forEach((k, v) -> { //一行详情就不进行合并 if(!unMergeList.contains(k)){ for (int i = 0; i < 22; i++) { //merge : 开始的列号,完结的列号,开始的行号,完结的行号,合并后的数据(主动填充输入数据的列表),是否保留原款式 writer.merge(k, v, i, i, "合并数据", false); } } }); writer.setOnlyAlias(true); writer.write(dataList,true); writer.close(); }最初,效果图 ...

January 2, 2023 · 2 min · jiezi

关于java:文档源码SpringBootMysql实现的宠物在线商城宠物交易平台宠物店源码讲解视频教程开发文档

   博主介绍:✌退职Java研发工程师、专一于程序设计、源码分享、技术交换、专一于Java技术畛域和毕业设计✌ 项目名称 [[文档+源码]SpringBoot+Mysql实现的宠物在线商城宠物交易平台宠物店源码](https://ym.maptoface.com/arch...) 视频演示 视频去哪了呢?_哔哩哔哩_bilibili 零碎介绍 随着中国市场经济的日趋成熟,中国企业面对的竞争压力也越来越大,企业要想生存,就必须有一种高效、便于客户购物和领取的购物模式,因而网上购物这种新的商业经营模式就越来越多的商有使用到竞争中,并失去了大多数客户的认可。这种基于浏览器、服务器实现的购物形式已初具规模,一些电子商务网站的成立,扭转了人们以往的购物观点。 零碎性能需要整体上分为管理员应用性能、用户应用性能,其中管理员应用性能包含系统管理、宠物店治理、新闻治理等性能;用户性能包含查看商品、查看照片库、查看新闻等性能。 依据以上性能需要剖析,通过用例图来形容零碎的次要性能。构建用例模型的第一步是确定模型中的使用者有哪些,确定使用者的准则有:谁是零碎的维护者、谁是零碎的参与者等。维护者处于零碎外部,对系统有相对的控制权;而参与者个别都位于零碎的内部,处于零碎的管制之外。 当初确定本零碎用例模型有两种,别离是管理员、用户。上面别离对这两个角色的性能进行形容: 管理员进入零碎后登陆管理员账号进入管理员页面。管理员次要性能如下(图3-1为管理员用例图): 零碎设置宠物店治理新闻治理前台治理图3-1管理员用例图 用户进入零碎后登陆用户账户进入用户页面。用户次要性能如下(图3-2为用户用例图): 商品咱们提供的照片库新闻列表集体核心购物车图3-2 用户用例图        在确定了管理员、用户性能后就能够构建在线宠物商城零碎的用例图了,整个零碎的用例图如图3-3零碎总体用例图所示: 图3-3 零碎总体用例图 环境须要 1.运行环境:最好是java jdk 1.8,咱们在这个平台上运行的。其余版本实践上也能够。2.IDE环境:IDEA,Eclipse,Myeclipse都能够。举荐IDEA;3.tomcat环境:Tomcat 7.x,8.x,9.x版本均可4.硬件环境:windows 7/8/10 1G内存以上;或者 Mac OS; 5.数据库:MySql 5.7版本;6.是否Maven我的项目:否; 技术栈 后端:Spring+SpringMVC+Mybatis前端:JSP+CSS+JavaScript+jQuery应用阐明 应用Navicat或者其它工具,在mysql中创立对应名称的数据库,并导入我的项目的sql文件;应用IDEA/Eclipse/MyEclipse导入我的项目,Eclipse/MyEclipse导入时,若为maven我的项目请抉择maven;若为maven我的项目,导入胜利后请执行maven clean;maven install命令,而后运行;将我的项目中springmvc-servlet.xml配置文件中的数据库配置改为本人的配置;运行我的项目,在浏览器中输出http://localhost:8080/ 登录运行截图 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑  用户管理控制层: package com.houserss.controller; ...

January 2, 2023 · 5 min · jiezi

关于java:SSM框架的图书借阅管理系统文档ppt实训报告

  博主介绍:✌退职Java研发工程师、专一于程序设计、源码分享、技术交换、专一于Java技术畛域和毕业设计✌ 项目名称 SSM框架的图书借阅管理系统+文档+ppt+实训报告 视频演示 视频去哪了呢?_哔哩哔哩_bilibili 零碎介绍 1.1.1功能分析 为实现图书规模化倒退的需要,本零碎须要反对多图书治理和用户治理,为了进步经营和管理效率,本零碎将借阅端和治理端整合,提供一站式服务。 后端具体性能如下: 用户注册:验证注册信息是否正确。 ADMIN登录:验证账号密码是否正确,并检查用户是管理权限。 用户登录:验证账号密码是否正确,并检查用户是否为读者权限。 读者信息保护:保护每个读者的信息。 管理员信息保护:保护每个管理员的信息。 批改明码信息保护:保护每个用户批改的明码信息。 上传头像信息保护:保护每个用户上传的头像。 图书信息保护:保护每本图书的信息。 图书类型信息保护:保护每种图书类型的信息。 借阅信息保护:保护读者的借阅信息。 布告信息保护:保护每条布告的信息。 数据统计保护:保护用户统计信息、图书统计信息、分类统计信息、借阅统计信息。 拜访拦挡与权限管制性能:拦挡所有申请,合乎接口拜访规定才放行。 前端具体性能如下: 注册页面:输出用户名、明码、实在姓名、性别、出生日期、地址、手机号、邮箱、验证码,注册进入登录页面。 登录页面:输出用户名、明码、验证码,登录进入零碎。 读者信息保护页面:本页面可能保护读者的根本信息。 管理员信息保护页面:本页面可能保护管理员的根本信息。 批改明码信息保护页面:本页面可能保护用户批改的明码信息。 上传头像信息保护:本页面可能保护每个用户上传的头像信息。 图书信息保护页面:本页面可能查问图书信息,申请借阅图书性能。 图书类型信息保护:本页面可能查问每种图书类型的信息。 借阅信息保护:本页面可能保护读者的借阅信息,包含读者信息、借阅的图书信息、借阅工夫等。 布告信息保护:本页面可能查看每条布告的信息。 数据统计保护页面:本页面可能保护用户统计信息、图书统计信息、分类统计信息、借阅统计信息。 环境须要 1.运行环境:最好是java jdk 1.8,咱们在这个平台上运行的。其余版本实践上也能够。2.IDE环境:IDEA,Eclipse,Myeclipse都能够。举荐IDEA;3.tomcat环境:Tomcat 7.x,8.x,9.x版本均可4.硬件环境:windows 7/8/10 1G内存以上;或者 Mac OS; 5.数据库:MySql 5.7版本;6.是否Maven我的项目:否; 技术栈 后端:Spring+SpringMVC+Mybatis前端:JSP+CSS+JavaScript+jQuery应用阐明 应用Navicat或者其它工具,在mysql中创立对应名称的数据库,并导入我的项目的sql文件;应用IDEA/Eclipse/MyEclipse导入我的项目,Eclipse/MyEclipse导入时,若为maven我的项目请抉择maven;若为maven我的项目,导入胜利后请执行maven clean;maven install命令,而后运行;将我的项目中springmvc-servlet.xml配置文件中的数据库配置改为本人的配置;运行我的项目,在浏览器中输出http://localhost:8080/ 登录运行截图 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑  用户管理控制层: package com.houserss.controller; import javax.servlet.http.HttpSession; import org.apache.commons.lang3.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.ResponseBody; ...

January 1, 2023 · 5 min · jiezi

关于java:Java-Nio-Example

selector模型 应用一个线程去监控多个IO申请,如果哪一个IO数据筹备结束后就告诉相应的线程来解决 select模型,它的基本原理是采纳轮询和遍历的形式。也就是说,在客户端操作服务器时,会创立三种文件描述符,简称FD。别离是writefds(写描述符)、readfds(读描述符)和 exceptfds(异样描述符) demo,让主线程监听IO事件而后进行解决 server public class NioServerExample { public static void main(String[] args) throws IOException { Selector selector = getSelector(); listen(selector); } public static Selector getSelector() throws IOException { Selector selector = Selector.open(); //创立可选通道,设置非阻塞 ServerSocketChannel serverSocketChannel = ServerSocketChannel.open(); serverSocketChannel.configureBlocking(false); //绑定通道到指定端口 ServerSocket socket = serverSocketChannel.socket(); socket.bind(new InetSocketAddress(8080)); //向selector注册IO事件,首先注册SelectionKey.OP_ACCEPT让server accept监听 serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT); return selector; } public static void listen(Selector selector) throws IOException { while (selector.select() > 0) { Set<SelectionKey> selectionKeys = selector.selectedKeys(); Iterator<SelectionKey> iterator = selectionKeys.iterator(); if (iterator.hasNext()) { SelectionKey key = iterator.next(); iterator.remove(); //判断IO事件类型进行解决 process(selector, key); } } } private static void process(Selector selector, SelectionKey key) throws IOException { if (key.isAcceptable()) { System.out.println("事件类型 accept"); ServerSocketChannel server = (ServerSocketChannel) key.channel(); SocketChannel channel = server.accept(); channel.configureBlocking(false); channel.register(selector, SelectionKey.OP_READ); } else if (key.isReadable()) { System.out.println("事件类型 read"); SocketChannel channel = (SocketChannel) key.channel(); ByteBuffer byteBuffer = ByteBuffer.allocate(500); int len = channel.read(byteBuffer); if (len > 0) { System.out.println(new String(byteBuffer.array(), 0, len)); channel.register(selector, SelectionKey.OP_WRITE); } else { channel.close(); } byteBuffer.clear(); } else if (key.isWritable()) { System.out.println("事件类型 write"); SocketChannel channel = (SocketChannel) key.channel(); String str = "client fuck you I am Nio Server"; channel.write(ByteBuffer.wrap(str.getBytes())); channel.close(); //向客户端发送数据后断开此通道连贯 } }}client ...

January 1, 2023 · 2 min · jiezi

关于java:OpenTelemetry系列-五|-OpenTelemetry-Java-Instrumentation二次开发指南

前言咱们上一章介绍了OpenTelemetry Java Instrumentation的应用,然而那些都是一些根本的应用,如果有一些自定义的性能,还是须要一些开发工作。本章节将以保姆级教程来介绍一下如何在OpenTelemetry Java Instrumentation上进行二次开发(本文中会将OpenTelemetry Java Instrumentation简写成OJI以不便浏览)。 本文中的相干源码以及相干的实现均为目前的OJI的最新main分支版本目前为1.22.0-SNAPSHOT开发筹备第一次编译OJI应用gradle来进行依赖治理,外围的依赖和仓库等等信息都蕴含在根目录下的settings.gradle.kts中,后续的相干保护也要在其中。并且OJI的开发须要jdk9+的版本,因而须要确认本人的jdk版本是否符合要求。 在确认好后期筹备后进入我的项目,执行gradle assemble来进行打包操作。首次打包可能须要破费超过1个小时,须要急躁期待。除此之外如果遇到依赖拉取失败问题,则能够在build.gradle.kts文件中增加如下配置以应用其余的仓库地址,此处应用的是阿里云仓库: allprojects { repositories { maven { setUrl("https://maven.aliyun.com/nexus/content/groups/public/") } mavenCentral() mavenLocal() jcenter { setUrl("https://jcenter.bintray.com/") } google() }}通过一段时间期待,当控制台输入如下文字,即示意编译胜利。 BUILD SUCCESSFUL in 12m 25s2464 actionable tasks: 2212 executed, 232 from cache, 20 up-to-dateA build scan was not published as you have not authenticated with server 'ge.opentelemetry.io'.For more information, please see https://gradle.com/help/gradle-authenticating-with-gradle-enterprise.之后咱们就能够在javaagent/build/libs目录下找到最终的agent包opentelemetry-javaagent-{version}.jar 新建组件为了便于管理,咱们后续的所有性能示例都将蕴含在一个组件中,而不会进行多组件的宰割。 在进行所有的开发之前咱们须要新建一个组件: 在instrumentation目录下新建一个目录作为组件的目录,我此处将其命名为bjwzds在此目录中新建javaagent目录,并在此目录下创立build.gradle.kts文件,文件内容如下: plugins { id("otel.javaagent-instrumentation")}dependencies {}在全局的settings.gradle.kts中增加hideFromDependabot(":instrumentation:bjwzds:javaagent")或者是include(":instrumentation:bjwzds:javaagent")来引入咱们新增的模块。开始在javaagent目录下构建咱们的我的项目构造,大抵如下:至此咱们开发的筹备工作曾经实现,接下来就是欢快的coding环节了! 自定义Instrumentation须要留神的是在晚期版本中能够本人齐全创立我的项目而后以内部插件的模式来注入,然而在后续版本中这种形式被废除,因而后续的开发都是在clone下来的OJI我的项目中进行开发。 尽管OJI曾经提供了十分多的Instrumentation类库,许许多多出名的开源我的项目都在其中,然而总是可能会有一些须要本人来解决的内容,比方一些商用库,比方一些公司自制的二方或者三方依赖。这些都不可能找到现成的实现,那么就只能本人来了! OJI提供了欠缺的Instrumentation扩大能力,大家能够自行定义本人须要的Instrumentation。 简略例子要创立一个自定义的Instrumentation,最根底的是要先创立一个继承InstrumentationModule的类: ...

January 1, 2023 · 4 min · jiezi

关于java:基于SpringBoot-Vue的电影售票及影院管理系统

   博主介绍:✌退职Java研发工程师、专一于程序设计、源码分享、技术交换、专一于Java技术畛域和毕业设计✌ 项目名称 基于SpringBoot + Vue的电影售票及影院管理系统 零碎介绍 采纳技术如下 数据库:MySQL 数据连接池:Druid Web容器:Apache Tomcat 项目管理工具:Maven 我的项目介绍 随着网络时代的到来,电子信息化的飞速发展,图书馆作为一种信息资源的聚集地,图书品种的繁多,用户借阅的繁琐,蕴含很多的信息数据的治理,以及信息数据的交互。 那么如果有一套具体的欠缺的图书管理系统就显得尤为重要,图书馆如果采纳人工来治理书籍和借阅治理,因为材料繁多,手工解决的形式不仅工作量大,管理效率低下, 也很容易因为疲劳而产生出错,更不不便读者对图书资料的查阅。为了进步图书治理的效率,本我的项目针对图书的治理,设计了一个面向图书的管理系统。 环境须要 1.运行环境:最好是java jdk 1.8,咱们在这个平台上运行的。其余版本实践上也能够。2.IDE环境:IDEA,Eclipse,Myeclipse都能够。举荐IDEA;3.tomcat环境:Tomcat 7.x,8.x,9.x版本均可4.硬件环境:windows 7/8/10 1G内存以上;或者 Mac OS; 5.数据库:MySql 5.7版本;6.是否Maven我的项目:否; 技术栈 后端:Spring+SpringMVC+Mybatis前端:JSP+CSS+JavaScript+jQuery应用阐明 应用Navicat或者其它工具,在mysql中创立对应名称的数据库,并导入我的项目的sql文件;应用IDEA/Eclipse/MyEclipse导入我的项目,Eclipse/MyEclipse导入时,若为maven我的项目请抉择maven;若为maven我的项目,导入胜利后请执行maven clean;maven install命令,而后运行;将我的项目中springmvc-servlet.xml配置文件中的数据库配置改为本人的配置;运行我的项目,在浏览器中输出http://localhost:8080/ 登录运行截图 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑  用户管理控制层: package com.houserss.controller; import javax.servlet.http.HttpSession; import org.apache.commons.lang3.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.ResponseBody; import com.houserss.common.Const;import com.houserss.common.Const.Role;import com.houserss.common.ServerResponse;import com.houserss.pojo.User;import com.houserss.service.IUserService;import com.houserss.service.impl.UserServiceImpl;import com.houserss.util.MD5Util;import com.houserss.util.TimeUtils;import com.houserss.vo.DeleteHouseVo;import com.houserss.vo.PageInfoVo; ...

December 31, 2022 · 5 min · jiezi

关于java:Mybatis事务管理机制

无关数据库事务的基础知识请翻看后面Spring事务管理的几篇文章,与Spring事务管理相比,Mybatis的事务管理非常简单。 底层构造先相熟一下Mabtis事务相干的几个概念、或者说他的底层构造。 TransactionFactory:事务工厂,Mybatis执行数据库操作、获取SqlSession之前要通过TransactionFactory来获取事务管理器。 Transaction:事务管理器,Mybatis最终通过Transaction来实现对数据库操作的事务管制。 TransactionFactory的配置从TransactionFactory的类图能够看到Mybatis共提供了3种不同的事务工厂: JDBCTransactionFactory:基于JDBC的事务工厂,负责创立JDBCTransaction。ManagedTransactionFactory:“被治理的事务工厂”,负责创立ManagedTransaction。SpringManagedTransactionFactory:Spring治理的事务工厂,负责创立SpringManagedTransaction。能够通过Mybatis的环境配置Environment来指定具体应用哪一种事务管理工厂: <environments default="development"> <environment id="development"> <transactionManager type="JDBC"> <property name="..." value="..."/> </transactionManager> <dataSource type="POOLED"> <property name="driver" value="${driver}"/> <property name="url" value="${url}"/> <property name="username" value="${username}"/> <property name="password" value="${password}"/> </dataSource> </environment></environments>通过transactionManager属性能够指定type=“JDBC”或者“MANAGED”,调配对应上述的JDBCTransactionFactory和ManagedTransactionFactory。 然而,如果你正在应用Spring + Mybatis,则SpringManagedTransactionFactory会笼罩掉以上两种设置。 TransactionMybatis的事务管制行为最终由Transaction实现,Transaction的接口定义非常简单: public interface Transaction { Connection getConnection() throws SQLException; void commit() throws SQLException; void rollback() throws SQLException; void close() throws SQLException; Integer getTimeout() throws SQLException;}getConnection负责获取数据库连贯,commit提交事务,rollback回滚事务,close敞开数据库连贯,getTimeout获取事务超时工夫设置。 Mybatis的三种不同的事务管理器须要实现Transaction接口的以上办法从而实现事务管制。 JDBCTransaction如果咱们的我的项目配置了Mybatis的事务管理器为JDBC的话,Mybatis会应用JDBCTransaction来最终实现事务管制,其实也就是上述Transaction接口的几个办法的实现。 JDBCTransactoin源码非常简单,高深莫测。如果事务曾经开启的话(数据库连贯autoCommit=false)则commit和rollback都是间接调用数据库连贯的commit和rollback办法实现事务的提交或回滚。 close办法略微有一点点非凡,就是在敞开数据库连贯之前还调用了一个resetAutoCommit()办法,将数据库连贯的autoCommit设置为true(默认值)。其实这个动作是为了兼容连接池的配置,如果是池化治理数据库连贯的话,close办法的其实是将connection交给连接池而并非真正的敞开,在偿还连接池之前复原其默认值应该也属于“最佳实际”的一种。 @Override public void close() throws SQLException { if (connection != null) { resetAutoCommit(); if (log.isDebugEnabled()) { log.debug("Closing JDBC Connection [" + connection + "]"); } connection.close(); } }JDBCTransactoin其实属于手动管制事务的一种,目前利用应该非常少了。因为他相当于是在获取SqlSession的同时获取数据库连贯并开启了事务,而咱们利用中一个交易往往须要屡次执行数据库操作,也就会屡次获取SqlSession,因而也就不太容易通过JDBCTransactoin管制事务。 ...

December 30, 2022 · 2 min · jiezi

关于java:JAVAJava-日志打印规范

为什么要标准日志标准的日志是养成良好编程习惯的开始,也是关键时刻解决重大BUG的救命稻草。程序员开发的过程中能够打印debug日志,在简单业务中提供日志来排查问题,也能够在呈现生产问题的时候疾速问题,及时处理。无论如何理解和学习日志的标准是程序员必备的基本功。 日志作用线上问题定位。日志次要的作用,外围业务必须要具备残缺的日志以便于问题排查。debug日志调试。在开发和测试中能够通过debug日志调试,在要害局部增加debug日志有利于测试的准确性,开发也能够借助Debug日志进行自测。用户日志行为。次要是记录一些用户敏感操作,用于监控或者经营团队反馈客户问题应用,这些行为一半具备肯定的产品标准。扯皮。次要是第三方对接的时候,如果呈现相似对面忽然改返回参数赖账的状况下能够拿日志作为证据。或者经营误操作也能够用日志讲道理。简略案例间接看一些较为优良的开源框架,或者浏览一些JDK源码的异样解决是不错的形式,这里简略介绍一些例子: 依据具体的异样信息捕捉而日志打印: try { File defaultAclFile = new File(fileName); if (!defaultAclFile.exists()) { defaultAclFile.createNewFile(); } } catch (IOException e) { // 进行具体的异样信息捕捉而日志打印 log.warn("create default acl file has exception when update accessConfig. ", e); }应用String.format 代替 + 拼接以及自定义异样的定义和抛出: try { byte[] signature = sign(data.getBytes(charset), key.getBytes(charset), algorithm); return new String(Base64.encodeBase64(signature), DEFAULT_CHARSET); } catch (Exception e) { // 应用String.format 代替 + 拼接 String message = String.format(CAL_SIGNATURE_FAILED_MSG, CAL_SIGNATURE_FAILED, e.getMessage()); log.error(message, e); // 自定义异样 throw new AclException("CAL_SIGNATURE_FAILED", CAL_SIGNATURE_FAILED, message, e); }有时候异样解决有着意想不到行为,我认为这种解决看上去不错然而实际上很容易“埋雷”,如果作者没有在Doc中进行相干介绍,会是非常危险的行为。 ...

December 30, 2022 · 4 min · jiezi

关于java:Mybatis缓存机制

Mybatis内置了弱小的事务性查问缓存机制,正确应用Mybatis的缓存机制能够无效进步利用的性能。因为个别状况下咱们利用的大部分性能耗费都和数据库查问无关,如果可能无效命中缓存、适当防止或缩小与数据库的交互,肯定是改善利用性能的不二抉择。 然而缓存机制是一把双刃剑,不失当的应用缓存可能会导致数据不统一的问题。 决不能为了解决性能问题而引入数据不统一问题,这是每个开发人员都应该具备的一个根本意识。 所以,为了既可能优雅的解决性能问题,又可能平安的躲避数据不统一问题。咱们有必要对Mybatis的缓存机制做一个透彻的理解。 意识Mybatis缓存机制Mybatis提供了两种不同的缓存机制,也就是咱们常常说的一级缓存、二级缓存。 一级缓存:也叫LocalCache,是基于SqlSession的缓存,也就是说缓存是存储在SqlSession这个级别的,会随着SqlSession的敞开而隐没。二级缓存:是跨SqlSession生命周期的,然而Mybatis的二级缓存的作用于是定义在namespace级别的,对应着mapper.xml文件的定义。跨作用于失效须要进行专门的定义。 其实程序员应该认真对待的是Mybatis的二级缓存机制,因为以及缓存机制是默认开启的、简直也不存在数据不统一的问题,二级缓存机制是须要通过配置开启、而且用不好很容易导致数据不统一的问题。 而且,一级缓存应用起来应该非常简单,所以Mybatis官网对于以及缓存的介绍简直没有,而官网无关缓存的阐明文字简直通篇都是介绍二级缓存的(参考https://mybatis.org/mybatis-3...)。 倡议大家对官网文档做认真学习钻研,对于官网曾经交代过的内容,咱们就不再啰嗦了,本篇文章次要补充一些官网文章没有提及的无关Mybatis缓存机制的技术细节。 一级缓存以及缓存是默认开启的,咱们不须要做任何配置就能够应用Mybatis的一级缓存。 如果你不想开启Mybatis的一级缓存,能够通过Settings配置做全局敞开(localCacheScope=STATEMENT)。 如果你只是针对某一句sql不想开启以及缓存,则能够在mapping的xml文件中针对该sql语句配置flushCache为true,留神flushCache对以及缓存和二级缓存都失效。 倡议还是采纳Mybatis的默认配置,开启一级缓存,尤其是对于那些有高级程序员参加的我的项目,他们对性能的问题思考的可能会少一点,在一个交易中对同一条数据可能会屡次查问,这个时候咱们当然能够通过框架设计、培训、code review等办法尽可能防止这种状况,然而如果无奈防止的话,起码Mybatis的一级缓存能够帮忙咱们在肯定水平上防止无谓的数据库申请。 二级缓存#开启官网说的十分明确,二级缓存须要须要在mapping配置文件中手动开启,否则Mybatis不会主动开启二级缓存。 摘抄官网的一段话: MyBatis 内置了一个弱小的事务性查问缓存机制,它能够十分不便地配置和定制。 为了使它更加弱小而且易于配置,咱们对 MyBatis 3 中的缓存实现进行了许多改良。 默认状况下,只启用了本地的会话缓存,它仅仅对一个会话中的数据进行缓存。 要启用全局的二级缓存,只须要在你的 SQL 映射文件中增加一行:<cache/>基本上就是这样。这个简略语句的成果如下: 映射语句文件中的所有 select 语句的后果将会被缓存。映射语句文件中的所有 insert、update 和 delete 语句会刷新缓存。缓存会应用最近起码应用算法(LRU, Least Recently Used)算法来革除不须要的缓存。缓存不会定时进行刷新(也就是说,没有刷新距离)。缓存会保留列表或对象(无论查询方法返回哪种)的 1024 个援用。缓存会被视为读/写缓存,这意味着获取到的对象并不是共享的,能够平安地被调用者批改,而不烦扰其余调用者或线程所做的潜在批改。不开启二级缓存的状况下,Mybatis底层用BaseExecutor对象执行sql,开启后应用CachingExecutor执行sql,CachingExecutor在创立的时候会持有Mapper初始化过程中以装璜器模式创立好的层层包装的SynchronizedCache对象,sql语句的执行后果最终由这个包装器持有从而实现缓存。 二级缓存#作用范畴咱们后面曾经说过了二级缓存的作用范畴是namespace,Mybatis官网也有一个与句话的提醒: 提醒 缓存只作用于 cache 标签所在的映射文件中的语句。如果你混合应用 Java API 和 XML 映射文件,在共用接口中的语句将不会被默认缓存。你须要应用 @CacheNamespaceRef 注解指定缓存作用域。咱们肯定要对这句话有足够的器重,因为这个中央如果使用不当的话,也是容易引起缓存一致性问题的。 咱们后面开篇也说过数据一致性问题,这个做一个简略的解释: 引入缓存的目标是为了尽可能减少数据库I/O从而进步零碎性能的,如果第一次查问从数据库中获取到了id=1的用户数据并缓存起来,第二次再执行该查问获取id=1的用户数据饿时候,Mybatis就会查看缓存中是否曾经有该数据,如果有的话Mybatis就不会再次执行数据库查问了,会间接给申请端返回缓存中的数据。这个时候咱们也常常称为缓存命中。 如果在二次查问之间有操作批改了id=1的用户信息怎么办,如果Mybatis不晓得本次批改而间接返回了缓存数据的话,就会导致数据不统一的问题,因为利用给前端返回了不正确的数据。 Mybatis当然有本人的解决方案,这个解决方案就是在更新数据的时候刷新缓存,刷新缓存其实就是清空缓存,那么在批改之后的首次查问就会因为无奈命中缓存而通过数据库查问来获取数据,这样的话就不会导致数据不统一的问题了。 然而现实情况往往会比你设想中的简单,比如说你的用户查问的sql语句定义在mapperA.xml中,而用户更新的sql语句定义在mapperB.xml中。 这种状况下,喜剧就产生了,用户更新后基本就不会触发用户信息查问的缓存刷新,因为他们两个作用域不一样,基本不在一个世界中。从技术角度来看,Mybatis底层在进行缓存的时候是以namespace或者说是mapper.xml文件为根底创立缓存对象的,上述的用户查问语句和用户更新语句的缓存对象不同,所以用户更新语句执行实现后基本就不会刷新用户查问语句所在的那个缓存对象! 咱们在开发过程中肯定要留神这个问题,否则的话你可能只晓得我的项目中有些奇怪的问题是Mybatis二级缓存机制导致的,然而却不晓得具体的底层起因,出问题之后要么就是关掉二级缓存,要么就是一通胡乱配置,flushCache或者userCache,这样有时候可能碰巧解决了问题,然而对于底层的技术原理还是没有把握,对集体来说也没有什么帮忙。 二级缓存#刷新距离通过参数flushInterval配置,比方: <cache eviction="FIFO" flushInterval="60000" size="512" readOnly="true"/>设置Mybatis二级缓存刷新距离为60秒,意思是两次查问工夫距离如果超过60秒的话,缓存将会被刷新。 倡议这个参数要么不做配置,Mybatis默认不刷新缓存,要么就配置大一点,比方3小时。 上一篇 MybatisL拦截器

December 29, 2022 · 1 min · jiezi

关于java:elastic-stack-那些事12

logs vs metricslogs 用于记录离散的事件 具备随机性 例如 应用程序的调试信息或谬误等metrics 用于记录度量或者可聚合的数据 具备计划性 例如 服务的响应时长等metrics 组成module metricbeat 收集指标的对象 例如 linux windows mysql 等metricset metricbeat 收集指标汇合 该汇合以缩小收集指标调用次数为划分根据 1个module能够有多个metricset

December 29, 2022 · 1 min · jiezi

关于java:java怎么完成输出语句

咱们在后面的文章和案例中,其实早就晓得Java是如何实现输入性能的了。没错,就是利用System.out.println()语句来实现的!接下来壹哥就给大家具体解读一下这个语句的作用及其含意。 1.System咱们先来看看System是个什么东东。 System是Java自带的一个类,它代表着零碎类。该类位于java.lang包中,很多有用的零碎级别的属性、管制办法都在该类外面。 System类的构造方法是private(公有)润饰的,所以咱们无奈间接创立该类的对象,即无奈实例化该类。对于这些对象的实例化,壹哥在前面解说面向对象时会再具体解说,大家先不要焦急哦。System外部的成员变量和成员办法都是static的,咱们能够很不便的间接进行调用。在System类外面,给咱们提供了如下几个外围性能: ●规范输入输出:如out、in、err; ●内部定义的属性和环境变量的拜访:如getenv()、setenv()、getProperties()和setProperties(); ●加载文件和类库的办法:如load()和loadLibrary(); ●疾速拷贝数组的办法:arraycopy(); ●jvm操作:如gc()、runFinalization()、exit(); ●获取工夫办法:如System.nanoTime 和 System.currentTimeMillis。 2.out与errout示意一种“规范”的输入流,它是System类中的动态成员,能够间接被咱们调用,且这个成员变量是java.io.PrintStream类的援用。 另外还有一个与out性能相似的输入流err。err示意“规范”的谬误输入流,此流能够关上并筹备承受输入的数据。个别err流用于显示谬误音讯,或者用于显示须要引起用户特地留神的信息,在控制台中会显示红色的文字。 其实out和err的用法齐全一样,性能也基本相同。out和err的惟一区别就是,out往往是带缓存性能的,而err没有缓存性能(默认设置,能够更改)。 3.print和printlnprint()和println()都是java.io.PrintStream类里的办法,它们的作用都是向控制台输入信息。两者的根本作用齐全一样,只是print()办法不会产生换行,println()会产生换行,因为println是print line的缩写,示意输入并换行。 通过以上这3个API(利用程序接口)的解说,咱们能够总结出一个根本的规定:在Java中,被static关键字润饰的成员变量,能够间接通过"类名.成员名"的模式来援用,不必创立类的实例对象。所以咱们能够间接调用System类里的动态成员out,即System.out。又因为System.out是java.io.PrintStream类的实例援用,所以又能够通过 System.out.println(); 的模式来调用。 以上这段话,如果你看着有点懵逼,请不必纠结。这属于面向对象的常识,咱们临时还没学到,在前面面向对象的章节中,壹哥会具体解说! 4.根本案例以下是对于规范输入的代码案例,大家对着练习一下即可,很简略的哦。 public class Demo01 { public static void main(String[] args) { //输入语句 //不换行输入 System.out.print("Hello"); System.out.print(" World"); //换行输入 System.out.println("你好"); System.out.println("一一哥"); //规范的谬误输入,控制台会用红色文字显示 System.err.append("规范的谬误输入,哈哈哈"); } }运行成果如下图所示: 5.格式化输入5.1 概念 有时候,计算机默认输入的数据格式,并不一定可能满足咱们的浏览需要,比方有的人想要保留小数点后两位,也有的人想要保留小数点后四位,大家的需要是个性化的,那么Java能不能针对非凡的需要,进行一些个性化的输入呢?这是能够实现的!这就须要用到格式化输入了! 利用格式化输入性能,能够把数据显示成咱们冀望的格局。咱们能够应用System.out.printf()语句,并联合%与?这两个占位符来实现,printf()办法能够把前面的参数格式化成指定的格局。 5.2 占位符 Java为了实现格式化性能,给咱们提供了多种占位符,能够把各种数据类型“格式化”成指定的字符串。罕用的占位符有如下这些: 这里咱们要留神,在输入语句中,%示意占位符。如果间断应用两个%%,应该传入两个对应的数字,否则会把前面的%字符给原文输入。 如果咱们想理解更具体的格式化参数,能够参考JDK文档:java.util.Formatter 5.3 案例 上面是壹哥设计的与本大节对应的代码案例,大家能够对照练习。 public class Demo01 { public static void main(String[] args) { //格式化输入 //默认输入格局 //double d = 88800000; //System.out.println(d); // 8.88E7 double d = 3.1415926; System.out.printf("%.2f\n", d); // 保留2位小数3.14 System.out.printf("%.4f\n", d); // 保留4位小数3.1416 //占位符与格式化 int n = 123456789; //%08x,输入16进制数据,如果有余8位,用0补齐 System.out.printf("n=%d, hex=%08x", n, n); // 留神,两个%占位符应该传入两个数字 }}

December 29, 2022 · 1 min · jiezi

关于java:java输入语句怎么写

壹哥在后面给大家讲过,Java中给咱们提供了有三个规范的“流”,他们被统称为standard streams。除了负责输入的流之外,还有一个负责输出的规范流,Java中对应的API是System.in。 与规范输入相比,规范输出则简单的多。尤其是间接应用System.in时,尽管能够读取到用户的输出,但该形式特地的简单,对咱们初学者来说很不敌对。所以为了更不便地实现输出性能,壹哥给大家介绍一个更简略的Scanner类。 Scanner类2.1 Scanner简介 Scanner类是Java 5中开始提供的,负责解析根本类型和字符串的简略文本扫描器。通过Scanner类,咱们能够获取用户在控制台里的输出数据。Scanner类里罕用API办法有如下几个: nextInt():获取输出的整数; nextDouble():获取输出的双精度浮点数; nextLine():获取输出的字符串,包含单词里的空格和除回车以外的所有字符; next():获取输出的字符串,只从无效字符计算。在无效字符之前遇到的空格键、Tab键、换行符或Enter键等结束符,next()办法会主动将其去掉。只有在输出无效字符之后,next()办法才会将其前面输出的空格键、Tab键或Enter键等都视为分隔符或结束符,并以空格完结。 2.2 应用步骤 咱们要想应用Scanner,须要遵循以下步骤: 1导入Scanner类; 2创立Scanner对象; 3应用Scanner对象扫描输出的内容。 接下来壹哥就给大家设计一个案例,解说Scanner的具体应用。 案例本案例对初学者来说,具备肯定的挑战性,大家要集中精力哦。 //1.import导包:导入Scanner类import java.util.Scanner; public class Demo03 { public static void main(String[] args) { //输出语句 //2.创立一个从键盘录入的Scanner扫描对象 Scanner sc = new Scanner(System.in); //3.应用Scanner对象,扫描输出的内容(整数、小数、字符串、布尔) //在控制台或命令行输出数字,并点击回车键完结 System.out.println("请输出一个数字"); int num = sc.nextInt(); System.out.println("你输出的数字为:"+num); System.out.println("请输出一个小数"); double num2 = sc.nextDouble(); System.out.println("你输出的数字为:"+num2); System.out.println("请输出一个字符串"); String str = sc.next(); System.out.println("你输出的字符串为:"+str);}} 本案例成果如下:

December 29, 2022 · 1 min · jiezi

关于java:京东三面惨遭被虐关于redis高并发分布式微服务一窍不通

京东三面惨遭被虐,对于redis,高并发,分布式,微服务无所不通2022-06-17 20:16·java高端开发三面大略九十分钟,问的货色很全面,须要做短缺筹备,就是除了概念以外问的有点懵逼了(呜呜呜~)。回来之后把这些题目做了一个分类并整顿出答案(强迫症的我~狂补常识~)分为redis缓存,高并发,分布式,微服务等,接下来分享一下我的这京东面试的面经+一些我的学习笔记。留神留神:须要小编整顿的redis缓存,高并发,分布式,微服务等,面试答案、学习笔记、思维脑图(xmind)的敌人能够点击这里即可收费获取。京东对于redis缓存面试真题:我的项目中缓存是如何应用的?为什么要用缓存?缓存使用不当会造成什么结果?redis 和 memcached 有什么区别?redis 的线程模型是什么?为什么 redis 单线程却能撑持高并发?redis 都有哪些数据类型?别离在哪些场景下应用比拟适合?redis 的过期策略都有哪些?内存淘汰机制都有哪些?手写一下 LRU 代码实现?如何保障 redis 的高并发和高可用?redis 的主从复制原理能介绍一下么?redis 的哨兵原理能介绍一下么?redis 的长久化有哪几种形式?不同的长久化机制都有什么优缺点?长久化机制具体底层是如何实现的?redis 集群模式的工作原理能说一下么?在集群模式下,redis 的 key 是如何寻址的?分布式寻址都有哪些算法?理解一致性 hash 算法吗?理解什么是 redis 的雪崩、穿透和击穿?redis 解体之后会怎么样?零碎该如何应答这种状况?如何解决 redis 的穿透?如何保障缓存与数据库的双写一致性?redis 的并发竞争问题是什么?如何解决这个问题?理解redis 事务的 CAS 计划吗?生产环境中的 redis 是怎么部署的?面试真题解析redis缓存学习笔记+xmind思维导图京东对于分布式面试真题:说一下的 dubbo 的工作原理?注册核心挂了能够持续通信吗?说说一次 rpc 申请的流程?dubbo 反对哪些通信协议?反对哪些序列化协定?说一下Hessian 的数据结构?PB 晓得吗?为什么 PB 的效率是最高的?dubbo 负载平衡策略和集群容错策略都有哪些?动静代理策略呢?dubbo 的 spi 思维是什么?如何基于 dubbo 进行服务治理、服务降级、失败重试以及超时重试?分布式服务接口的幂等性如何设计(比方不能反复扣款)?分布式服务接口申请的程序性如何保障?如何本人设计一个相似 Dubbo 的 RPC 框架?zookeeper 都有哪些应用场景?个别实现分布式锁都有哪些形式?应用 redis 如何设计分布式锁?应用 zk 来设计分布式锁能够吗?这两种分布式锁的实现形式哪种效率比拟高?分布式事务理解吗?你们是如何解决分布式事务问题的?面试官心理剖析集群部署时的分布式 session 如何实现?分布式学习笔记+xmind思维导图:京东对于微服务面试真题:什么是 Spring Cloud?应用 Spring Cloud 有什么劣势?服务注册和发现是什么意思?Spring Cloud 如何实现?负载平衡的意义什么?什么是 Hystrix?它如何实现容错?什么是 Hystrix 断路器?咱们须要它吗?什么是 Netflix Feign?它的长处是什么?什么是 Spring Cloud Bus?咱们须要它吗?微服务学习笔记+xmind思维导图:总结:自从在京东碰壁之后,花了一个月的工夫学习梳理了这些知识点,筹备来日再战,除了高并发,分布式,微服务之外,还整顿了有java根底,微服务,Kafka等知识点的笔记。以及1500道大厂面试题的整顿。面试整体以及思维导图获取形式:[点击这里即可](https://docs.qq.com/doc/DY0Fr...) ...

December 29, 2022 · 1 min · jiezi

关于java:实践动手封装springbootstarter

把之前写的繁难RPC框架封装下 [1] 简述主动拆卸原理在springboot的外围注解@SpringBootApplication里蕴含一个名为@EnableAutoConfiguration的注解,这是执行主动拆卸的要害 而在 @EnableAutoConfiguration 注解中理论执行主动拆卸 的是AutoConfigurationImportSelector 类 该类的getAutoConfigurationEntry办法调用getCandidateConfigurations办法扫描resource目录下META-INF/spring.factories文件返回须要被加载进IOC容器的配置类列表 总结:springboot主动拆卸是因为在启动类上存在@EnableAutoConfiguration注解,所以在启动时会扫描被援用starter的jar包下META-INF/spring.factories文件,把外面申明的主动配置类加载进IOC容器中 [2] 封装spring-boot-starterPOM文件中写好该starter信息 在resource/META-INF下新建spring.factories文件外面写上主动配置类的全限定类名(包门路+类名) 而后在以后我的项目的子模块中就能够了援用了,或者应用maven打包后mvn install:install-file -Dfile={} -DgroupId={} -DartifactId={} -Dversion={} -Dpackaging={} 转存至本地maven仓库就能够在其余我的项目中援用了。 [3] 对于RPC基于注解的服务主动注册,发现BeanPostProcessor类是IOC容器对外提供的扩大接口,外部有两个办法bean 初始化前的解决: postProcessBeforeInitializationbean 初始化后的解决: postProcessAfterInitialization 因为咱们的主动定义注解是这样被应用于service bean的,所以服务注册是须要在bean初始化前执行 自定义服务发现的注解作用于controller bean的属性字段上,所以是在bean初始化后在对其进行解决 扫描到该bean的field存在注解时,获取该字段信息,应用动静代理使该字段的bean加强,而后field.set(bean, proxyObject)从新对controller bean的该字段设置新值

December 29, 2022 · 1 min · jiezi

关于java:mybatis拦截器

Mybatis反对四种类型的拦截器,这一点能够从Mybatis的初始化类Configuration.java中失去验证(源码体不贴出了,改天剖析Mybatis初始化过程的时候具体说)。具体包含: ParameterHandler拦截器ResultSetHandler拦截器StatementHandler拦截器Executor拦截器四种拦截器别离有各自不同的用处,当咱们相熟Mybatis的运行机制之后,了解起来就绝对容易一些。 目前,如果咱们对Mybatis还不是很理解的话,也没有关系,不影响咱们对Mybatis的拦截器做初步的理解。 咱们不须要一次性对四种类型的拦截器都理解,因为他们的工作机制及底层原理大致相同。 咱们明天以Executor拦截器为切入点,理解Mybatis拦截器的实现办法、以及初步剖析其实现原理。 明天的指标是:用Mybatis拦截器技术,计算每一句sql语句的执行时长,并在控制台打印进去具体的sql语句及参数。 在此过程中,咱们会理解: 编写Mybatis拦截器。Mybatis拦截器注册。Mybatis拦截器的初始化过程。Mybatis拦截器是如何失效的。筹备工作Springboot我的项目,并引入Mybatis,pom文件退出依赖: <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>2.1.3</version></dependency>而后配置数据库拜访、建表、创立mapper.xml文件及mapper对象,在mapper.xml中写一个简略的获取数据的sql、应用mapper对象通过该sql语句获取数据。 明天文章的次要指标是拦截器,所以以上对于通过Mybatis获取数据库数据的代码就不贴出了。 编写拦截器Mybatis拦截器是AOP的一个具体实现,咱们后面文章剖析过AOP的实现原理其实就是动静代理,java实现动静代理有两种形式:cglib和java原生(咱们后面有一篇文章专门剖析过两者的区别),Mybatis拦截器是通过java原生的形式实现的。 其实咱们实现的拦截器在java原生动静代理的框架中属于回调对象的一部分,回调对象其实是Plugin,Plugin对象持有Interceptor,Plugin的invoke办法才是JDK动静代理中的那个回调办法、其中会调用Interceptor的intercept办法,所以Plugin的invoke办法其实又相似于一个模板办法(这部分前面会有具体分析)。 所以Mybatis都曾经替咱们安顿好了,咱们的拦截器只须要实现这个intercept办法即可。 @Slf4j@Component@Intercepts(@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}))public class myInterceptor implements Interceptor { @Override public Object intercept(Invocation invocation) throws Throwable { MappedStatement ms = (MappedStatement) invocation.getArgs()[0]; Object param = invocation.getArgs()[1]; BoundSql boundSql = ms.getBoundSql(param); String sql=boundSql.getSql(); sql=sql.trim().replaceAll("\\s+", " "); log.info("sql:"+ sql); log.info("param:" + param); long startTime=System.currentTimeMillis(); Object result=invocation.proceed(); long endTime=System.currentTimeMillis(); log.info("sql statement take :"+ (endTime - startTime)); return result; }}要实现的指标都在下面这段代码中,高深莫测。 ...

December 28, 2022 · 2 min · jiezi

关于java:elastic-stack-那些事11

input 插件指定数据输出源 一个pipeline能够有多个input插件 次要有三 stdin file kafka最简略的输出 从规范输出读取数据 通用配置为 codec 类型为codectype类型为string 自定义该事件的类型 可用于后续判断tags类型为array 自定义该事件的tag 可用于后续判断add_field 类型为hash 为该事件增加字段input plugin file从文件读取数据 如日志文件 文件通常要解决几个问题 文件内容如何只被读取一次,即重启ls是,从上次地位持续读 -sincedb如何读取到文件的新内容 定时查看文件是否更新如何发现新文件并进行读取 定时查看文件文件产生了归档 rotation 操作 是否影响以后的内容读取?不影响 被归档的文件内容能够持续被读取path类型 为 数据 指定读取的文件门路 基于 glob匹配语法 path => ["/var/log/*/.log"]exclude 乐星为数据 排除不想监听的文件规定 基于glob匹配语法 exclude => "*.gz"sincedb_path 类型为字符串 记录sincedb文件门路start_position类型为字符串 beginning or end 是否从头读取文件stat_interval 类型为数值 单位秒 定时查看文件是否更新discover_interval 类型为数据 单位秒 定时查看是否有新文件待读取,默认15秒ignore_older 类型为数据 单位秒 扫描文件列表时 如果该文件上次更改事件超过设定时长,则不做解决,但仍然会监控是否有新内容close_older类型为数值 单位秒 如果监听的文件超过该设定事件内没有新内容 会变为敞开文件句柄 开释资源 但仍然会监控是否有新内容 默认3600秒 即一个小时codec plugincodec plugin 作用域input和output plugin 负责将数据在原始与logstash event 之间做转换 常见的有 ...

December 28, 2022 · 1 min · jiezi

关于java:elastic-stack-那些事10

logstash架构pipeline input-filter-output 3阶段解决流程队列治理插件生命周期治理logstash event 外部流转的数据表现性时原始数据在input被转换为event 在output event被转换为指标格局数据在配置文件中可对event中的属性进行增删改查 queuein memory 无奈解决 crash 宕机等状况 导致数据失落persistent queue in disk 可解决crash 等状况 数据不会失落保证数据至多生产一次充当缓冲区 代替kafka等音讯队列queue.type:persisted (default memory)queue.max_bytes:4gb 队列存储最大数据量线程配置pipeline.workers|-w pipeline线程数即filter_output解决线程数 默认是cpu核数pipeline.batch.size|-b batcher 一次批量获取待处理文档数 默认125 能够依据输入进行调整 越大 占用的heap空间 能够通过jvm.options调整pipeline.batch.delay|-u Batcher期待的时长 单位为ms配置logstash 设置配置文件 logstash.yml logstash配置 例如 node.name path.data pipeline.workers queue.typejvm.options 批改jvm参数 例如 heap sizepipeline 定义数据处理流程文件以conf结尾多实例运行bin/logstash --path.settings instance1/2不同的instance中批改logstash.yml 自定义path.data 确保其不雷同pipeline 配置用于配置 input filter output 插件input{}filter{}output{} 次要的数值类型 boolean : isFailed => true数值类型 Number port=>33字符串类型 String name=>"hello world"数组 users => [{id=>1, name=>bob},{id=>2, name=> lili}]path => ["/var/log/messages","/var/log/*.log"]hash match=>{ ...

December 28, 2022 · 1 min · jiezi

关于java:一篇文章搞定Netty-三大组件如果搞不定再加俩钟

1. 三大组件简介Channel 与 Buffer Java NIO 零碎的外围在于:通道 (Channel) 和缓冲区 (Buffer)。通道示意关上到 IO 设施 (例如:文件、套接字) 的连贯。若须要应用 NIO 零碎,须要获取用于连贯 IO 设施的通道 以及用于包容数据的缓冲区。而后操作缓冲区,对数据进行解决 简而言之,通道负责传输,缓冲区负责存储 常见的 Channel 有以下四种,其中 FileChannel 次要用于文件传输,其余三种用于网络通信 FileChannelDatagramChannelSocketChannelServerSocketChannelBuffer 有以下几种,其中应用较多的是 ByteBuffer ByteBuffer MappedByteBufferDirectByteBufferHeapByteBufferShortBufferIntBufferLongBufferFloatBufferDoubleBufferCharBuffer 1、Selector在应用 Selector 之前,解决 socket 连贯还有以下两种办法 应用多线程技术 为每个连贯别离开拓一个线程,别离去解决对应的 socket 连贯 这种办法存在以下几个问题 内存占用高 每个线程都须要占用肯定的内存,当连贯较多时,会开拓大量线程,导致占用大量内存线程上下文切换老本高只适宜连接数少的场景 连接数过多,会导致创立很多线程,从而呈现问题应用线程池技术 应用线程池,让线程池中的线程去解决连贯 这种办法存在以下几个问题 阻塞模式下,线程仅能解决一个连贯 线程池中的线程获取工作(task)后,只有当其执行完工作之后(断开连接后),才会去获取并执行下一个工作若 socke 连贯始终未断开,则其对应的线程无奈解决其余 socke 连贯仅适宜短连贯场景 短连贯即建设连贯发送申请并响应后就立刻断开,使得线程池中的线程能够疾速解决其余连贯应用选择器 selector 的作用就是配合一个线程来治理多个 channel(fileChannel 因为是阻塞式的,所以无奈应用 selector),,获取这些 channel 上产生的事件,这些 channel 工作在非阻塞模式下,当一个 channel 中没有执行工作时,能够去执行其余channel 中的工作。适宜连接数多,但流量较少的场景 若事件未就绪,调用 selector 的 select () 办法会阻塞线程,直到 channel 产生了就绪事件。这些事件就绪后,select 办法就会返回这些事件交给 thread 来解决 ...

December 28, 2022 · 12 min · jiezi

关于java:OSI网络七层模型和TCPIP模型

如果你是计算机专业毕业或者学习过网络通信,那你肯定听晓得OSI模型OSI 是Open System Interconnection 的缩写,译为“开放式系统互联”。 OSI模型把网络通信的工作分为7层,从下到上别离是物理层、数据链路层、网络层、传输层、会话层、表示层和应用层。 然而它的毛病是分层太多,减少了网络工作的复杂性,所以没有大规模利用。 起初人们对 OSI 进行了简化,合并了一些层,最终只保留了4层,从下到上别离是接口层、网络层、传输层和应用层,这就是大家相熟的TCP/IP模型。 OSI 7层 TCP/IP 4层 OSI 7层 和 TCP/IP 4层 比照图 这个网络模型到底是干什么呢?简而言之就是进行数据封装的。 咱们通常应用的程序(或软件)通常通过应用层拜访网络,程序生成的数据将逐层向下传输,直到最终的网络接口层,而后通过网线发送到互联网。每次数据向下一层时,它都将被该层的协定包装。当它被发送到互联网时,比原始数据多了四层包装。整个数据封装过程就像一个俄罗斯套娃医院。 当另一台计算机接管到数据包时,它将从网络接口层传输到下层。每个传输层将被解包。直到最初一个应用层,将取得最原始的数据,即程序将应用的数据。 打包数据的过程实际上是在数据的头中增加一个标记(数据块),以批示数据曾经通过该层,并且我曾经对其进行了解决。解包数据的过程正好相同,即移除数据头的标记,让其逐步显示其原始形态 你看,在互联网上传输一段数据是如许简单,但咱们感觉不到。这就是网络模型的威力。咱们只须要在代码中调用一个函数,就能够让所有的网络层为咱们工作。 大家相熟的socket编程,是站在传输层的根底上,所以能够应用TCP/UDP 协定,然而不能做拜访网页事件,因为拜访网页所须要的http协定位于应用层。 当两台计算机通信时,必须恪守的准则: 必须是同一档次进行通信,比方,A 计算机的应用层和 B 计算机的传输层就不能通信,因为它们不在一个档次,数据的拆包会遇到问题。每一层的性能都必须雷同,也就是领有完全相同的网络模型。如果网络模型都不同,那不就乱套了,谁都不意识谁。数据只能逐层传输,不能跃层。每一层能够应用上层提供的服务,并向下层提供服务。

December 28, 2022 · 1 min · jiezi

关于java:面试官问为啥不建议使用-Select-请你大声地回答他

作者:小指标青年\起源:https://blog.csdn.net/qq_3538... 前言不倡议应用 select *这几个字眼,做开发的都不生疏吧。 阿里的开发手册下面也是有提到: 这个完整版能够关注公众号Java核心技术,而后在公众号后盾回复手册获取。 昨晚收到一个小兄弟的反馈: 随后也问了下学习群里的兄弟们, 不敢吱声的: 如同派: 离谱的: 那么,我作为一个出手侠, 我必然要出手了。 出手侠: 习惯用语,等到xxxxx的时候,我就会出手。注释 这个完整版能够关注公众号Java核心技术,而后在公众号后盾回复手册获取。其实阿里巴巴手册上阐明的三点了: 1) 减少查问分析器解析老本什么是分析器老本,什么货色,我顺手画个简图,大家晓得一下: 就是这个分析器,这里会去解析你的sql的语法,词法。 举例,如果是select * from user , 看到 * ,就会去看看是哪个表 user,而后 Query Table Metadata For Columns,把所有列值给你支楞进去,填充成相似 select id ,name ,age,phone form user 这样子。(当然还有其余剖析了,例如如语法的判断, 字段的判断, 表名等等) 说实话。这个分析器的老本....你要是说减少了解析老本,我的确能了解。 然而我感觉老本也不是很大.... 除非是个大表,大到查问完所有列值? so,我能承受,然而承受得不多。 2) 增减字段,容易与resultMap 配置不统一这一点我不想说。说切实的,有时候写select *(须要查表所有列值的时候), 我实体加了字段,我改了resultMap ,我sql还不必动。 这一点属于是平时应用标准上的躲避点了,不多言。 3)无用字段减少网络耗费、磁盘IO开销这一点有考究。 能够看到我第一点外面画的简图, 如果说 不思考缓存 存在的时候: 最终会走到执行器,而后执行器前面其实是引擎层 引擎层这里我就不开展了,引擎层外面其实包含了各种日志(undo、redo、binlog等)的记录,还有就是在内存里找数据。 简略点演绎,其实这种查问操作就是刷盘操作,从磁盘刷入内存,波及到的 磁盘IO开销。那么在刷盘操作的时候,是不是真的selec * 就真的会 减少 磁盘IO开销呢? ...

December 28, 2022 · 1 min · jiezi

关于java:elastic-stack-那些事9

集群调优elasticsearch.yml 中尽量只写必备参数其余通过api动静设置参见文档 setup elasticsearch -》impotant elasticsearch configuration随着es降级 很多网络流传的配置参数不再反对根本参数设置cluster.namenode.namenode.master/node.data/node.ingestnetwork.host 倡议指定的内网ip 而不是偷懒设置为0.0.0.0discovery.zen.ping.unicast.hosts 设置为集群其余节点地址discovery.zen.minimum_master_nodes个别设定为2path.data/path.log除上述参数外再依据须要再减少其余动态配置参数动静设定的参数有transient和persistent两种,前者再集群重启后会失落,后者不会,然而两种设置都会笼罩elasticsearch.yml的配置jvm内存不要超过31GB余留一半给操作系统,用来做文件缓存具体大小杜绝存储的数量来估算,为了性能,在内存和数据量间有一个倡议的比例 搜寻类我的项目的比例倡议在1:16以内日志类我的项目比例在1:48 - 1:96假如总数据量大小为1TB 3个node 1正本 那么每个node存储的数量为666GB,即700GB,预留20%,每个node存储850GB数据如果是搜寻类,每个node内存大小为850GB/16=53GB 大于31GB 31*16=496 即每个node最多存储496GB数据 即起码须要5个node如果是日志类我的项目 每个node内存大小为850GB/48=18GB因而三个节点足够写性能优化指标是增大写的吞吐量eps客户端 多线程写es 在高质量数据建模的前提下 次要在refresh translog flush 之间做文章 升高refresh频率 减少refresh_interval 升高实时性 增大每次refresh文档解决数,默认为1s 设置为-1 禁止主动refresh减少index buffer size 参数为indices.memory.index_buffer_size 动态参数 须要设定在elasticsearch.yml 默认为10%升高translog写磁盘的频率 进步写效率 然而 升高了灾备的能力 index.translog.durability 设置为async index.translog.sync_interval设置须要的大小 例如 120s那么translog每120s写一次磁盘index.translog.flush_threshold_size 默认为512mb 即translog超过大小时会触发一次flush,那么调大该大小能够防止flush产生设置正本数0 写入结束后再减少正当设计shard数 保障shard均匀分布在集群上 充分利用资源 index.routing.allocation.total_shards_per_node限定每个索引在每个node上可调配的总主副分片数5个node某索引有10个主分片 1个正本 上述值该设置为多少? (10+10)/5=4理论设置5个 搁置在node下线时 分片迁徙失败读优化高质量的数据建模是优化的根底将须要通过script脚本动静计算的值进步筹备好作为字段存储在文档中尽量使得数据模型贴近业务模型设定shard数es性能是线性扩大的 只须要测出一个shard的性能指标,而后依据需要算出须要几个shard,例如单个shard写入eps是10000 那么需要是50000 则须要5个shard测试单个shard 搭建与生产雷同配置的单节点集群设定一个单分片零正本索引写入理论生产数据进行测试 获取性能指标针对数据进行查问申请 获取读性能指标压测器具可选esrally搜寻场景 单个shard大小不要超过15gb,如果是日志场景 单个shard不要超过50GB shard越大 查问性能越低此时只有估算出索引总数居大小再除以单个shard大小也能够失去分片数

December 27, 2022 · 1 min · jiezi

关于java:全网最全java进制转换详解

前言在上一篇文章中,壹哥给大家讲了Java里的各种运算符。其中在解说位运算符时,我给大家提到了计算机中进制的概念。然而当初很多小白同学,对进制的概念还不够理解,比方二进制、八进制、十六进制都是怎么回事?有什么特点?进制之间怎么转换?原码、反码、补码都是什么意思?......这些问题还困扰着很多童鞋。所以明天壹哥会再利用一篇文章,专门给大家解说计算机中进制相干的内容,尤其是二进制,你须要认真浏览哦。 ------------------------------前戏已做完,精彩即开始-------------------------- 全文大概【3600】字,不说废话,只讲能够让你学到技术、明确原理的纯干货!本文带有丰盛案例及配图,让你更好地了解和使用文中的技术概念,并能够给你带来具备足够启迪的思考...... 一、进制1、概念 首先咱们得晓得进制的概念。所谓的进制,也叫做进位计数制,这是人为定义的带进位的计数办法。当然也有不带进位的计数办法,比方原始的结绳计数法,唱票时罕用的“正”字计数法等。 任何一种进制,每一位上的数在运算时都是满X进一位。比方十进制是逢十进一,十六进制是逢十六进一,二进制就是逢二进一,以此类推,X进制就是逢X进1位。以咱们最相熟的十进制为例,每逢十进一,当数为19时,下一位数的尾数便满足该进制的最大数,于是下一位末位清零,前置位+1,变成20。 2、分类 在计算机中,目前罕用的进制有如下几种: ●十进制;●二进制;●八进制;●十六进制 因为在计算机的底层只能解决二进制格局的数据,也就是0和1,其余的文字、数字、字符等信息都要转换成二进制的格局,计算机的底层能力辨认解决。所以作为一个程序员,二进制是咱们必须要了解和把握的哦。 3、二进制 作为一个程序员,必须要把握的进制就是二进制了,其实咱们只须要参考十进制就能够很容易了解进制的问题了。所谓的二进制,外面只有0和1,且满二进一,所以在二进制里是看不到>=2的数的。比方二进制的前10位数别离是0、1、10、11、100、101、110、111、1000、1001。 4、八进制 八进制中有0~7共8个数字,但没有8哦,其规定是满八进一,所以7的下一位数不是8,而是10。17的下一位数不是18,而是20。比方八进制的前10位数别离是0、1、2、3、4、5、6、7、10、11...... 5、十六进制 十六进制中有0~F共16个数字,同样没有16,其规定是满十六进一。在十六进制中,这16个数字别离是0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F。即9的下一位不是10,而是A,10这个数只是十进制的衍生物,这一点大家要留神! 同理,在十六进制中,19的下一位不是20,而是1A,1F的下一位才是20;99的下一位是9A,FF的下一位才是100。 6、原码、反码与补码 6.1 原码对一个正整数来说,所谓的原码,就是指一个整数对应的二进制,比方整数10的原码就是00001010。所以原码就是一个正整数本来对应的二进制模式。但正数的原码和负数却不一样,正数的原码要将负数原码的符号位(最高位)改为1,比方-10的原码就是10001010。 6.2 反码负数的反码就是其原码,即负数的原码和反码完全相同。而正数的反码则是将原码中除符号位以外的所有位(数值位)都取反,即 0 变成 1,1 变成 0。如10的原码和反码都是00001010,而-10的原码是10001010,反码则是11110101。 6.3 补码负数的补码就是其原码,所以负数的原码、反码、补码都雷同。而正数的补码是其反码加1,-10的原码是10001010,反码则是11110101,补码则是11110110。咱们能够认为,补码是在反码的根底上打了一个补丁,进行了一点修改,所以叫做“补码”。 所以原码、反码、补码的概念只对正数有实际意义,对于负数来说,原码、反码、补码其实都是一样的,如下图所示: 理解完这些进制的概念之后,接下来壹哥就给大家解说最重要的进制转换问题,拿出小本本做好记录哦,重点来啦。 二、进制转换1、十进制和二进制的转换(把握) 首先咱们来学习十进制与二进制之间的转换,这是必须要把握的哦。 1.1 十转二 如果咱们想将十进制转为二进制,能够采纳辗转法,将十进制除以2再取余,而后将余数和最初的1依照从下向上倒序写的办法。例如咱们想将十进制的302转为对应的二进制,过程如下: 302➗2 = 151 余0 151➗2 = 75 余1 75➗2 = 37 余1 37➗2 = 18 余1 18➗2 = 9 余0 9➗2 = 4 余1 4➗2 = 2 余0 2➗2 = 1 余0 ...

December 27, 2022 · 1 min · jiezi

关于java:Spring-Cloud-2022-正式发布我的天OpenFeign-要退出历史舞台了

大家好,我是栈长。 明天给大家通报一则框架更新音讯,时隔 2021.x 版本公布一年,Spring Cloud 2022.0.0 最新版公布了,来看下最新的 Spring Cloud 版本状况: Spring Cloud 无疑是当初 Java 微服务事实上的规范,齐全基于 Spring Boot 构建,依赖 Spring 生态体系,能够很好的与各种 Spring 生态我的项目无缝对接。 Maven 依赖先给大家奉上: <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>2022.0.0</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies></dependencyManagement>Spring Cloud 依赖治理采纳的是 import 导入形式,外面治理了许多依赖,对立引入治理,应用时只须要引入对应依赖的坐标即可,不须要指定版本号。 Spring Cloud 目前保护着 4 条版本主线: Spring Cloud 2022.xSpring Cloud 2021.xSpring Cloud 2020.xSpring Cloud Hoxton.x(实际上曾经进行保护了)对于这些版本线的命名是不是很奇怪? 另外,还有几天都要 2023 年了,怎么当初才公布 2022 版本? 其实 Spring Cloud 最新的版本命名形式早曾经变更了,当前就是 YEAR.x 这种命名形式了,不分明的能够看下栈长之前写的两篇文章: Spring Cloud 2020.0.0 正式公布,全新颠覆性版本!Spring Cloud 2020 版本重大改革,更好的命名形式!所以说,Spring Cloud 2022.0.0 中的 2022 是指 Spring Cloud 2022.x 版本线,2022.0.0 则是指 2022 这个版本线的第 1 个版本,而不是指某个年份公布的版本。 ...

December 27, 2022 · 2 min · jiezi

关于java:学习下Redis内存模型

作者:京东批发 吴佳前言redis,对于一个java开发工程师来讲,其实算不得什么简单离奇的技术,但可能也很少人去深刻理解学习它的底层的一些货色。上面将通过对内存统计、内存划分、存储细节、对象类型&外部编码这四个模块来学习学习redis的内存模型,手字笔录,潜心修行。 一、redis的内存统计info memory 命令查看内存应用状况:服务器根本信息、CPU、内存、长久化、客户端连贯信息等等,如下图: (1)used_memory和used_memory_rssused_memory:Redis分配器调配的内存总量 + 虚拟内存(磁盘) used_memory_rss:Redis过程占据操作系统的内存 + 过程运行自身须要的内存 + 内存碎片等 (*:留神 used_memory_rss 不包含虚拟内存) 两者区别: ①面向角度:used_memory: Redis角度 used_memory_rss:操作系统角度 ②大小不肯定是后者大于前者:内存碎片和Redis过程运行须要占用内存,使得前者可能比后者小,另一方面虚拟内存的存在,使得前者可能比后者大 (2)mem_fragmentation_ratio内存碎片比率, 等于 used_memory_rss / used_memory mem_fragmentation_ratio > 1 : 值越大,内存碎片比例越大 mem_fragmentation_ratio < 1 : 阐明Redis应用了虚拟内存 *:因为虚拟内存的媒介是磁盘,比内存速度要慢很多,当这种状况呈现时,应该及时排查,如果内存不足应该及时处理,如减少Redis节点、减少Redis服务器的内存、优化利用等。 失常状况下:mem_fragmentation_ratio = 1.03左右 (衰弱:对于jemalloc来说) 下面的状况:没有向Redis中存入数据,Redis过程自身运行的内存使得used_memory_rss 比used_memory大得多 (3)mem_allocator:Redis应用的内存分配器,在编译时指定,能够是 libc 、jemalloc或者tcmalloc,默认是jemalloc。 (4)used_memory_peak:Redis的内存耗费峰值 (5)used_memory_human和used_memory_peak_human:字面含意,以人类浏览的形式返回。 二、redis的内存划分数据:最次要的局部,会统计在used_memory。实际上,在Redis外部,每种类型可能有2种或更多的外部编码实现。此外,Redis在存储对象时,并不是间接将数据扔进内存,而是会对对象进行各种包装:如RedisObject、SDS等。 过程自身内存:Redis主过程自身运行必定须要占用内存,如代码、常量池等等。这部分内存大概几兆,在大多数生产环境中与Redis数据占用的内存相比能够疏忽。这部分内存不是由jemalloc调配,因而不会统计在used_memory中。 缓冲内存:蕴含客户端缓冲区、复制积压缓冲区、AOF缓冲区 客户端缓冲区:存储客户端连贯的输入输出缓冲 复制积压缓冲区:用于局部复制性能 AOF缓冲区:用于在进行AOF重写时,保留最近的写入命令 内存碎片:内存碎片是Redis在调配、回收物理内存过程中产生的。 三、redis的数据存储细节当咱们执行一个redis指令,比方:set hello world,redis底层存储到底干了什么? 下面就波及到两个概念:jemalloc和RedisObject(1)jemalloc内存分配器:能够是 libc 、jemalloc或者tcmalloc,默认jemalloc jemalloc内存划分:小、大、微小,每个又分许多小内存块单位 ...

December 27, 2022 · 1 min · jiezi

关于java:10-种超好用的-MyBatis-写法同事都说好用

作者:smile_lg \起源:blog.csdn.net/smile_lg/article/details/71215619 用来循环容器的标签forEach,查看例子foreach元素的属性次要有item,index,collection,open,separator,close。 item:汇合中元素迭代时的别名,index:汇合中元素迭代时的索引open:常用语where语句中,示意以什么开始,比方以'('开始separator:示意在每次进行迭代时的分隔符,close 常用语where语句中,示意以什么完结,在应用foreach的时候最要害的也是最容易出错的就是collection属性,该属性是必须指定的,然而在不同状况下,该属性的值是不一样的,次要有一下3种状况: 如果传入的是单参数且参数类型是一个List的时候,collection属性值为list .如果传入的是单参数且参数类型是一个array数组的时候,collection的属性值为array .如果传入的参数是多个的时候,咱们就须要把它们封装成一个Map了,当然单参数也能够封装成map,实际上如果你在传入参数的时候,在MyBatis外面也是会把它封装成一个Map的,map的key就是参数名,所以这个时候collection属性值就是传入的List或array对象在本人封装的map外面的key.针对最初一条,咱们来看一下官网说法: 留神 你能够将一个 List 实例或者数组作为参数对象传给 MyBatis,当你这么做的时候,MyBatis 会主动将它包装在一个 Map 中并以名称为键。List 实例将会以“list”作为键,而数组实例的键将是“array”。所以,不论是多参数还是单参数的list,array类型,都能够封装为map进行传递。如果传递的是一个List,则mybatis会封装为一个list为key,list值为object的map,如果是array,则封装成一个array为key,array的值为object的map,如果本人封装呢,则colloection里放的是本人封装的map里的key值 //mapper中咱们要为这个办法传递的是一个容器,将容器中的元素一个一个的//拼接到xml的办法中就要应用这个forEach这个标签了public List<Entity> queryById(List<String> userids);//对应的xml中如下 <select id="queryById" resultMap="BaseReslutMap" > select * FROM entity where id in <foreach collection="userids" item="userid" index="index" open="(" separator="," close=")"> #{userid} </foreach> </select>concat含糊查问//比如说咱们想要进行条件查问,然而几个条件不是每次都要应用,那么咱们就能够//通过判断是否拼接到sql中 <select id="queryById" resultMap="BascResultMap" parameterType="entity"> SELECT * from entity <where> <if test="name!=null"> name like concat('%',concat(#{name},'%')) </if> </where> </select>举荐一个开源收费的 Spring Boot 最全教程: https://github.com/javastacks/spring-boot-best-practicechoose (when, otherwise)标签choose标签是按程序判断其外部when标签中的test条件出否成立,如果有一个成立,则 choose 完结。当 choose 中所有 when 的条件都不满则时,则执行 otherwise 中的sql。相似于Java 的 switch 语句,choose 为 switch,when 为 case,otherwise 则为 default。 ...

December 27, 2022 · 6 min · jiezi

关于java:elastic-stack-那些事8

数据建模对事实世界进行形象形容的工具和办法通过形象的实体以及实体之间的分割的模式去形容业务规定,从而实现对事实世界的映射。概念模型 确定零碎的外围需要和范畴边界,设计实体和实体之间的关系逻辑模型 进一步梳理业务需要,确定每个实体的属性 关系 束缚规定物理模型 联合具体的数据库产品,在满足业务读写性能等需要的前提下确定最终的定义mysql mongodb elasticsearch第三范式es中的数据建模es 是基于lucene以倒排索引为根底实现的存储系统,不遵循关系型数据库的范式约定 mapping相干字段enable true|false 仅存储,不做搜寻和聚合剖析index true|false 是否构建倒排索引index_options docs|freqs|positions|offsets 存储倒排索引哪些信息norms true|false 是否存储归一化参数,如果字段仅仅用于过滤和聚合剖析 可敞开doc_values true|false 是否启用doc_values 用于排序和聚合剖析field_data false|true 是否为text类型启用fielddata 实现排序和聚合剖析store false|true 是否存储该字段coerce true|false是否开启主动数据类型转换性能,例如字符串转为数字,浮点转为整型multifields多字段 灵便应用多字段来解决业务多样性需要dynamic true|false|strict 管制mapping自动更新date_detection true|false 是否自动识别日期类型 何种类型字符串类型 须要分词设定为text 否设置为keyword枚举类型 基于性能思考将其设定为keyword类型,即使该数据为整型数值类型 尽量抉择贴近的类型,例如 byte即可示意所有数值时,选用byte 而不是long其余类型 比方 布尔类型 日期 地理位置等是否须要检索齐全不须要检索 排序 聚合剖析 enabled设置为false不须要检索的字段 index 设置为false须要检索的字段 能够通过如下设置设定须要存储的粒度 index_options 联合须要设定norms不须要归一化数据时敞开即可 reindex指重建所有数据的过程 个别产生在如下状况 mapping 设置变更 例如字段类型变动 分词器字典更新等index设置变更 例如 分片数更改等迁徙数据es提供了线程api实现该工作 _update_by_query 在现有索引上重建reindex 在其余索引上重建reindex task数据重建的工夫受源索引文档规模影响 规模越大 所需工夫越多 此时须要设定url参数wait_for_completion为false进行异步执行,es以task来形容工作es提供了taskapi来查看工作执行的进度和相干数据 对mapping进行版本治理蕴含在代码或者专门以文件进行治理,增加正文 退出 git等版本治理仓库中 不便回顾为每个减少的metadata字段 在其中保护一些文档相干的元数据 不便对数据进行治理避免字段过多字段过多,难于保护mapping信息存储在cluster state中 过多字段导致mapping过大,最终导致变慢听过设置index.mapping_total_fields.limit能够限定索引中最大字段数 默认 1000能够通过key value的形式解决字段过多的问题 然而并不完满keyvalue形式尽管通过此种形式极大低缩小field数目 但也有害处 ...

December 27, 2022 · 1 min · jiezi

关于java:IO-和Netty

IO 和Netty

December 27, 2022 · 1 min · jiezi

关于java:Netty中8大组件详解

Netty 概述1、什么是 NettyNetty is an asynchronous event-driven network application frameworkfor rapid development of maintainable high performance protocol servers & clients.Netty 是一个异步的、基于事件驱动的网络应用框架,用于疾速开发可保护、高性能的网络服务器和客户端 留神:netty的异步还是基于多路复用的,并没有实现真正意义上的异步IO2、Netty 的劣势如果应用传统 NIO,其工作量大,bug 多 须要本人构建协定解决 TCP 传输问题,如粘包、半包因为 bug 的存在,epoll 空轮询导致 CPU 100%Netty 对 API 进行加强,使之更易用,如 FastThreadLocal => ThreadLocalByteBuf => ByteBuffer3、入门案例1、服务器端代码public class HelloServer { public static void main(String[] args) { // 1、启动器,负责拆卸netty组件,启动服务器 new ServerBootstrap() // 2、创立 NioEventLoopGroup,能够简略了解为 线程池 + Selector .group(new NioEventLoopGroup()) // 3、抉择服务器的 ServerSocketChannel 实现 .channel(NioServerSocketChannel.class) // 4、child 负责解决读写,该办法决定了 child 执行哪些操作 // ChannelInitializer 处理器(仅执行一次) // 它的作用是待客户端 SocketChannel 建设连贯后,执行 initChannel 以便增加更多的处理器 .childHandler(new ChannelInitializer<NioSocketChannel>() { @Override protected void initChannel(NioSocketChannel nioSocketChannel) throws Exception { // 5、SocketChannel的处理器,应用StringDecoder解码,ByteBuf=>String nioSocketChannel.pipeline().addLast(new StringDecoder()); // 6、SocketChannel的业务解决,应用上一个处理器的处理结果 nioSocketChannel.pipeline().addLast(new SimpleChannelInboundHandler<String>() { @Override protected void channelRead0(ChannelHandlerContext channelHandlerContext, String s) throws Exception { System.out.println(s); } }); } // 7、ServerSocketChannel绑定8080端口 }).bind(8080); }}2、客户端代码public class HelloClient { public static void main(String[] args) throws InterruptedException { new Bootstrap() .group(new NioEventLoopGroup()) // 抉择客户 Socket 实现类,NioSocketChannel 示意基于 NIO 的客户端实现 .channel(NioSocketChannel.class) // ChannelInitializer 处理器(仅执行一次) // 它的作用是待客户端SocketChannel建设连贯后,执行initChannel以便增加更多的处理器 .handler(new ChannelInitializer<Channel>() { @Override protected void initChannel(Channel channel) throws Exception { // 音讯会通过通道 handler 解决,这里是将 String => ByteBuf 编码收回 channel.pipeline().addLast(new StringEncoder()); } }) // 指定要连贯的服务器和端口 .connect(new InetSocketAddress("localhost", 8080)) // Netty 中很多办法都是异步的,如 connect // 这时须要应用 sync 办法期待 connect 建设连贯结束 .sync() // 获取 channel 对象,它即为通道形象,能够进行数据读写操作 .channel() // 写入音讯并清空缓冲区 .writeAndFlush("hello world"); }}3、运行流程左:客户端 右:服务器端 ...

December 27, 2022 · 13 min · jiezi

关于java:探访-MSDN-艺术馆展品首次亮相

2022年的日历,曾经翻过去了厚厚一沓 每个人的日历上或者都标记着一些“to-do” 当初,那些曾经实现的事项变为了回顾 或欣慰,或冲动,或丧气...... 总有一个时刻,咱们会停下来,缓缓回头 才发现,那都是咱们的独家“宝藏” MSDN 的回顾被画笔记录了下来 欢送进入咱们的艺术馆 观赏那些首次面向公众的展品吧! 扫描上方二维码或点我疾速探馆~ 看过了这些有温度的展品 有没有开启你的某些回顾? 如果你喜爱咱们的数字艺术欢送转发本文一起分享咱们独特走过的2022年 MSDN 微软开发者社区衷心感谢各位开发者的反对与陪伴,将来咱们也将继续为大家提供优质的内容与流动。最初,提前祝大家新年快乐~

December 27, 2022 · 1 min · jiezi

关于java:JMM未完

JMMJava Memory Model,即java内存模型,在JSR-133标准中定义 JSR-133在 1997 年,在此时 Java 版本中的内存模型中发现了几个重大的缺点,这个缺点常常会呈现诡异的问题,比方字段的值常常会产生扭转,并且非常容易减弱编译器的优化能力。 为了修复这些缺点,JSR-133专家组提出了JSR-133标准。该标准是JSR-176(定义了JavaTM平台 Tiger(5.0)公布版的次要个性)的一部分。该标准的规范内容将合并到JavaTM语言标准、JavaTM虚拟机标准以及java.lang包的类阐明中。 JSR - 133 的设计指标次要包含1.保留 Java 现有的安全性保障,比方类型平安,并增强其余安全性保障,比方线程察看到的每个变量的值都必须是某个线程对变量进行批改之后的。2.程序的同步语义应该尽可能简略和直观。3.将多线程如何交互的细节交给程序员进行解决。4.在宽泛、风行的硬件架构上设计正确、高性能的 JVM 实现。5.应提供初始化平安的保障,如果一个对象被正确结构后,那么所有看到对象结构的线程都可能看到构造函数中设置其最终字段的值,而不必进行任何的同步操作。6.对现有的代码影响要尽可能的小。 参考资料:https://blog.csdn.net/u011080... https://blog.csdn.net/zjcjava... https://blog.csdn.net/zjcjava... https://www.cnblogs.com/cxuan...

December 26, 2022 · 1 min · jiezi

关于java:追踪解析-Netty-IntObjectHashMap-源码

零 后期筹备0 FBI WARNING文章异样啰嗦且绕弯。 1 版本Netty : 5.0.0.Alpha5IDE : idea 2022.2.4maven 坐标: <dependency> <groupId>io.netty</groupId> <artifactId>netty5-all</artifactId> <version>5.0.0.Alpha5</version></dependency>一 简介IntObjectHashMap 是 netty 封装的,key 必须是 int 的 HashMap 容器。在 netty 4 中,该类位于 netty-all 包下的 io.netty.util.collection 门路下;在 netty 5 中,该类位于 netty5-common 包下的 io.netty5.util.collection 门路下。本文应用 netty 5 进行源码跟踪。值得注意的是,截止到 2022 年 12 月,netty 5 还没有进入生产就绪的状态,不倡议在生产环境应用。 二 Demoimport io.netty5.util.collection.IntObjectHashMap;import io.netty5.util.collection.IntObjectMap;public class IntHashMapTest { public static void main(String[] args) { // 创立一个容器 // Map<Integer, String> map = new IntObjectHashMap<>(); IntObjectMap<String> map = new IntObjectHashMap<>(); // 存值 map.put(1, "t1"); map.put(2, "t2"); // 输入 t2 System.out.println(map.get(2)); // 删除 map.remove(2); }}三 IntObjectMapIntObjectMap 是 IntObjectHashMap 的顶层接口。 ...

December 26, 2022 · 5 min · jiezi

关于java:elastic-stack-那些事7

聚合剖析 aggregationes 在搜寻性能之外,提供的针对数据统计分析的性能 功能丰富,提供bucket metric pipeline 等多种剖析形式实时性高,所有后果都是即时返回,而hadoop等大数据系统是t+1级别聚合剖析品种bucket 分桶类型 相似sql中的group by 语法metric 指标剖析类型 如计算最大值 最小值 平均值等pipeline 管道剖析类型,基于上一级的聚合剖析后果进行再剖析matrix 矩阵剖析类型metric 聚合剖析单值剖析 min max avg sumcardinality多值剖析 stats extends statspercentile percentile ranktop hitsbucket 聚合剖析将文档归类为不同的bucket中 termsrangedate rangehistogram 直方图 以固定距离策略来宰割数据date histogrampipelinepipeline 的剖析后果会输入到原后果中 依据输入地位不同 分为两类 parent 后果内嵌到现有的聚合剖析后果中 derivativemoving averagecumulative sumsibling 后果与现有聚合剖析后果同级 max min avg sum bucketstats extended stats bucketpercentile bucket作用范畴es默认的作用范畴是query后果集,也能够设置其余范畴 filter 为了聚合剖析设定过滤条件,不更改整体query语句的状况下调整作用范畴post_filter 作用域文档过滤 但在聚合剖析后失效global 忽视query过滤条件 基于全副文档进行剖析排序能够应用自带的要害数据进行排序 _count文档数_key依照key值排序原理与精准度问题起因 数据扩散在多个shard上 设置shard为1 打消苏韩剧扩散问题设置shard size 即每次从shard上额定取得文档terms聚合返回后果中有如下两个统计值 doc_count_error_upper_bound 被脱漏的term的可能的最大值sum_other_doc_count返回后果bucket的term外其余term的文档总数shard size 默认大小如下 size*1.5 + 10通过调整shard size的大小升高 doc_count_error_upper_bound 来晋升准确度 大了整体计算量 升高了响应工夫 ...

December 26, 2022 · 1 min · jiezi

关于java:elastic-stack-那些事6

search 的运行机制node3在接管到用户申请时,先进行query阶段,此时为coordinating Node 角色 node3 在六个主副分片中随机抉择三个分片,发送search被选中的分片会别离执行查问并拍寻,返回 from+size的文档id和排序值node3整合三个分片返回的from+size文档id,依据排序值排序后选取from到from+size的文档id相关性算分相关性算分在shard与shard之间是独立的,也就意味着同一个term的idf等值在不同的shard上是不同的,文档的相关性算分和它所处的shard相干。在文档数量不多,会导致相关性算分重大不准的状况产生。解决思路 设置分片数为1,从根本上排除问题,在文档不多时能够应用该办法,例如 百万到千万级别的文档数量应用dfs query-then-fetch查问形式 dfs 在拿到所有文档后再从新进行相关性算分,须要更多cpu和内存资源,性能较差,个别不倡议应用。sortes会默认采纳相关性算分进行排序,用户可指定sort字段,来设置排序规定依照字符串排序比拟非凡,因为es有text和keyword两种类型,针对text类型排序的过程本质是对字段原始内容排序的过程,这个过程倒排索引无奈发挥作用,须要用到正排索引,也就是通过文档id和字段能够疾速失去字段的原始内容。es对此提供两种实现形式 fielddata默认禁用doc values 默认启用 除了text类型 fielddata通过api开启 此时字符串是依照分词后的term排序,往往后果很难复合预期个别是对分词做聚合剖析时开启doc values 默认启用,在创立索引时关系,若须要再次开启,则须要reindex操作可通过该字段获取fielddata或者doc values中存储的内容from size 分页from 起始地位 size 获取总数 深度分页 在数据分片存储的状况下如何获取前1000个文档获取990-1000文档时,会在每个分片上都获取1000文档,而后再由coordinatingnode聚合素有的分片后果再排序选取前1000个页数越深,解决文档越多,占用内存越多,耗时越唱,尽量避免深度分页,es通过index.max_result_window限定最多到10000条数据scroll遍历文档汇合的api 以快照的形式来防止深度分页问题 不能用来做实时搜寻,数据不是实时的尽量不应用简单的sort条件,应用_doc最高效应用时稍显麻烦search_after防止深度分页的性能问题 提供实时的下一页文档获取性能 毛病时不能应用from参数 即不能指定页数只能下一页 不能上一页应用简略 失常搜寻 但要指定sort值 并且保障值惟一应用上一步最初一个文档的sort值进行查问如何防止深度分页问题 通过惟一排序定位将每次要解决的文档数管制在size内

December 26, 2022 · 1 min · jiezi

关于java:高频时序数据的储存与统计方案

问题背景发电设备中经常会搁置传感器(DCS)来采集数据以监控设施运行的情况,某团体设计的电力监控统计零碎,须要实时采集传感器的数据后保留,而后提供按时段的实时查问统计性能。 零碎设计规模将反对20万个传感器(以下称为测点),采集频率为每秒一个数据,即每秒总共会有20万条数据,总时间跨度在1年以上。在这个根底上实现任意指定时段的多个测点数据统计,包含最大、最小、均匀、方差、中位数等。 零碎原结构图为: 零碎中,用户冀望的统计响应提早为:从20万个测点中任取100个测点,统计频率最高可能每隔若干秒调用一次,从总时间跨度中统计任意一天的数据,预期执行工夫在1分钟内,另外还会有少许离线工作,最长的时间段跨度长达一年。 现有的数据中台中没有计算能力,仅存储数据,计算时须要通过RESTful接口取出数据再统计。经测试,通过RESTful接口从数据中台取数,取出100个测点一天的数据量就须要10分钟工夫,还没有开始计算,取数的工夫曾经远远超出了实现计算的预期工夫。 基于现有构造,实现上述统计工作,性能上无奈达到预期要求,须要将数据从新存储。 解决办法第一步,梳理数据和计算要求数据结构如下: | 字段名 | 类型 | 中文名| | --- | ---| ---| | TagFullName | 字符串 | 测点名| | Time | 长整型| 工夫戳| | Type | 数值| 数据类型| | Qualitie | 数值 | 品质码| | Value | 浮点数| 数值| 计算要求为:在每秒生成20万条记录的时序数据中,任意时间段内,从20万个测点中任取100个测点的数据,别离基于每个测点的数值序列统计最大、最小、方差、中位数等后果。 第二步,确定存储和计算计划20万测点一天的数据,仅Value字段,就要200000*86400*4字节,至多64g内存,当总时间跨度为1年时,数据量会有数十T,单台服务器内存显然装不下。多台服务器集群,又会带来很高的治理和洽购老本。 简略按工夫为序存储的数据,能够迅速找到相应工夫区间,但即便是这样,单个测点一天也有86400条记录,20万个测点共17.28亿条,每次统计都要遍历这个规模的数据,也很难满足性能要求。 那么测点号上建设索引是否可行? 索引只能疾速定位数据,但这些数据如果在外存中不是间断存储的,硬盘有最小读取单位,会导致大量无用数据量读出,使得计算变得很慢,同样也无奈满足性能要求。此外,索引占用空间会随着数据量增大而增大,并且插入数据的保护开销也更大。 如果数据能够按测点号物理有序存储,并在测点号上建设索引,相比时序物理有序存储,查找时,待查找的测点记录变得紧凑了,须要读入的块也就少了。100个测点的数据存成文本约300m不到,这样即便应用外存也能够满足性能要求。 只有历史冷数据时,解决起来比较简单,定时将数据按指定字段排序即可。但实际上,每秒都会有20万个测点的新数据,因为历史数据规模微小,如果每次获取几秒热数据都与历史数据整体按测点号、工夫排序,即便不算排序,仅是重写一遍的工夫老本上都无奈承受。 这时,须要将冷热数据辨别看待。不再变动的冷数据能够按测点秩序筹备好。这里有一点变通,因为要将十分晚期的数据删除(比方一年前的),如果所有冷数据都按测点排序时,会导致数据保护比拟麻烦,删除晚期数据会导致重写一遍所有数据。因而,能够设计为先按工夫分段,每段时间内的数据按测点、工夫有序,整体数据还是按工夫有序。工作需要是按天计算,这里按天分段就比拟适合,更长跨度的离线计算性能损失也不是很大。每当一天过来时,将昨天数据按上述规定排序后存储,当天的数据作为热数据处理。然而,当天内的数据量还是太大了,仍然无奈全副装入内存,还须要再分。 通过一些测试后确认,咱们发现将数据按热度分为三层能够满足要求。第一层,十分钟内的热数据通过接口读入内存;第二层,每过10分钟,将过来10分钟的内存数据按测点、工夫有序保留到外存;第三层,每过一天,将过来24小时内的所有每10分钟的数据按测点、工夫有序归并。总数据为:一年的数据由365段每天数据,加144段当天数据和一段内存数据。 分层后的冷热数据属于不同的数据源,须要独立计算同源数据的后果后,再将后果合并起来,算出最终的统计后果。即便计算方差、中位数这种须要全内存统计的状况,100个测点一天的数据量,也只须要64m内存。 第三步,确定技术选型和计划从上述的存储计划中得悉,须要将实时数据按工夫分段,段内按测点号、工夫物理有序存储,惯例数据库显然没方法做到这点。此外,拆分数据须要能够反对按自定义时间段灵便地拆分;数据存储时要具备高性能索引;冷热数据属于不同层(不在同一个数据源),计算时须要别离计算后再合并。 实现该工作,用Java硬编码工作量微小,Spark写起来也很麻烦。开源的集算器SPL语言提供上述所有的算法反对,包含高性能文件、物理有序存储、文件索引等机制,可能让咱们用较少的代码量疾速实现这种个性化的计算。 取数不能再用原零碎的RESTful接口,也不适合间接通过API从DCS获取数据。用户方约定后引入kafka缓冲数据,屏蔽DCS层,同时还能够将DCS的数据提供给不同的消费者应用。变更后的零碎结构图如下: 阐明: DCS零碎每秒推送20万个测点数据至Kafka MQ。Kafka MQ到SPL:应用SPL基于Kafka API封装的Kafka函数,连贯Kafka、生产数据。内存缓冲:循环从Kafka生产数据(kafka_poll),每轮循环确保10秒以上的数据量,将每轮前10秒的数据补全后,按测点、工夫序,保留成文件并读入内存。分层数据文件:按不同时间段将冷热数据文件分层。统计时将冷热数据混合计算。反对每个测点名对应一个CSV文件作为数据源计算。统计接口以HTTP服务形式供内部利用调用并将统计后果通过回调接口返回给内部利用。第四步,施行优化计划现有的RESTful接口取数太慢了,接口变为从kafka生产数据。存储数据时,将字符串类型的测点名数字化后保留,以取得更小的存储量和更好的运算性能。 在第二步中曾经提到,数据量较大时,无奈将数据都放在内存中计算,所以思考采纳冷热分层计划,将数据分为三层,每天的冷数据按测点号、工夫有序(下文中的所有外存文件存储均采纳该序,不再反复阐明),用组表存储,因为大表对性能的影响很大,存储成组表有利于晋升零碎整体性能;当天的每10分钟的冷数据用,集文件存,因为集文件创建和应用都更简略,用来存储小表会很便捷,也不会因为索引块而升高存储效率;10分钟内的热数据从kafka间接读到内存,因为数据自身是通过kafka接口获取的,另外数据可能有肯定的提早,不适宜每秒取数即写出。 测试后发现,10分钟内的热数据,从kafka获取后再解析json,岂但须要耗费大量内存,而且解析json也须要破费很长的工夫。这样在内存中间接加载热数据是没方法用来统计计算的,所以将热数据改为每10秒存成一个集文件。 接下来开始实现统计计算局部。每天组表中的冷数据计算较快,然而当天的144个集文件计算很慢。通过计算能够晓得,每10分钟的数据量约1.2亿条记录,这个规模的数据能够用组表来存储,另外还能够再加一层每2小时一个组表文件,来缩小当天总文件数的数量(从144个变成了24个)。实际上,计算时采纳的二分查找是对单个文件内有序的测点号应用的,缩小了文件个数,也就是缩小了总查找次数。 最终,咱们把数据分成了4层。第一层:提早10秒的集文件热数据;第二层,每10分钟的组表冷数据;第三层,每2小时的组表冷数据;第四层,每天的组表冷数据。因为每层数据都按测点号、工夫有序,所以每一层都能够用归并,疾速生成下一层数据文件。 这时的冷数据计算曾经很快了,能够满足理论应用,然而热数据的计算相比冷数据还是很慢。察看发现,热数据的所有集文件都加起来大概3G,不算很大,内存能够装下。理论测试,把文件读到内存中再查找相比间接外存文件查找能够快出好几倍。 ...

December 26, 2022 · 1 min · jiezi

关于java:elastic-stack-那些事5

分布式个性es 反对集权模式,是一个分布式系统,益处有二: 增大零碎容量,磁盘 内存 使得 es集群能够反对pb级别的业务进步零碎可用性 即便局部节点进行服务 整个集群能够失常应用es集群由多个es实例组成 不同的集群通过集群名称组成,通过 cluster.name 定义每个es实例实质上是一个jvm过程,且有本人的名字 通过 node.name定义构建集群启动一个节点bin/elasticsearch -E cluster.name=my_cluster -E node.name=node1 cluster statees集群的相干数据称为 cluster state 次要记录如下信息: 节点信息 节点名称 连贯地址等索引信息 索引名称 配置等master node能够批改 cluster state 的节点称为 master 节点 一个集群只能有一个cluster state 存储在每个节点上,master 保护最新版本并同步给其余节点master节点通过集群中所有节点选举产生,能够被选举的节点称为master eligible节点node.master=true 分片如何将数据分簿于所有节点上 引入分片解决问题分片是es反对pb事务的基石 分片存储了局部数据,能够散布于任意节点上分片数在索引创立时指定,且后续不容许更改,默认为五个分片有主分片和正本分片的区别,实现数据高可用正本分片数据由主分片同步,能够有多个,从而进步吞吐量持续减少节点是否进步索引的数据容量? 不能,只有三个分片,新增节点上的资源无奈被利用持续减少正本数是否进步索引的数据吞吐量? 不能,新增正本还是散布在已有节点上,资源并没有增多衰弱状态通过api GET _cluster/health 能够查看集群的健康状况,包含三种: green 衰弱 指所有的主副分片都失常yellow 指所有的主分片都失常 然而有正本分片未失常调配red 所有分片都未调配故障转移node1 所在的集器宕机,集群会如何解决? node2 发现主分片p0未调配,将R0晋升为主分片,此时因为所有的主分片都失常,集群状态为yellownode2 为p0和p1生成新的正本,集群状态为绿色分布式存储应用映射算法将文档平均的散布在所有的分片上,以充分利用资源es 应用 shard = hash(routing)%number_of_primary_shardshash算法能够保障将数据平均的散布在分片中routing 默认为文档id文档创立流程client向node3发动文档创立申请node3通过routing计算出该文档应该存储在shard1上,查问cluster state后确认主分片在p1在node2中,转发创立申请到node2上p1接管并创立文档,将同样的申请发送到正本分片r1r1接管并执行创立文档申请后告诉p1创立胜利p1接管正本分片后果后,告诉node3创立胜利node3将后果返回给client文档读取流程client向node3发动读取文档1的申请node3通过routing计算该文档在shard1上,查问cluster state后获取shard1的主副分片列表,而后轮询获取shard,例如R1,转发申请到node1R1接管并执行读取文档,将后果返回node3node3返回后果给client脑裂问题当集群中呈现网络网体,node2 与 node3 从新组成集群选举一个master,并更新cluster statenode1 本人组成集群后,也会更新cluster state同一个大集群有两个master 并且有两个 cluster state 网络复原后无奈决定哪个是正确的master 和 cluster state解决 减少选举条件 可被选举为master-eligible节点数大于等于quorum 时才能够进行master选举 ...

December 25, 2022 · 1 min · jiezi

关于java:AQS-公平锁-非公平锁

AQSjava.util.concurrent.locks.AbstractQueuedSynchronizer,译为形象队列式同步器AQS 提供了原子式治理同步状态、阻塞和唤醒线程性能以及期待队列模型的简略框架; AQS 蕴含了一个虚构的Node双向链表(即期待队列),由 volatile 润饰的头&尾节点,以及同步状态标记state,节点期待状态标记waitStatus,和以后线程信息 AQS 提供了共享锁与独占锁的反对 独占锁同一个时刻只能被一个线程占有,如ReentrantLock,ReentrantWriteLock等,其中又蕴含了偏心锁与非偏心锁 共享锁同一时间点能够被多个线程同时占有,如ReentrantReadLock,Semaphore等 偏心锁 & 非偏心锁初始化 // 偏心锁 ReentrantLock lock = new ReentrantLock(true); // 非偏心锁 ReentrantLock lock = new ReentrantLock(); ReentrantLock lock = new ReentrantLock(false);加锁过程java.util.concurrent.locks.ReentrantLock.FairSync#lock final void lock() { // 尝试将以后锁的状态置为1 即为加锁胜利 acquire(1); } public final void acquire(int arg) { /** * 尝试加锁 tryAcquire = true 则加锁胜利 * 加锁失败时进入后续的期待流程 acquireQueued * acquireQueued 将有限循环获取锁 * 若获取到锁间接开始执行 * 或前节点成为头部 本人行将执行 则临时挂起 */ if (!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)) selfInterrupt(); }1.尝试加锁(偏心锁模式) /** * 尝试获取锁 设置锁状态 锁状态的数值理论为获取锁线程的加锁的次数(可重入) * 返回true为加锁胜利 false为失败 */ protected final boolean tryAcquire(int acquires) { // 以后线程 final Thread current = Thread.currentThread(); // 获取以后锁的状态 int c = getState(); // 以后锁状态为0 则为能够加锁 if (c == 0) { /** * 非偏心锁模式将不会判断队列是否有其余节点 会间接尝试获取锁 * hasQueuedPredecessors = false * 则期待队列中没有其余线程 * 即以后线程是下一个该当获取锁的线程 */ if (!hasQueuedPredecessors() && /** * 思考到有其余线程同时判断结束 * 故进行CAS操作 尝试批改锁状态 */ compareAndSetState(0, acquires)) { // 前两步都已胜利 则将以后线程设置为持有锁的线程 setExclusiveOwnerThread(current); return true; } } // 以后锁状态不为0 且持有锁的线程是以后线程 则间接重入 else if (current == getExclusiveOwnerThread()) { // 设置以后锁状态+1 即以后线程总共上锁的次数 int nextc = c + acquires; // 若上锁次数为负 实为上锁次数越界 if (nextc < 0) throw new Error("Maximum lock count exceeded"); setState(nextc); return true; } return false; }判断是否期待队列中是否有其余线程(非偏心锁没有此步骤)public final boolean hasQueuedPredecessors() { // The correctness of this depends on head being initialized // before tail and on head.next being accurate if the current // thread is first in queue. Node t = tail; // Read fields in reverse initialization order Node h = head; Node s; /** * 队列头部 与 队列尾部元素 不相等 * 且头部后一个元素不为空 或头部后一个期待线程不是以后线程 * 阐明队列中至多有其余的线程在期待 */ return h != t && ((s = h.next) == null || s.thread != Thread.currentThread());}CAS操作进行锁状态变更protected final boolean compareAndSetState(int expect, int update) { // See below for intrinsics setup to support this return unsafe.compareAndSwapInt(this, stateOffset, expect, update);}2.加锁失败 进入期待队列/** * 将以后线程构建为期待队列的元素 即Node * 下文将用Node示意以后线程构筑的期待队列元素 * 将该Node期待的线程设置为以后锁的持有线程 * CAS操作 尝试将以后Node 设置为队列尾部元素 */ private Node addWaiter(Node mode) { Node node = new Node(Thread.currentThread(), mode); // Try the fast path of enq; backup to full enq on failure Node pred = tail; // 判断以后尾部元素 是否为空 if (pred != null) { // 尾部不为空 设置尾部元素为以后线程Node 的前节点元素 node.prev = pred; // 尝试将以后线程Node设置成尾部元素 if (compareAndSetTail(pred, node)) { // 胜利后 批改旧的队尾元素的后一个节点为以后Node pred.next = node; return node; } } enq(node); return node;} final boolean acquireQueued(final Node node, int arg) { boolean failed = true; try { boolean interrupted = false; // 以后Node会在此处有限循环 直到前节点成为头部 本人获取到锁才返回 for (;;) { // 获取以后Node的前节点 final Node p = node.predecessor(); // 若以后节点的前节点已成为队列头部 则再次尝试加锁 if (p == head && tryAcquire(arg)) { // 胜利后 设置以后Node为头部元素 setHead(node); p.next = null; // help GC // 此时已获取到锁 故无需再设置本人为中断状态 // 进入队列后果则为失败 failed = false; return interrupted; } /** * shouldParkAfterFailedAcquire 判断以后线程是否可能挂起 * 革除队列中已勾销的节点 * 判断为true 则能够挂起 */ if (shouldParkAfterFailedAcquire(p, node) && /** * parkAndCheckInterrupt 执行挂起 * 并返回以后线程是否有过中断请求 */ parkAndCheckInterrupt()) /** * 以后线程在期待过程中无奈响应中断 直到获取到锁 * 如果在整个期待过程中被中断过 则interrupted = true * acquireQueued最终返回true 否则返回false * 并在外层响应中断 * 须要其余线程调用以后线程的interrupt()办法 */ interrupted = true; } } finally { if (failed) cancelAcquire(node); }}参考资料:https://blog.csdn.net/Java_zh...https://blog.csdn.net/Leon_Ji...https://blog.csdn.net/yy_dieg... ...

December 25, 2022 · 3 min · jiezi

关于java:volatile

volatile 关键字的作用1.批改即可见2.避免指令重排 批改即可见读取 volatile 润饰的对象时,每次都从主内存中读取值批改 volatile 润饰的对象时,批改后立即写入到主内存中然而 volatile 无奈保障原子性,多个线程可能同时读取了最新的值,都基于这个值在工作内存中进行批改,并在批改后同步至主内存中,案例如下图 避免重排的意义以下图为例,当产生指令重排时,A线程获取到锁,开始创建对象,B线程判断对象曾经不为空间接返回并应用,但理论对象并没有实现初始化,导致报错;volatile 字段的意义就在于禁止此处的指令进行重排 参考资料:https://www.cnblogs.com/zhong...https://www.miaokee.com/57027...https://cloud.tencent.com/dev...

December 25, 2022 · 1 min · jiezi

关于java:为什么-Spring-提供的-Redis-插件中的-setIfAbsent-方法调用的是-set-命令

Spring Redis 插件中的分布式锁org.springframework.data.redis.core.ValueOperations#setIfAbsent(K, V, long, java.util.concurrent.TimeUnit) 通过正文可见,其意义为【当key不存在时,设置这个key,并设置过期工夫】 为什么不应用 setnx 命令?在通常的印象中,分布式锁命令不应该是setnx嘛?setnx命令在Redis官网文档中的释义如下要留神的是该命令并不蕴含过期工夫的设置,通常在设置一个分布式锁的时候都须要给锁加一个过期工夫避免程序异样而没有开释锁,那么如果应用setnx命令,就须要额定给这个key设置一个过期工夫,即expire命令,那么应用setnx命令去实现分布式锁就变成了2条命令,即1.setnx key value 2.expire key seconds此时加锁的命令就无奈保障原子性,如果在setnx胜利之后,零碎异样导致expire没有胜利执行,这个锁就变成了永不过期 为什么是 set 命令?Redis在2.6.12版本中,为set命令退出了新的参数,使该命令间接反对了分布式锁,而加锁的命令为 set key value ex timeout nx,其含意为【当key不存在时,设置这个key,过期工夫为timeout,单位为秒】,此命令保障了操作的原子性,故Spring插件的分布式锁命令是set 加锁解锁中的并发问题在上述的问题中,咱们曾经发现,加锁须要保障操作的原子性,那么在解锁的过程中呢?例如A线程加锁,过期30秒,而A线程执行的工夫曾经超过了30秒,锁曾经主动开释;此时B线程加锁胜利,开始执行,而A线程执行完结,删除了锁,但此时删除的锁理论为B线程加的;此时C线程又加锁胜利,开始执行;在此案例中,就无奈满足ABC三个线程的串行执行;在此案例中,就引出了3个问题1.须要以后线程只能解除本人加的锁2.解锁须要保障原子性操作3.锁过期工夫不够时须要续期操作 如何保障解锁的线程是加锁的线程?线程应该应用本身的惟一标识来加锁,解锁时应用此惟一标识校验,如ThreadId,亦或uuid,只有保障不反复即可 如何保障解锁的原子性?即便退出理解锁唯一性校验,在判断胜利开始解锁的霎时,也可能呈现B线程加锁胜利的状况,那么此时就须要保障判断可能解锁与解锁的这个过程是原子性的,具体能够参考org.redisson.RedissonLock#unlockInnerAsync 分布式锁如何续期?加锁时,能够启动一个监督线程,通过定期轮循的形式来判断持有锁的线程有没有执行结束,如果没有执行完就主动续期,具体能够参考org.redisson.RedissonLock#tryAcquireOnceAsync在上述办法中,胜利设置了锁之后会启动一个主动renew(也就是续期)的办法,在此办法中,如果持有锁的线程没有执行完结,就会将这个锁缩短过期 参考资料:https://blog.csdn.net/weixin_...https://blog.csdn.net/weixin_...

December 25, 2022 · 1 min · jiezi

关于java:elastic-stack-那些事4

search api实现对es中存储的数据进行查问剖析,endpoint为_search,如 GET /_search查问有两种模式 URI searchRequest body search es 提供的齐备的查问语法 Query DSL domain specific languageURI search通过url query参数来实现搜寻,罕用参数如下: q 指定查问的语句,语法为query string syntaxdf q 中不指定字段时默认查问的字段,如果不指定,es 会查问所有的字段sort 排序timeout 指定超时工夫from size 分页 GET /my_index/_search?q=alfred&df=user&sort=age:asc&from=4&size=10&timeout=1s 查问user字段中蕴含alfred的文档,后果依照age升序排列,返回第5-14个文档,如果超时1s则完结term and phrasealfred way 等于 alfred OR way"alfred way" 词语查问 要求先后顺序泛查问alfred 等效与在所有的字段取匹配该term在指定字段name:alfredGroup 分组group分组设定,应用括号指定匹配规定 (quick OR brown) AND foxstatus:(active OR pending) title:(full text search)boolean 操作符AND OR NOT name:(tom NOT leee)必须大写+-对应must 和 must_not name:(tom +lee -alfred)name:((lee && !alfred) || (tom && lee && !alfred))在url中会被解析为空格 要应用encode后后果才能够 %2B范畴查问范畴查问 反对数值和日期 ...

December 24, 2022 · 2 min · jiezi

关于java:elastic-stack-那些事3

Mappingmapping 相似数据库中的表构造定义,作用如下: 定义index下字段名定义字段类型,例如数值型,字符串型等定义倒排索引的配置,例如是否为索引,记录position等自定义mappingmapping字段类型一旦设计后,禁止间接批改,因为其生成的倒排索引生成后不容许批改,然而能够建设新的索引,做reindex。然而容许做新增字段,通过dynamic属性设置字段字段规定 true 默认 容许新增字段false 不容许主动新增字段,然而文档可失常写入,但无奈对字段进行查问等操作strict 文档不可写入,否则报错copy_to将该字段的值复制到指标字段,实现相似_all的作用不会呈现在_source中,只用来搜寻 index设置index为true时,记录这个字段为索引,false不记录 index_options 用于管制倒排索引的记录内容,四种配置docs 只记录docidfreqs 记录 docid 和 term frequenciespositions 记录 doc id 、term frequencies 、 term positionoffsets 记录 doc id、term frequencies、term position、character offsetstext 类型默认配置为positions 其余默认docs记录内容越多 占用空间越大数据类型外围数据类型字符串数值型日期型布尔二进制范畴简单数据类型数组对象嵌套类型地理位置专用类型ip主动补全 completion记录分词数 token_count记录字符串hashpercolatorjoin多字段个性容许对同一个字段采纳不同的配置,例如分词,常见例子如对人名实现拼音搜寻,只须要再任命中新增子一个子字段pinyin即可 dynamic-mapping没有指定字段类型时,字段会依据json的类型自动识别。 dynamic datees可自动识别日期 默认为["strict_date_optional_time","yyyy/MM/dd HH:mm:ss Z||yyyy/MM/dd Z"]strict_date_option_time 是 ISO datatime 格局,残缺格局相似如下 YYYY-MM-DDThh:mm:ssTZD(eg 1997-07-16T19:20:30+01:00)dynamic_date_formats能够自定义日期类型date_detaction 能够敞开日期自动识别的机制字符串是数字时,默认不会自动识别为整形,numeric_detection能够开启字符串中数字的自动识别 dynamic template容许es自动识别的数据类型,字段名等动静设定字段类型,能够实现如下成果 所有字符串类型都设定为keyword类型 默认不分词以message结尾的字段都设定为text类型 分词所有以long结尾的字段都设定为long类型所有主动匹配为double类型的都设定为float类型 节俭空间自定义mapping的操作步骤如下写入一条文档到es长期索引中,获取es主动生成的mapping批改步骤1失去的mapping,自定义配置应用步骤2的mapping创立理论所需索引索引模板用于再新增索引时主动利用事后设定的配置,简化索引创立的操作步骤 能够设定索引的配置和mapping能够有多个模板,依据order设置 order值大的笼罩小的

December 24, 2022 · 1 min · jiezi

关于java:elastic-stack-那些事2

倒排索引与正排索引正排索引相似书的目录 由书的章节指向章节关键词es 中文档id 对应的单词倒排索引相似书的索引 由内容的关键词指向页数es 单词对应文档id倒排索引的应用 通过倒排索引获取关键词的文档id通过正排索引查出对应id文档返回文档内容倒排索引由 单词词典和倒排列表组成单词词典 term dictionary 记录所有文档的单词记录单词到倒排列表的关联信息个别用B+ Tree实现倒排列表 posting list 记录了单词对应的文档汇合 由倒排索引项组成倒排索引项包含:文档Id 单词频率 地位 偏移分词指将文本转换成一系列单词的过程,也能够叫做文本剖析,在es中成为Analysis。分词器 es 中专门解决分词器的组件,英文为Analyzer,组成如下 也是 analyzer 调用的程序 character filter 针对原始文本进行解决 例如 去除 html标记tokenizer 将原始文本依照肯定的会泽切分为单词token filter 针对 tokenizer解决的单词再加工 例如 转小写等analyzer apies 提供测试分词的api接口,_analyzer 能够间接指定analyzer能够指定索引中的字段可自定义分词器

December 23, 2022 · 1 min · jiezi

关于java:elastic-stack-那些事1

术语阐明document 用户在库中存储的数据,能够类比数据库中的一条数据index 具备雷同字段的文档汇合,能够类比与数据库中的tabletype 将来将会勾销documentobject json类型的数据,外面能够蕴含多种类型的字段 字符串: text keyword数值型: long short integer float double byte half_float scaled_float布尔: boolean日期: date二进制: binary范畴: integer_range float_range long_range double_range date_range元数据字段 _id 文档惟一id 可自主生成或es生成_type_uid _id+_type_index 索引名_source 文档原始json数据 能够从这里获取所有字段数据_all 整合所有的字段内容到该字段 默认禁用index索引中存储具备雷同构造的文档 doc 每个索引都有各自的mapping构造,用于定义字段名和类型每个集群能够有多个索引 例如存储nginx日志时 能够用每个日期作为索引来存储restapi 新增索引 put /${indexName}查看索引 get /${indexName}删除索引 delete /${indexName}document rest api创立 post /${indexName}/doc/${docId}批改 put /${indexName}/doc/${docId}删除 delete /${indexName}/doc/${docId}查找 get /${indexName}/doc/${docId}

December 23, 2022 · 1 min · jiezi

关于java:含文档PPT源码等基于SSM框架图书借阅管理系统开发与设计

  博主介绍:✌退职Java研发工程师、专一于程序设计、源码分享、技术交换、专一于Java技术畛域和毕业设计✌ 项目名称 [含文档+PPT+源码等]基于SSM框架图书借阅管理系统开发与设计 零碎介绍 《基于SSM框架图书管理系统开发与设计》 该我的项目含有源码、配套开发软件、软件装置教程、我的项目公布教程等 采纳技术如下 数据库:MySQL 数据连接池:Druid Web容器:Apache Tomcat 项目管理工具:Maven 后端技术:Spring + SpringMVC + MyBatis(SSM) 前端框架:LayUI 我的项目介绍 随着网络时代的到来,电子信息化的飞速发展,图书馆作为一种信息资源的聚集地,图书品种的繁多,用户借阅的繁琐,蕴含很多的信息数据的治理,以及信息数据的交互。 那么如果有一套具体的欠缺的图书管理系统就显得尤为重要,图书馆如果采纳人工来治理书籍和借阅治理,因为材料繁多,手工解决的形式不仅工作量大,管理效率低下, 也很容易因为疲劳而产生出错,更不不便读者对图书资料的查阅。为了进步图书治理的效率,本我的项目针对图书的治理,设计了一个面向图书的管理系统。 性能形容: 用户登录、退出、借阅治理、图书治理、读者治理、类型治理、布告治理、管理员治理、数据统计分析等 我的项目性能介绍: 操作员蕴含以下性能:登录、退出、老师信息管理、学生信息管理、课程信息管理、学生问题治理、明码批改、问题查问、老师集体信息管理、学生集体课程管理、学生集体信息管理等性能 环境须要 1.运行环境:最好是java jdk 1.8,咱们在这个平台上运行的。其余版本实践上也能够。2.IDE环境:IDEA,Eclipse,Myeclipse都能够。举荐IDEA;3.tomcat环境:Tomcat 7.x,8.x,9.x版本均可4.硬件环境:windows 7/8/10 1G内存以上;或者 Mac OS; 5.数据库:MySql 5.7版本;6.是否Maven我的项目:否; 技术栈 后端:Spring+SpringMVC+Mybatis前端:JSP+CSS+JavaScript+jQuery应用阐明 应用Navicat或者其它工具,在mysql中创立对应名称的数据库,并导入我的项目的sql文件;应用IDEA/Eclipse/MyEclipse导入我的项目,Eclipse/MyEclipse导入时,若为maven我的项目请抉择maven;若为maven我的项目,导入胜利后请执行maven clean;maven install命令,而后运行;将我的项目中springmvc-servlet.xml配置文件中的数据库配置改为本人的配置;运行我的项目,在浏览器中输出http://localhost:8080/ 登录运行截图 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑 编辑  用户管理控制层: package com.houserss.controller; import javax.servlet.http.HttpSession; import org.apache.commons.lang3.StringUtils;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RequestParam;import org.springframework.web.bind.annotation.ResponseBody; import com.houserss.common.Const;import com.houserss.common.Const.Role;import com.houserss.common.ServerResponse;import com.houserss.pojo.User;import com.houserss.service.IUserService;import com.houserss.service.impl.UserServiceImpl;import com.houserss.util.MD5Util;import com.houserss.util.TimeUtils;import com.houserss.vo.DeleteHouseVo;import com.houserss.vo.PageInfoVo; ...

December 22, 2022 · 5 min · jiezi

关于java:Spring如何实现可插拔配置

大家好,我是3y,一年CRUD教训用十年的markdown程序员长年被誉为职业八股文选手 我又又又又被吐槽了,随之而来,我的音讯推送平台开源我的项目Austin又又又又更新啦,迭代本人的我的项目多是一件美事啊。 源码Gitee链接:gitee.com/austin 01、可插拔我的我的项目逐步成型了之后,有挺多小伙伴吐槽过我的我的项目太重了,依赖的中间件有点多。 在最开始的那一版须要强依赖MySQL/Redis/Kafka/Apollo(我的项目启动就须要部署这些中间件),弱依赖prometheus/graylog/flink/xxl-job(想要有残缺的我的项目体验,就须要把这些给部署起来)。 MySQL是没有人吐槽的,数据库这种货色,能够说是后端必须的了。Redis临时还没人吐槽,毕竟用的还是太多了,也没有什么弱小的竞品。Apollo常常被吐槽能不能换成Nacos。Kafka时而有人吐槽,想要反对RabbitMQ、RocketMQ。我以前存在个观点:在公司里中间件是不会轻易替换的,当初我的代码曾经实现了一种姿态,感觉没多大必要反对多种中间件实现,你想换就本人入手改改嘛,又不难。 「“Apollo太重啦,Apollo不好用!快点反对Nacos!”」「“反对RocketMQ好不好啊”」「“能不能反对RabbitMQ?”」 对我来说并不是啥大理由,我还是感觉Apollo挺好用,足够成熟稳固,同理Kafka亦是如此。不过当我被吐槽多了,总会狐疑本人是不是做得不够好,也会跟身边的大佬探讨探讨,有没有必要反对一些性能。 思来想去,我变了,我又懂了 为了让音讯推送平台Austin易上手,我首先把Apollo做成弱依赖,能够通过配置抉择读本地文件还是读配置核心(Apollo)。其实当咱们应用Apollo时,即使Apollo挂了,Apollo自身就有很强的容灾能力(自带本地文件) 其次,我把Kafka做成弱依赖,能够通过配置抉择用Guava的eventbus还是走分布式音讯队列(Kafka),后续可能还会反对RocketMQ/RabbitMQ,感兴趣的也能够在我的代码根底上实现一把,蹭个pull request也很香的。 一方面是升高应用门槛而做的,另一方面是能够对具体实现进行可插拔,这是开源我的项目所须要的。我认为如果是公司级生产环境线上的我的项目,对这块更多思考的是异构容灾(而非可插拔)。 于是乎,当初音讯推送平台Austin默认的强依赖只剩下了MySQL和Redis,其余中间件的都是弱依赖,要做到可插拔我是借助配置去实例化不同的中间件。 当我的配置austin-mq-pipeline=eventbus时,我就不去实例化Kafka相干的生产者和消费者,转而去初始化eventBus的生产者和消费者,那天然接口下的实现类就是为eventbus的 02、反对Nacos分布式配置核心我的项目曾经将Nacos曾经接入了!从我做我的项目开始,就始终有小伙伴留言是不是要反对Nacos作为分布式配置核心,为什么偏偏就抉择Apollo。我始终错觉认为我遇到了邪教组织了,当初Nacos都风行到这个境地了? 接入完Nacos,又发现了低版本的客户端会导致SpringBean的懒加载生效,从而导致我的Kafka消费者失败了,折腾了好一阵子! 03、(彩蛋)KAFKA反对TAG过滤我的股东们是能间接用我的近程服务的:Kafka的Topic是共享的,Group消费者也是共享的,在不批改的前提下,间接应用会带来一个问题。 当同时有两个或以上的股东在本地启动了Austin,那就会争抢生产这个Topic(相当于一个消费者组里起了多个消费者),导致在测试下发的时候可能收不到本人调试的音讯(被别的股东抢去了)。 要解决这个问题我第一工夫的想法很简略:不同的股东应用不同的group(相当于每个股东都会有独立的消费者组),那不就完事了嘛?正好我的groupId生成是依赖渠道的code,改掉code就完事咯。 但这还是有问题的:每个股东有独立的消费者组,意味着每个股东能生产整个topic的所有音讯,这又意味着股东会承受到其余股东的测试音讯(明明只想要本人测试的音讯,却来了一条其他人发的)。 要解决这个问题,除了给每个股东一个独立的topic,那就是依据tag过滤啦。 在Kafka实现这种成果,挺简略的:在发送的时候,把tag写进Kafka的头部,在生产前把非本身tag的音讯过滤掉就完事了。 04、总结从开始写这个我的项目到当初还始终在迭代,这个过程受到了不少的吐槽。这种吐槽大多数是正向的,毕竟有人吐槽那才阐明我这个我的项目是真的有人在用的,有人在看的。 最近有个想法:把这个零碎做成是线上的,能够由各大开发者在推送音讯的时候调用我的接口,做成这样肯定会很有意思,面临的挑战和需要也会更多。那我就始终能够迭代,在这过程中肯定我还能学到很多以前所不晓得的货色。 这次我用@ConditionAlOnProperties这个注解来实现可插拔的配置,但其实如果是提供二方库的模式的话,应用SPI的姿态会更加优雅。 如果想学Java我的项目的,我还是强烈推荐我的开源我的项目音讯推送平台Austin,能够用作毕业设计,能够用作校招,又能够看看生产环境是怎么推送音讯的。 仓库地址(求各位兄弟们三连哟!) 我的项目Gitee仓库链接:http://gitee.com/zhongfucheng/austin我的项目GitHub仓库链接:http://github.com/ZhongFuCheng3y/austin

December 22, 2022 · 1 min · jiezi

关于java:Redis集群的三种方式详解附优缺点及原理区别

Redis提供了三种集群形式,上面我重点详解Redis三种集群形式的原理及优缺点等区别@mikechen 目录 [**]() Redis主从复制模式Redis哨兵模式Redis集群模式Redis主从复制模式1.Redis主从复制定义 主从模式是三种模式中最简略的,主从模式指的是应用一个Redis实例作为主机,其余的实例作为备份机,主机和从机的数据完全一致。 如下图所示: 主机反对数据的写入和读取等各项操作,而从机则只反对与主机数据的同步和读取,也就是说客户端能够将数据写入到主机,由主机主动将数据的写入操作同步到从机。   2.Redis主从复制工作原理 当slave启动后被动向master发送SYNC命令;master接管到SYNC命令后在后盾保留快照和缓存保留快照这段时间的命令,而后将保留的快照文件和缓存的命令发送给slave;slave接管到快照文件和命令后加载快照文件和缓存的执行命令;复制初始化后,master每次接管到的写命令都会同步发送给slave,保障主从数据一致性。  3.Redis主从复制优缺点 Redis主从复制长处: 做到读写拆散,进步服务器性能; Redis主从复制毛病: 在主从模式中,一旦Master节点因为故障不能提供服务,须要人工将Slave节点晋升为Master节点。   Redis哨兵模式1.为什么须要哨兵模式? 刚刚下面讲到了主从模式当主服务器宕机后,须要手动把一台从服务器切换为主服务器,须要人工干预麻烦费劲,为了解决这个问题呈现了哨兵模式。 如下图所示: 哨兵模式由一个或多个Sentinel实例组成的Sentinel零碎,它能够监督所有的Master节点和Slave节点,并在被监督的Master节点进入下线状态时,主动将下线Master服务器。 2.哨兵模式工作原理 当主节点呈现故障时,由Redis Sentinel主动实现故障发现和转移,并告诉利用方,实现高可用性。 如下图所示: 哨兵机制建设了多个哨兵节点(过程),独特监控数据节点的运行状况。同时哨兵节点之间也相互通信,替换对主从节点的监控情况。每隔1秒每个哨兵会向整个集群:Master主服务器+Slave从服务器+其余Sentinel(哨兵)过程,发送一次ping命令做一次心跳检测。  3.哨兵模式的优缺点 哨兵模式长处:最大的长处就是主从能够主动切换,零碎更强壮,可用性更高; 哨兵模式毛病:最大的毛病就是还要多保护一套哨兵模式,实现起来也变的更加简单减少保护老本;   Redis集群模式1.为什么须要Redis集群模式 哨兵模式基于主从模式,实现读写拆散,它还能够主动切换,零碎可用性更高。然而它每个节点存储的数据是一样的,节约内存,因而在Redis3.0后Cluster集群应运而生。 Redis Cluster是一种服务器Sharding技术(分片和路由都是在服务端实现),采纳多主多从,每一个分区都是由一个Redis主机和多个从机组成,片区和片区之间是互相平行的。   2.Redis集群模式原理 在Redis的每一个节点上,都有这么两个货色,一个是插槽(slot),它的的取值范畴是:0-16383,还有一个就是cluster。 如下图所示: 当咱们的存取的时候Redis会依据crc16的算法得出一个后果,而后把后果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽。 通过这个值去找到对应的插槽所对应的节点,而后间接主动跳转到这个对应的节点上进行存取操作。 为了保障高可用,RedisCluster集群引入了主从模式,一个主节点对应一个或者多个从节点,当主节点宕机的时候,就会启用从节点。 Redis集群模式利用 次要是针对海量数据+高并发+高可用的海量数据场景,Redis集群模式的性能和高可用性均优于哨兵模式。 作者简介陈睿|mikechen,10年+大厂架构教训,mikechen的互联网架构作者,专一于互联网架构技术。 浏览mikechen的互联网架构更多技术文章合集 Java并发|JVM|MySQL|Spring|Redis|分布式|高并发

December 22, 2022 · 1 min · jiezi

关于java:搞定-Redis-数据存储原理别只会-setget-了

我的外围模块如图 1-10。 图 1-10 Client 客户端,官网提供了 C 语言开发的客户端,能够发送命令,性能剖析和测试等。网络层事件驱动模型,基于 I/O 多路复用,封装了一个短小精悍的高性能 ae 库,全称是 a simple event-driven programming library。在 ae 这个库外面,我通过 aeApiState 构造体对 epoll、select、kqueue、evport四种 I/O 多路复用的实现进行适配,让下层调用方感知不到在不同操作系统实现 I/O 多路复用的差别。Redis 中的事件能够分两大类:一类是网络连接、读、写事件;另一类是工夫事件,也就是特定工夫触发的事件,比方定时执行 rehash 操作。命令解析和执行层,负责执行客户端的各种命令,比方 SET、DEL、GET等。内存调配和回收,为数据分配内存,提供不同的数据结构保留数据。长久化层,提供了 RDB 内存快照文件 和 AOF 两种长久化策略,实现数据可靠性。高可用模块,提供了正本、哨兵、集群实现高可用。监控与统计,提供了一些监控工具和性能剖析工具,比方监控内存应用、基准测试、内存碎片、bigkey 统计、慢指令查问等。把握了整体架构和模块后,接下来进入 src 源码目录,应用如下指令执行 redis-server可执行程序启动 Redis。 ./redis-server ../redis.conf每个被启动的服务我都会形象成一个 redisServer,源码定在server.h 的redisServer 构造体。 这个构造体蕴含了存储键值对的数据库实例、redis.conf 文件门路、命令列表、加载的 Modules、网络监听、客户端列表、RDB AOF 加载信息、配置信息、RDB 长久化、主从复制、客户端缓存、数据结构压缩、pub/sub、Cluster、哨兵等一些列 Redis 实例运行的必要信息。 构造体字段很多,不再一一列举,局部外围字段如下。 truct redisServer { pid_t pid; /* 主过程 pid. */ pthread_t main_thread_id; /* 主线程 id */ char *configfile; /*redis.conf 文件绝对路径*/ redisDb *db; /* 存储键值对数据的 redisDb 实例 */ int dbnum; /* DB 个数 */ dict *commands; /* 以后实例能解决的命令表,key 是命令名,value 是执行命令的入口 */ aeEventLoop *el;/* 事件循环解决 */ int sentinel_mode; /* true 则示意作为哨兵实例启动 */ /* 网络相干 */ int port;/* TCP 监听端口 */ list *clients; /* 连贯以后实例的客户端列表 */ list *clients_to_close; /* 待敞开的客户端列表 */ client *current_client; /* 以后执行命令的客户端*/};1.2.1 数据存储原理其中redisDb *db指针十分重要,它指向了一个长度为 dbnum(默认 16)的 redisDb 数组,它是整个存储的外围,我就是用这玩意来存储键值对。 ...

December 22, 2022 · 3 min · jiezi

关于java:阿里问题定位神器-Arthas-的骚操作定位线上BUG超给力

定位过程 剖析代码剖析调用流程Arthas剖析问题 watch办法执行数据观测为什么间断申请不会呈现问题为什么本地不会复现如何解决降级spring boot版本 公司有个渠道零碎,专门对接三方渠道应用,没有什么业务逻辑,次要是转换报文和参数校验之类的工作,起着一个承前启后的作用。 最近在优化接口的响应工夫,优化了代码之后,然而工夫还是达不到要求;有一个诡异的100ms左右的耗时问题,在接口中打印了申请解决工夫后,和调用方的响应工夫还有差了100ms左右。比方程序里记录150ms,然而调用方等待时间却为250ms左右。 上面记录下过后具体的定位&解决流程(其实解决很简略,关键在于怎么定位并找到解决问题的办法) 定位过程剖析代码渠道零碎是一个常见的spring-boot web工程,应用了集成的tomcat。剖析了代码之后,发现并没有非凡的中央,没有非凡的过滤器或者拦截器,所以初步排除是业务代码问题 剖析调用流程呈现这个问题之后,首先确认了下接口的调用流程。因为是内部测试,所以调用流程较少。 Nginx -反向代理-> 渠道零碎 公司是云服务器,网络走的也是云的内网。因为不明确问题的起因,所以用排除法,首先确认服务器网络是否有问题。 先确认发送端到Nginx Host是否有问题: [jboss@VM_0_139_centos ~]$ ping 10.0.0.139PING 10.0.0.139 (10.0.0.139) 56(84) bytes of data.64 bytes from 10.0.0.139: icmp_seq=1 ttl=64 time=0.029 ms64 bytes from 10.0.0.139: icmp_seq=2 ttl=64 time=0.041 ms64 bytes from 10.0.0.139: icmp_seq=3 ttl=64 time=0.040 ms64 bytes from 10.0.0.139: icmp_seq=4 ttl=64 time=0.040 ms从ping后果上看,发送端到Nginx主机的提早是无问题的,接下来查看Nginx到渠道零碎的网络。 # 因为日志是没问题的,这里间接复制下面日志了[jboss@VM_0_139_centos ~]$ ping 10.0.0.139PING 10.0.0.139 (10.0.0.139) 56(84) bytes of data.64 bytes from 10.0.0.139: icmp_seq=1 ttl=64 time=0.029 ms64 bytes from 10.0.0.139: icmp_seq=2 ttl=64 time=0.041 ms64 bytes from 10.0.0.139: icmp_seq=3 ttl=64 time=0.040 ms64 bytes from 10.0.0.139: icmp_seq=4 ttl=64 time=0.040 ms从ping后果上看,Nginx到渠道零碎服务器网络提早也是没问题的 ...

December 22, 2022 · 6 min · jiezi