开发者博客 – IT技术 尽在开发者博客

开发者博客 – 科技是第一生产力


  • 首页

  • 归档

  • 搜索

为什么IDEA不推荐你使用Autowired ? Spri

发表于 2021-11-05

@Autowired注解相信每个Spring开发者都不陌生了!在DD的Spring Boot基础教程和Spring Cloud基础教程中也都经常会出现。

但是当我们使用IDEA写代码的时候,经常会发现@Autowired注解下面是有小黄线的,我们把小鼠标悬停在上面,可以看到这个如下图所示的警告信息:

IDEA警告:Field injection is not recommended

那么为什么IDEA会给出Field injection is not recommended这样的警告呢?

下面带着这样的问题,一起来全面的了解下Spring中的三种注入方式以及他们之间在各方面的优劣。

Spring中的三种依赖注入方式

Field Injection

@Autowired注解的一大使用场景就是Field Injection。

具体形式如下:

1
2
3
4
5
6
7
java复制代码@Controller
public class UserController {

@Autowired
private UserService userService;

}

这种注入方式通过Java的反射机制实现,所以private的成员也可以被注入具体的对象。

Constructor Injection

Constructor Injection是构造器注入,是我们日常最为推荐的一种使用方式。

具体形式如下:

1
2
3
4
5
6
7
8
9
10
java复制代码@Controller
public class UserController {

private final UserService userService;

public UserController(UserService userService){
this.userService = userService;
}

}

这种注入方式很直接,通过对象构建的时候建立关系,所以这种方式对对象创建的顺序会有要求,当然Spring会为你搞定这样的先后顺序,除非你出现循环依赖,然后就会抛出异常。

Setter Injection

Setter Injection也会用到@Autowired注解,但使用方式与Field Injection有所不同,Field Injection是用在成员变量上,而Setter Injection的时候,是用在成员变量的Setter函数上。

具体形式如下:

1
2
3
4
5
6
7
8
9
10
java复制代码@Controller
public class UserController {

private UserService userService;

@Autowired
public void setUserService(UserService userService){
this.userService = userService;
}
}

这种注入方式也很好理解,就是通过调用成员变量的set方法来注入想要使用的依赖对象。

三种依赖注入的对比

在知道了Spring提供的三种依赖注入方式之后,我们继续回到本文开头说到的问题:IDEA为什么不推荐使用Field Injection呢?

我们可以从多个开发测试的考察角度来对比一下它们之间的优劣:

可靠性

从对象构建过程和使用过程,看对象在各阶段的使用是否可靠来评判:

  • Field Injection:不可靠
  • Constructor Injection:可靠
  • Setter Injection:不可靠

由于构造函数有严格的构建顺序和不可变性,一旦构建就可用,且不会被更改。

可维护性

主要从更容易阅读、分析依赖关系的角度来评判:

  • Field Injection:差
  • Constructor Injection:好
  • Setter Injection:差

还是由于依赖关键的明确,从构造函数中可以显现的分析出依赖关系,对于我们如何去读懂关系和维护关系更友好。

可测试性

当在复杂依赖关系的情况下,考察程序是否更容易编写单元测试来评判

  • Field Injection:差
  • Constructor Injection:好
  • Setter Injection:好

Constructor Injection和Setter Injection的方式更容易Mock和注入对象,所以更容易实现单元测试。

灵活性

主要根据开发实现时候的编码灵活性来判断:

  • Field Injection:很灵活
  • Constructor Injection:不灵活
  • Setter Injection:很灵活

由于Constructor Injection对Bean的依赖关系设计有严格的顺序要求,所以这种注入方式不太灵活。相反Field Injection和Setter Injection就非常灵活,但也因为灵活带来了局面的混乱,也是一把双刃剑。

循环关系的检测

对于Bean之间是否存在循环依赖关系的检测能力:

  • Field Injection:不检测
  • Constructor Injection:自动检测
  • Setter Injection:不检测

性能表现

不同的注入方式,对性能的影响

  • Field Injection:启动快
  • Constructor Injection:启动慢
  • Setter Injection:启动快

主要影响就是启动时间,由于Constructor Injection有严格的顺序要求,所以会拉长启动时间。

所以,综合上面各方面的比较,可以获得如下表格:

三种依赖注入的对比

结果一目了然,Constructor Injection在很多方面都是优于其他两种方式的,所以Constructor Injection通常都是首选方案!

而Setter Injection比起Field Injection来说,大部分都一样,但因为可测试性更好,所以当你要用@Autowired的时候,推荐使用Setter Injection的方式,这样IDEA也不会给出警告了。同时,也侧面也反映了,可测试性的重要地位啊!

总结

最后,对于今天的问题讨论,我们给出两个结论,方便大家记忆:

  1. 依赖注入的使用上,Constructor Injection是首选。
  2. 使用@Autowired注解的时候,要使用Setter Injection方式,这样代码更容易编写单元测试。

好了,今天的学习就到这里!如果您学习过程中如遇困难?可以加入我们超高质量的Spring技术交流群,参与交流与讨论,更好的学习与进步!

原创不易,欢迎转发分享本篇内容,您的支持是我坚持的动力!

欢迎关注我的公众号:程序猿DD,分享外面看不到的干货与思考!

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

百度爱番番数据分析体系的架构与实践 一、前言 二、面临的挑战

发表于 2021-11-05

导读:讲述在业务快速迭代发展过程中,为了让大数据更好地赋能业务,高效的为用户提供有业务价值的数据产品和服务,百度爱番番的数据团队构建实时和离线大数据基础平台的心路历程,包括如何应对业务、技术、组织等方面的挑战和解决实际痛点过程中的思考与实践。

全文9911字,预计阅读时间24分钟。

一、前言

作为一站式的公私域智能营销与销售加速器,爱番番既承载着百度内部生态的各类推广平台的线索数据(例如:搜索、信息流、基木鱼自建站等营销推广平台的业务沟通、询价收集、表单留资等用户行为形成的线索)的落潜、管控、跟进以及转化等业务能力,也有外部公域的广告投放平台和租户私域的自建系统里各类用户行为和属性相关的线索自动化接入,同时还提供线索自拓导入的业务功能;进而形成业务数据、用户数据、事件行为等有价值的数据为核心的大数据分析体系建设的思考与实践。

如何在敏捷迭代中持续交付,对客户有价值的并且满足其时效性、准确性和稳定性的数据分析服务,是数据团队需要思考的长期目标;所以打造一套高屋建瓴的架构设计是至关重要的根基,本文就百度爱番番数据分析团队因势利导的进行数据驱动的技术实践经验和心得体会展开表述。

1.1 名词解释

名词/缩写 描述
瓦特/Watt 数据流开放平台,用于MySQL、BaikalDB等数据库Binlog日志的集成平台,可支持多表Join、UDF等扩展功能。
凤阁平台 商业平台研发部门打造的面向业务优化的数据资产中心、数据研发与治理中台,针对业务端的核心数据、核心场景统一管理,充分提升效率。其充分利用公司数仓引擎、资源调度、数据传输等标准化能力,面向业务方提供流程托管、数据应用管理、血缘分析、资源规划、监控治理等功能。
Bigpipe/BP 分布式数据传输系统。不仅可以完成传统消息队列可以实现的诸如消息、命令的实时传输,也可以用于日志数据的实时传输。 其能够帮助模块间的通信实现解耦,并能保证消息的不丢不重。同时也有助于运维的统一、流量的统一。
AFS 大数据文件存储及系统,类似于开源的HDFS的功能。
Palo 基于Apache Doris(百度自研的分析型数据库引擎)构建的MPP数据仓库,支持高并发低延时查询,支持PB级以上的超大数据集,可有效地支持在线实时数据分析。

二、面临的挑战和痛点

2.1【业务方面】

为了让客户清晰地、全面多视角的、多维度指标的查看在爱番番系统中创建线索、分配线索,跟进线索,成单等过程的详细漏斗情况以及了解员工跟进情况,需要数据统计分析为客户提供各环节有价值的数据产品。

1)有价值:如何为客户提供有价值的数据产品服务,是贯穿需求审评阶段需要重点考虑的问题;

2)及时性:例如客户给自已的员工分配了一条线索或者员工跟进线索的细节,希望能够快速的在系统里秒级展示;

3)丰富度:单一的Count和Sum很容易实现,比较难的是为客户的线索管理跟进以及公私域营销活动等工作有指导性意义的数据分析产品。

2.2【技术方面】

业务数据、用户行为事件数据、百度生态内部与外部业务数据需要体系化的接入数仓统一管理、加工、产出。

1)业务快速发展,使业务数据的体量较大,导致业务数据库(Mysql)分库和分表,销售域的线索相关的核心数据的OLAP分析场景无法直接利用从库查询;

2)采集数据源和业务数据源的等元数据,散落在各个代码里,无法统一管理,迁库、修改密码或业务下线影响抽取数据;

3)存在一份数据多处重复存储和使用,公共数据亟须管理降底维护成本和运行、存储资源成本;

4)数据团队的研发人数有限,既有运维任务,又有内部业务支撑,还有对客的分析业务产品研发工作,在规模较小的情况下,如何利用有限的人力资源来发挥更大的价值;

5)数据抽取,逻辑加工,转储同步等环节有成百上千的任务在线调度和运行,其稳定性如何保证。

2.3【组织方面】

在爱番番业务部将产研测、市场、商业化、客户成功等人员划分为15个左右的敏捷小组,每个小组有自己明确的业务目标,数据团队需要敏捷支撑各团队。

1)各团队的月度、季度和年度的内部OKR以及各团队监测其业务所涉及的客户增长情况、业务增长情况、运营情况,作为数据团队如何快速响应;

2)对于仅一次性的取数情况,其投入和产出比较低,而且屡见不鲜;

3)爱番番业务的核心指标口径一致的问题,如何统一收口,管理和数据服务化、平台化对接。

===

三、实践及经验分享

在本文讲述的架构实践落地之前,基本都是保持点状的工程思维处理业务数据,不能全面的、系统的解决所面临的数据应用现状,但是后来我们在实践中不断探索学习、思考以及注重经典方法论的运用并最终落实到技术架构中,在此过程中会从研发的人效、运维的人效、计算和存储资源等相关成本的角度来考虑,尽量不重复造轮子,所以在建设中会使用“云上百度”(侧重将内部私有云与外部公有云的混合,既发挥内部自研技术能力又推动技术互通和适配)以及“百度智能云”(致力于提供全球领先的人工智能、大数据和云计算服务和工具)的平台化大数据组件或解决方案。

接下来通过集成、存储、计算、调度、治理、查询、分析、洞察客户价值等环节分享总体数据技术架构和实践经验。

3.1 数据架构

3.1.1 什么是数据架构

提起数据架构,不得不说的是Google为了高效处理海量的广告、搜索、营销数据,而在2003年开始陆续发布的“三驾马车”,其包括可扩展的大型数据密集型应用的分布式文件系统(GFS),超大集群的简单数据处理引擎(MapReduce),结构化数据的分布式存储系统(BigTable)三篇论文,基于这三个大数据存储和计算的组件,后来的架构师们体系化的设计了两套主流的大数据解决方案,分别是Kappa和Lambda架构,其实还有一种Unified架构落地有一定的局限性,所以在此不赘述Unified架构,但我们要清楚的认识到没有一种架构能解决所有问题。

3.1.1.1 Lambda架构

Nathan Marz提出的Lambda架构是目前进行实时和离线处理的常用架构,其设计的目的是以低延迟处理和兼顾处理离线数据、支持线性扩展和容错机制等特点。

图片

Lambda 是充分利用了批处理和流处理各自处理优势的数据处理架构。它平衡了延迟,吞吐量和容错。利用批处理生成稳定且有利于聚合的数据视图,同时借助流式处理方法提供在线数据分析能力。在展现数据之前最外层有一个实时层和离线层合并的动作,此动作是Lambda里非常重要的一个动作,可以将两者结果融合在一起,保障了最终一致性。

维基百科中指出Lambda 经典的三大元素包括:批次处理层(batch), 高速处理也称为实时处理(speed or real-time),和响应查询的服务层(serving)。

3.1.1.2 Kappa架构

Jay Kreps提出的Kappa架构只关注流式计算,是在Lambda架构的基础上提出的,并不是为了取代Lambda架构,除非完全吻合你的使用案例。Kappa这种架构,数据以流的方式被采集过来,实时层(Real-time Layer)将计算结果放入服务层(Serving Layer)以供查询。

图片

Kappa将实时数据处理与数据的持续从处理集成到单一流处理引擎上,且要求采集的数据流可以从新从特定位置或全部快速被回放。例如计算逻辑被更改,会重新起动一个流式计算,即图中的虚线处,将之前的数据快速回放,重新计算并将新结果同步到服务层。

