聊聊我与流式计算的故事

聊聊流式计算吧 , 那一段经历于我而言很精彩,很有趣,想把这段经历分享给大家。

1 背景介绍

2014年,我在艺龙旅行网促销团队负责红包系统。

彼时,促销大战如火如荼,优惠券计算服务也成为艺龙促销业务中最重要的服务之一。

而优惠券计算服务正是采用当时大名鼎鼎的流式计算框架 Storm

流式计算是利用分布式的思想和方法,对海量“流”式数据进行实时处理的系统,它源自对海量数据“时效”价值上的挖掘诉求。

优惠券计算服务的逻辑是:每个城市每个酒店的使用优惠券的规则并不相同,当运营人员修改规则之后,触发优惠券计算服务,计算完成之后,用户下单时在使用优惠券时会呈现最新的规则。

优惠券计算服务是我们团队的明星项目,很多研发的同学都对 Storm 特别感兴趣 , 因为 Storm 的核心开发语言是 clojure , 比较小众。

于是,在团队内部,发现一个很有趣的现象:很多同学的办公桌上放着《clojure in Action 》这本书

彼时,艺龙开始发力移动互联网,业务量的激增,优惠券计算服务开始遇到了瓶颈。

比如运营人员修改全量规则时,整个计算流程要耗时一上午,也就谈不上实时计算了。

CTO 几次找团队负责人,并严厉批责成他尽快优化。经过一个半月几次优化,系统的瓶颈依然明显,时不时运营同事会走到我们的工位附近,催促我们:“系统生效了么? ”

我并不负责计算服务,每当同事被质疑时,我都感到很疑惑:“优惠券计算服务真的那么复杂吗? ” , 同时也跃跃欲试:“ Storm 真有那么难搞吗?”

我心中暗暗下定了决心,一定要弄清楚优惠券计算服务的逻辑 。

2 国图学习

北京有很多景点都让我流连忘返,比如史铁生小说里的地坛,满山枫叶的香山,如诗如画的颐和园,美仑美奂的天坛 。

在我心里,有一处很神圣的地方,它是知识和希望的象征,那就是国家图书馆

中国国家图书馆位于北京市中关村南大街33号,与海淀区白石桥高粱河、紫竹院公园相邻。它是国家总书库,国家书目中心,国家古籍保护中心,同时也是世界最大、最先进的国家图书馆之一

每到周末,当我想安静下来,专注思考时,我就会背着笔记本电脑来到国家图书馆。

选择自己喜欢的书,然后将笔记本电脑打开,一边看书,一边在电脑上写点笔记。

偶尔抬起头,望着那些正在阅读的读者,心里面感觉很阳关,觉得生命充满了希望。

我并不负责流式计算服务,但想要揭开 Storm 神秘面纱的探索欲,同时探寻优惠券计算服务为什么会这么慢的渴望,让我好几天晚上没睡好。

于是周六上午9点半, 我来到国家图书馆 ,想让自己安静下来,思考如何解决这个问题。解决问题的快感,是我一直追求的。

当我把笔记本电脑放平在桌上,我很兴奋,同时灵台一片澄清:优惠券计算服务的核心是 Storm ,那么我需要先了解 Storm 的整体概念

打开官网,浏览官网的文档,第一次看到 Storm 的逻辑流程图时, 做为程序员,我第一次竟然感受到抽象之美:从源头流下来的水通过水龙头( Spout ),再经过层层转接头( Bolt )过滤,不就是我们想要的纯净水吗?

其实我们原来都是 CRUD boy ,机械的使用那些框架,只会做增删改查,并不会思考框架背后的设计思路。 但框架到底是什么?从来没有思考过。 我一直觉得我很笨拙,学什么都很慢,但那一刻我突然恍然大悟:框架本身是将解决问题的思路抽象化,从而便于研发人员使用,把复杂的问题抽象成有美感,是需要功底的。

了解完 Storm 整体概念 , 下一步也就是大家熟知的写 Hello World 阶段了 。

我参考教程写了一个简单的 Storm 应用(简称:拓扑),在部署后,程序正常跑了起来。

我脑海里一直有一个疑问:“是不是优惠券计算服务的 storm 集群的配置没有调优,才导致计算的性能太差 ? ” 所以我必须去理解 storm 的并发度是如何计算的

