概述

ES是一个搜索引擎,我们之所以要使用它就是为了借助它快速构建全文索引,帮助我们快速检索数据。

本文接着上篇文章ElasticSearch1初步使用继续来通过blogs索引实例说明如何简单的借助ES实现轻量级搜索功能。

问题

本文主要以应用ES为基本问题,主要探索ES通过GET方法进行搜索的使用方法。在实验的示例中本文也会简要的描述ES相关的理论知识。

如何使用索引进行搜索,对搜索结果进行分页,并使用简单的条件来过滤搜过结果是本文需要探讨的问题。

方法

本文采用对照RDBMS中SELECT功能的方法来描述ES中的轻量级搜索的概念,从总体上来讲,在ES中搜索数据其实和在RDBMS中SELECT数据是一样的,都可以指定搜索(查询)条件,都可以设置返回字段,也都可以进行一定的聚合运算。只不过ES搜索引擎使用全文搜索得到的结果会根据内容与搜索关键字的匹配程度给与每个结果一个权重,这个权重就作为搜索结果排序的依据。而RDBMS完全是依照ORDER BY子句中指定的排序规则进行排序的。

说明:

ES REST API所提供的完全在URL中描述参数的接口就是轻量级搜索接口,换句话说轻量级搜索接口都是使用GET方法的。所以文中示例使用的地址和API语法总结如没有对HTTP请求方法做出特殊声明,均使用GET方法。