3.1.2 架构选型

正因为之前点状的工程思维来处理大数据不能够全面的、系统的解决所面临的数据应用现状和痛点,所以我们急需要设计并研发一套适合我们爱番番这种体量和发展阶段的数据处理体系的方案。

3.1.2.1 全面系统的梳理

【数据形态】涵盖私域和公域的用户行为事件数据、用户属性数据以及线索管家、IM沟通、营销活动、账号管理、潜客定投等等大量业务数据、行为事件数据、文件数据;

【数据集成】数据团队是不生产数据的,就需要从各业务线、终端、内部和外部渠道等数据源,把数据集成进来统一进行OLAP(联机分析处理)相关工作;

【数据存储】包括离线T+1形式数据存储需求可以存储到AFS和时效性要求较高的数据存储需求可以存在MPP架构的分析型数据库中;

【数据计算】包括实时计算场景和离线计算场景,实时计算采用Spark Streaming或Flink,离线计算可以采用MR或者基础架构部比较推荐的SparkSQL;

【数据治理及监控】包括平台稳定性、元数据管理、基础信息和血缘关系管理、调度管理、数据源管理、异常处理机制等方面;

【数据研发】包括考虑研发与运维的的人力资源是否够用,数据复用、操作规范,从业务建模到逻辑建模再到物理建模等通用方案落地。

【数据业务场景】包括线上业务运行过程的数据在线分析、用户参与活动、点击、浏览等数据用以行为分析和统计,用户身份属性类的数据用于ID打通后用于精准营销,内外部运营决策类的指标和报表场景,即席查询与下载、通用服务化、OpenAPI等。

3.1.2.2 快慢齐驱

鉴于现阶段爱番番的数据形态和业务需求,内部经过多轮讨论和对齐认知,最终决定两条路并行的方式,一方面“短平快”的支撑部分紧急的对客业务需求,另一方面搭建具有长远目标的体系化的数据架构实现。

2020年9月建设初期,恰逢销售域(现在的线索管理及IM沟通)分库分表,因为业务发展到,不得不将原来多套系统在同一个业务数据库里拆分开,并且一些上亿级数据量的业务表面临分表,利用租户ID取模之后分成128张分表,这时无论是在线业务还是OLAP场景的业务都随之面临重构升级,经过几次技术评审会之后,OLAP场景的数据抽取,从原来的SparkSQL任务直接拉数方式,敲定在Sqoop(开源)、DTS(厂内)、Watt(厂内)三个里面选其一。

最终调研的结论是抽取业务库选择Watt平台的方案,因为很好的支持分表接入,读Binglog时效性高,自身的监控完善、BNS负载均衡、多表Join、丰富的UDF、有平台专职运维保障人员等等优势特性。

图片

三位研发同学历经2个多月,将上图中1.0版的仅满足于紧急需求的架构落地,但是整个链路的稳定性比较牵强,经常收到内部和外部的投诉,甚至想办法开发了一套报警电话外呼的功能,从而经常半夜起床修复作业。

回过头来看,一直到2021年1月份1.0版的数据处理架构才稳定运行,撇开与CDC文件交互的部分,1.0版的架构更像是Kappa架构的变种,与此同时我们也进行调研行业最佳实践经验。

3.2 业务诉求及架构演进

软件产品有两种常态,其一是有源源不断的客户需求驱动产品迭代,另一种是从专业的角度规划对客户有价值的功能。爱番番恰好处于发展期,以上两种诉求都比较强烈。

3.2.1 追求时效性

不仅有客户反馈我们的线索分析和跟进分析等等线上产品的数据延迟严重,就连销售人员拓展新客户时,现场演示为了不突出这一产品的弱点,操作之后有意和客户谈话来延长加载时间的尴尬局面;

根据当时记录的线上稳定性报告里显示,延迟最严重的时候达到18分钟才出来数据,针对这样的困局,我们做了三个改进。

【措施1】解决Spring Streaming运行资源抢占的问题,进行作业迁移至独立集群并作相关资源隔离;

【措施2】Bigpipe的异地容灾方案落地,正常情况下主要使用苏州机房的Bigpipe,遇到故障时立即切换到北京机房,同时做好故障切换期间的数据补偿;

【措施3】利用Watt具有的多Binglog可Join的特性,将较复杂的计算提前到Watt平台上,同时在Spark Streaming中也做一部分数据处理,相当于原来利用在线实时现算的方式,优化为在实时流过程中增加两次ETL计算。

经过以上三个措施的改进,OLAP分析场景的时效性提升到10至15秒出结果。

3.2.2 BI场景需求

为了战略规划更清晰,嗅觉更敏锐,洞察更快速,我们市场、运营、商业化销售及客户成功团队的取数需求层出不穷,数据团队仅有的几位研发出现无力支持这么大量的需求。

  • 急需解决核心诉求,数据团队梳理共性需求进行产品化落地。

f71cc7ab3f96a6eb7b0b20afabde3f5f.jpg

  • 对于周期性的数据需求,我们通过自动邮件等方式制作定时推送任务

图片

3.2.3 公共数据仓库

截止2021年3月份,我们仍然有较多的取数或用数的场景无法支撑,例如:业务域统一数据源,数据能力模型复用,自助取数平台化或者一次性取数等等能力输出,鉴于我们一直对行业最佳实践经验的学习,发现适合爱番番现状的技术架构需要有所调整。

  • 在前文提到的1.0版之上,想要继续扩展的话,比较困难,特别是诸如Ad-hoc、数据建模或研发平台化,通用数据治理等等方面。
  • 经过与商业平台研发部门的技术交流期间,发现在之前Watt平台使用经验之上与凤阁平台集成,实现便捷的转储,其产品设计的背后为使用者省去很多工作量,不仅可以提高我们的人效,而且可以解决我们的技术和业务方面的诉求。
  • 此时产品和运营人员急需我们支持自助取数平台化即席查询的功能,并且领导写进团队的OKR。

POC完成后,决定将我们的架构从原来的1.0版改造为2.0版,携手凤阁团队将我们的离线数据迁移到凤阁,历时一个半月的时间,不但支持了Ad-hoc的强需求,而且很好的支持数仓分层管理、元数据、分主题、数据源管理、血缘关系,状态监控等数据资产治理方面的功能。

图片

2.0版本的架构一经推广,帮助了运营支撑团队解决了底层数据统一,摒弃了之前各敏捷小组各自花费人力开发底层数据,更有价值的是,经过凤阁平台化、规范化、流程化的提供可视化的开发工具之后,一位普通的研发人员,接受短暂的培训就可以基于现有的底层明细数据加工出各团队个性化的月度、季度和年度的内部OKR以及各团队监测其业务所涉及的客户增长情况、业务增长情况、运营情况报表,为数据研发团队解放了大量劳动力。


3.3 数仓建模过程

基于凤阁平台进行数据的分主题建模工作,主要采用Kimball维度建模的方法论,首先确定一致性维度和业务过程,产出总线矩阵,再确定各主题的事实内容,声明粒度进行相关研发工作。

图片

3.3.1 分层ETL

评判一个数仓建设好与坏的标准,不仅从丰富完善、规范、复用等角度看,还要从资源成本,任务量是否膨胀,查询性能及易用性,所以我们的数仓进行分层规划,避免了牵一发而动全身的烟囱式结构。

图片

3.3.2 模型选择

在数据模型的设计和落地过程中,选择以星型为主,以下用线索跟进过程的事实和维度为例,从逻辑模型到物理模型的详细情况展示。

图片

3.4 数据治理

广义上讲,数据治理是对数据的全生命周期内任何环节进行管理,包含数据采集、存储、清洗、计算转换等传统数据集成和应用环节的工作、同时还包含数据资产目录、数据标准、质量、安全、数据开发、数据价值、数据服务与应用等,整个数据生命期而开展开的业务、技术和管理活动都属于数据治理范畴。

图片

可以将数据治理分为数据资产的治理和数据质量方面的治理展开讨论。

3.4.1 数据资产治理

数据资产治理是建立规范的数据研发和应用标准,权限打通,实现数据内外部共享,并能够将数据作为组织的宝贵资产应用于业务、管理、战略决策中,发挥数据资产价值。

3.4.1.1 主题管理

区分数据主题,分门别类的管理数据内容,让使用者快速找到想要的数据。

图片

3.4.1.2 基础信息及血缘关系

体现出数据的归属性、多源性、可追溯性、层次性,这样可以清楚地表明数据的提供方和需求方以及其他详细信息。

图片

3.4.1.3 权限控制及自助化

无论是产品、运营、研发在授予其数据权限之后可以方便的在平台上查询和下载数据,同时凤阁平台的数据在“一脉平台”或其他即席查询平台,通过拖拽勾选的方式进行灵活取数。

图片

图片

3.4.2 数据质量治理

经过架构升级之后,运维保障工作提上了日程,诸如每日增量的数据差异监控、异常数据导致作业链路阻塞、集群稳定性监控、网络或相关组件抖动导致的数据缺失,如何补偿恢复等方面急需完善。

通过运维脚本或工具的开发,目前长效监控或例行检查的范围如下图所示。

图片


3.5 易于扩展

2.0版的数据架构,趋于稳定之后,我们迎来了新的目标,正逢新的系统一站式智能营销的上线,发现租户的大量的营销活动,旅程转化等私域营销功能,客户无法直观的通过量化的手段来清晰的看到营销场景的效果数据,所以我们面临在2.0版的基础上做扩展延伸。

3.5.1 营销效果分析

因为私域营销是基于CDP的Impala&Kudu里的数据,这里包含了事件数据和用户身份属性等数据,所以我们起初的分析是直接利用Imapla作为查询引擎,后来发现已上线的表结构设计时没有太多的兼顾分析场景的特点,并且Impala的并发能力有限,也不符合爱番番的2秒内出结果的稳定性指标要求。开始的几个需求可以勉强上线,但是分析场景和功能越来越丰富之后发现,客诉量明显增加。

因此营销效果分析这一业务场景经历了Impala+Kudu的解决方案迁到现在的Palo(Doris)作为数据分析场景的存储,这期间也参考过其他同类的主流分析型MPP架构数据库产品,最终我们还是选择了Palo,具体对比描述如下:

图片

3.5.2 实时能力提升

在2.0版的实时链路的基础上,我们与数据架构平台部交流了接下来分析场景的应用,并提前做POC和压力测试相关工作,确定了其可行性,然后承担实时分析的数据链路增加了如下部分架构:

图片

因为时效性要求提升至2秒以内,所以不影响原有的业务数据的Broker Load导入方式为前提增加了以上部分的架构,与CDP合作在数据加工链路中,将明细数据以实时流的方式下发到Kafka,然后会利用Flink to Palo和Kafka to Palo两种导入方式,对应到Doris本身的设计原理,也就是Stream Load方式是利用流数据计算框架Flink 消费Kafka的业务数据Topic,使用Stream Load 方式,以HTTP协议向Palo写入数据;Routine Load方式是提交一个常驻Palo的导入任务,通过不断的订阅并消费Kafka中的JSON格式消息,将数据写入到Palo中。

最终选择Palo作为分析场景的查询引擎及存储的方案,Palo由BE模块和FE模块组成,用户通过Mysql协议的客户端工具查询FE节点,FE节点和其中一个BE节点进行交互,各个BE节点将计算结果汇聚到负责协调的BE节点并返回给查询客户端。

3.5.2.1 Palo原理介绍

Palo的数据导入是采用LSM-Tree的算法实现,写的过程是先进入内存中,Compaction 可以后台异步完成,不阻塞写入,在磁盘上顺序写入同时merge sort;查询方面支持大宽表与多表join,具有CBO优化器等特性可以很好的应对复杂的分析场景。

图片

3.5.3 构建指标体系

基于私域营销的服务模式可以看作是B to B to C的模式,数据产品经理为了租户多维度清晰的掌握营销效果,建立起指标体系,我们结合数据产品经理按照私域的产品形态和有价值的对于私域的指标体系的各项逻辑计算规则生成可视化的报表以及相关实时分析服务。

解决了租户对于其私域用户参与营销活动情况的掌握之后,爱番番系统自身也定制了对于租户的使用产品情况的指标体系,例如DAU、MAU、每天、每周的PV和UV等,这样很好与租户之间建立起桥梁,更加清楚的知道哪些功能是租户每天都要使用并依赖的,就要保留并长期优化迭代,对于用户不使用的产品功能,进行定期清理并下线。

对于经营分析类指标和通用标准类指标,作为核心指标在运营报表系统内统一收口维护,随着业务迭代发展的的过程定期安排梳理计算逻辑,并设计通用的指标服务接口,提供给内外部统一标准化调用。

3.6 数据分析体系全景