整个下午,我一直在查阅相关的资料,并结合下图思考:Nimbus, Supervisor ,Worker ,Task 这些名词到底是什么概念,以及他们之间是如何交互的。

进而思考:拓扑到底会启动几个进程,每个进程内部线程模型是怎样的,颇有些庖丁解牛的味道。

这个习惯一直保持到现在,当我看到一个系统,我会下意思的去思考:“这个系统的线程模型如何,每次操作有哪些线程参于,他们之间如何交互”。我知道有更厉害的大牛,运行一行代码就知道 CPU 会运行的哪些指令,我做不到,但我觉得那就更加深刻了。

不管怎样,这一天,我的思绪经过多次的变化,兴奋,犹疑,放弃,阳光,激动,畏难心理一直存在,很多次想放弃,但好奇心一直鼓励着我。

等天色已黑,我走出国图的大门,脑子里全部都是 Storm 进程,线程模型,内心里面,有了莫名的自信。感觉自己就像仙剑奇侠传里的酒剑仙,伴随着激昂的 BGM ,拔剑四顾,斩妖除魔。

御剑乘风来,除魔天地间,有酒乐逍遥,无酒我亦癫。

一饮尽江河,再饮吞日月,千杯醉不倒,唯我酒剑仙。

3 找到瓶颈

当我理解了 Storm 的整体概念,接下来我需要去找到优惠券计算服务的性能瓶颈。这个时候,梳理计算服务整体流程非常关键。

计算服务整体流程分为三个步骤 :

  1. 抽取数据:酒店信息拉取服务拉取酒店信息,并存储到水源头( Redis A/B 集群 ) ;
  2. 计算过程:Storm 拓扑从水源头获取酒店数据,通过运营配置的规则对数据进行清洗 ,将计算好的数据存储到水存放池 ( Redis C 集群) ;
  3. 入库阶段:入库服务水存放池获取数据,将计算结果存储到数据库 。

当我们把整个计算的过程拆分成 抽取-->计算 --> 存储 三个阶段的时候,计算服务的架构就变得异常清晰,那到底在哪个阶段最耗时 ,也成为我追查的目标。

优惠券计算服务当时没有详细的性能监控体系,所以我只能先从日志着手。 在运营同事触发全量计算后,分别观察三个阶段对应服务的日志:

  • 抽取数据:酒店信息拉取服务
  • 计算过程: Storm 拓扑
  • 入库阶段: 入库服务

令人惊讶的现象:一次全量计算需要耗时4个多小时,但抽取数据的任务竟然跑了2个多小时,和我预期完全不一样。

假如我把酒店信息拉取服务比作抽水泵,那么整个系统最大的问题竟然是抽水泵抽水马力不足

4 推进重构

为什么抽水泵抽水马力不足 ?

通过阅读源码,我发现因为线程模型不够好,应用在部署多个节点后,每个节点只能有两个线程执行拉取酒店信息。

怎么处理呢? 在原有代码上优化可行吗? 好像也不太容易,因为老代码最初是一个 C# 研发同事写的,他当时也不熟悉 JAVA ,从设计层面来讲,有很多冗余且不合理的代码,而且经过3年左右的维护,代码老化严重,于是我只能想到重构。

当我把想法和团队负责人沟通后,他有点半信半疑,他认为我的判断没有问题,但不确定我是否可以将系统重构好。 我那时候信心爆棚,主动请缨,打包票不会出问题的。可能是由于 CTO 逼的太紧了,他同意了。

在重构之间,梳理好系统的整体逻辑。

重构的重点原则有两条:

  1. 拉取服务可水平扩展,若性能不足时,增加服务节点即可提升性能;
  2. 配置文件可配置 worker 线程数量。

那思想层面,我已经做好准备了,那硬实力层面我有没有做好准备吗? 非常自信的讲,准备好了,因为我遇到了 RocketMQ

我在《我与消息队列的8年情缘》这篇文章写到:

2014年,我搜罗了很多的淘宝的消息队列的资料,我知道MetaQ的版本已经升级MetaQ 3.0,只是开源版本还没有放出来。

