-
Notifications
You must be signed in to change notification settings - Fork 0
/
atom.xml
75 lines (44 loc) · 28.3 KB
/
atom.xml
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
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Arthur 的技术人生</title>
<subtitle>C'est la vie.</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="https://blog.arthurzwl.com/"/>
<updated>2019-05-16T03:36:11.255Z</updated>
<id>https://blog.arthurzwl.com/</id>
<author>
<name>Arthur Zhang</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>基于 Jenkins 搭建持续集成系统</title>
<link href="https://blog.arthurzwl.com/2019/04/03/%E5%9F%BA%E4%BA%8E-Jenkins-%E6%90%AD%E5%BB%BA%E6%8C%81%E7%BB%AD%E9%9B%86%E6%88%90%E7%B3%BB%E7%BB%9F/"/>
<id>https://blog.arthurzwl.com/2019/04/03/基于-Jenkins-搭建持续集成系统/</id>
<published>2019-04-03T03:26:05.000Z</published>
<updated>2019-05-16T03:36:11.255Z</updated>
<content type="html"><![CDATA[<blockquote><p>这是我在公司部署 Jenkins 时写的部署文档&使用手册,现在放到博客上,可以给大家一些参考,以后自己也好回顾。</p></blockquote><h2 id="1-系统介绍"><a href="#1-系统介绍" class="headerlink" title="1. 系统介绍"></a>1. 系统介绍</h2><h3 id="1-1-CI-CD-介绍"><a href="#1-1-CI-CD-介绍" class="headerlink" title="1.1 CI/CD 介绍"></a>1.1 CI/CD 介绍</h3><p>持续集成,Continuous integration (CI),强调开发人员提交了新代码之后,立刻进行构建、(单元)测试。根据测试结果,我们可以确定新代码和原有代码能否正确地集成在一起。</p><p>持续交付,Continuous delivery (CD or CDE),在持续集成的基础上,将集成后的代码部署到更贴近真实运行环境的「类生产环境」(production-like environments)中。比如,我们完成单元测试后,可以把代码部署到连接数据库的 Staging 环境中更多的测试。如果代码没有问题,可以继续手动部署到生产环境中。</p><p>持续部署,Continuous deployment (CD),则是在持续交付的基础上,把部署到生产环境的过程自动化。</p><h3 id="1-2-Jenkins-介绍"><a href="#1-2-Jenkins-介绍" class="headerlink" title="1.2 Jenkins 介绍"></a>1.2 Jenkins 介绍</h3><p>Jenkins是一个独立的开源自动化服务器,可以用来自动化与构建、测试、交付或部署软件相关的各种任务。</p><h3 id="1-3-SonarQube-介绍"><a href="#1-3-SonarQube-介绍" class="headerlink" title="1.3 SonarQube 介绍"></a>1.3 SonarQube 介绍</h3><p>SonarQube,是一个开源的代码静态扫描工具。</p><h2 id="2-系统搭建"><a href="#2-系统搭建" class="headerlink" title="2. 系统搭建"></a>2. 系统搭建</h2><h3 id="2-1-Jenkins-服务搭建"><a href="#2-1-Jenkins-服务搭建" class="headerlink" title="2.1 Jenkins 服务搭建"></a>2.1 Jenkins 服务搭建</h3><p>Jenkins 可以通过原生的系统安装包,Docker,或者任何安装了Java运行时环境( JRE )的机器都可以独立运行。</p><p>我们可以直接在官网下载 war 包,可以使用 Servlet 容器部署,也可以使用 Jenkins war 包嵌入的 Jetty 容器部署。</p><p>由于现在最新的 Jenkins 依赖 Servlet API 3.1,而我们目前使用的 Resin 实现的是 Servlet 3.0,无法部署最新的 Jenkins server。所以本着快速部署不折腾的原则,我这里使用的是 war 包嵌入的 Jetty 容器部署的。运行命令如下:</p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">java -jar jenkins.war --httpPort=8080</span><br></pre></td></tr></table></figure><h3 id="2-2-SonarQube-服务搭建"><a href="#2-2-SonarQube-服务搭建" class="headerlink" title="2.2 SonarQube 服务搭建"></a>2.2 SonarQube 服务搭建</h3><p>SonarQube 使用了 Docker 部署。</p><h2 id="3-服务整合"><a href="#3-服务整合" class="headerlink" title="3. 服务整合"></a>3. 服务整合</h2><blockquote><p>服务目前已经都配置好,不需要重复配置,这里列出详细步骤是方便大家了解服务整合方法,提供一些参考。</p></blockquote><h3 id="3-1-Gitlab-amp-Jenkins-服务整合"><a href="#3-1-Gitlab-amp-Jenkins-服务整合" class="headerlink" title="3.1 Gitlab & Jenkins 服务整合"></a>3.1 Gitlab & Jenkins 服务整合</h3><p>Gitlab 和 Jenkins 服务整合,主要是需要当开发同学 push 代码,或者提交 merge request 时可以自动触发 Jenkins 持续集成任务,而非手动运行持续集成任务。</p><p>配置步骤:</p><ol><li>Jenkins 需要安装 gitlab-plugin 插件</li><li>在 Mange Jenkins -> Configure System -> Gitlab 添加 Gitlab 配置</li><li>在 Gitlab 里对应项目给 robot 用户赋予 Developer 权限</li><li>在 Gitlab 里对应项目添加 webhook,添加步骤参考下文</li></ol><h3 id="3-2-Jenkins-amp-SonarQube-服务整合"><a href="#3-2-Jenkins-amp-SonarQube-服务整合" class="headerlink" title="3.2 Jenkins & SonarQube 服务整合"></a>3.2 Jenkins & SonarQube 服务整合</h3><p>Jenkins 和 SonarQube 服务整合的目的,是在 Pipeline 中可以调用 SonarQube Server 对代码进行静态扫描,并且在扫描结束后可以获取扫描结果</p><p>配置步骤:</p><ol><li>Jenkins 安装 sonar 插件</li><li>Sonar 登录 -> 点击头像 -> My Account -> Security -> Generate Tokens,这里保存生成的 token,后续会使用到</li><li>Jenkins, 选择 Manage Jenkins -> Configure System -> SonarQube servers, 添加 SonarQube Server 配置,填写上一步生成的 token</li><li>Sonar, 选择 Administration -> Configuration -> Webhooks 添加 Jenkins webhook</li></ol><h2 id="4-如何使用"><a href="#4-如何使用" class="headerlink" title="4. 如何使用"></a>4. 如何使用</h2><h3 id="4-1-Jenkins-使用介绍"><a href="#4-1-Jenkins-使用介绍" class="headerlink" title="4.1 Jenkins 使用介绍"></a>4.1 Jenkins 使用介绍</h3><h4 id="4-1-1-新建任务"><a href="#4-1-1-新建任务" class="headerlink" title="4.1.1 新建任务"></a>4.1.1 新建任务</h4><p>目前我搭建好的 Jenkins 支持新建几种任务</p><ol><li>Freestyle project</li><li>Maven project</li><li>Pipeline</li><li>Multi-configuration project</li><li>Multibranch Pipeline</li></ol><p>我目前推荐使用的是 Pipeline。新建任务步骤如下:</p><ol><li>点解 New Item</li><li>填写任务名(注意任务名不能重复,最好以项目名开头,后续可能会根据项目名分配权限),选择任务类型 Pipeline</li><li>GitLab Connection 选择对应配置</li><li>选择 Build Triggers,勾选 Build when a change is pushed to GitLab(需要在 gitlab 里添加 webhook,后续会说),勾选需要的 event,这里需要保存 GitLab webhook URL,后续会用到</li><li>填写 Pipeline,这里支持两种方式,可以根据需要选择,6、7中选择一种</li><li>Pipeline script,直接在Jenkins 上写 Pipeline definition</li><li>Pipelione script from SCM,从代码仓库里下载 Jenkinsfile</li><li>在 Gitlab 里对应项目给 robot 用户赋予 Developer 权限,也可以直接在 Gitlab Group 里赋予 robot 用户赋予 Developer 权限</li><li>在GitLab里配置 webhook,这里 GitLab 配置 webhook 需要 master 权限打开项目点击 Settings,选择 Integrations</li><li>勾选需要的Trigger,填写 URL,点击 Add webhook,填写第4步得到的 GitLab webhook URL,注意这里需要在url上添加认证信息,类似 [<a href="http://user:token@localhost:8080/project/project-name],建议使用" target="_blank" rel="noopener">http://user:token@localhost:8080/project/project-name],建议使用</a> robot 的 token</li></ol><h4 id="4-1-2-Pipeline-介绍"><a href="#4-1-2-Pipeline-介绍" class="headerlink" title="4.1.2 Pipeline 介绍"></a>4.1.2 Pipeline 介绍</h4><p>Jenkins Pipeline 是一组插件,支持在 Jenkins 里实现和集成持续交付。</p><p>简而言之,就是一套运行于Jenkins上的工作流框架,将原本独立运行于单个或者多个节点的任务连接起来,实现单个任务难以完成的复杂流程编排与可视化。</p><p>Pipeline 提供了一套可扩展的工具,通过 Pipeline 领域特定语言 (DSL) syntax 可以实现 Pipelines as code。</p><h4 id="4-1-3-Jenkinsfile-语法介绍"><a href="#4-1-3-Jenkinsfile-语法介绍" class="headerlink" title="4.1.3 Jenkinsfile 语法介绍"></a>4.1.3 Jenkinsfile 语法介绍</h4><blockquote><p>待完善</p></blockquote><p>可参考:</p><ol><li>Pipeline Syntax, [<a href="https://jenkins.io/doc/book/pipeline/syntax/]" target="_blank" rel="noopener">https://jenkins.io/doc/book/pipeline/syntax/]</a></li><li>abayer, Jenkinsfile, In GitHubGist, [<a href="https://gist.github.com/abayer/925c68132b67254147efd8b86255fd76]" target="_blank" rel="noopener">https://gist.github.com/abayer/925c68132b67254147efd8b86255fd76]</a></li></ol><h4 id="4-1-4-任务结果通知"><a href="#4-1-4-任务结果通知" class="headerlink" title="4.1.4 任务结果通知"></a>4.1.4 任务结果通知</h4><p>目前任务结果通知可以支持邮件和Gitlab comment 的方式<br>Pipeline 配置方式</p><p>post {<br> always {<br> echo ‘send email’</p><pre><code> script { env.committeremail = sh ( script: 'git --no-pager show -s --format=\'%ae\'', returnstdout: true ).trim() }emailext ( subject: "[Jenkins] ${currentbuild.currentresult}: job ${env.job_name} #${env.build_number}", body: """ check console output at <a href="${env.build_url}">${env.job_name} #${env.build_number}</a>""", to: "${env.committeremail}", ) script { // gitlab comment def resulticon = currentbuild.result == 'success' ? ':white_check_mark:' : ':anguished:' addgitlabmrcomment comment: "$resulticon jenkins build $currentbuild.result\n\nresults available at: [jenkins [$env.job_name#$env.build_number]]($env.build_url)" }</code></pre><p> }<br>}</p><h4 id="4-1-5-权限管理"><a href="#4-1-5-权限管理" class="headerlink" title="4.1.5 权限管理"></a>4.1.5 权限管理</h4><p>Jenkins 目前已经对接了公司的单点登录,权限是基于角色进行管理的。在 Manage Jenkins -> Manage and Assign Roles 里进行管理。</p><h4 id="4-1-5-一些-Jenkins-插件的使用介绍"><a href="#4-1-5-一些-Jenkins-插件的使用介绍" class="headerlink" title="4.1.5 一些 Jenkins 插件的使用介绍"></a>4.1.5 一些 Jenkins 插件的使用介绍</h4><blockquote><p>待完善</p></blockquote><h5 id="4-1-5-1-如何安装插件"><a href="#4-1-5-1-如何安装插件" class="headerlink" title="4.1.5.1 如何安装插件"></a>4.1.5.1 如何安装插件</h5><p>Jenkins 安装插件有多种方式。</p><ol><li>在 Manage Jenkins -> Plugin Manager 里直接安装</li><li>从网站将插件下载下来,放到 $JENKINS_HOME/plugins 目录下,重启 Jenkins 服务</li></ol><p>因为内网的服务器无法正常连接 Jenkins 的插件更新网站,且为了能够方便部署,在服务器有问题时,能够快速恢复服务,切换服务器,我这里选择了第二种方式。</p><p>这里推荐我之前写的脚本,[<a href="https://github.com/arthurzwl/jenkins-ci-plugins-installer],可以方便批量下载插件以及插件的依赖,里面已经列举了常用插件,可以直接使用" target="_blank" rel="noopener">https://github.com/arthurzwl/jenkins-ci-plugins-installer],可以方便批量下载插件以及插件的依赖,里面已经列举了常用插件,可以直接使用</a></p><h3 id="4-2-SonarQube-使用介绍"><a href="#4-2-SonarQube-使用介绍" class="headerlink" title="4.2 SonarQube 使用介绍"></a>4.2 SonarQube 使用介绍</h3><blockquote><p>待完善</p></blockquote><h2 id="5-参考链接"><a href="#5-参考链接" class="headerlink" title="5. 参考链接"></a>5. 参考链接</h2><ul><li>如何理解持续集成、持续交付、持续部署? - yumminhuang的回答 - 知乎 [<a href="https://www.zhihu.com/question/23444990/answer/89426003]" target="_blank" rel="noopener">https://www.zhihu.com/question/23444990/answer/89426003]</a></li><li>Jenkins User Documentation, [<a href="https://jenkins.io/doc/#jenkins-user-documentation]" target="_blank" rel="noopener">https://jenkins.io/doc/#jenkins-user-documentation]</a></li><li>SonarQube Documentation, [<a href="https://docs.sonarqube.org/7.7/]" target="_blank" rel="noopener">https://docs.sonarqube.org/7.7/]</a></li><li>SonarQube. In Wikipedia, [<a href="https://en.wikipedia.org/wiki/SonarQube]" target="_blank" rel="noopener">https://en.wikipedia.org/wiki/SonarQube]</a></li></ul>]]></content>
<summary type="html">
<blockquote>
<p>这是我在公司部署 Jenkins 时写的部署文档&amp;使用手册,现在放到博客上,可以给大家一些参考,以后自己也好回顾。</p>
</blockquote>
<h2 id="1-系统介绍"><a href="#1-系统介绍" class="hea
</summary>
<category term="持续集成" scheme="https://blog.arthurzwl.com/categories/%E6%8C%81%E7%BB%AD%E9%9B%86%E6%88%90/"/>
<category term="jenkins" scheme="https://blog.arthurzwl.com/tags/jenkins/"/>
<category term="CI/CD" scheme="https://blog.arthurzwl.com/tags/CI-CD/"/>
</entry>
<entry>
<title>Hadoop文件读取问题定位分析</title>
<link href="https://blog.arthurzwl.com/2019/01/31/Hadoop%E6%96%87%E4%BB%B6%E8%AF%BB%E5%8F%96%E9%97%AE%E9%A2%98%E5%AE%9A%E4%BD%8D%E5%88%86%E6%9E%90/"/>
<id>https://blog.arthurzwl.com/2019/01/31/Hadoop文件读取问题定位分析/</id>
<published>2019-01-31T10:06:56.000Z</published>
<updated>2019-05-16T06:44:58.624Z</updated>
<content type="html"><![CDATA[<h2 id="问题描述"><a href="#问题描述" class="headerlink" title="问题描述"></a>问题描述</h2><p>后台定时任务并发读取hdfs文件时,出现报错,无法正常读取hdfs上的文件内容。<br>具体错误内容如下:</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">java.io.IOException: Filesystem closed</span><br><span class="line"> at org.apache.hadoop.hdfs.DFSClient.checkOpen(DFSClient.java:<span class="number">883</span>)</span><br><span class="line"> at org.apache.hadoop.hdfs.DFSClient.getFileInfo(DFSClient.java:<span class="number">2114</span>)</span><br><span class="line"> at org.apache.hadoop.hdfs.DistributedFileSystem$<span class="number">21</span>.doCall(DistributedFileSystem.java:<span class="number">1300</span>)</span><br><span class="line"> at org.apache.hadoop.hdfs.DistributedFileSystem$<span class="number">21</span>.doCall(DistributedFileSystem.java:<span class="number">1296</span>)</span><br><span class="line"> at org.apache.hadoop.fs.FileSystemLinkResolver.resolve(FileSystemLinkResolver.java:<span class="number">81</span>)</span><br><span class="line"> at org.apache.hadoop.hdfs.DistributedFileSystem.getFileStatus(DistributedFileSystem.java:<span class="number">1312</span>)</span><br><span class="line"> at org.apache.hadoop.fs.FilterFileSystem.getFileStatus(FilterFileSystem.java:<span class="number">416</span>)</span><br><span class="line"> at org.apache.hadoop.fs.viewfs.ChRootedFileSystem.getFileStatus(ChRootedFileSystem.java:<span class="number">224</span>)</span><br><span class="line"> at org.apache.hadoop.fs.viewfs.ViewFileSystem.getFileStatus(ViewFileSystem.java:<span class="number">379</span>)</span><br><span class="line"> at org.apache.hadoop.hdfs.FederatedDFSFileSystem.getFileStatus(FederatedDFSFileSystem.java:<span class="number">721</span>)</span><br><span class="line"> at org.apache.hadoop.fs.FileSystem.exists(FileSystem.java:<span class="number">1426</span>)</span><br></pre></td></tr></table></figure><h2 id="问题定位"><a href="#问题定位" class="headerlink" title="问题定位"></a>问题定位</h2><p>通过日志内容,我们可以发现,在我们调用FileSystem.exists方法时,底层调用的DFSClient.checkOpen方法抛出了IOException异常,FileSystem closed,可以大概确认是FileSystem异常关闭导致的问题。FileSystem 实现了Closeable接口,根据我们日常的最佳编程实践,一般在申请IO资源后,IO操作结束后都会调用close方法释放资源。代码里我们也确实使用JDK7 try-with-resources释放了FileSystem,难道这里有问题,或者是我们获取FileSystem的方法有问题吗?带着这些问题我继续查看了FileSystem的源码。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">public</span> <span class="keyword">static</span> FileSystem <span class="title">get</span><span class="params">(URI uri, Configuration conf)</span> <span class="keyword">throws</span> IOException </span>{</span><br><span class="line"> String scheme = uri.getScheme();</span><br><span class="line"> String authority = uri.getAuthority();</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (scheme == <span class="keyword">null</span> && authority == <span class="keyword">null</span>) { <span class="comment">// use default FS</span></span><br><span class="line"> <span class="keyword">return</span> get(conf);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (scheme != <span class="keyword">null</span> && authority == <span class="keyword">null</span>) { <span class="comment">// no authority</span></span><br><span class="line"> URI defaultUri = getDefaultUri(conf);</span><br><span class="line"> <span class="keyword">if</span> (scheme.equals(defaultUri.getScheme()) <span class="comment">// if scheme matches default</span></span><br><span class="line"> && defaultUri.getAuthority() != <span class="keyword">null</span>) { <span class="comment">// & default has authority</span></span><br><span class="line"> <span class="keyword">return</span> get(defaultUri, conf); <span class="comment">// return default</span></span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> String disableCacheName = String.format(<span class="string">"fs.%s.impl.disable.cache"</span>, scheme);</span><br><span class="line"> <span class="keyword">if</span> (conf.getBoolean(disableCacheName, <span class="keyword">false</span>)) {</span><br><span class="line"> <span class="keyword">return</span> createFileSystemWithConfigurationService(uri, conf);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">return</span> CACHE.get(uri, conf);</span><br><span class="line">}</span><br></pre></td></tr></table></figure><p>我们使用的是静态方法FileSystem.get(uri, conf) 获取的FileSystem实例。通过源码查看,我们可以发现这个静态方法并不是每次都穿件一个全新实例,而是默认去缓存里获取实例。</p><p>进一步查看FileSystem$Cache的源码,我们可以看到缓存使用了HashMapp<Key, FileSystem>存储了每次创建的FileSystem实例,并使用同步代码块保证线程安全问题。Key是通过uri和conf创建的,而在我们的代码里uri和conf在访问相同集群时是一样。这样就导致了在并发访问同一集群时,多个线程共享使用的同一个FileSystem实例,如果一个线程关闭了资源,另一个线程没有执行完,那么势必会导致抛出IOException Filesystem closed异常。</p><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 只截取了部分源码</span></span><br><span class="line"><span class="keyword">static</span> <span class="class"><span class="keyword">class</span> <span class="title">Cache</span> </span>{</span><br><span class="line"></span><br><span class="line"> <span class="keyword">private</span> <span class="keyword">final</span> Map<Key, FileSystem> map = <span class="keyword">new</span> HashMap<Key, FileSystem>();</span><br><span class="line"></span><br><span class="line"> <span class="function">FileSystem <span class="title">get</span><span class="params">(URI uri, Configuration conf)</span> <span class="keyword">throws</span> IOException</span>{</span><br><span class="line"> Key key = <span class="keyword">new</span> Key(uri, conf);</span><br><span class="line"> <span class="keyword">return</span> getInternal(uri, conf, key);</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="function"><span class="keyword">private</span> FileSystem <span class="title">getInternal</span><span class="params">(URI uri, Configuration conf, Key key)</span> <span class="keyword">throws</span> IOException</span>{</span><br><span class="line"> FileSystem fs;</span><br><span class="line"> <span class="keyword">synchronized</span> (<span class="keyword">this</span>) {</span><br><span class="line"> fs = map.get(key);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">if</span> (fs != <span class="keyword">null</span>) {</span><br><span class="line"> <span class="keyword">return</span> fs;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="keyword">if</span> (conf.getBoolean(<span class="string">"dfs.client.filesystem.leak.debug"</span>, <span class="keyword">false</span>)) {</span><br><span class="line"> <span class="keyword">try</span> {</span><br><span class="line"> <span class="keyword">throw</span> <span class="keyword">new</span> IllegalThreadStateException(<span class="string">"New file system instance is created"</span>);</span><br><span class="line"> } <span class="keyword">catch</span> (IllegalThreadStateException e) {</span><br><span class="line"> LOG.error(<span class="string">"Create a new file system for key: "</span> + key + <span class="string">" cache size: "</span> + map.size(), e);</span><br><span class="line"> }</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> fs = createFileSystemWithConfigurationService(uri, conf);</span><br><span class="line"> <span class="keyword">synchronized</span> (<span class="keyword">this</span>) { <span class="comment">// refetch the lock again</span></span><br><span class="line"> FileSystem oldfs = map.get(key);</span><br><span class="line"> <span class="keyword">if</span> (oldfs != <span class="keyword">null</span>) { <span class="comment">// a file system is created while lock is releasing</span></span><br><span class="line"> fs.close(); <span class="comment">// close the new file system</span></span><br><span class="line"> <span class="keyword">return</span> oldfs; <span class="comment">// return the old file system</span></span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="comment">// now insert the new file system into the map</span></span><br><span class="line"> <span class="keyword">if</span> (map.isEmpty()</span><br><span class="line"> && !ShutdownHookManager.get().isShutdownInProgress()) {</span><br><span class="line"> ShutdownHookManager.get().addShutdownHook(clientFinalizer, SHUTDOWN_HOOK_PRIORITY);</span><br><span class="line"> }</span><br><span class="line"> fs.key = key;</span><br><span class="line"> map.put(key, fs);</span><br><span class="line"> <span class="keyword">if</span> (conf.getBoolean(<span class="string">"fs.automatic.close"</span>, <span class="keyword">true</span>)) {</span><br><span class="line"> toAutoClose.add(key);</span><br><span class="line"> }</span><br><span class="line"> <span class="keyword">return</span> fs;</span><br><span class="line"> }</span><br><span class="line"> }</span><br></pre></td></tr></table></figure><h2 id="问题解决"><a href="#问题解决" class="headerlink" title="问题解决"></a>问题解决</h2><p>发现问题以后,我们如何解决呢?<br>通过阅读代码和网上搜索,目前大概有三种解决方案:</p><ol><li>代码里使用FileSystem最后不调用close方法</li><li>设置 fs.hdfs.impl.disable.cache 为true,关闭缓存</li><li>使用 FileSystem.newInstance 方法,每次获取新的实例</li></ol><p>关于第三种方法,在网上搜索的过程中,我发现<a href="https://issues.apache.org/jira/browse/HADOOP-4655" target="_blank" rel="noopener">HADOOP-4655</a>以前有人也在类似的使用场景下遇到了同样的问题,他们最终的解决方案是修改了API,增加了newInstance静态方法。</p><p>方案选择上,基于我们的使用场景,低频次的离线后台任务,对时间不是很敏感,并不需要长时间保持连接,我选择了方案三。</p>]]></content>
<summary type="html">
<h2 id="问题描述"><a href="#问题描述" class="headerlink" title="问题描述"></a>问题描述</h2><p>后台定时任务并发读取hdfs文件时,出现报错,无法正常读取hdfs上的文件内容。<br>具体错误内容如下:</p>
<fig
</summary>
<category term="大数据" scheme="https://blog.arthurzwl.com/categories/%E5%A4%A7%E6%95%B0%E6%8D%AE/"/>
<category term="hadoop" scheme="https://blog.arthurzwl.com/tags/hadoop/"/>
</entry>
</feed>