至此爱番番的数据分析体系已成为一套完整的适合现阶段以及易于后期扩展的总体解决方案,从全景图中可以清晰的看出从基础层、平台层、中间处理层、公共服务层、数据产品化等是大数据分析体系必不可少的根基。

图片


3.7 数据分析体系建立的收益

【业务方面】数据产品经理或分析师深入客户的核心业务场景并梳理业务过程,对于关键业务过程建立运营分析指标,例如“全员推广”这一业务场景,抽象出“获客”、“运营”、“再培育”这三个业务过程,然后再与业务线的产品经理一起细化出这些过程中的“时间”、“地点”、“租户”,“销售推广员”、“访问”、“推广积分规则”、“推广渠道”、“是否裂变”等一致性维度,这样就可以得出前文提到的建模方法论中的“总线矩阵”,基于总线矩阵可以逻辑建模,产生星形或星座模型之后,可以多视角、多维度的计算丰富的指标,再结合用户研究(UBS)团队反馈的刚需、产品功能上的行为埋点以及其他客户访谈等技术和产品手段来解决自身的或客户的业务痛点;同时会根据租户所在行业的横向同行水平的指标统计出合理阈值,再通过技术手段定期主动为客户发送业务相关的预警,最后在预警基础上指导客户操作相关功能提升其业务在行业内的高度;再者利于通用的指标或标签来有引导的提示用户完成相关操作任务或者通过多种形式直接触用户等数据分析服务来解决对客户有业务价值和对业务增长有指导意义的数据产品这方面痛点。

【技术方面】技术是为产品服务的,产品是为客户服务的,数据分析产品需要的及时性,稳定性,准确性也是技术架构需要做到的。爱番番的数据分析架构和治理体系在产品与技术相辅相承的过程中完善起来后,之前的时效性不达标,数据不准确、分库分表技术支持不到位,数据到处散落不统一复用、业务线取数需求积压,统计逻辑不一致等情况都可以通过前文描述的数据分析架构解决或者快速试错后解决。

【组织方面】经过凤阁平台化、规范化、流程化的提供可视化的开发工具之后,一位普通的研发人员,接受短暂的培训就可以基于现有的底层明细数据加工出各团队个性化的月度、季度和年度的内部OKR以及各团队监测其业务所涉及的客户增长情况、业务增长情况、运营情况报表,技术赋能业务的同时为数据研发团队解放了大量劳动力;有了即席查询和下载功能之后,一次性查询、取数变得自助化;有了数据服务化和平台化对接的模式使我们企业通用经营分析类指标和产品线个性化运营类指标的产出及维护职责分工更明确。

四、总结与展望

  • 在过去的几个月内,我们一直在思考并落实将离线的(天级或小时级)数据指标和报表通过实时的方案来实现,其中既有已经完成的基于用户行为实时采集上来的数据,为租户提供私域营销场景的效果实时分析也有公域线索数据的实时状态分析、实时跟时分析、销售漏斗分析等等,接下来会思考如何让数据分析与CDP(内部客户数据平台)的架构融为一体,让用户行为事件和业务数据结合以及全域用户统一身份ID-mapping等技术进一步配合,达到精细化运营,发挥更大的业务产品价值;
  • 湖仓一体的技术是未来的趋势,接下来会调研一下离线和实时数仓对接内部私有云或百度智能云的数据湖解决方案;
  • 设计研发平台化的数据处理方案,让研发工作更加便捷,提高人效;
  • 进一步简化数据加工链路,提升数据加工效率,提升数据产品的时效性;
  • 引入中台化的思想和服务能力,落地执行数据标准,量化数据健康分,提高复用能力等智能评分体系,达到降本增效的终极目标。

———- END ———-

百度 Geek 说

百度官方技术公众号上线啦!

技术干货 · 行业资讯 · 线上沙龙 · 行业大会

招聘信息 · 内推信息 · 技术书籍 · 百度周边

欢迎各位同学关注

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

java命令行参数详解 引言 创建和编译应用 java的命令

发表于 2021-11-05

引言

这是我参与11月更文挑战的第4天,活动详情查看:2021最后一次更文挑战

作为一个java程序员,我始终保持谦逊进取的态度去对待,始终重视基础知识的学习,我觉得工作久了势必需要一些工具在身边,我的老大老是diss我,说我能发现和解决问题,但是效率不高,那是因为我每次都面向百度编程,没有收集和整理工具的习惯,于是就有了本篇文章。

读完本篇文章你会了解到java命令参数的含义,并可初步使用java命令来更好的启动和创建我们的应用。

创建和编译应用

image.png

这里可以看到一些内置命令工具,我按使用程度对他们进行了排序:

  • java:Launches a Java application.,启动一个java应用比如java -jar
  • javac:Reads Java class and interface definitions and compiles them into bytecode and class files.,编译工具,将源代码编译成字节码或者class文件
  • javap:Disassembles one or more class files.,反汇编
  • javadoc:Generates HTML pages of API documentation from Java source files.java API文档生成工具
  • jar:Manipulates Java Archive (JAR) files.操作jar包的,jar包本质上也是zip文件。
  • jdb:Finds and fixes bugs in Java platform programs.java debug,有idea后几乎不用了。

java的命令行参数描述

这么多工具,我们主要来介绍java命令,文档里说明了:当我们使用java命令启动应用时,该应用就通过jre来加载特定的类,并调用main方法,该方法必须声明为 public 和 static,它不能返回任何值,并且它必须接受一个 String 数组作为参数。

image.png

java命令的选项参数

java命令给我们提供了非常多的命令参数,当然也有非常多的划分,但我认为主要是两种划分:第一种是按选项进行划分,第二种是按照使用环境区分,我们可以使用java命令来看下:

image.png

选项划分

  • 标准选项:以“-”开头,比如-help -version,Java 虚拟机 (JVM) 的所有实现都保证支持标准选项。
  • 非标准选项:以“-X”开头,特定于Java HotSpot 虚拟机的通用选项,因此不能保证所有 JVM 实现都支持它们,并且可能会发生变化。
  • 高级选项:以“-XX”开头,这些是用于调整 Java HotSpot 虚拟机操作的特定区域的开发人员选项,这些区域通常具有特定的系统要求,并且可能需要对系统配置参数的特权访问。也不能保证所有 JVM 实现都支持它们,并且可能会发生变化。
  • 布尔选项:用于启用默认禁用的功能或禁用默认启用的功能。此类选项不需要参数。布尔 -XX 选项使用加号 (-XX:+OptionName) 启用,使用减号 (-XX:-OptionName) 禁用。

使用环境划分

1.系统属性

java -D:设置属性值
java -D属性名 = 属性值
比如:java -Dfile.encoding=utf-8

image.png

2.运行模式

java -server 选择虚拟机模式,默认是“server”
java虚拟机在启动应用时,启动器会对虚拟机模式进行检测,检测应用是否在服务器上的机器运行,如果是,那就以服务器的模式运行,目的是提高性能。

java虚拟机分为客户端模式和服务器模式,客户端模式下默认-Xms是1M,-Xmx是64M,适用于占用内存小,启动更快的产品,而服务端模式默认-Xms是128M,-Xmx是1024M,启动慢,但运行时性能和内存管理效率高,适用于生产环境。

  • java -Xmixed 混合模式执行 (默认)
  • java -Xint 仅解释模式执行

3.堆内存设置

1
2
3
4
5
6
arduino复制代码-Xms<size>        设置初始 Java 堆大小
-Xmx<size> 设置最大 Java 堆大小
-Xss<size> 设置 Java 线程堆栈大小
-Xms<size> 设置初始 Java 堆大小
-Xmx<size> 设置最大 Java 堆大小
-Xmn<size> 设置最大java年轻代堆大小

4.GC设置

  • -XX:+UseParallelGC
  • -XX:+UseParallelOldGC
  • -XX:+UseParNewGC
  • -XX:+UseSerialGC
  • -XX:+UseParallelGC
  • -XX:+UseConcMarkSweepGC
  • -XX:+UseG1GC

5.分析诊断

-XX:+HeapDumpOnOutOfMemoryError:异常堆的快照,默认关闭,示例:-XX:+HeapDumpOnOutOfMemoryError -Xmx 256m 再指定个文件名

-XX:HeapDumpPath=path与上面的配合使用,指定转存文件目录,示例:
-XX:HeapDumpPath=C:/log/java/java_heapdump.log

-XX:OnError=string,当错误发生的时候运行的命令,%p代表当前进程示例:- -XX:OnError="userdump.exe %p"

-XX:OnOutOfMemoryError=string 与上面一样。

6.JavaAgent

1
2
xml复制代码-javaagent:<jarpath>[=<选项>]
加载 Java 编程语言代理, 请参阅 java.lang.instrument

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

测试用例又双叒叕失败了,NLP帮你来分析

发表于 2021-11-05

​​摘要:本文将介绍如何使用AI技术实现失败测试用例的智能分析。

本文分享自华为云社区《测试用例又双叒叕失败了,啥原因?NLP帮你来分析》,作者: 敏捷的小智 。

随着软件行业的快速发展,为了实现高质量的快速迭代,越来越多的公司开始推进测试自动化来缩短测试周期,较成熟的软件公司开始追求80%甚至更高的测试自动化率。一轮耗时一周的手工测试在自动化后可能一天或更短时间内就能完成全部执行。在每一轮自动化测试中,对失败用例进行根因分析是一份十分重要的工作,而海量测试日志的人工分析开始成为瓶颈。本文将介绍如何使用AI技术实现失败测试用例的智能分析。

基于日志分析辅助开发人员发现及定位系统问题早已不是新鲜课题,在过去几十年里都有广泛的研究。随着数据的持续积累,学术界的研究和工业实践都有尝试使用机器学习来求解,包括监督方法和非监督方法。在发现问题方面,2017年的一篇《DeepLog:Anomaly Detection and Diagnosis from System Logs》引起了广泛的关注。文中介绍了通过多重LSTM模型,学习日志模板及日志参数组成的时序数据特征,对系统行为及系统状态进行异常检测,辅助开发人员提前感知系统的潜在风险。本文将从定位问题的角度,介绍如何使用日志分析的技术在测试场景下辅助失败用例的根因定位。

本文的使用的算法简单很多,但对测试日志及历史分析有较高的要求。首先,基于大数定律,样本量越大越能接近数据的原始分布,所以要求待分析的失败用例要有足够的量级,-否则不仅有杀鸡用牛刀之嫌,效果也不会好。其次,要有一定的失败测试用例分析数据,本文介绍的是有监督学习的解决方案,带标签的数据质量将会决定学习效果的上线。

好了,既然上来就揭了谜底:用文本分类模型来实现失败测试用例的根因定位。就先给大家展示一下完整的解决方案。

图一:失败测试日志分析服务构建流程

图一:失败测试日志分析服务构建流程

如图一所示,失败测试日志分析服务构建流程可以概括为以下步骤:

  1. 测试日志分析数据的准备:确认测试日志被正确记录并保存,对失败测试日志的根因分析也被妥善保存。日志中应该包含可以用来定位根因的高价值信息,如系统返回的错误码、报错信息等。
  1. 模型的训练:根据已有的分析数据训练模型。

a) 日志清洗:在失败用例的日志中,充斥的大量与失败原因不相关的内容。这些噪音数据会增加模型训练的不确定性。结合历史经验,对日志数据进行清洗,提取关键信息,在训练初期是不可缺少的关键一步。例如,实践中发现,几乎所有失败用例中都有系统返回的错误信息。如果没有,需要仔细检查一下是日志设计不合理,还是可以直接认定为测试环境问题。测试人员拿到失败测试用例,看到错误信息基本就能定位大概的失败原因。所以在日志清洗时,只截取错误信息,是目前实践下来效果较好的一个预处理步骤。

样例:

Case001 配置问题 参数比对失败

Case002 环境问题 无法连接*.*.*.*

……

b) 日志预处理:人参与的越少,后期维护的成本越低,所以在日志预处理阶段,只对日志做简单预处理,如分词、去除停用词等。

c) 模型训练:将历史分析数据载入TextCNN文本分类模型。TextCNN最大的优势是网络结构简单,在多项数据集上轻松超越benchmark。网络结构简单,参数数目少,计算量少,训练速度较快。想了解模型细节的同学,可以戳Convolutional Neural Networks for SentenceClassification 。

d) 模型调参:通过修改embedding dim长度、调整随机策略等,尝试获得最优的模型。当模型能在实验室实现train test的准确率在85%左右,可以认为是ready to go的模型。

  1. 将步骤2训练获得的模型host成在线分析服务。
  1. 测试自动化执行中,失败测试用例的日志在预处理后,被自动post到预测服务,获得预测的结果,包括预测的根因和置信度。

测试人员可以在一轮测试执行后立刻得到测试结果分析报告。