大约秋天的样子,我加入了RocketMQ技术群。誓嘉(RocketMQ创始人)在群里说:“最近要开源了,放出来后,大家赶紧fork呀”。他的这句话发在群里之后,群里都炸开了锅。我更是欢喜雀跃,期待着能早日见到阿里自己内部的消息中间件。

终于,RocketMQ终于开源了。我迫不及待想一窥他的风采。

因为我想学网络编程,而RocketMQ的通讯模块remoting底层也是Netty写的。所以,RocketMQ的通讯层是我学习切入的点。

我模仿RocketMQ的remoting写了一个玩具的rpc,这更大大提高我的自信心。正好,艺龙举办技术创新活动。我想想,要不尝试一下用Netty改写下Cobar的通讯模块。于是参考Cobar的源码花了两周写了个netty版的proxy,其实非常粗糙,很多功能不完善。后来,这次活动颁给我一个鼓励奖,现在想想都很好玩。

在重构酒店信息拉取服务时,我将 RocketMQ 如何创建线程的知识点正好也用了上去,并学习如何将模块拆分得更加合理。同时在重构过程中,不断 Review 新老代码的差别,确保核心逻辑正确。

非常幸运,大概一周时间,我就重构完了。

重构完成并不意味着结束,怎么验证呢 ? 我当时采取了两种方式:

  • 代码评审

我拉着优惠券计算服务的同事,一起 review 代码 。整个过程,大家也并没有提出异议,并对我创建线程的技巧感到很好奇。我心中窃喜:”那是学习 RocketMQ 的“。

  • 测试环境数据验证

我们将新旧两版服务同时触发,比对两个版本的数据的异同,将比对结果输出到日志文件,然后从中找到差异的地方,修复重构版的 BUG 。 然后在测试环境部署重构版,观察一段时间,确保无异常。

从编写第一行代码,三周时间,重构版终于上线了。 我将原来的老服务替换后,部署了3个节点, 每个节点8个 worker 并行拉取酒店信息 。

令人开心和激动的是,重构是非常成功的。 因为业务给我们的时间需求也是1个小时左右。一次全量计算从原来4个小时急速缩减到1小时15分钟,整个酒店拉取服务耗时40分钟左右。

我心里长舒一口气,内心吟诵李白的诗:"十步杀一人,千里不留行。事了拂衣去,深藏身与名。"

5 向前一步

前 Facebook COO 谢丽尔·桑德伯格 写了一本书《向前一步》,我特别喜欢这本书的书名 。

在优化优惠券计算服务的前期,团队经过一个多月的时间,也没有什么成效。 我自己也犹豫:”我能不能解决这个问题?“ ,但最终我还是向前一步,并帮助团队大大提升了服务的性能,负责人也有了信心,他也敢投入资源优化Storm 拓扑入库流程

在阅读优惠券计算服务的代码中,我发现两个问题:

  1. 流式计算逻辑中有大量网络 IO 请求,主要是查询特定的酒店数据,用于后续计算;
  2. 每次计算时需要查询基础配置数据,它们都是从数据库中获取。

对于Storm 拓扑优化,我提了两点建议:

  1. 流式计算拓扑和酒店拉取服务各司其职,将流式计算中的网络 IO 请求挪到酒店拉取服务,将数据前置准备好;
  2. 基础配置缓存化,引入读写锁(也是 RocketMQ 名字服务的技巧)。

对于入库流程,一位研发同学将原来的单条数据入库修改成批量入库。

经过大家一起努力 ,优惠券计算服务的整体性能大大提升了,全量计算耗时已经变成40分钟了,再也不会有运营同事在我们的工位附近吐槽系统慢了。

6 写到最后

2014年,我向前一步推动了公司流式计算服务的优化,并取得了一点点进步。

时光荏苒,我已中年,生命中遇到越来越多的挫折,有的时候也会让人低落,但每当想起这个故事,我会深深感动于当时的一往无前。

当再次面临选择时,我希望自己也能够向前一步,想着如何帮助读者成长,或是实现一个产品帮助更多的人。

本文转载于网络 如有侵权请联系删除

