修改blog防火墙设置

      最近发现了一个叫推酷的网站,非常恶心,把你的内容抓取后放到了他的网站上,其它用户搜索直接到他的网站,好听点叫聚合,难听点就是偷窃,虽然给了一个链接地址,但是你的所有内容都能够在他的网站访问。

      看到网上也有人提到这个问题,没办法,对待这种臭流氓就是封杀,把他的网段搞死,查看apache日志,它是通过rss来抓取,一开始想要把rss全部停用,后来觉得得不偿失,看了下他的ip就是三个:

211.144.76.143
211.144.76.144
211.144.76.244

      加防火墙规则,把他的网段给封了。中国人是不是就没有知识产权的概念啊!

近况

     最近去北欧四国旅行,感受大自然之美,看到了极光,自驾300KM。2015,开始了。

JAVA对象内存layout

       迟到的文章,4年前就有所研究,但是总是用的时候现看,补上这篇blog,方便自己查询记忆。 通常情况上来说,Java程序员不需要了解对象在内存中的情况,这是一件非常幸福的事情,不需要malloc,free等等,更不需要管垃圾回收。但是,在一些情况下,比如内存占用非常大的应用(像hadoop namenode),就需要对内存占用十分敏感,比如我之前的blog曾经计算过,如果大规模设置ACLs后对hadoop集群内存的压力。 这种情况就需要仔细的计算java类的内存使用情况,一点点的内存节省,当面临成千万的对象的时候效果就会很明显。

       JAVA对象内存计算分为shallow size和deep size。shallow size就是这个对象自己占用的内存空间,包括有基本数据类型占用的内存,其它reference对象的reference 占用的内存。和deep size就是这个除了这个对象自己占用的内存空间,再加上reference对象的占用内存综合。我更感兴趣的是deep size。 一下所有计算都是按照64 bit进行的,32 bit请自行查询。默认情况下java6都是开启-XX:+UseCompressedOops,会对object 的header计算有影响。

        64 bit object的header压缩的占用12byte,不压缩的占用16byte,包括有对象类型的指针,锁信息,以及hash等等。 基本的类型内存占用如下: mem1

       对象的reference64位不压缩的占用8 bytes, 开启压缩占用4 bytes。

       内存layout规则如下:

       1、对象在内存中都是8字节对齐的,即内存计算后不能被8整除,要补充到8字节对齐

       2、基本数据类型也需要对齐,根据类型占用字节数对齐,比如long、double8字节对齐, int,float 4字节对齐

       3、在多数情况下,由于对齐的原因,JVM会按照类型占用的字节多少排列顺序,占用多的排在前面,占用少的排在后面,对象的reference排在最后。比如:

class MyClass {
   byte a;
   int c;
   boolean d; 
   long e;
   Object f; 
}

       如果按照定义的顺序,那么内存使用如下,总共有14 bytes的padding。

[HEADER: 16 bytes] 16 
[a: 1 byte ] 17
[padding: 3 bytes] 20 
[c: 4 bytes] 24 
[d: 1 byte ] 25 
[padding: 7 bytes] 32 
[e: 8 bytes] 40 
[f: 4 bytes] 44 
[padding: 4 bytes] 48

       如果按照大小排列,也就是2中的规则排列,少使用了6 bytes。

[HEADER: 16 bytes] 16 
[e: 8 bytes] 24 
[c: 4 bytes] 28 
[a: 1 byte ] 29 
[d: 1 byte ] 30 
[padding: 2 bytes] 32 
[f: 4 bytes] 36 
[padding: 4 bytes] 40

       4、class field之间不会混在一起,如果class B extends class A,那么父类所有field先去排列,接下来是子类,同时子类起始位置需要对齐4 byte。

       5、对于数组来说,header除了上面说的以外,还需要加入8 bytes,标识array 长度

DataNode BlockReport bug解决(二)

三、bug复现

       测试环境生成一个5M的测试文件,文件路径为/test/missdisk/part-m-0000,fsck查看了一下,该文件只有一个block,blockid为blk_1074399823_659259,该block的三个副本分别分布在5.42、5.26和5.27上面。