首先测试人员结合历史经验,对可直观感知到失败原因的测试用例及时进行定位并做出处理,比如是测试环境问题则修复环境,重新执行测试用例。

其次,结合模型输出的置信度,对预测结果做好分级。历史上大量出现过的的错误日志,一般置信度较高,直接给出根因。置信度较低的失败用例,可能是新增问题,及时给出警告。

不同的业务场景会生成不同的日志,随着业务场景的不断增加,日志的特征空间趋于无限,无法用同一个模型适配所有场景。尽量减少人工参与,针对特定业务场景,使用较轻量级的模型快速训练迭代,是能够在工业界落地实现的一个很重要的特性,本文介绍的TextCNN文本分类模型目前实践来看是能够满足以上要求的。在提升模型准确度上,结合主动学习提升数据质量,引入小样本学习减少人工依赖将是后续重点的探索方向。

参考资料

  1. ExperienceReport: System Log Analysis for Anomaly Detection, 2016.

点击关注,第一时间了解华为云新鲜技术~

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

干货 1分钟售票8万张!门票抢票背后的技术思考

发表于 2021-11-05

一、背景

去年疫情后,为了加速启动旅游市场,湖北在全域范围内开展“与爱同行 惠游湖北”活动——全省所有A级旅游景区向全国游客免门票,敞开怀抱欢迎全国人民。本文将介绍在这一活动期间,线上预约抢票系统遇到的核心问题,系统的改造过程以及实施的一些经验。这是高并发、高可用场景下,提升系统稳定性的一次实战优化,希望能给面对同样问题的同学提供一些借鉴思路。

图片

活动页面

二、风险与挑战

在活动初期,系统面临以下四类风险:

  • 流量大,入口流量瞬间增长100倍,远超系统承载能力;
  • 高并发下,服务稳定性降低;
  • 限购错误;
  • 热门门票、热门出行日期扣库存热点;

图片

高并发下系统的挑战

下面我们一起来看下每个问题的影响和解决策略。

2.1 入口流量增长100倍

问题

活动开始时入口流量增长100倍,当前系统无法通过水平扩展解决问题。

图片

请求量监控

目标

提升入口应用吞吐能力,降低下游调用量。

策略

减少依赖

1)去除0元票场景不需要的依赖。例如:优惠、立减;

2)合并重复的 IO(SOA/ Redis/DB),减少一次请求中相同数据的重复访问。

图片

上下文传递对象减少重复IO

提升缓存命中率

这里说的是接口级缓存,数据源依赖的是下游接口,如下图所示:

图片

服务层-接口级缓存-固定过期

接口级缓存一般使用固定过期+懒加载方式来缓存下游接口返回对象或者自定义的DO对象。当一个请求进来,先从缓存中取数据,若命中缓存则返回数据,若没命中则从下游获取数据重新构建缓存,由于是接口级的缓存,一般过期时间设置都比较短,流程如下图:

图片

固定过期+懒加载缓存

这种缓存方案存在击穿和穿透的风险,在高并发场景下缓存击穿和缓存穿透问题会被放大,下面会分别介绍一下这几类常见问题在系统中是如何解决的。

1)缓存击穿

描述:缓存击穿是指数据库中有,缓存中没有。例如:某个 key访问量非常高,属于集中式高并发访问,当这个 key 在失效的瞬间,大量的请求就击穿了缓存,直接请求到下游(接口/数据库),造成下游压力过大。

解决方案:对缓存增加被动刷新机制,在缓存实体对象中增加上一次刷新时间,请求进来后从缓存获取数据返回,后续判断缓存是否满刷新条件,若满足则异步获取数据重新构建缓存,若不满足,本次不更新缓存。通过用户请求异步刷新的方式,续租过期时间,避免缓存固定过期。

例如:商品描述信息,以前缓存过期时间为5min,现在缓存过期时间为24H,被动刷新时间为1min,用户每次请求都返回上一次的缓存,但每1min都会异步构建一次缓存。

2)缓存穿透

描述:缓存穿透是指数据库和缓存中都没有的数据,当用户不断发起请求,比如获取id不存在的数据,导致缓存无法命中,造成下游压力过大。

解决方案:当缓存未命中,在下游也没有取到数据时,缓存实体内容为空对象,缓存实体增加穿透状态标识,这类缓存过期时间设置比较短,默认30s过期,10s刷新,防止不存在的id反复访问下游,大部分场景穿透是少量的,但是有些场景刚好相反。例如:某一类规则配置,只有少量商品有,这种情况下我们对穿透类型的缓存过期时间和刷新时间设置同正常的过期和刷新时间一样,防止下游无数据一直频繁请求。

3)异常降级

当下游出现异常的时候,缓存更新策略如下:

缓存更新:

  • 下游是非核心:超时异常写一个短暂的空缓存(例如:30s 过期,10s刷新),防止下游超时,影响上游服务的稳定性。
  • 下游是核心:异常时不更新缓存,下次请求再更新,防止写入空缓存,阻断了核心流程。

4)缓存模块化管理

将缓存key按照数据源做分类,每一类key对应一个缓存模块名, 每个缓存模块可以动态设置版本号、过期时间和刷新时间,并统一埋点与监控。模块化管理后,缓存过期时间粒度更为细致,通过分析缓存模块命中率监控,可以反推过期和刷新时间是否合理,最终通过动态调整缓存过期时间与刷新时间,让命中率达到最佳。

图片

缓存模块命中率可视化埋点

我们将以上功能封装为了缓存组件,在使用的时只需要关心数据访问实现,既解决了使用缓存本身的一些共性问题,也降低了业务代码与缓存读写的耦合度。

下图为优化前后缓存使用流程对比:

图片

缓存使用对比

效果

通过解决缓存穿透与击穿、异常降级、缓存模块化管理,最终缓存命中率提升到98%以上,接口性能 (RT) 提升50% 以上,上下游调用量比例从1 : 3.9 降低为 1 : 1.3,下游接口调用量降低70%。

图片

处理性能提升50%

2.2 高并发下服务稳定性低

问题

在每天上午8:00抢票活动开始时,DB连接池被打满,线程波动大,商品服务超时。

图片

数据库线程波动

思考

  • DB 连接池为什么会被打满?
  • API为什么会超时?
  • 是DB不稳定影响了API,还是API流量过大影响了DB?

问题分析

1)DB 连接池为什么会被打满?分析三类SQL日志。

  • Insert 语句过多 – 场景:限购记录提交,将限购表单独拆库隔离后,商品API依然超时(排除)
  • Update 语句耗时过长 – 场景:扣减库存热点引起(重点排查)
  • Select 高频查询 – 场景:商品信息查询

2)API为什么会超时?

排查日志可以看到,8:00活动开始后,大量热门商品信息查询到DB与Select高频查询一致。

3)是DB不稳定影响了API,还是API流量过大影响了DB?

根据#2初步判断是由于缓存击穿,导致大量流量穿透到DB。

为什么缓存会被击穿?

梳理系统架构后发现,由于8:00定时可售通过离线Job控制,8:00商品上线引发数据变更,数据变更导致缓存被刷新(先删后增),在缓存失效瞬间,服务端流量击穿到DB,导致服务端数据库连接池被打满,也就是上文所说的缓存击穿的现象。

图片

数据访问层-表级缓存-主动刷新

如下图所示,商品信息变更后主动让缓存过期,用户访问时重新加载缓存:

图片

数据访问层缓存刷新架构(旧)- 消息变更删除缓存Key

目标

为了防止活动时缓存被删除导致缓存击穿,流量穿透到DB,采用了以下2种策略:

1)避开活动时数据更新导致缓存失效

我们将商品可售状态拆分商品可见、可售状态。

  • 可见状态:7:00提前上线对外可见,避开高峰;
  • 可售状态:逻辑判断定时售卖,既解决定时上线修改数据后,导致缓存被刷新的问题,也解决了Job上线后,商品可售状态延迟的问题。

图片

逻辑判断定时可售避开高峰缓存击穿

2)调整缓存刷新策略

原缓存刷新方案(先删后增)存在缓存击穿的风险,所以后面缓存刷新策略调整为覆盖更新,避免缓存失效导致缓存击穿。新缓存刷新架构,通过Canal监听 MySQL binlog 发送的MQ消息,在消费端聚合后,重新构建缓存。

图片

数据访问层缓存刷新架构(新)- 消息变更重新构建缓存

效果

服务(RT)正常,QPS提升至21w。

图片

上面两类问题与具体业务无关,下面我们介绍一下两个业务痛点:

  • 如何防止恶意购买(限购)
  • 如何防止库存少买/超买(扣库存)

2.3 限购

什么是限购?

限购就是限制购买,规定购买的数量,往往是一些特价和降价的产品,为了防止恶意抢购所采取的一种商业手段。

限购规则(多达几十种组合)例如:

1)同一出行日期同一景区每张身份证只能预订1张;

2)7天内(预订日期)某地区只能预约3个景区且最多限购20份;

3)活动期间,预约超过5次,没有去游玩noshow限购;

问题

扣库存失败,限购取消成功(实际数据不一致),再次预订被限购了。

原因

限购提交是Redis和DB双写操作,Redis是同步写,DB是线程池异步写,当请求量过大时,线程队列会出现积压,最终导致Redis写成功,DB延时写入。在提交限购记录成功,扣库存失败后,需要执行取消限购记录。

如下图所示:

图片

限购检查-提交限购-取消限购

在高并发的场景下,提交限购记录在线程池队列中出现积压,Redis写入成功后,DB并未写入完成,此时取消限购Redis删除成功,DB删除未查到记录,最终提交限购记录后被写入,再次预订时,又被限购。

如下图:

图片

线程队列积压,先提交的“提交限购”请求晚于“取消限购”

目标

服务稳定,限购准确。

策略

确保取消限购操作Redis/DB最终一致。

由于提交限购记录可能会出现积压,取消限购时提交限购记录还未写入,导致取消限购时未能删除对应的提交记录。我们通过延迟消息补偿重试,确保取消限购操作(Redis/DB)最终一致。在取消限购的时候,删除限购记录影响行数为0时,发送MQ延迟消息,在Consumer端消费消息,重试取消限购,并通过埋点与监控检测核心指标是否有异常。

如下图所示:

图片

下单-提交限购与取消限购

效果

限购准确,没有误拦截投诉。

2.4 扣减库存

问题

  • 商品后台显示1w已售完,实际卖出5000,导致库存未售完。
  • MySQL出现热点行级别锁,影响扣减性能。

原因

  • 扣库存与库存明细SQL不在一个事务里面,大量扣减时容易出现部分失败的情况,导致库存记录和明细不一致的情况。
  • 热门景点热门出行日期被集中预订,导致MySQL出现扣减库存热点。

目标

库存扣减准确,提升处理能力。

策略

1)将扣减库存记录和扣减明细放在一个事务里面,保证数据一致性。

图片

DB事务扣减库存

效果

优点:数据一致。

缺点:热点资源,热门日期,扣减库存行级锁时间变长,接口RT变长,处理能力下降。

2)使用分布式缓存,在分布式缓存中预减库存,减少数据库访问。

秒杀商品异步扣减,消除DB峰值,非秒杀走正常流程。

图片

商品上线的时候将库存写入Redis,在活动扣减库存时,使用incrby原子扣减成功后将扣减消息MQ发出,在Consumer端消费消息执行DB扣减库存,若下单失败,执行还库存操作,也是先操作Redis,再发MQ,在Consumer端,执行DB还库存,如果未查询到扣减记录(可能扣库存MQ有延迟),则延时重试,并通过埋点与监控检测核心指标是否有异常。

图片

异步扣减库存

效果

  • 服务RT平稳,数据库IO平稳
  • Redis 扣减有热点迹象

3)缓存热点分桶扣减库存

当单个Key流量达到Redis单实例承载能力时,需要对单key做拆分,解决单实例热点问题。由于热点门票热门日期产生热点Key问题,观察监控后发现并不是特别严重,临时采用拆分Redis集群,减少单实例流量,缓解热点问题,所以缓存热点分桶扣减库存本次暂未实现,这里简单描述一下当时讨论的思路。

如下图所示:

图片

缓存热点分桶扣减

分桶分库存:

秒杀开始前提前锁定库存修改,并执行分桶策略,按照库存Id取模分为N个桶, 每个分桶对应缓存的Key为Key [0~ N-1],每个分桶保存m个库存初始化到Redis,秒杀时根据 Hash(Uid)%N 路由到不同的桶进行扣减,解决所有流量访问单个Key对单个Redis实例造成压力。

桶缩容:

正常情况下,热门活动每个桶中的库存经过几轮扣减都会扣减为0。

特殊场景下,可能存在每个桶只剩下个位数库存,预订时候份数大于剩余库存,导致扣减不成功。例如:分桶数量为100个,每个桶有1~2个库存,用户预订3份时扣减失败。当库存小于十位数时,缩容桶的数量,防止用户看到有库存,扣减一直失败。