相关文章

  • docker-compose logs 用法

    前言最近用docker-compose的时候,想看下程序运行的日志,就想到使用logs进行查看。help使用docker-composehelplogs可以看到具体的用法比如:#docker-composehelplogs Viewoutputfromcontainers. Usage:logs[options][SERVICE...] Options: --no-colorProducemonochromeoutput. -f,--followFollowlogoutput. -t,--timestampsShowtimestamps. --tail="all"Numberoflinestoshowfromtheendofthelogs foreachcontainer.复制logs使用查看最近100条日志#docker-composelogs-t--tail="100"djc8redis Attachingtodockercompose_djc8redis_1 djc8redis_1|2021-03-28T07:32:35.0128198

  • 零售商超固定资产管理系统解决方案

    零售超市在日常的固定资产管理和运营中比较复杂,遇到的各种实际操作问题比较多,为此,易点易动在对多家商业超市进行深入调查和需求梳理之后,提出了符合零售商超行业的固定资产管理方案。零售商超在固定资产管理中的特征如下:1)零售商城普遍存在的门店众多,而且门店之间以经常进行固定资产的调拨、借用等。使用手工表格进行管理时,无法对实物资产的调拨、借出资产进行跟踪管理和掌握情况。经常发生固定资产丢失或者损坏后找不到使用人和责任门店的情况。2)固定资产缺乏统一的平台管理,导致实物资产分散在各门店,缺乏统筹管理。有的门店有很多闲置的固定资产,由于信息没有实时共享,有的门店还一直在采购。由于这些实物资产缺乏动态和统一的掌握和管理,增加了门店的运营成本,严重影响了固定资产的管理效率。3)由于人员流动较快,每个人名下的固定资产并不能实时更新,导致使用人和固定资产不匹配。员工离职时,固定资产无法顺畅退库。4)由于固定资产的种类和数量都比较多,每年各家分店盘点都是一项大工程,不但耗时耗力而且结果并不准确。导致账实不一致,给最后的固定资产审计带来困难。零售商超固定资产管理解决方案:引入易点易动固定资产管理系统后,将

  • 如何远程服务器 服务器的价格贵吗

    说到服务器,有些小伙伴绝对这门技术有些困难,甚至还是带着一丝神秘感。其实服务器的操作方法很简单,只是大家的潜意识中觉得难才觉得玩服务器的人是高端操作技术。其中服务器就有一个远程操作玩法,通过远程操作别人的电脑,看似很难实际很简单。那么如何远程服务器?下面就给大家介绍一下吧。如何远程服务器如何远程服务器如何远程服务器?想要对服务器进行远程操作,就先学会配置。打开命令控制面板,输入命令参数:mstsc,在弹出的窗口中选中“选项”之后再输入计算机名称、用户名以及密码,确定之后就要进行连接,连接成功就能远程服务器了,服务器的远程与桌面的远程差不多,建立一个虚拟路线来获取局域网中的资源。服务器的价格贵吗想要搭建属于自己的网站,就要舍得花钱,网站的搭建少不了源码、域名以及服务器。其中服务器的价格是比较昂贵的,这得看大家的需求,如果搭建的网站比较大,是门户网站,那所要用到的服务器带宽就要大,而且运行性能还要确保稳定,不稳定的服务器是无法将网站的排名做起来的。最好询问相关的技术人士,根据自己的网站类型推荐合适好用的服务器。以上就是关于如何远程服务器的相关介绍。想要购买服务器的小伙伴,前期要做好充分的了

  • linux shell快速入门

    Shell是一个命令行解释器,它为用户提供了一个向Linux内核发送请求以便运行程序的界面系统级程序,用户可以用Shell来启动、挂起、停止甚至是编写一些程序。1.shell脚本格式要求1.脚本以#!/bin/bash开头 2.脚本需要有可执行权限 复制2Shell的变量1.Shell中的变量分为系统变量和用户自定义变量。 2.系统变量:$HOME、$PWD、$SHELL、$USER等等,比如:echo$HOME等等.. 3.显示当前shell中所有变量:set复制2.1shell变量的定义1.定义变量:变量名=值 2.撤销变量:unset变量 3.声明静态变量:readonly变量,注意:不能unset复制定义变量的规则1.变量名称可以由字母、数字和下划线组成,但是不能以数字开头。5A=200(×) 2.等号两侧不能有空格 3.变量名称一般习惯为大写,这是一个规范复制将命令的返回值赋给变量1.A=`date`反引号,运行里面的命令,并把结果返回给变量A 2.A=$(date)等价于反引号 复制3设置环境变量1.export变量名=变量值(将shell变量输出为环境变量/全局变量) 2

  • python实现跨excel sheet复制代码实例

    功能要求: 将test1表中的Sheet1中所有内容复制到新表test的Sheet1表中测试环境:python3.7;importopenpyxl;execl2016注意事项:openpyxl只能处理.xlsx文件,对于较早的.xls版本需要引入xlrd模块及xlwd模块进行操作代码:#python3读写excel ''' 实现功能: 要把test1中的sheet表内容复制到test表sheet1中 ''' fromopenpyxlimportWorkbook fromopenpyxlimportload_workbook importopenpyxl importos #execl文件存放位置 os.chdir("C:\Users\rtmart213\Desktop\month") #新建excel wb2=openpyxl.Workbook() wb2.save('test.xlsx') print('新建成功') #读取数据 wb1=openpyxl.loa

  • 我为什么要创建一个不能被实例化的类

    摄影:产品经理感谢小何的上等牛肉当我们创建一个Python类并初始化时,一般代码这样写:classPeople: def__init__(self,name): self.name=name defsay(self): print(f'我叫做:{self.name}') kingname=People('kingname') kingname.say() 复制运行效果如下图所示:上面是众所周知的写法。但如果有一天,你发现我写了这样一个类:classPeople: defsay(self): print(f'我叫做:{self.name}') def__new__(self): raiseException('不能实例化这个类') kingname=People() kingname.say() 复制一旦初始化就会报错,如下图所示:你会不会感到非常奇怪?一个不能被初始化的类,有什么用?这就要引入我们今天讨论的一种设计模式——混入(Mixins)。Python由于多继承的原因,可能会出现钻石继承[1

  • 流量私域化,商家可以使用的三个打法

    流量的变迁什么是流量,就是我们的产品能带来的客户流量。不管是传统线下门店的客流还是通过互联网搜索引擎、电商平台等获取的各类流量,一切生意的本质都是流量和流量变现。互联网的上半场,从浏览器到门户到搜索引擎到各类细分平台(以腾讯为首的社交平台如公众号、小程序、朋友圈等,以阿里为首的电商平台如淘宝、京东、拼多多等以及像美团外卖、滴滴打车等垂直平台),我们可以看到,流量的变迁越来越细分和下沉。随着互联网进入下半场,中国互联网人口红利见底、平台活跃用户增长乏力、用户移动互联网时长增速大幅下降。商家要么被平台绑架,要么只能自寻出路。一方面是整个互联网流量成本越来越高,另一方面是各种私域流量生态正在慢慢成熟,传统的商家在这个剪刀差之下,一定会在行动上向私域流量倾斜,迫切需要降低获客成本提高复购的新模式。商家流量私域化,这必然是商家未来运营的一个趋势。私域流量起源实际上,早在私域流量概念出现之前很多商家就在做这件事。回想我们平时买什么东西时会考虑听听别人的意见?母婴、教育、保险、房子、汽车、招聘等等,这些产品有个共同特征——买卖双方存在明显的信息不对称。而站在用户角度,迫切需要专家或者顾问来提供给自己

  • Qt4与Qt5的QUrl兼容性

    我们使用QUrl装载url请求的时候,往往需要写参数,但是由于Qt4与Qt5的改动导致QUrl接口也会不一样。http://www.example.com?key1=value1&key2=value2 复制Qt4写法QUrlurl("http://www.example.com"); url.addQueryItem("key1","value1"); url.addQueryItem("key2","value2"); 复制Qt5写法QUrlurl("http://www.example.com"); QUrlQueryurlQuery(url); urlQuery.addQueryItem("key1","value1"); urlQuery.addQueryItem("key2","value2"); url.setQuery(urlQuery); 复制兼容Qt4/Qt5写

  • 周礼栋:现在是计算机系统和网络研究“最好的时代”

    编者按:随时随地使用各种系统和工具,对现代人来说早已是司空见惯的事,但这一切完美工作的技术和服务并不是凭空出现的。正是因为微软亚洲研究院副院长周礼栋博士和他带领的团队这样从事系统和网络研究工作的研发人员在幕后不断的努力和创新,才能保证各种技术无缝、稳定、高效、持续地协同进行。在本文中,周礼栋博士接受访谈,介绍了在这个系统拥有前所未有的复杂性的时代,如何精进系统与网络的研究工作,解释了像CloudBrain这样的项目针对实时故障排查来解决云规模问题,也探讨了网络相关的“灰色故障”问题,并告诉我们为什么现在是系统和网络研究的“最好的时代”。本文编译自微软研究院播客“Thebravenewworldofcloud-scalesystemsandnetworkingwithDr.LidongZhou”。作者|微软亚洲研究院转载自微软研究院AI头条(ID:MSRAsia)主持人:作为微软亚洲研究院的副院长,您领导着计算机系统和网络方面的研究,我知道您自己也从事很多研究。先简单告诉我们您做了些什么,为什么要做这些事情。让您每天起床的动力是什么?周礼栋:我认为现在是研究系统和网络最激动人心的时刻之一

  • 如何通过其他主机查看Apahce服务器的运行状态

    这篇文章主要介绍了如何通过其他主机查看Apahce服务器的运行状态,需要的朋友可以参考下要查看Apache服务器的运行状态,可通过<Location>命令来实现。具体步骤如下: 1.在Apache的主配置文件/etc/httpd/conf/httpd.conf中找到以下内容: 复制代码代码如下: <Location/server-status> SetHandlerserver-status Orderdeny,allow Denyfromall Allowfrom.example.com </Location> 将其前面的注释去掉(“#”),并修改成允许客户机192.168.1.4访问:复制代码代码如下: <Location/server-status> SetHandlerserver-status Orderdeny,allow Denyfromall Allowfrom192.168.1.4 </Location> 2.为了使服务器可以显示自己的运行状态,以便客户端随时掌控,需要将语句ExtendedStatusO

  • BAT面试题30:过拟合怎么产生的?防止措施有哪些?

    什么是过拟合?过拟合(overfitting)是指在模型参数拟合过程中的问题,由于训练数据包含抽样误差,训练时,复杂的模型将抽样误差也考虑在内,将抽样误差也进行了很好的拟合。 过拟合带来什么问题?具体表现就是最终模型在训练集上效果好;在测试集上效果差。模型泛化能力弱。过拟合产生的原因?在对模型进行训练时,有可能遇到训练数据不够,即训练数据无法对整个数据的分布进行估计的时候;权值学习迭代次数足够多(Overtraining),拟合了训练数据中的噪声和训练样例中没有代表性的特征。通过下图可以看出,随着模型训练的进行,模型的复杂度会增加,此时模型在训练数据集上的训练误差会逐渐减小,但是在模型的复杂度达到一定程度时,模型在验证集上的误差反而随着模型的复杂度增加而增大。此时便发生了过拟合,即模型的复杂度升高,但是该模型在除训练集之外的数据集上却不work。如何解决过拟合问题?1Earlystopping对模型进行训练的过程即是对模型的参数进行学习更新的过程,这个参数学习的过程往往会用到一些迭代方法,如梯度下降(Gradientdescent)学习算法。Earlystopping便是一种迭代次数截

  • JVM活学活用——Jvm内存结构

    Java内存结构:JVM内存结构主要是有三大块:堆内存、方法区和栈。堆内存是JVM中最大的一块由年轻代和老年代组成,而年轻代内存又被分为三部分,Eden空间、FromSurvivor空间、ToSurvivor空间,默认情况下年轻代按照8:1:1的比例来分配;方法区存储类信息、常量、静态变量等数据,是线程共享的区域,为与Java堆区分,方法区还有一个别名Non-Heap(非堆);栈又分为Java虚拟机栈和本地方法栈,主要用于方法的执行。在通过一张图来了解如何通过参数来控制各区域的内存大小:控制参数-Xms  设置堆的最小空间大小-Xmx  设置堆的最大空间大小-XX:NewSize  设置新生代最小空间大小-XX:MaxNewSize  设置新生代最大空间大小-XX:PermSize  设置永久代最小空间大小-XX:MaxPermSize  设置永久代最大空间大小-Xss  设置每个线程的堆栈大小。没有直接设置老年代的参数,但是可以设置堆空间大小和新生代空间大小两个参数来间接控制。老年代空间大小=堆空间大小-年轻代空间大小从更高的一个维度再次来看JVM和系统调用之间的关系 方法区和堆是所

  • java中 == 与 equal 的区别

    废话不多说了,开门见山吧,先来看一段代码:Stringstr1=newString("str"); Stringstr2=newString("str"); System.out.println("==比较:"+(str1==str2)); System.out.println("equal比较:"+str1.equals(str2)); Stringstr3="str1"; Stringstr4="str1"; System.out.println("==比较:"+(str3==str4)); System.out.println("equal比较:"+str3.equals(str4));复制输出的答案:以上的输出结果有误,应该是falseequal比较:truetrueequal比较:true根据打印的可以发现使用equal比较时无论是使用自动装箱来实例化还是用new来实例化,返回的都true,而用==则不一样了,自动装箱

  • 关于 devbridge-autocomplete 插件多选操作的实现方法

    目前据我所知最好用的autocomplete插件就是jquery-ui的autocomplete以及devbridge的autocomplete插件。我最终选择了devbridge的autocomplete插件,主要是不想引用jquery-ui的css文件。官方网址:https://www.devbridge.com/sourcery/components/jquery-autocomplete/先看一下autocomplete的参数serviceUrl:服务器端的URL或者是返回Url字符串的回调函数ajaxSettings:jQueryAjax请求的额外配置lookup:查询的数据列表。字符串数组或者对象字面量(格式{value:'string',data:any})lookupFilter:function(suggestion,query,queryLowerCase){}本地数据查询的过滤函数lookupLimit:查询条数限制,默认值:nolimitonSelect:function(suggestion){},用户选择查询结果后的毁掉函数minChar

  • 软件测试100天上岸3-测试有哪些最高原则

    测试原则是一个测试人员时刻要铭记在心的,甚至要形成一种本能,指导测试工作。 原则1:测试找不出所有的Bug 软件的复杂性仅次于生命体,甚至现在很多软件都已经有了人工智能的属性。对于这样精妙的系统,一小点异常都有可能产生连锁反映,最终让整个系统无法运行。就好像人体只需要吸入一粒微小的尘埃,就可能感染病菌,从而引起人体的高能反应,最终导致人病倒,无法行动。 像软件这样的精妙系统,就算做再多测试,也无法找出所有的错误,就好像你永远无法保证,人不生病一样。 原则2:2/8原则 少数功能模块会测试到大多数缺陷,用数字来表示就是80%的问题出现在20%的功能模块中。在很多领域中都存在2/8原则,而在测试中同样会运用到这个原则。 为什么会这样的原因很多,我们只能适当分析。比如开发某个功能模块的程序员水平不行,引入了大量缺陷;也可能是这个功能模块非常复杂,可能出现大量没有考虑到的因素。 原则3:尽早介入测试 一个软件越复杂,越有可能产生新bug。热力学第二定律指出:孤立系统自发地朝著热力学平衡方向──最大熵状态──演化,同样地,第二类永动机永不可能实现。 这个定律同样适用于信息系统。当一个软件引入

  • 【原创】日志文件清理工具V1.0

           最近公司的系统服务器经常出现磁盘空间不足的情况,登陆服务器发现原来是公司的HR系统日志造成的(插个话题:我们公司的HR系统都实施两年多了还没上线,且不说软件功能如何,服务太TMD差劲了,更可气的是软件顾问把系统的组织架构都实施错误了,造成公司的大部分模块使用了一年的数据都得重新再录入。),原来这个系统每天的日志文件都自动保存在服务器C盘,时间久了,造成磁盘空间不足。不指望软件商再改程序,毕竟这些历史日志文件关键时候还是很有用的,但时间太久的肯定留着也没用。还有就是也不能每天都登陆服务器去看磁盘空间情况。干脆自力更生,自己做个小程序实现自动清理服务器日志信息。 日志文件格式是按照时间自动生成的文本文件,这个知道了就好说了。无非就是定时删除几天的前的文本文件,然后用XML保存配置信息。 删除日志代码: ///<summary> ///定期删除日志 ///</summary> ///<paramname="strPath">日志路径</param> ///&l

  • R2DBC正式孵化成功,利好Spring Webflux

    2022年4月25日,R2DBC社区宣布具有普遍可用性的1.0.0.RELEASE正式发布。 R2DBC致力于为反应式编程API操作关系型数据库带来规范支持,R2DBC不同于我们熟知的JDBC规范,它是异步的、响应式的。 R2DBC经历了社区5年的努力和268张投票表决,终于达到了可以发布1.0的状态。经过0.8和0.9两个版本的孵化和验证,社区已经确认R2DBC朝着可靠数据库连接规范的正确方向上前进。 除其他功能外,该规范还包含以下突出显示的功能: 驱动程序SPI和TCK(技术兼容性套件) 集成BLOB和CLOB类型 可扩展的事务定义 普通语句和参数化语句(“PreparedStatements”) 支持存储过程/服务器侧IN和OUT参数绑定的执行函数 数据更新计数、记录行数和存储过程结果的消耗统计 批量操作 可分类的操作异常 基于ServiceLoader的驱动程序发现 新的数据库连接URL方案 可编程的配置API 从1.0开始,R2DBC将不再像SpringCloud一样发布一个train类型的BOM供开发者根据自己的需要选用合适的套件,数据库厂商和规范的实现者将按照自己

  • 云计算的三层SPI模型

    (转自:http://hi.baidu.com/fengjun8216/item/b15bbef4dcf74049922af27b) 一般而言,云计算架构可以用三层SPI模型来表述。   一、基础设施即服务(IaaS,InfrastructrueasaService)   把硬件资源集中起来一个关键性技术突破就是虚拟化技术。虚拟化可以提高资源的有效利用率,使操作更加灵活,同时简化变更管理。单台物理服务器可以有多个虚拟机,同时提供分离和安全防护,每个虚拟机就象在自己的硬件上运行一样。这种把主机集中管理,以市场机制通过虚拟化层对外提供服务,用按使用量收费的盈利模式,形成了云计算的基础层。这就是基础设施即服务(IaaS,InfrastructrueasaService),构成了云计算的基础层。 硬件平台在云计算中是极其重要的,事实上只有硬件设备能以低成本实现大规模处理量的时候,云计算的实现才有可能。硬件平台的低成本大规模处理量有赖于专业化分工,这也是一个行业走向成熟的标志。通过虚拟机的方式提供硬件设备有很多好处:1,云计算的管理平台能够动态的把计算平台定位到所需要的物理

  • eclipse 配置tomcat 日志

    一般情况下,eclipse中集成tomcat,会直接在控制台打印日志,稍微顶几下,就看不到早期的日子了。可以在Servers视图,               右键open ,               选择“openlaunchconfiguration”,               选择“common”选项卡,               勾选“File”,      

  • Orcal常用查询实例集合

    本文的初衷主要是记录工作中碰到的一些查询实例,便于后续的工作参考从而提高效率。 一、A表拼接B表的数据,A、B两个表字段相同,当B表有数据时用B表的,否则用A表的。区分粒度为业务日期。 selectz.fundid, z.busidate, z.cloumn1, z.cloumn2 fromtableaz wherez.fundidin(fundids) andz.busidatebetweenbegindateandenddate andz.fundid||z.busidatenotin (selectt.fundid||t.busidateasunioncode fromtableabt groupbyt.fundid||t.busidate) union selectt.fundid, t.busidate, '89'||t.cloumn1, t.cloumn2 fromtableabt wheret.fundidin(fundids) andt.busidatebetweenbegindateandenddate复制    二、orcal将多条查询记录拼

  • Sublime Text3左侧文件导航如何自动识别文件类型以展示不同文件图标?

    1、下载“AFileIcon”插件 github地址:https://github.com/SublimeText/AFileIcon 方法:gitclone https://github.com/SublimeText/AFileIcon 下载到本地计算机 2、将下载完成的插件复制到SublimeText3安装路径下的Packages中 方法:“C:\Users\wangqin\AppData\Roaming\SublimeText3\Packages” 注意:根据个人安装路径而定 3、完成以上步骤之后,就能看到如下图所示各类型文件的图标样式 这样看上去直观了很多!

相关推荐

推荐阅读