为了重现问题,选择5.26和5.27停掉DN,同时在5.42上面将将存放块blk_1074399823的盘data6下线。

       使用命令 echo “scsi remove-single-device 00 02 06 00″ > /proc/scsi/scsi

       

       查看5.42的DN日志,日志显示FsDatasetImpl移除data6盘,同时从FsDatasetImpl的数据结构中移除data6上面的所有副本信息,5.42会errorReport 将data6盘掉盘信息汇报给NN,NN记录下了。但是NN并没有将该盘上面的块信息从NN的数据结构blockmap中移除,由于5.26和5.27的DN停掉了,所以这个时候NN会从5.42上面仅存的副本(实际上已经坏了)repicate到其他两个节点上面去。当从5.42拷贝数据副本到其他节点时,实际上DN认为该副本其实已经损坏,并将块损坏了不能拷贝到其他节点上报给NN,最终副本拷贝失败。等待一段时间之后执行fsck,发现nn显示42节点副本是好的,但是get文件时报错。50070页面显示没有missing block,但是在Live Nodes页面对应的DN又有Failed Volumes。该问题成功重现。


四、解决方案

https://issues.apache.org/jira/browse/HDFS-7208?jql=project%20%3D%20HDFS%20AND%20text%20~%20errorReport

社区提出了解决这个问题的四种方案:

1、DN通过DatanodeProtocol.reportBadBlocks将坏盘中对应的数据块信息通知NN,让NN从数据结构中移除这些块信息。这种方式比较慢,因为每次只能上报一个block。

2、DN通过 DatanodeProtocol.errorReport将坏盘的storageId告诉给NN,从而让NN移除storageId下面所要的块信息,这种方式需要修改DatanodeProtocol.errorReport接口,增加storageId参数,同时DN端代码需要大量调整,比较麻烦。 

3、DN通过blockReport的方式告诉NN有坏盘,并从NN中移除坏盘中得数据块信息,由于blockReport每6小时才会执行一次block的全量汇报,这种方式会有很大的延迟。

4、DN通过心跳的方式告诉NN有坏盘,并从NN中移除坏盘中得数据块信息,社区提供的patch就是基于这种方式。这种方式不用只用修改NN端的代码。


DataNode BlockReport bug分析(一)

一、现象描述

       上周2.4集群迁移升级,使用平滑升级将中心机从较差的几台机器迁移到真正的中心机服务器上,升级前原始中心机一切状态都是正常的,不存在丢块等问题,将image等文件拷贝到新集群并启动一起正常,随后将所有DataNode重启,将ns地址换位新中心机节点地址,汇报所有block,猛然发现竟然后18个missing block。回滚后,重新将ns地址位置换位老中心机节点地址,重启所有DataNode发现竟然也有missing block,没有办法只能将ns地址还是换为新中心机地址,重启DataNode,继续向下升级。

       第二天去调查这个问题,可以肯定的是原先中心机内存中blockmap肯定是不正确的,深入调查这个问题,从文件入手,看块的分布,得到了以下情况分(只分析一个文件中的一个block)。

       1、9月30号,block被写入,三个副本,分别写入到A,B,C三台机器,一切正常,pipeline无异常,block 文件写入datanode没有问题,说明在这一时刻没有任何问题。

                                                Miss1

       2、10月10号问题产生了

       机器A  /data10在13:00磁盘损坏,机器B,机器C由于服务器硬件问题,分别在13:57和14:15下线。按照以前的方式,这种方式没有任何问题,每下线一台服务器都会等足够的时间,使namenode将under  replica给repicate出去,保证3副本的稳定性。

       然而机器B、C下线后,namenode一直认为机器A是正常的,并且反复要求机器A去replicate block。A机器由于磁盘损坏,没有该Block反复报错。

                                               Miss2

                                                   Miss3

       至此,该Block丢失,但是NameNode仍然认为机器A保留该块,产生了严重的问题。

 

 

二、产生原因

       首先看一下DataNode BlockReport及Disk Error处理流程。DataNode默认第一次启动以及稍后的每六个小时向NameNode汇报一次全量数据,其它时候只汇报增量数据。

       Block Report流程为: 

       1、BPServiceActor读取每个盘的所有Block数据,包括finalized和underConstrunction

                                         Miss4

       2、如果block过多(超过1M),会按照磁盘分批发送,否则一次发送 

                                          Miss5