优化前后对比

图片

扣减库存方案对比

三、回顾总结

回顾“与爱同行 惠游湖北”整个活动,我们整体是这样备战的:

  • 梳理风险点:包括系统架构、核心流程,识别出来后制定应对策略;
  • 流量预估:根据票量、历史PV、节假日峰值预估活动峰值QPS;
  • 全链路压测:对系统进行全链路压测,对峰值 QPS进行压测,找出问题点,优化改进;
  • 限流配置:为系统配置安全的、符合业务需求的限流阀值;
  • 应急预案:收集各个域的可能风险点,制作应急处理方案;
  • 监控:活动时观察各项监控指标,如有异常,按预案处理;
  • 复盘:活动后分析日志,监控指标,故障分析,持续改进;

本文阐述了在抢票活动中遇到的四个具有代表性的问题,在优化过程中,不断地思考和落地技术细节,沉淀核心技术,以最终达到让用户预订及入园顺畅,体验良好的目标。

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

为何项目做到最后都成为“屎山”,代码无法改动

发表于 2021-11-05

开头先来个小故事:张三是一个程序员,在金九银十的季节去了一家新公司就职。新的公司看起来前景不错,做的产品也属于行业前沿,张三发誓自己要在此一展鸿图,用自己精湛的开发技术为公司的上市添砖加瓦。

张三就职的第一天,公司就开放了代码的权限,他熟悉起公司的核心项目。结果却惊呆了,张三发现公司的项目就像是一个垃圾场,各种代码堆成山,而他要做的事情,就是去维护这些老项目,在那一刻,张三内心的幻想瞬间破灭。

但在维护了一段时间项目之后,事情出现了转机。有一天,新项目下来,老板任命张三为负责人,他内心狂喜,终于可以证明自己了。

“我一定要让代码显得优雅,跟烂代码说再见。”

刚开始,张三用了各种设计模式,疯狂抽象业务,越做越有劲,感觉一身的才学终于有了展示的机会。但项目是多人合作的,随着时间的流逝,和项目的不断迭代,很多新人不再按照预定的规范来开发代码。

为了方便,微服务如雨后春笋般一个个往外面冒,开发人员在代码里填充了一个又一个if语句。于是,张三开始手动地限制那些不符合规范的代码提交。可是项目时间的压力越来越大,张三最终迫于交付压力又放开了限制。虽然项目顺利的交付完成,但是奇怪的代码却永久的留在了项目中。

慢慢的,原始精美的设计开始变得越来越臃肿,逻辑变得复杂无比。没有人敢去重构,也不可能重构了。终于,张三实在无法忍受,辞职去了一家新公司就职,新的公司看起来前景不错,做的内容也是行业前沿的产品,张三再次发誓自己要在新公司一展鸿图,用自己精湛的开发技术为公司的上市添砖加瓦…

这样的故事在互联网行业内一遍一遍地上演,似乎任何项目随着时间演进,一个个补丁打到最后都会变成“屎山型”项目,充斥着各种历史遗留问题,新功能开发越来越慢,最终无法演进走向项目的终结。有些互联网公司会为延长项目的生命周期,在某个节点聘请资深的软件架构师,他们往往熟读《重构》,用各种各样的技术手段去延缓这个过程。

产品架构是啥

像软件架构一样,产品设计也是有架构的。

在做项目的时候,我们觉得从技术上,所有的问题都能得到解决,但是整个项目却在不知不觉间一步步的走向“屎山型”项目。按照研发的思维,问题的根源是抽象还不够,技术水平不行,需要更强大的架构师来重构。

聘请了资深的软件架构师后,一开始项目似乎变得好了一些,但最终结果并没有发生改变,只是延缓了而已,到了某个阶段也只能抛弃,重新开始。

复盘后会发现,我们的主要精力都在解决技术上的问题,而忽略了产品层面。按照网上的一种说法,产品架构就是在充分理解产品用户需求基础上对产品数据流转的逻辑梳理。

而我对产品架构的理解是从**“理念世界”**开始的。编程是用计算机能够理解的语言来描述现实事物,计算机能够理解的语言是什么?是逻辑。在编程的时候,研发人员需要在脑海中构思出事件的全貌,并且用逻辑的语言将它描述出来。

在西方的哲学里面有一个”理念世界”的说法,大概意思是人们做的任何事情,都是在脑海中预先构建出事物的本体,再到现实中对预先构建的内容进行模仿。这与我们编程的过程很相似,那么产品是否也遵循这个过程?

回想起以前做项目时的思考方式,发现确实如此,我们或多或少都需要在脑海中构建出产品的运行轨迹。但是在做项目的时候,作为研发的我们都在想如何用技术解决问题,却忽略了更重要的东西,任何产品都是为了解决客户的问题而存在,解决客户的问题是根本,无论用什么手段……

如何设计产品架构

在设计之前,先解决人的问题,什么样的人适合做产品架构?

产品架构就是在充分理解产品用户需求基础上对产品数据流转的逻辑梳理。

所以这个人需要具备以下素质:

  • 能够调研并理解用户需求的能力
  • 能够知道产品的核心价值
  • 能够理解产品运行原理
  • 面向对象设计思维

有了这些素质,就可以开始构建”理念世界”了。

构建理念世界

构建”理念世界”其实就是将现实中将要发生的事情,用面向对象设计思维将事情转换成纯粹的逻辑描述,这个过程叫抽象。

举个例子,如果我们需要做一个流量治理类型的产品,抽象过程大概是这样的:流量治理基本分为2个大的内容,流量监控和流量管理,这是核心价值。

而传统的流量治理工具基本都是采用SDK的方式实现,它们普遍具有以下的问题:

  • 侵入性强
  • 治理功能不全
  • 内容多、门槛高
  • 中间件演变困难
  • 版本碎片化严重
  • 升级成本高

如果能解决此类型的问题,将会使得服务网格在流量治理解决方案上会优于SDK的方式,这是比较优势。

有了上面的分析,可以得出:如果希望产品可以快速升级且侵入性弱,势必不能与客户的代码进行强绑定,需要一种与语言无关,又能够做到流量监控,流量管理的手段,只能去操作系统上面找。

如果能操纵操作系统上的某些功能,使得流量在进入服务之前,先进入编写的程序中,就做到了语言无关。

思路大概是这样:一个请求进来,先被操作系统转发到编写的程序中,然后我们自己编写的程序会将数据上报到某个东西保存起来,最后程序转发到真正的服务中,流量监控就做完了。同时,还需要一个用于存储上报数据的东西,它需要具备持久化的能力。

在这个流程当中,使用了一种设计模式,叫sidecar模式,就用sidecar称呼我们自己编写的程序好了,存储的那个就叫数据库。

接下来推导一下流量控制的逻辑,要做到流量控制,需要用到sidecar,毕竟流量已经被操作系统转发到了sidecar上面,我们可以做过处理之后再转发到真正的服务当中。那么就需要一个另外的东西,它来告诉sidecar要怎么对流量进行处理,毕竟每个sidecar需要处理的东西是不同的,而且策略内容需要持久化,不然找不到与sidecar的对应关系,这个东西叫做控制端。

所以流程大概变成:控制端配置流量控制策略,控制端将策略下发到sidecar上,一个流量请求过来,被操纵系统转发到sidecar,sidecar先上报流量数据到数据库,然后根据流量策略对流量进行处理,最后将请求转发到真正的服务中。

在完全理想的状态下,通过这样一个流程,基本实现了流量治理的核心能力,并且这个流程相比SDK的方式更具有优势,这就是所谓”理念世界”的构建过程,纯粹的逻辑描述。

验证理念世界

“理念世界”是否正确的唯一衡量标准是它是否完全正确的描述了现实,就像面向对象思维里面的类和对象的关系,”理念世界”是对现实的抽象。

要想知道抽象的好不好,有一个非常有效的办法。随便找几个人,把你的逻辑说一遍,如果表述的过程是顺畅的,对方能够理解并且没有感觉到逻辑上的遗漏,这个抽象就是比较好的。

在做项目的时候,可以把这个过程尽量的描述给不同岗位的人,一边加深团队成员对产品的理解,一边又通过不断的表述来完善这个流程没有考虑完善的内容。

如何落地

当”理念世界”被建立,就需要在现实中对它进行模仿,在软件工程学当中,这一步就要开始脱离设计,到实操的阶段。一般项目分2类,一类是从零开始,一类是存量项目。

从零开始的项目

从零开始的项目在动手之前,一般会面临2个问题,从哪开始?要模仿到什么程度?

通过流程可以发现以下是一切的基石。

1.操纵操作系统上的某些功能,使得流量在进入服务之前,先进入我们编写的sidecar中

2.sidecar

3.数据库

所以在没有外部特殊情况干扰的时候流量监控功能肯定要优先于流量控制功能做,这是从哪开始。

至于做到什么程度主要依托于时间,人员的关系,看实际情况把握。但无论做多少,只要方向是对的,对整个 产品的迭代都是具有正向的意义。

通过这张图,服务划分变得很清楚,在交给研发时,每个服务的边界也有明确的规定。就算研发人员出现新入职或者水平良莠不齐的现象,在这个框架内所能造成的破坏力也有限,不会对整个产品造成结构性的问题,在未来的某个时候只需要找一个足够强的研发重新写一遍,问题就都解决了。

存量项目

存量项目的落地就十分的复杂,历史遗留害人不浅……

大的思路应该是先用”抽象”映照现实,看看到底现在的代码是否完全符合”抽象”的”流程”,先搞清楚现状再想办法修枝剪叶。

如果有新的需求到来时,还是要先抽象,任何正当的需求都是符合逻辑的,如果抽象出来不符合逻辑,那肯定是需求挖掘的不够,不能盲目的加代码。

还是那个例子,如果需要添加一个对sidecar的监控,那流程就会变成这样。

但是监控单独拎出来是否有必要?如果没有必要的话流程可以变成这样。

这2种形态没有优劣之分,可以结合具体情况做选择。

总结

如果有了解到服务网格领域的朋友应该很早就发现,上诉说的例子就是一个弱鸡版Istio的诞生。

我尝试着从需求出发,纯粹的逻辑推导Istio的架构。很多有名的开源项目为什么历经这么多年,反而越来越精炼,这里面一定有值得探讨的地方。

本文只是提供一种解决问题的方法,解决问题的核心还得看人,一群大佬,无论用什么方法做出来的东西都精美而优雅。

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

五分钟,让你明白MySQL是怎么选择索引《死磕MySQL系列

发表于 2021-11-05

系列文章

二、一生挚友redo log、binlog《死磕MySQL系列 二》

三、MySQL强人“锁”难《死磕MySQL系列 三》

四、S 锁与 X 锁的爱恨情仇《死磕MySQL系列 四》

五、如何选择普通索引和唯一索引《死磕MySQL系列 五》

如果你对索引的知识点还不太清楚,可以直接通过传送门查看咔咔总结的索引知识点。

揭开MySQL索引神秘面纱

索引是为加速查询速度,创建的索引也符合所有规则,但MySQL就是不使用理想的索引,导致查询速度变慢并产生大量慢查询记录。

今天就从这个问题来聊聊MySQL选择索引时都做一些什么事情。

一、如何选择索引

影响优化器的几大因素

一条查询SQL执行需要经过连接器、分析器、优化器、执行器,而选择索引的重任就交给了优化器。

优化器在多个索引中选择目的是为了找出执行代价最低的方案。

影响优化器选择无非就这几个因素,扫描行数、是否使用了临时表、是否使用文件排序。

临时表、文件排序这个两个点会在后期文章给大家慢慢引出,今天只聊扫描行数。

扫描行数越少则访问磁盘数据的次数就越少,消耗的CPU资源越少。

那么这个扫描行数是从哪里取的呢?

扫描行数从何而来?

创建索引一直提倡大家给区分度高的列建立索引,在一个索引上不同值的个数称之为基数(cardinality)。

使用show index from table_name可以查看每个索引的基数是多少。

索引基数

索引基数

索引基数怎么计算

MySQL使用采样统计的方法,会选出N个数据页,每个数据页大小16kb,接着统计选出来的数据页上的不同值就会得到一个平均值,用平均值在乘以索引的页面数得到的结果就是这个索引的基数。

表数据是持续增加或删减的,统计的这个数据也不是时时变化的,当变更的数据超过1/M时会自动触发重新计算。

这个M是根据参数innodb_stats_persistent的值选则的,设置为on值为10,设置为off值为16。

索引基数通过这种方式计算不是精准的但也差不了多少

为什么优化器选择了扫描行数多的索引?

第一种情况

表增删十分频繁,导致扫描行数不准确

第二种情况