对本文中语法说明特殊字符的声明:

  • {a} 代表a变量,如{host}代表主机名或ip地址,{index}代表索引名
  • [] 代表可出现也可不出现,一般情况下带有[]标识的变量出现和不出现会有不同的含义。对于URL开头的[http[s]://]表达式,如果省略整个表达式则系统会默认使用http协议。
  • … 对返回结果或请求内容进行部分省略。

全量数据搜索

语法

请求信息:

[http[s]://]{host}:{port}/[{index}/[{type}/]]_search

响应信息:

{
    "took": 7,//执行搜索请求的耗时,单位毫秒
    "timed_out": false,//搜索是否超时
    "_shards":{//参与本次搜索的分片信息
        "total": 5,//参与本次搜索的分票总个数
        "successful": 5,//有多少个分片成功的完成了搜索任务
        "failed": 0 //有多少分片执行搜索任务失败
    },
    "hits":{ //搜过结果信息
        "total": 1,//匹配到的文档总数
        "max_score": 1.0193838,//查询所匹配文档的 _score 的最大值。
        "hits":[...]//匹配到的文档详细信息结果集
    }
}

在没有指定分页条件的情况下,响应信息默认返回10条结果。

示例

搜索blogs索引下,articles类型下的全部文档。这是一个没有任何过滤条件的最简单的搜索。

请求信息:

http://ubuntu:9200/blogs/articles/_search

响应信息:

{
  ...,
    "hits" : [
      {
        "_index" : "blogs",
        "_type" : "articles",
        "_id" : "AV6GlxJvP5Roqj_P-AOw",
        "_score" : 1.0,
        "_source" : {
          "title" : "ES自动生成id索引",
          "author" : "为为",
          "since" : "2017-09-16 20:20:20",
          "categorie" : "搜索引擎",
          "tags" : [
            "java",
            "研发"
          ],
          "body" : "如果你无法手动对文档进行编号,可以使用POST方法向ES中索引一个新文档,其操作方法和链接规则如图8所示。"
        }
      },
      ...//更多内容暂时省略
    ]
  }
}

简单条件筛选

简单的条件筛选就像是给SQL中的SELECT语句加上WHERE子句,从而限定只查找满足某些条件的结果。

语法

在请求路径中使用q参数,并将查询条件赋值给q

[http[s]://]{host}:{port}/[{index}/[{type}/]]_search?q={param_name}:{param_value}
示例

我们搜索一下文章的tags包含 标签1 的文章。

请求参数:

http://ubuntu:9200/blogs/articles/_search?q=tags:标签1

响应参数:

{
  ...,
  "hits" : {
    ...
    "hits" : [
      {
        "_index" : "blogs",
        "_type" : "articles",
        "_id" : "1",
        "_score" : 1.0193838,
        "_source" : {
          "title" : "第一篇文章",
          "author" : "马华",
          "since" : "2017-09-10 20:20:20",
          "categorie" : "科学读物",
          "tags" : [
            "标签1",
            "标签2"
          ],
          "body" : "测试文章内容"
        }
      }
    ]
  }
}

分页

我们在SQL中SELECT语句可以使用LIMIT关键字进行分页,来保证我们每次查询只拿符合需求的数据条数。刚刚也提到过ES也支持分页,默认每页有10条数据。

语法

在搜索URL中可以使用size参数指定页大小,from应跳过的结果集条数。

请求信息:

[http[s]://]{host}:{port}/[{index}/[{type}/]]_search[?[size={size}][[&]from={from}]]
示例

不使用任何过滤条件搜索blogs索引type类型下的所有文档,指定页大小为2,从第跳过1条结果。

请求信息:

http://ubuntu:9200/blogs/articles/_search?size=2&from=1

响应信息请自行演示。

多索引和类型

如果你需要在一个或多个特殊的索引并且在一个或者多个特殊的类型中进行搜索。我们可以通过在URL中指定特殊的索引和类型达到这种效果,下面举例说明如何使用多索引或多类型。
在所有的索引中搜索所有的类型

http://ubuntu:9200/_search

在 blogs 索引中搜索所有的类型

http://ubuntu:9200/blogs/_search

在 blogs 和 pictures 索引中搜索所有的文档

http://ubuntu:9200/blogs,pictures/_search

在任何以 b 或者 p 开头的索引中搜索所有的类型

http://ubuntu:9200/b*,g*/_search

在 blogs 索引中搜索 aiticles 类型

http://ubuntu:9200/blogs/articles/_search

在 blogs 和 pictures 索引中搜索 articles 和 a_images 类型的文档

http://ubuntu:9200/blogs,pictures/articles,a_images/_search

在所有的索引中搜索 articles 和 a_images 类型的文档

http://ubuntu:9200/_all/articles,a_images/_search

当在单一的索引下进行搜索的时候,Elasticsearch 转发请求到索引的每个分片中,可以是主分片也可以是副本分片,然后从每个分片中收集结果。多索引搜索恰好也是用相同的方式工作的,只是会涉及到更多的分片。

多个搜索条件

刚刚介绍的条件搜索只能使用一个搜索条件,而我们一般的业务都需要更为复杂的搜索条件。

_all字段

在 blogs/aiticles 中搜索“为为”的相关信息,注意该搜索中并未指定“为为”属于哪个字段。

http://ubuntu:9200/blogs/_search?q=为为
同时搜索多个字段

在 blogs/aiticles中搜索author包含”为为”, title包含”ES”的信息。

http://ubuntu:9200/blogs/articles/_search?q=+title:ES自动生成id索引 +author:为为
  • 前缀表示必须与查询条件匹配。类似地, -前缀表示一定不与查询条件匹配。没有 + 或者 -的所有其他条件都是可选的——匹配的越多,文档就越相关。在存在多个条件时,如果没有明确使用default_operator=AND指定多个条件的关系为AND,则多个条件的关系为OR。
同一个字段下多种可能性

在 blogs/aiticles中搜索author包含”为为”,tags为”java”或”编码”的信息。

http://ubuntu:9200/blogs/articles/_search?q=+tags:(java 研发)  +author:为为

在 blogs/aiticles中搜索author包含”为为”,tags为”java”或”编码”的信息。

http://ubuntu:9200/blogs/articles/_search?q=+tags:(java 研发)  +author:为为&default_operator=AND

总结

经过本文示例我们可以看出ES不仅可以作为一个NoSQL数据库,存储格式化的JSON数据,其更强大的功能在于搜索。ES不仅会存储文档,文档中的每个字段都将被索引并且可以被查询 。不仅如此,在简单查询时,Elasticsearch 可以使用 所有(all)索引字段,快度返回结果,我们甚至不必指定具体要搜索哪个字段就。

总之ES的搜索可以完成以下任务:

  • 在结构化的数据(JSON)中使用结构化查询。
  • 全文检索。

    轻量级搜索虽然简单方便,但其也有缺点:

  • 当查询字符串中很小的语法错误,像 - , : , / 或者 “ 不匹配等,将会返回错误而不是搜索结果。
  • 允许任何用户在索引的任意字段上执行可能较慢且重量级的查询,这可能会暴露隐私信息,甚至将集群拖垮。

    基于以上两点原因,不推荐向用户直接开放轻量级搜索功能,一般情况下只在开发调试中使用。

引用

本文是我在学习使用ES时的笔记,在本文的写过过程中参考了大量其它资料,有些材料来源于网络,我由衷的表示感谢,但由于原作者不明,恕不能一一记述。

  1. Elasticsearch 权威指南.——https://www.elastic.co/
  2. Elasticsearch技术解析与实战/朱林编著.——北京:机械工业出版社,2016.12(数据分析与决策技术丛书)

关于

本项目和文档中所用的内容仅供学习和研究之用,转载或引用时请指明出处。如果你对文档有疑问或问题,请在项目中给我留言或发email到
weiwei02@vip.qq.com 我的github:
https://github.com/weiwei02/ 我相信技术能够改变世界 。

链接

评论和共享

elastic search初步使用

ElasticSearch是一个基于Lucene的搜索引擎,是当前世界上最受欢迎的全文搜索引擎,其主要特点如下:

  • 横向可拓展性: 往集群中增加机器时只需要更改一点配置就可以将新机器加入集群
  • 分片机制: 同一个索引切分成不同的分片
  • 高可用: 提供复制集机制,一个分片可以设置多个复制集,某台机器如果宕机不至于使集群无法工作
  • 使用简单,基于 REST api就可以完成搜索引擎的全部工作,所需学习成本低。

如无特殊声明,本文和后续文档将 Elastic Search 简称为ES

全文搜索

全文搜索是指搜索程序扫描整个文档,通过一定的分词方法,对每一个词建立索引,并指明该词在文档中出现的位置和次数,最后搜索引擎再通过索引关键字搜索出文档并返回给用户的过程。

Lucene

Lucene是Apache下的一个开源全文搜索引擎工具,提供了完整的查询引擎和索引引擎和部分文本分析引擎。不过Lucene仅仅是一个工具包,其目的是为了让研发人员能够通过这些工具包快速的为自己的应用搭建一个搜索引擎或者基于这些工具包开发出一个完整的搜索引擎。

倒排序索引

Lucene中的索引采用的是倒排序索引的模式。所谓的倒排序索引(Inverted Index)是通过属性的值来确定整条纪录的位置,而不是由纪录来确定属性的值。倒排索引把普通索引中的文档编号和值的关系倒过来,变成:“关键词”对“拥有该关键词的所有文章号”。带有倒排索引的文件我们称为倒排索引文件,简称倒排文件(inverted file)。倒排索引主要就由索引关键字和倒排文件所组成。

建立搜索引擎的关键步骤就在于建立倒排索引,倒排索引一般以以下数据结构出现:

关键字 文章号[出现频率] 出现位置
简单 1[3] 2,9,89
美女 5[1] 1
tip 9[2] 2,7,22

表1 倒排索引数据结构示例

倒排索引在存储上使用LSM树,维护其索引方法是当需要新增文档进入系统时,首先解析文档,之后更新内存中维护的临时索引,文档中出现的每个单词,在其倒排表列表末尾追加倒排表列表项;一旦临时索引将指定内存消耗光,即进行一次索引合并,这里需要倒排文件里的倒排列表存放顺序已经按照索引单词字典顺序由低到高排序,这样直接顺序扫描合并即可。

实现

lucene在实现倒排索引时将索引划分为词典文件(Term Dictionary)、频率文件(Frequencies)、位置文件(Positions)保存。其中词典文件不仅包含关键词,还有该关键词指向频率文件和位置文件的指针。

为了节省存储空间,提升索引效率。Lucene还对索引进行了压缩。

安装

ES使用JAVA语言开发,所以在安装ES之前需要在系统中安装有JDK。

表2是本文中的示例所使用的软件环境信息。

类型 名称 版本
操作系统 ubuntu server 16.04.2 LTS
内核 Kernel 4.4.0-62-generic
容器 docker 1.28
java openjdk 1.8.0_141
搜索引擎 elasticsearch 5.5.2

表2 本机软件环境信息

docker镜像安装

为了方便部署,我直接采用docker镜像的方式搭建ES。镜像启用命令为:

$ docker run -d -v "$PWD/esdata":/usr/share/elasticsearch/data --name elasticsearch -H elasticsearch elasticsearch  -Etransport.host=0.0.0.0 -Ediscovery.zen.minimum_master_nodes=1 elasticsearch

系统内核参数

由于elastic search需要用到nio和mmap(虚拟内存映射)技术,在启动该镜像之前首先需要检查一下系统内核对虚拟内存映射数目的限制(vm.max_map_count参数)是否大于262144,如果不满足这个条件,elastic search镜像将不会启动。

我们可以通过以下两种方式去设置系统内核的vm.max_map_count参数:

sysctl -w vm.max_map_count=262144

如果想永久修改此参数,可以通过修改 /etc/sysctl.conf 文件的方式使其永久性的成为系统内核参数。

测试

在linux系统下,我们可以使用 curl 程序来完成REST接口的调用与测试,《Elasticsearch权威指南》对 curl 调用REST接口的方式描述如图1所示。

image
图一 curl命令示意图

使用以下命令可以检测elastic search是否启动成功。

curl -i -XGET 'localhost:9200/'

-i 参数是说明要打印http请求头信息,GET是请求方法,localhost:9200/就是我们服务器的地址和端口,elastic search默认与外部交互的端口就是9200.如果服务启动成功,你会收到类似虾苗的响应信息。

HTTP/1.1 200 OK
content-type: application/json; charset=UTF-8
content-length: 331

{
  "name" : "Franz Kafka",
  "cluster_name" : "elasticsearch",
  "cluster_uuid" : "JP677C9kRNqjEWYnFae_gQ",
  "version" : {
    "number" : "5.5.2",
    "build_hash" : "b2f0c09",
    "build_date" : "2017-08-14T12:33:14.154Z",
    "build_snapshot" : false,
    "lucene_version" : "6.6.0"
  },
  "tagline" : "You Know, for Search"
}

使用

为了方便操作,本文与后续内容都将使用chrome浏览器的 Restlet Client插件来模拟REST请求,在这里推荐一下,感谢该插件的作者将本插件开源。

创建索引

Elastic Search就像是一个nosql数据库一样,存储我们要进行查询的信息,在ES中,数据库名就是索引名。一个 Elastic Search 集群可以包含多个索引,相应的每个索引可以包含多个类型 。这些不同的类型存储着多个文档 ,每个文档又有多个属性。

我们可以使用PUT方法创建blogs库,详细请求信息如图2所示。

image
图二 创建blogs数据库

如果收到以下回应内容,则说明blogs数据库创建成功。

image
图3 创建blogs数据库成功的回应信息

使用GET地址 http://ubuntu:9200/_cat/indices?v可以查看库的状态,返回结果如下:

health status index uuid                   pri rep docs.count docs.deleted store.size pri.store.size
yellow open   blogs Y9hkRePSQmiAzjNQ_K_FSw   5   1          0            0       810b           810b

其中yellow代表健康度,状态是活动,索引为blogs,主分片数量5,复制集1,已存储的文档数为0.

新建文档

ES是一个面向文档的数据库,每一个文档都代表一条完整的实体记录,本文实例中一个文档就代表一篇文章。存储一个文档到ES的行为就叫做索引,在索引一个文档之前,首先应该明确应该将文档存储在哪里。

本文对于数据存储使用以下设计:

  • 每一篇文章被定义为一个文档,包含作者,发布时间,文章分类,正文等信息。
  • 每个文档都属于articles类型
  • articles类型保存在blogs索引里
  • blogs索引在我们的ES集群中。

    按照这个设计思路,我们向ES中索引一篇文章,其请求信息图4所示。

image
图4 向blogs索引articles类型插入一篇新文档

如果新建文档成功,则会收到HTTP状态码为201的回应,回应信息如图5所示。

image
图5 向blogs索引articles类型插入一篇新文档回应信息

接着我们再索引几篇新文档,如图6,图7.
image
图6 向blogs索引articles类型插入更多新文档
image
图7 向blogs索引articles类型插入更多新文档。

如果你无法手动对文档进行编号,可以使用POST方法向ES中索引一个新文档,其操作方法和链接规则如图8所示。
image
图8 向blogs索引articles类型POST插入一篇新文档

从其相应结果中可以看出ES通过自己的规则为文档增加了_id字段,相应结果如图9所示.
image
图9 向blogs索引articles类型POST插入一篇新文档响应信息

检索文档

在ES中检索已存在的文档只需使用GET方法访问刚刚新增文档时的连接就可以了。

GET http://ubuntu:9200/blogs/articles/2

返回结果如图10所示。
image
图10 从blogs索引articles类型检索文档

_index属性代表文档所属索引, _type是文档所属类型, _id是文档编号, _version是文档的版本(每对文档做一次修改, _version就会加1), _found代表是否查询到指定文档, _source就是文档中所存储的内容。

更新与删除文档

使用REST API对ES中的数据进行修改或删除也是极其方便的。如果我们要删除某个文档,只需使用DELETE方法访问这个文档的链接就可以了。

DELETE http://ubuntu:9200/blogs/articles/2

我们先介绍一种全量更新文档的方法,使用PUT方法访问我们的文档地址,参数信息加上文档的新内容就可以全量更新文档了。文档更新后,ES会犯规给我们新的文档版本和操作结果。

示例,对文档2进行全量更新,其请求与回应信息如图11,图12所示。

image
图11 PUT文档全量更新
image
图12 PUT文档全量更新响应

ES的文档不能被修改,只能被替换。但ES为我们提供了 update API。通过update API操作从整体来看,我们可以对文档的某个位置进行部分更新。不过在底层实现上 update API 还是需要进行完整的检索-修改-重建索引 的处理过程。 区别在于这个过程发生在分片内部,这样就避免了多次请求的网络开销。因为减少了检索和重建索引步骤之间的时间,更新此文档时与其他进程的更新操作冲突的可能性也会减少。
update 请求最简单的一种形式将待更新的字段作为doc的参数, 它只是与现有的文档进行合并。对象被合并到一起,覆盖现有的字段或者新增字段。

示例,修改文档2的author和tags属性,其请求、新文档内容如图13、图14所示。
image
图13 POST update文档部分更新
image
图14 POST update文档部分更新后的结果

如果更新文档是一个并发操作,当前工作在更新文档的检索步骤会获取当前版本号,在重建索引之前会检查文档此时的版本号是否与检索时的版本号一致,如果版本号不一致,当前线程就会发生操作失败,放弃文档的修改。如果业务上允许重复更新的话,可以通过retry_on_conflict属性,来设置失败重试。该属性用法如下面代码所示。对于不能重试的业务场景,update API提供了version属性进行乐观并发控制。

PUT http://ubuntu:9200/blogs/articles/2/_update?retry_on_conflict=5

搜索文档

搜索是ES的核心,不过鉴于篇幅原因,关于搜索功能的使用将放到下篇文章中。

引用

本文是我在学习使用ES时的笔记,在本文的写过过程中参考了大量其它资料,有些材料来源于网络,我由衷的表示感谢,但由于原作者不明,恕不能一一记述。

  1. Elasticsearch 权威指南.——https://www.elastic.co/
  2. Elasticsearch技术解析与实战/朱林编著.——北京:机械工业出版社,2016.12(数据分析与决策技术丛书)

    非原创声明

    本文并非我的原创文章,而是我学习jvm时的笔记。文中的材料与数据大部分来自于其它资料,详细请查看本文的引用章节。

关于

本项目和文档中所用的内容仅供学习和研究之用,转载或引用时请指明出处。如果你对文档有疑问或问题,请在项目中给我留言或发email到
weiwei02@vip.qq.com 我的github:
https://github.com/weiwei02/ 我相信技术能够改变世界 。

链接

评论和共享

概述

言之有物,论之有据才是有效的交谈。

我们是工程师,我们的理想是做出完美的产品,我们希望人类能够通过我们的产品来改变某种生活习惯。在很多情况下我们都在默默的付出,为商务人员对客户的售后提供强力而有效的技术保障。可能是因为我们习惯了默默的奉献,平时没有注意过与人交流,故而会出现自己明明知道的东西却说不出来的情况。我们是曾经努力过,我们是做出许多傲人的成绩,但是如果我们不能说出来,别人会知道吗?难道能让别人去猜我们是什么样的人?

默默的付出其实就是在闭门造车,我们要把自己的想法的打算说出来,我们要告诉产品经理我们队建设良好应用的看法。我们要告诉领导,我们对架构的设计。我们要告诉其它工程师,我们对代码的想法。或许你真的是才华横溢,但如果连介绍自己都不会,没人会看好你。我们是工程师,不是程序员也不是码农,我们需要为自己的闭门造车打开一扇窗户。

本文主要是以我亲身的经历,从发言者的角度来探索该如何去发言,如何表达出内心的想法。本文也是我对自己犯过的错的反思。

问题

我们勤奋努力,我们有理想有追求,我们认为做比说更重要,但是我们无法完美的表达自己,我们的辛苦几乎不被人理解。

层次

层次就是对具体事物的抽象,想要有效的表达你的思想。不要再试图向业务人员/客户或与项目不相干的人员介绍你的代码,他们只关心功能。我曾经试过向客户从技术角度来解释我所负责的项目的优势,我告诉他以我们的的系统经过预编译,多级缓存等策略优化后,我们的系统能够在双机环境下吞吐量达到300。客户只回复了我:”xx公司的系统并发能达到5000。”听见客户这么说我真的想给他解释清楚在双机条件下涉及到大数据分析的时候,我们无法使用内存存储全部数据,所谓的并发5000真的是不可能,xx公司肯定是在骗人。

工程师都知道,系统访问一次数据库都需要几十至数百毫秒,何况我们业务的要求每次核心操作都需要操作数十次数据库中的数据。先不说应用进程与数据库进程之间的通信损耗,单是磁盘寻址时间就是现代服务器无法克服的性能瓶颈。但是我们能告诉客户吗?即便花上一两个小时给客户分析明白为什么说300就是极限,为什么5000是骗人又有什么意义呢?客户关心的只是业务,只要能在保证数据精准无差的前提下把功能给实现了,这就是合格。

一个项目有技术层次的理解,有业务层次的理解,有对细节方面的理解,也有对整体流程的理解。我们要给项目进行一个抽象,分别建立出业务层,架构层,代码层和核心功能层,简要介绍层。当遇到一个圈外人只想知道这个项目能干嘛的时候,我们只需要给别人简单的说一下简要介绍层的知识。例如当一个从没用过微信的人问你微信可以干嘛,你就应该回答他:“微信是一个实时聊天工具,可以免费的跟朋友进行聊天,通话与视频。”可以试想一下如果你拿业务层的知识来回答:“微信可以发表情,表情是一种比聊天更好玩的交流方式。可以建群聊,可以发朋友圈,朋友圈是。。。”,这样对方一定很疑惑。如果你直接回答:“微信是一个C/S架构的,有数万台服务集群提供服务,拥有2亿用户高性能高可用的应用。。。”对方一定会直接懵了。

在向别人介绍你你自己或你的产品之前,首先你要对要介绍的内容根据听众的需求进行抽象,抽象的方法就是尽量讲些让听众能够清晰理解的,尽量少用专业名词。当然恰当的使用专业名词更能说明你的专业性。

条理

条理不清晰是一个贬义词,意思是说一个人说话天马行空,无迹可寻。条理不清晰就意为着可能你滔滔不绝的长篇大论过后,听众都不知道你在说什么。

以你工作中都是如何进行性能优化这个话题为例。你可能不假思索的就可以回答:

  • 首先我会优化慢SQL,因为在现在系统中一般情况下性能瓶颈都是出现在数据库上,所以第一步先优化SQL。
  • 代码上的优化,如不要在循环中写异常捕获等具体优化方法。
  • 看系统中有没有长时间阻塞的线程,优先进行去锁优化,如果实在需要保证线程安全,那就尽量使用轻量级锁,读写锁,注意重入锁等作为优化策略。
  • 其次根据实际需要设置大小合适的堆空间,然后选择合适的垃圾收集算法(如注重响应时间就选择CMS或G1)。

    上述回答的确是一般的优化方法,你能回答以上的答案可以证明你确实做过性能优化,知道一般的优化点在哪里,但是这么讲解着实有不妥之处。当我们要回答一个问题时,我们首先需要知道在哪会发生这个问题,然后寻找问题发生的原因,最后再提出解决方案,动手解决问题。性能优化和我们在生活中遇见的大多数问题一样,没有什么固定程序的解决方案。

    还回到上个问题上面,当我们发布性能优化的论述时,如果按照以下步骤可能有条理点:

  • 当项目不再能满足性能需求时,首先我们需要找到性能的瓶颈点。可以通过linux的top命令分析一下各个服务器的主要瓶颈是在cpu上、内存上还是I/O上。

  • 首先是应用服务器,如果瓶颈在CPU上,首先定位最耗资源的进程,借助jvm的一些工具如JProfiles,jvisualvm等工具我们还可以将问题定位到代码上。然后再详细分析哪些操作造成了高密度的CPU运算,尝试是否有优化的余地。

  • 如果系统CPU阻塞时间比很大且I/O负载过高,则首先去分析这个负载是来自于磁盘还是网卡,则尝试寻找降低阻塞原因,找到硬件资源瓶颈,然后使用NIO等技术降低系统阻塞。

  • 如果系统内存占用很大,则需要定位具体进程。如果占用内存过大的是我们的应用,则需要查看JVM堆空间设置,看是否是堆空间设置不合理或者使用了大量的直接内存而没有释放。

  • 如果还没定位到问题,则尝试分析JVM中的线程快照,看是否有死锁或长时间持有互斥锁的线程,并尝试优化这些。

  • 接着才是垃圾回收策略的等虚拟机参数级的优化。

  • 若问题在以上应用服务器优化思路下没有优化空间,或者优化后也无法满足性能需求,可以考虑布置集群或给集群增加机器。

    以上几条只是简要的说明了应用服务器的优化思路,对于数据库服务器和缓存服务器,根据他们不同的业务需要有专属的优化方案,本文不再对此作出详细讨论。当我们要向听众去介绍一个方案或设计时,可以依照先定位问题,再分析问题,最后再提出解决方案,实施方案的过程来逐步的展现我们的思想。在这种条理下我们的私立也鞥更加清晰,不至于因漫谈而忘记重点。

总结

刚刚说到了条理,我们怎么能让我们演讲时更有条理呢?想要有条理就要善于总结,并且将总结作为一种习惯。只有经过总结后的语言才能更有条理,除非你有很高的演讲技巧,否则不要将总结的时间放到你将要说话前一刻,不然你在演讲前的紧张会让你根本无心总结。

为演示总结的好处,我在这里提问一个简单的问题,什么样的代码才是好代码?

作为工程师,你一定有自己的衡量代码好坏的标准,不知你是否总结过这个问题? 假如你没有总结过,这个问题你可能这么回答:

  • 可扩展性
  • 易读性
  • 架构,符合项目需求
  • 代码不要太冗余
  • 整体的风格保持统一
  • 好性能

    当然你可能有回答出其他的特性,我们暂且抛开,我这边有几条经过总结后可能更好的答案:

  • 领域驱动,完全满足需求,可测试

  • 整洁规范,注释清晰,可读性高
  • 简单高效,逻辑清晰,性能优秀
  • 善于抽象,层次合理,避免重复
  • 高内聚,低耦合,易于扩展维护

事实

事实胜于雄辩!再好的理论如果没有实例的支撑也只是空谈。

比如我们上面所说到的“总结”这一节里,我们总结了几条好代码的标准,乍一听好像很有理,但仔细想又空无一物,这种情况出现的原因就是我们没有拿出事实论证,没有实例去支撑。对于“简单高效,逻辑清晰,性能优秀”这条,我们可以进行一个举例说明。假如我们以前使用100行代码才能完成一个Excel文件导出的代码,而现在我们只需要10行代码就能完成这项工作,那么这10行代码相对来说就是好代码。

对于其它几条所涉及的事实,这边不再一一讲述,如果你对此有兴趣,可以翻看一下spring的源码,看看spring是如何的设计成“高内聚,低耦合,易于扩展维护”如何层次合理。

故而当我们需要表达时,说出理论总结后,或者在总结前,尽量的拿出具体事实来为自己的总结做一个证据,让别人对你的观点深信不疑。

最后

在文章的背后我还是要说明,我们是工程师,应当以知识为重。所有的交流都在我们具有业务知识或技术知识的前提之下,所以不可因锻炼交流放弃知识学习。你会什么很重要,把你的知识或者知识转化的产品分享出来同样重要。

引用

在写作本文的受过一位阿里的不知名的前辈的提点,为为在此谢过。今天必是我在成为架构师之路上迈出的又一关键步伐。

关于

本项目和文档中所用的内容仅供学习和研究之用,转载或引用时请指明出处。如果你对文档有疑问或问题,请在项目中给我留言或发email到
weiwei02@vip.qq.com 我的github:
https://github.com/weiwei02/ 我相信技术能够改变世界 。

评论和共享

  • 第 1 页 共 1 页
Copyrights © 2017 weiwei02. All Rights Reserved. github空间地址: https://weiwei02.github.io/ 国内空间地址: https://weiwei02.cording.me/
作者的图片

weiwei02

技术,改变世界


软件工程师


北京,海淀
国外主站 国内主站