一般不会超过1M,所以都是一次发送,但是注意,blockReport方法第三个参数reports是一个数组,表示每个磁盘对应的不同storageId所有的block。

       如果磁盘没有问题的话这个逻辑没有什么问题,但是,假如磁盘除了问题,同时设置了dfs.datanode.failed.volumes.tolerated这个参数,就出现了问题。

       dfs.datanode.failed.volumes.tolerated是DataNode可容忍出错的磁盘数,默认是0,它指的是当磁盘损坏多少块时,DataNode 下线,停止提供服务。在我们集群中,这一参数设置为3,即损失3块磁盘仍然能够提供服务。

       为了继续深入研究这个问题,还需要看一下Disk Error的处理流程。对于Hadoop集群,磁盘损坏是非常正常的,较大的集群一天损坏2、3块盘都是可以忍受的。 

       DataNode当接收或者发送Block出现异常时候都会对磁盘进行检查,检查的方法是

                              Miss6

       随后会对每个磁盘进行检查,首先对出现问题的磁盘从FsVolumeList去掉,同时从内存中Block对应存储的映射volumeMap清除。

随后会立即做一次BlockReport,让NameNode迅速将掉的盘中的Block通过别的机器replicate出去。

 

       NameNode中处理Block Report的主要方法是:

                                                Miss7

       参数解释为dn是当前DataNode,storage对应汇报的磁盘,newReport是该DataNode得对应磁盘汇报的所有block,剩下的是经过diff后需要处理的相应block。

       首先看一下0.20.203版本时期的report: 

                              Miss8

 

       DataNode汇报所有Block,NameNode将汇报的所有Block与内存中数据比较,如果多余内存中数据并且该block属于某个INode,则加入ToAdd中,稍后加入blockMap中;如果不属于任何INode,则加入ToRemove,放入invalidateSet中,稍后让DataNode进行删除。如果内存中数据有汇报不存在的Block,则加入ToRemove中,从blockMap中删除该节点对应Block得映射,同时更新neededBlock,即需要replicate的block列表,随后让其他存有该节点的Block将该block repicate出去。

       然而,2.4中并不是全量进行处理,而是按照磁盘处理,这样处理主要是为了异构存储而设计的。这就出现了问题,由于磁盘故障后该磁盘Volume会被清除,这样就不会汇报该Volume得任何信息了。这个磁盘就不会调用reportDiff去更新NameNode中的数据结构,这样NameNode会一直认为这个节点中其实由于磁盘故障而丢失的Block是一直存在的。就出现了我一开始提到的问题。

Hadoop debug 方法

      做hadoop开发,需要对hdfs,mapreduce组件等进行修改、测试,如果每次做修改后都打成jar包上传到服务器打log测试的话将非常麻烦和耗时的。所以如果能够通过eclipse进行远程调试将会非常方便与惬意的。

      hadoop远程调试十分简单,只需要自己hack很少的代码就可以完成。步骤如下:

      首先拷贝$HADOOP_HOME/bin/hadoop   到一个文件如$HADOOP_HOME/bin/hadoop-debug

      在最后一行修改,原来的bash代码是

else # run it exec "$JAVA" -Dproc_$COMMAND $JAVA_HEAP_MAX $HADOOP_OPTS -classpath "$CLASSPATH" $CLASS "$@" fi

      修改为

else
  # run it
  #exec "$JAVA" -Dproc_$COMMAND $JAVA_HEAP_MAX $HADOOP_OPTS -classpath "$CLASSPATH" $CLASS "$@"
   exec "$JAVA" -Xdebug -Xrunjdwp:transport=dt_socket,address=7777,server=y,suspend=y $JAVA_HEAP_MAX $HADOOP_OPTS -classpath "$CLASSPATH" $CLASS "$@"
fi

  address后面是监听的地址,可以改为任意空闲地址。

      启动十分简单,如想要调试DataNode代码,就启动$HADOOP_HOME/bin/hadoop-debug datanode

      这时候会提示监听端口信息。

[××××@×××× bin]$ ./hadoop-debug.sh datanode Warning: $HADOOP_HOME is deprecated. Listening for transport dt_socket at address: 7777

      在本地启动eclipse远程调试,如下图:

      

ganglia配置加入ACL

        经常有配置好的ganglia由于别人拿走配置文件又不熟悉ganglia而无端加入一些不相关的机器,看起来很不舒服。ganglia的ACL正好解决了这一问题,配置方法也很简单,只需在监听UDP选项加入需要监听的机器就可以了。

        例如,我的中心机gmond只想接收来自中心机的gmond信息,我就只配置这些中心机信息就可以了。配置如下:

/* You can specify as many udp_recv_channels as you like as well. */
    udp_recv_channel {
       port = 8649
       acl {
         default = “deny”
         access {
            ip = 10.39.7.21
           mask = 32
           action = “allow”
         }
        access {
           ip = 10.39.7.22
           mask = 32
           action = “allow”
         }
        access {
            ip = 10.39.7.23
           mask = 32
           action = “allow”
        }
       access {
          ip = 10.39.7.24
         mask = 32
         action = “allow”
        }
       }
    }

   这样就可以限制特定IP接收。

 

OSX Mavericks下使用Synergy进行多台主机通过wifi共享键鼠问题的解决方法

转帖:

OSX 10.9 几天用下来还是遇到几处问题的:
之前先是遇到了OSX Mavericks GM598无法从Appstore升级到完全正式版的问题,下载无反应,后来找到了解决方法,发在以下链接:http://bbs.feng.com/read-htm-tid-7161018.html

之后又遇到Synergy不能启动服务的问题,Synergy可是神器哦,多台电脑间跨系统支持键盘和鼠标的共享,win,osx,linux通吃啊。
可是在osx 10.9下居然歇菜了,软件作者暂时没有给出更新版本,通过一番查找,终于发现了临时的解决方案,想用的朋友们往下看:
1. osx 10.9的 开启 允许辅助设备控制 的选项从原先的,偏好设置下的万能辅助,改到了现在的“安全与隐私->“隐私”,解锁后,可单独为应用程序打勾开启权限,我们给Synergy勾上,虽然这是没用的…hehe,Synergy服务依然无法启动,会继续提示你去开启这个选项。

2. 如果已经启动,则先退出之前打开的Synergy,打开命令行,输入sudo open /Applications/Synergy.app/Contents/MacOS/Synergy
输入你的密码后,现在就从命令行启动了Synergy了,再次进入“安全与隐私->“隐私”后,你会发现列表中多了一个“终端”项,给它打上勾。

3. 勾刚打上,应此之前启动的Synergy是没有权限的,所以还是先退出Synergy和“终端”,然后重新从“终端"用 /Applications/Synergy.app/Contents/MacOS/Synergy 直接打开,此时你就可以顺利启动服务了。

造成这个问题的原因,官网论坛上有人认为是苹果改动了辅助授权API后,使得权限不再从主程序继承到子线程或进程,导致Synergy出问题,到底怎么回事现在不得而知,咱们也就不去操那闲心了,只是为了方便起见,大家可以写个unix命令文件,免得每次启动都得从终端输命令。

java.lang.IncompatibleClassChangeError 错误分析

    最近帮助同事把之前给他搭建的Hadoop2.2集群升级到2.4,并将之前我们做的实时应用程序迁移部署到Hadoop2.4上。

       在迁移的过程中,他发现之前通过Scribe客户端向Scribe中继发送日志的程序总是报错,异常日志是:

java.lang.IncompatibleClassChangeError: com/sina/mis/calligraphus/thrift/CalligraphusService$Client
	at com.sina.mis.client.ClientMulti.connect(ClientMulti.java:176)
	at com.sina.mis.client.ClientMulti.access$100(ClientMulti.java:37)
	at com.sina.mis.client.ClientMulti$1.run(ClientMulti.java:156)
	at java.util.TimerThread.mainLoop(Timer.java:512)
	at java.util.TimerThread.run(Timer.java:462)

      看一场应该是接口或者类的实现改变,导致的IncopatibleClassChangeError。 仔细检查了一下出错的代码为  inco1       分析一下Client一直是个抽象类,没有问题,Iface一直是接口也没有问题,出问题的就在TServiceClient接口上,联想到之前也是遇到过这个问题,Thrift在0.7以后这个接口就变成了抽象类,导致了implements报错,仔细的查看了一下集群上面使用这个累的jar包,确定是hive-exec.jar,反编译以后得到了印证:

col1

      最后解决方法,目前想到的是修改程序,明天查看一下是否可以通过选项将用户提交的jar包覆盖父类继承的CLASSPATH。

Jvm 参数选取顺序

      Jvm会选取最右侧的参数作为有效参数,当参数重复的时候,比如在Hadoop中修改启动的Jvm内存大小,需要将-Xmx或者-Xms放在最右侧,才能生效。