假设你主键索引扫描行数是10W行,而普通索引需要扫描5W行,这种情况就会遇到优化器选择了扫描行数多的。

在索引那一期文章中知道主键索引是不需要回表的,找到值直接就返回对应的数据了。

而普通索引是需要先拿到主键值,再根据主键值获取对应的数据,这个过程优化器选择索引时需要计算的一个成本。

如何解决这种情况

扫描行数不准确时可以执行analyze table table_name命令,重新统计索引信息,达到预期优化器选择的索引。

二、索引选择异常如何处理

方案一

在MySQL中提供了force index来强制优化器使用这个索引。

使用方法:select * from table_name force index (idx_a) where a = 100;

但别误解force index的使用方法,之前在代码中看到这样一个案例,给查询列使用了函数操作导致使用不上索引,然后这哥们就直接使用force index,肯定不行的哈!

当优化器没有正确选择索引时是可以使用这种方案来解决。

缺点

使用force index的缺点相信大家也知道就是太死板,一旦索引名字改动就会失效。

方案二

删掉误选的索引,简单粗暴,很多索引建立其实也是给优化器的一个误导,直接删掉即可。

方案三

修改SQL语句,主动引导MySQL使用期望的索引,一般情况这种做法使用的很少除非你对系统十分熟悉,否则尽量少操作。

三、总结

优化器选择索引首先会根据扫描行数再由执行成本决定。

当索引统计信息不准确时,使用analyze table 解决。

优化器选择了错误的索引,只用force index来快速矫正,再通过优化SQL语句来引导优化器选择正确的索引,最暴力的手法是直接删除误选的索引。

“

坚持学习、坚持写作、坚持分享是咔咔从业以来所秉持的信念。愿文章在偌大的互联网上能给你带来一点帮助,我是咔咔,下期见。

”

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

jenkins(一)安装

发表于 2021-11-05

「这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战」。

Jenkins 是一个独立的开源自动化服务器,可用于自动化与构建、测试、交付或部署软件相关的各种任务。

Jenkins 可以通过本机系统包、Docker 安装,甚至可以由安装了 Java 运行时环境 (JRE) 的任何机器独立运行。

一、安装jdk

查看jdk版本

1
perl复制代码yum search java|grep jdk

安装openjdk1.8

1
复制代码yum install java-1.8.0-openjdk

查看是否安装成功:

1
2
3
4
java复制代码[root@localhost lib]# java -version
openjdk version "1.8.0_292"
OpenJDK Runtime Environment (build 1.8.0_292-b10)
OpenJDK 64-Bit Server VM (build 25.292-b10, mixed mode)

配置环境变量:

1
bash复制代码vi /etc/profile

增加以下内容

1
2
3
4
5
bash复制代码export JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.292.b10-1.el7_9.x86_64

export CLASSPATH=.:$JAVA_HOME/jre/lib/rt.jar:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar

export PATH=$PATH:$JAVA_HOME/bin

二 、安装git

安装:

1
复制代码yum install -y git

查看是否安装成功:

1
2
csharp复制代码[root@localhost lib]# git version
git version 1.8.3.1

三、安装maven

安装:

1
复制代码yum -y install maven

查看maven版本:

1
2
3
4
5
6
7
yaml复制代码[root@localhost lib]# mvn -version
Apache Maven 3.0.5 (Red Hat 3.0.5-17)
Maven home: /usr/share/maven
Java version: 1.8.0_292, vendor: Red Hat, Inc.
Java home: /usr/lib/jvm/java-1.8.0-openjdk-1.8.0.292.b10-1.el7_9.x86_64/jre
Default locale: zh_CN, platform encoding: UTF-8
OS name: "linux", version: "3.10.0-1062.el7.x86_64", arch: "amd64", family: "unix"

四、安装jenkins

4.1 yum安装

1
2
3
4
5
6
arduino复制代码sudo wget -O /etc/yum.repos.d/jenkins.repo \
https://pkg.jenkins.io/redhat-stable/jenkins.repo
sudo rpm --import https://pkg.jenkins.io/redhat-stable/jenkins.io.key
sudo yum upgrade
sudo yum install jenkins
sudo systemctl daemon-reload

4.2 war包

下载路径:www.jenkins.io/download/

image.png

上传war到服务器,执行:

1
javascript复制代码nohup java -jar jenkins.war >/dev/null &

首次会创建admin账号,密码在:

1
bash复制代码/root/.jenkins/secrets/initialAdminPassword

通过cat查看得到密码:

1
2
csharp复制代码[root@localhost jenkins]# cat  /root/.jenkins/secrets/initialAdminPassword
fca057398c8f4b618794f0c2a77dbf91

五、访问

默认端口是8080,访问http://ip:8080,无法访问请查看端口是否开放,输入查询到的密码:

image.png

选择初始化插件,安装推荐的:

image.png

过程中可能会有部分插件安装失败,直接继续就好,后面需要的可以手动安装。

接下来创建用户,可以使用admin账号:

image.png

直接保存完成:

image.png

六、插件安装

在使用之前我们需要安装一些会用到的插件:

image.png

image.png

image.png

需要安装的插件:
Maven Integration
用来创建项目初始化为maven项目

SSH
用来SSH远程登录

Publish Over SSH
用来远程SSH登录并发送文件

Git Parameter
用来在构建中,通过参数方式获取git分支

七、全局配置

image.png

7.1 configure System

7.1.1 SSH

配置远程服务SSH:

image.png

需要填写ip,端口,和Credentials(凭证),目前证书是没有的,到图“系统配置”中的manage Credentials中去添加,如下入所示:

image.png

image.png

在下图输入账号、密码、描述即可:

image.png

保存后,即可在配置SSH处选到此凭证:

image.png

7.1.2 Publish over SSH

如下图所示,点击新增,多个服务器可配置多个

image.png

分别输入下面四个配置,最后一个配置Remote Directory表示后续文件上传时的根目录

image.png

点击高级(advance),勾选use password,输入服务器密码

image.png

点击 Test Configration,返回success则表示连接成功。

7.2 Global Tool Configuration

7.2.1 JDK

点击新增jdk

image.png

取消勾选,输入JAVA_HOME

image.png

image.png

7.2.2 Maven

我们都知道使用maven需要配置maven的settings,jenkins可以通过直接选择本地文件的方式,可以将文件放在jenkins所在的服务器,如下图所示:

image.png

也可以使用插件的方式,在jenkins上面管理settings:
安装插件Config File Provider Plugin

安装完成后,有如下:

image.png

新建一个新配置:

image.png

填写settings内容:

image.png

此时可以进行如下配置:

image.png

maven的MAVEN_HOME配置,类似于JDK时候配置,日下所示:

image.png


兄弟们,看到这了,点个赞吧!!

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

2021Java开发工程师必备知识,Java后端学习主流知识

发表于 2021-11-05

「这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战」

初 前言

大家好,菜菜希望这个系列的文章能够帮助各位大佬和菜菜自己,文章内容包含Java基础+操作系统+计算机网络+数据结构+算法+数据库+热门框架技术+微服务分布式架构+服务器中间件+前沿技术等。内容涵盖较多,涉及知识面比较广。当然也可以点击目录直达想看的内容哈,初衷是希望日积月累,量变引发质变,培养好我们自己!您觉得有用的话三连支持一下,菜菜感激不尽!!!
在这里插入图片描述

一、Java基础

什么是JDK?

JDK 是 Java Development ToolKit 的简称,也就是 Java 开发工具包。JDK 是整个 Java 的核心,包括 Java 运行环境(Java Runtime Envirnment,简称 JRE),Java 工具(比如 javac、java、javap 等等),以及 Java 基础类库(比如 rt.jar)。

平时安装的JDK会有以下几部分(了解)

  1. bin:包含了最主要的是编译器(javac.exe)
  2. include:Java 和 JVM 交互用的头文件
  3. lib:类库
  4. jre:Java 运行环境

JDK的三种类型

  1. J2SE:Standard Edition,标准版,是我们通常用的一个版本,从 JDK 5.0 开始,改名为 Java SE。
  2. J2EE:Enterprise Edition,企业版,从 JDK 5.0 开始,改名为 Java EE。
  3. J2ME:Micro Edition,主要应用于移动设备、嵌入式设备,从 JDK 5.0 开始,改名为 Java ME

Java的三种技术架构

  1. JAVAEE:Java Platform Enterprise Edition,开发企业环境下的应用程序,主要针对web程序开发;
  2. JAVASE:Java Platform Standard Edition,完成桌面应用程序的开发,是其它两者的基础;
  3. JAVAME:Java Platform Micro Edition,开发电子消费产品和嵌入式设备,如手机中的程序;

什么是JRE?

Java Runtime Environment:是Sun的产品,java程序的运行环境,java运行的所需的类库+JVM(java虚拟机)。 是面向Java程序的使用者,而不是开发者。

如果安装了JDK,会发同你的电脑有两套JRE,一套位于 \jre 另外一套位于 C:\Program Files\Java\jre1.5.0_15 目录下,后面这套比前面那套少了Server端的Java虚拟机,不过直接将前面那套的Server端Java虚拟机复制过来就行了。而且在安装JDK可以选择是否安装这个位于 C:\Program Files\Java 目录下的JRE。如果你只安装JRE,而不是JDK,那么只会在 C:\Program Files\Java 目录下安装唯一的一套JRE。

Java 基本数据类型

变量就是申请内存来存储值。也就是说,当创建变量的时候,需要在内存中申请空间。
内存管理系统根据变量的类型为变量分配存储空间,分配的空间只能用来储存该类型数据。
八种基本类型(四个整数型+两个浮点型+字符类型+布尔型)

下表列出了 Java 各个类型的默认值

数据类型 字节 (1字节=8位) 默认值
byte 8位 0
short 16 位 0
int 32位 0
long 64 位 0L
float 32位 0.0f
double 64 位 0.0d
char 16 位 Unicode 字符 ‘u0000’
boolean 一位 false

Java 引用数据类型

引用类型包括三种:

  1. 类 Class
  2. 接口 Interface
  3. 数组 Array

引用类型一般是通过new关键字来创建,比如Integer num = new Integer(3);它存放在内存的堆中,可以在运行时动态的分配内存大小,生存期也不必事先告诉编译器,当引用类型变量不被使用时,Java内部的垃圾回收器GC会自动回收走。引用变量中存放的不是变量的内容,而是存放变量内容的地址。
在参数传递时,基本类型都是传值,也就是传递的都是原变量的值得拷贝,改变这个值不会改变原变量,而引用类型传递的是地址,也就是参数与原变量指向的是同一个地址,所以如果改变参数的值,原变量的值也会改变。这点要注意。

在java中,8种基本类型在java中都有对应的封装类型,也就是引用类型:

  1. 整数类型 Byte、Short、Integer、Long
  2. 浮点数类型 Float、Double
  3. 字符型 Character
  4. 布尔类型 Boolean

在这里插入图片描述

二、操作系统

操作系统的四个特性

  1. 并发:同一段时间内多个程序执行(注意区别并行和并发,前者是同一时刻的多个事件,后者是同一时间段内的多个事件)
  2. 共享:系统中的资源可以被内存中多个并发执行的进线程共同使用
  3. 虚拟:通过时分复用(如分时系统)以及空分复用(如虚拟内存)技术实现把一个物理实体虚拟为多个
  4. 异步:系统中的进程是以走走停停的方式执行的,且以一种不可预知的速度推进

死锁定义

在两个或多个并发进程中,如果每个进程持有某种资源而又都等待别的进程释放它或它们现在保持着的资源,在未改变这种状态之前都不能向前推进,称这一组进程产生了死锁。通俗地讲,就是两个或多个进程被无限期地阻塞、相互等待的一种状态。

死锁产生条件(4个)

  1. 互斥条件:一个资源一次只能被一个进程使用
  2. 请求保持条件:一个进程因请求资源而阻塞时,对已经获得资源保持不放
  3. 不可抢占条件: 进程已获得的资源在未使用完之前不能强行剥夺
  4. 循环等待条件;若干进程之间形成一种头尾相接的循环等待资源的关系

死锁处理

  1. 预防死锁:破坏产生死锁的4个必要条件中的一个或者多个;实现起来比较简单,但是如果限制过于严格会降低系统资源利用率以及吞吐量
  2. 避免死锁:在资源的动态分配中,防止系统进入不安全状态(可能产生死锁的状态)-如银行家算法
  3. 检测死锁:允许系统运行过程中产生死锁,在死锁发生之后,采用一定的算法进行检测,并确定与死锁相关的资源和进程,采取相关方法清除检测到的死锁。实现难度大
  4. 解除死锁:与死锁检测配合,将系统从死锁中解脱出来(撤销进程或者剥夺资源)。对检测到的和死锁相关的进程以及资源,通过撤销或者挂起的方式,释放一些资源并将其分配给处于阻塞状态的进程,使其转变为就绪态。实现难度大

什么是银行家算法?

银行家算法(Banker’s Algorithm)是一个避免死锁(Deadlock)的著名算法,是由艾兹格·迪杰斯特拉在1965年为T.H.E系统设计的一种避免死锁产生的算法。它以银行借贷系统的分配策略为基础,判断并保证系统的安全运行。

银行家算法的实现思想:

  • 允许进程动态地申请资源,系统在每次实施资源分配之前,先计算资源分配的安全性,若此次资源分配安全(即资源分配后,系统能按某种顺序来为每个进程分配其所需的资源,直至最大需求,使每个进程都可以顺利地完成),便将资源分配给进程,否则不分配资源,让进程等待。

操作系统分类

批处理操作系统、分时操作系统(Unix)、实时操作系统、网络操作系统、分布式操作系统、微机操作系统(Linux、Windows、IOS等)、嵌入式操作系统。

在这里插入图片描述

三、计算机网络

网络层次划分
为了使不同计算机厂家生产的计算机能够相互通信,以便在更大的范围内建立计算机网络,国际标准化组织(ISO)在1978年提出了”开放系统互联参考模型”,即著名的OSI/RM模型(Open System Interconnection/Reference Model)。它将计算机网络体系结构的通信协议划分为七层,自下而上依次为:

  • 物理层(Physics Layer)、数据链路层(Data Link Layer)、网络层(Network
    Layer)、传输层(Transport Layer)、会话层(Session Layer)、表示层(Presentation
    Layer)、应用层(Application Layer)。

其中第四层完成数据传送服务,上面三层面向用户。除了标准的OSI七层模型以外,常见的网络层次划分还有TCP/IP四层协议以及TCP/IP五层协议

TCP/IP协议

TCP/IP协议是Internet最基本的协议、Internet国际互联网络的基础,由网络层的IP协议和传输层的TCP协议组成。通俗而言:TCP负责发现传输的问题,一有问题就发出信号,要求重新传输,直到所有数据安全正确地传输到目的地。而IP是给因特网的每一台联网设备规定一个地址。
在这里插入图片描述

应用层:

  • 向用户提供一组常用的应用程序,比如电子邮件、文件传输访问、远程登录等。远程登录TELNET使用TELNET协议提供在网络其它主机上注册的接口。TELNET会话提供了基于字符的虚拟终端。文件传输访问FTP使用FTP协议来提供网络内机器间的文件拷贝功能。

传输层:

  • 提供应用程序间的通信。其功能包括:一、格式化信息流;二、提供可靠传输。为实现后者,传输层协议规定接收端必须发回确认,并且假如分组丢失,必须重新发送。

网络层 :

  • 负责相邻计算机之间的通信。

网络接口层:

  • 这是TCP/IP软件的最低层,负责接收IP数据报并通过网络发送之,或者从网络上接收物理帧,抽出IP数据报,交给IP层。

IP地址

IP地址是IP协议提供的一种统一的地址格式,它为互联网上的每一个网络和每一台主机分配一个逻辑地址,以此来屏蔽物理地址的差异。

首先出现的IP地址是IPV4,它只有4段数字,每一段最大不超过255。由于互联网的蓬勃发展,IP位址的需求量愈来愈大,使得IP位址的发放愈趋严格,各项资料显示全球IPv4位址可能在2005至2010年间全部发完(实际情况是在2019年11月25日IPv4位地址分配完毕)。地址空间的不足必将妨碍互联网的进一步发展。为了扩大地址空间,拟通过IPv6重新定义地址空间。IPv6采用128位地址长度。在IPv6的设计过程中除了一劳永逸地解决了地址短缺问题以外,还考虑了在IPv4中解决不好的其它问题。

DNS协议是什么?

DNS是域名系统(DomainNameSystem)的缩写,该系统用于命名组织到域层次结构中的计算机和网络服务,可以简单地理解为将URL转换为IP地址。域名是由圆点分开一串单词或缩写组成的,每一个域名都对应一个惟一的IP地址,在Internet上域名与IP地址之间是一一对应的,DNS就是进行域名解析的服务器。

DNS命名用于Internet等TCP/IP网络中,通过用户友好的名称查找计算机和服务。

NAT协议是什么?

NAT网络地址转换(Network Address Translation)属接入广域网(WAN)技术,是一种将私有(保留)地址转化为合法IP地址的转换技术,它被广泛应用于各种类型Internet接入方式和各种类型的网络中。

原因很简单,NAT不仅完美地解决了lP地址不足的问题,而且还能够有效地避免来自网络外部的攻击,隐藏并保护网络内部的计算机。

DHCP协议是什么?

DHCP动态主机设置协议(Dynamic Host Configuration Protocol)是一个局域网的网络协议。

使用UDP协议工作,主要有两个用途:

  1. 给内部网络或网络服务供应商自动分配IP地址
  2. 给用户或者内部网络管理员作为对所有计算机作中央管理的手段

在这里插入图片描述

四、数据结构

一些概念

数据

  • 所有能被输入到计算机中,且能被计算机处理的符号的集合。是计算机操作的对象的总称。

数据元素

  • 数据(集合)中的一个“个体”,数据及结构中讨论的基本单位

数据项

  • 数据的不可分割的最小单位。一个数据元素可由若干个数据项组成。

数据类型

  • 在一种程序设计语言中,变量所具有的数据种类。整型、浮点型、字符型等等

逻辑结构

  • 数据之间的相互关系

算法五个特性
有穷性、确定性、可行性、输入、输出

算法设计要求
正确性、可读性、健壮性、高效率与低存储量需求。(好的算法)

时间复杂度
算法的执行时间与原操作执行次数之和成正比。时间复杂度有小到大:O(1)、O(logn)、O(n)、O(nlogn)、O(n2)、O(n3)。幂次时间复杂度有小到大O(2n)、O(n!)、O(nn)

空间复杂度
若输入数据所占空间只取决于问题本身,和算法无关,则只需要分析除输入和程序之外的辅助变量所占额外空间。

物理结构/存储结构
数据在计算机中的表示。物理结构是描述数据具体在内存中的存储(如:顺序结构、链式结构、索引结构、哈希结构)等
在这里插入图片描述

五、算法

贪心算法

在对问题求解时,总是做出在当前看来是最好的选择。也就是说,不从整体最优上加以考虑,他所做出的是在某种意义上的局部最优解。
从问题的某一个初始解出发一步一步地进行,根据某个优化测度,每一步都要确保能获得局部最优解。每一步只考虑一个数据,他的选取应该满足局部优化的条件。若下一个数据和部分最优解连在一起不再是可行解时,就不把该数据添加到部分解中,直到把所有数据枚举完,或者不能再添加算法停止。

基本思路

  • 建立数学模型来描述问题
  • 把求解的问题分成若干个子问题
  • 对每个子问题求解,得到子问题的局部最优解
  • 把子问题的解局部最优解合成原来问题的一个解

存在的问题

  1. 不能保证求得的最后解是最佳的
  2. 不能用来求最大值或最小值的问题
  3. 只能求满足某些约束条件的可行解的范围

贪心策略适用的前提是:局部最优策略能导致产生全局最优解。
实际上,贪心算法适用的情况很少。一般对一个问题分析是否适用于贪心算法,可以先选择该问题下的几个实际数据进行分析,就可以做出判断。

贪心算法的实现框架

从问题的某一初始解出发;
while (能朝给定总目标前进一步)
{
利用可行的决策,求出可行解的一个解元素;
}
由所有解元素组合成问题的一个可行解;

例题:
[背包问题]

有一个背包,背包容量是M=150。有7个物品,物品可以分割成任意大小。 要求尽可能让装入背包中的物品总价值最大,但不能超过总容量。 物品
A B C D E F G 重量 35 30 60 50 40 10 25 价值 10 40 30 50 35 40 30

这个例子,可以说很经典。

分析:
目标函数: ∑pi最大
约束条件是装入的物品总重量不超过背包容量,即∑wi<=M( M=150)
(1)根据贪心的策略,每次挑选价值最大的物品装入背包,得到的结果是否最优?
(2)每次挑选所占重量最小的物品装入是否能得到最优解?
(3)每次选取单位重量价值最大的物品,成为解本题的策略?
贪心算法是很常见的算法之一,这是由于它简单易行,构造贪心策略简单。但是,它需要证明后才能真正运用到题目的算法中。一般来说,贪心算法的证明围绕着整个问题的最优解一定由在贪心策略中存在的子问题的最优解得来的。
对于本例题中的3种贪心策略,都无法成立,即无法被证明,解释如下:
(1)贪心策略:选取价值最大者。反例:
W=30
物品:A B C
重量:28 12 12
价值:30 20 20
根据策略,首先选取物品A,接下来就无法再选取了,可是,选取B、C则更好。
(2)贪心策略:选取重量最小。它的反例与第一种策略的反例差不多。
(3)贪心策略:选取单位重量价值最大的物品。反例:
W=30
物品:A B C
重量:28 20 10
价值:28 20 10
根据策略,三种物品单位重量价值一样,程序无法依据现有策略作出判断,如果选择A,则答案错误。
值得注意的是,贪心算法并不是完全不可以使用,贪心策略一旦经过证明成立后,它就是一种高效的算法。比如,求最小生成树的Prim算法和Kruskal算法都是漂亮的贪心算法。

[最大整数]

设有n个正整数,将它们连接成一排,组成一个最大的多位整数。
例如:n=3时,3个整数13,312,343,连成的最大整数为34331213。
又如:n=4时,4个整数7,13,4,246,连成的最大整数为7424613。 输入:n N个数 输出:连成的多位数

算法分析:
此题很容易想到使用贪心法,在考试时有很多同学把整数按从大到小的顺序连接起来,测试题目的例子也都符合,但最后测试的结果却不全对。按这种标准,我们很容易找到反例:12,121应该组成12121而非12112,那么是不是相互包含的时候就从小到大呢?也不一定,如12,123就是12312而非12123,这种情况就有很多种了。是不是此题不能用贪心法呢?
其实此题可以用贪心法来求解,只是刚才的标准不对,正确的标准是:先把整数转换成字符串,然后在比较a+b和b+a,如果a+b>=b+a,就把a排在b的前面,反之则把a排在b的后面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
bash复制代码@Test
public void testMaxNum() {
//有n个正整数,将它们连接成一排,组成一个最大的多位整数
//12112错误
//12121正解
// int[] nums = {12, 121};
int[] nums = {12, 123};
String result = maxNum(nums);
System.out.println("组成最大整数:" + result);
}

/**
* 根据给定的整数组成最大的多位数
* @param nums
*/
public String maxNum(int[] nums) {
String result = "";
for (int i = 0; i < nums.length; i++) {
String num1 = nums[i] + "";
for (int j = 1; j < nums.length; j++) {
String num2 = nums[j] + "";
if ((num1 + num2).compareTo(num2 + num1) < 0) {
int temp = nums[j];
nums[j] = nums[i];
nums[i] = temp;
}
}
}
for (int i = 0; i < nums.length; i++) {
result += nums[i];
}
return result;
}

【纸币找零问题】

假设1元、2元、5元、10元、20元、50元、100元的纸币,张数不限制,现在要用来支付K元,至少要多少张纸币?

代码如下

1
2
3
4
5
6
7
8
9
10
11
12
13
bash复制代码
public static void greedyGiveMoney(int money) {
System.out.println("需要找零: " + money);
int[] moneyLevel = {1, 5, 10, 20, 50, 100};
for (int i = moneyLevel.length - 1; i >= 0; i--) {
int num = money/ moneyLevel[i];
int mod = money % moneyLevel[i];
money = mod;
if (num > 0) {
System.out.println("需要" + num + "张" + moneyLevel[i] + "块的");
}
}
}

(1)如果不限制纸币的金额,那这种情况还适合用贪心算法么。比如1元,2元,3元,4元,8元,15元的纸币,用来支付K元,至少多少张纸币?

经我们分析,这种情况是不适合用贪心算法的,因为我们上面提供的贪心策略不是最优解。比如,纸币1元,5元,6元,要支付10元的话,按照上面的算法,至少需要1张6元的,4张1元的,而实际上最优的应该是2张5元的。

(2)如果限制纸币的张数,那这种情况还适合用贪心算法么。比如1元10张,2元20张,5元1张,用来支付K元,至少多少张纸币?

同样,仔细想一下,就知道这种情况也是不适合用贪心算法的。比如1元10张,20元5张,50元1张,那用来支付60元,按照上面的算法,至少需要1张50元,10张1元,而实际上使用3张20元的即可;

(3)所以贪心算法是一种在某种范围内,局部最优的算法。

六、数据库

什么是事务?

事务是应用程序中一系列严密的操作,所有操作必须成功完成,否则在每个操作中所作的所有更改都会被撤消。也就是事务具有原子性,一个事务中的一系列的操作要么全部成功,要么一个都不做。

事务的结束有两种,当事务中的所以步骤全部成功执行时,事务提交。如果其中一个步骤失败,将发生回滚操作,撤消撤消之前到事务开始时的所以操作。

事务四大特性

原子性( Atomicity )、一致性( Consistency )、隔离性( Isolation )和持续性( Durability)

原子性,要么执行,要么不执行
隔离性,所有操作全部执行完以前其它会话不能看到过程
一致性,事务前后,数据总额一致
持久性,一旦事务提交,对数据的改变就是永久的

MySQL的四种隔离级别来源

读未提交
就是一个事务可以读取另一个未提交事务的数据。

事例:老板要给程序员发工资,程序员的工资是3.6万/月。但是发工资时老板不小心按错了数字,按成3.9万/月,该钱已经打到程序员的户口,但是事务还没有提交,就在这时,程序员去查看自己这个月的工资,发现比往常多了3千元,以为涨工资了非常高兴。但是老板及时发现了不对,马上回滚差点就提交了的事务,将数字改成3.6万再提交。

分析:实际程序员这个月的工资还是3.6万,但是程序员看到的是3.9万。他看到的是老板还没提交事务时的数据。这就是脏读。

读提交
就是一个事务要等另一个事务提交后才能读取数据。

事例:程序员拿着信用卡去享受生活(卡里当然是只有3.6万),当他埋单时(程序员事务开启),收费系统事先检测到他的卡里有3.6万,就在这个时候!!程序员的妻子要把钱全部转出充当家用,并提交。当收费系统准备扣款时,再检测卡里的金额,发现已经没钱了(第二次检测金额当然要等待妻子转出金额事务提交完)。程序员就会很郁闷,明明卡里是有钱的…

分析:这就是读提交,若有事务对数据进行更新(UPDATE)操作时,读操作事务要等待这个更新操作事务提交后才能读取数据,可以解决脏读问题。但在这个事例中,出现了一个事务范围内两个相同的查询却返回了不同数据,这就是不可重复读。

重复读
就是在开始读取数据(事务开启)时,不再允许修改操作。

事例:程序员拿着信用卡去享受生活(卡里当然是只有3.6万),当他买单时(事务开启,不允许其他事务的UPDATE修改操作),收费系统事先检测到他的卡里有3.6万。这个时候他的妻子不能转出金额了。接下来收费系统就可以扣款了。

分析:重复读可以解决不可重复读问题。写到这里,应该明白的一点就是,不可重复读对应的是修改,即UPDATE操作。但是可能还会有幻读问题。因为幻读问题对应的是插入INSERT操作,而不是UPDATE操作。

序列化

Serializable 是最高的事务隔离级别,在该级别下,事务串行化顺序执行,可以避免脏读、不可重复读与幻读。但是这种事务隔离级别效率低下,比较耗数据库性能,一般不使用。

MySQL的索引

索引 区别
Hash hash索引,等值查询效率高,不能排序,不能进行范围查询
B+ 数据有序,范围查询

索引的优缺点

  1. 索引最大的好处是提高查询速度,
  2. 缺点是更新数据时效率低,因为要同时更新索引
  3. 对数据进行频繁查询进建立索引,如果要频繁更改数据不建议使用索引。

InnoDB索引和MyISAM索引的区别

  1. 一是主索引的区别,InnoDB的数据文件本身就是索引文件。而MyISAM的索引和数据是分开的。
  2. 二是辅助索引的区别:InnoDB的辅助索引data域存储相应记录主

在这里插入图片描述

七、热门框架技术

Spring

到目前为止,Spring 仍然是最流行的 Java 开发框架,并且几乎应用在了所有地方 —— 从流媒体平台到在线购物。 它的设计目的是为 基于 Java EE 平台的 Java 应用程序创建后端。Spring 框架基于依赖注入的功能(控件反转 IOC 的一部分),它是在 Java 中构建业务应用程序的理想解决方案:微服务、复杂的数据处理系统、云应用程序或快速、安全且响应迅速的 Web 应用程序。 Spring 的特点是轻量级且易于实现和使用,生态非常活跃,因此完全可以预计 2021 年 Spring 将会更加普及,也会有更多强大的功能。对于 Java 开发者而言,Spring 仍然是不得不学的优秀框架。
Spring的初衷:

  • 1、JAVA EE开发应该更加简单。
  • 2、使用接口而不是使用类,是更好的编程习惯。Spring将使用接口的复杂度几乎降低到了零。
  • 3、为JavaBean提供了一个更好的应用配置框架。
  • 4、更多地强调面向对象的设计,而不是现行的技术如JAVA EE。
  • 5、尽量减少不必要的异常捕捉。
  • 6、使应用程序更加容易测试。

Spring的目标:

  • 1、可以令人方便愉快的使用Spring。
  • 2、应用程序代码并不依赖于Spring APIs。
  • 3、Spring不和现有的解决方案竞争,而是致力于将它们融合在一起。

Spring的基本组成:

  • 1、最完善的轻量级核心框架。
  • 2、通用的事务管理抽象层。
  • 3、JDBC抽象层。
  • 4、集成了Toplink, Hibernate, JDO, and iBATIS SQL Maps。
  • 5、AOP功能。
  • 6、灵活的MVC Web应用框架。

八、微服务分布式架构

微服务的诞生
微服务是基于分而治之的思想演化出来的。过去传统的一个大型而又全面的系统,随着互联网的发展已经很难满足市场对技术的需求,于是我们从单独架构发展到分布式架构,又从分布式架构发展到 SOA 架构,服务不断的被拆分和分解,粒度也越来越小,直到微服务架构的诞生。

分布式事务

分布式事务顾名思义就是要在分布式系统中实现事务,它其实是由多个本地事务组合而成。

分布式事务场景如何设计系统架构及解决数据一致性问题,个人理解最终方案把握以下原则就可以了,那就是:大事务=小事务(原子事务)+异步(消息通知),解决分布式事务的最好办法其实就是不考虑分布式事务,将一个大的业务进行拆分,整个大的业务流程,转化成若干个小的业务流程,然后通过设计补偿流程从而考虑最终一致性。

九、服务器中间件

RocketMQ:

为什么使用mq?具体的使用场景是什么?

mq的作用很简单,削峰填谷。以电商交易下单的场景来说,正向交易的过程可能涉及到创建订单、扣减库存、扣减活动预算、扣减积分等等。每个接口的耗时如果是100ms,那么理论上整个下单的链路就需要耗费400ms,这个时间显然是太长了。
如果这些操作全部同步处理的话,首先调用链路太长影响接口性能,其次分布式事务的问题很难处理,这时候像扣减预算和积分这种对实时一致性要求没有那么高的请求,完全就可以通过mq异步的方式去处理了。同时,考虑到异步带来的不一致的问题,我们可以通过job去重试保证接口调用成功,而且一般公司都会有核对的平台,比如下单成功但是未扣减积分的这种问题可以通过核对作为兜底的处理方案。
使用mq之后我们的链路变简单了,同时异步发送消息我们的整个系统的抗压能力也上升了。

异步,解耦,消峰,MQ的三大主要应用场景。
异步处理
用户注册后,需要发送注册邮件和注册短信。传统的做法:

将注册信息写入数据库成功后,发送注册邮件,再发送注册短信。以上三个任务全部完成后,返回给客户端

引入消息队列(mq),异步处理。
在这里插入图片描述
在这里插入图片描述
应用解耦

交易系统作为淘宝/天猫主站最核心的系统,每笔交易订单数据的产生会引起几百个下游业务系统的关注,包括物流、购物车、积分、流计算分析等等,整体业务系统庞大而且复杂,消息队列
MQ 可实现异步通信和应用解耦,确保主站业务的连续性。

削峰填谷

诸如秒杀、抢红包、企业开门红等大型活动时皆会带来较高的流量脉冲,或因没做相应的保护而导致系统超负荷甚至崩溃,或因限制太过导致请求大量失败而影响用户体验,消息队列 MQ 可提供削峰填谷的服务来解决该问题。

十、前沿技术

架构&云计算

2020 年,微服务领域出现了一个新词汇:“宏服务”(Macro Services)由Uber团队提出。宏服务其实并不是一个全新的架构,而是一种在单体和微服务间取得平衡的理念。
目前,微服务的发展增加了系统的复杂性,微服务日趋细化、复用率达到顶峰,服务之间的关系变得愈加复杂,维护成本增加。在这种情况下,技术人员提出了“宏服务”,它只是个整体式程序,其中所有业务服务都作为单个程序包部署在应用程序服务器中,并共享同一个数据库(物理上和逻辑上)。它不太复杂,服务之间奉行紧密耦合。
2021 年,化繁为简仍然会是微服务的重点课题。

脑机接口帮助人类超越生物学极限

链接
在这里插入图片描述

大数据&人工智能

随着 IT 基础设施加速往云上迁移,云原生正在成为新一代数据架构的主流标准。越来越多企业客户从 On-Premise 的数仓方案转向基于云(包含公有云和私有云)的解决方案,这种趋势在美国toB市场已经被广泛接受,在国内toB 市场也方兴未艾。新的一年大数据与云的融合还会继续加深,大数据领域将加速拥抱“融合”或“一体化”演进的新方向。

总结

俗话说是笨鸟先飞,我还得笨鸟多飞《活着》

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

全文检索服务器-Solr简介 1Solr是什么? 2So

发表于 2021-11-05

「这是我参与11月更文挑战的第5天,活动详情查看:2021最后一次更文挑战」。

1.Solr是什么?

Solr是一个独立的企业级搜索应用服务器,它对外提供类似于Web-service的API接口。用户可以通过http请求,向搜索引擎服务器提交一定格式的XML文件,生成索引;也可以通过Http Get操作提出查找请求,并得到XML格式的返回结果。

2.Solr怎么来的?

Solr是apache的顶级开源项目,它是使用java开发 ,基于lucene的全文检索服务器。

3.Solr比lucene多了什么?

  • lucene是什么?
    Lucene是一个全文检索引擎工具包,它只是一个jar包,不能独立运行,对外提供服务。
  • Solr优点
    Solr是一个全文检索服务器,它可以单独运行在servlet容器,也可以单独对外提供搜索和索引功能。Solr比lucene在开发全文检索功能时,更快捷、更方便。Solr比lucene提供了更多的查询语句,而且它可扩展、可配置,同时它对lucene的性能进行了优化。

4.Solr是如何实现全文检索的呢?

  • 索引流程
    solr客户端(浏览器、java程序)可以向solr服务端发送POST请求,请求内容是包含Field等信息的一个xml文档,通过该文档,solr实现对索引的维护(增删改)
  • 搜索流程
    solr客户端(浏览器、java程序)可以向solr服务端发送GET请求,solr服务器返回一个xml/json文档。

5.Solr如何下载和启动?

注意:Solr和lucene的版本是同步更新的,最新的版本是8.1.0

下载地址:mirrors.tuna.tsinghua.edu.cn/apache/luce…

下载:根据Solr的运行环境,Linux下需要下载solr-8.1.0.tgz,windows下需要下载solr-8.1.0.zip。

说明:

  1. src.tgz:带src表示是带源码文件的压缩包,无src是已经编译过的压缩包
  2. tgz:Linux相关操作系统使用的压缩包
  3. zip:Windows操作系统使用的压缩包

image.png

image.png

启动Solr:

solr的启动、停止、查看命令:

  1. 启动:bin\solr.cmd start
  2. 停止:bin\solr stop 或bin\solr stop -all
  3. 查看:bin\solr status

image.png

访问地址:http://localhost:8983/solr/#/

image.png

6.Solr性能优化

  • 将所有只用于搜索的,而不需要作为结果的field的stored设置为false
  • 将不需要被用于搜索的,而只是作为结果返回的field的indexed设置为false
  • 删除所有不必要的copyField声明
  • 为了索引字段的最小化和搜索的效率,将所有的 text fields的index都设置成field,然后使用copyField将他们都复制到一个总的 text field上,然后进行搜索。
  • 为了最大化搜索效率,使用java编写的客户端与solr交互
  • 在服务器端运行JVM,使用尽可能高的Log输出等级,减少日志量。

总结

经过对solr大致了解,我们知道了它支持更多格式的数据,比如JSON、XML、CSV;查询快,用于电商等查询多的应用;比较成熟,有一个更大,更成熟的用户、开发和贡献者社区。

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

1…416417418…956

开发者博客

9558 日志
1953 标签
RSS
© 2025 开发者博客
本站总访问量次
由 Hexo 强力驱动
|
主题 — NexT.Muse v5.1.4
0%