jdk8_cannot_access_class_file

之前有个项目用 jdk6跑运行正常,用 jdk8跑的时候,会报java cannot access ....class file ...as class file not found though it exists. 虽然可以通过加上报错的类到依赖里解决.但是一直没想明白,为啥 jdk6下没报错. 最近再次遇到,于是想一次性搞清楚.搜了一下,看 so 上有这么个说法.大意就是以前,如果 A 依赖 B,B 实现了 C 接口,编译的时候, 用 jdk8编译的时候, C 必须在 classpath 中, http://stackoverflow.com/questions/40255718/compiling-with-jdk-1-8-java-cannot-access-class-file-class-file-not-found 给出了一个 bug 连接,但是这里跟我们的问题有差异,不过这个点提醒了我.于是我搜索了一下 jdk8的relase note http://www.oracle.com/technetwork/java/javase/8-compatibility-guide-2156366.html 注意观看这一段: Area: Tools / javac Synopsis Interfaces need to be present when compiling against their implementations 好了.也就是说还是乖乖加依赖.但是清楚了原因了……

阅读全文

oom介绍

oom 之前知道, 但是并不是很了解,最近遇到了由 oom 引发的问题,所以学习记录一下. OOM-killer:Out-of-Memory (OOM) Killer是一种保护机制,用于当内存严重不足时,为了系统的继续运转,内核迫不得已挑选一个进程,将其杀死,以释放内存,缓解内存不足的问题。 可以看出这种方式对进程的保护是有限的,不能完全的保护进程的运行。 如何知道是否发生了 oom 两种方法,第一种,查看 /var/log/messages,会有类似 Out of memory: Kill process 9682 (mysqld) score 9 or sacrifice child Killed process 9682, UID 27, (mysqld) total-vm:47388kB, anon-rss:3744kB, file-rss:80kB httpd invoked oom-killer: gfp_mask=0x201da, order=0, oom_adj=0, oom_score_adj=0 httpd cpuset=/ mems_allowed=0 Pid: 8911, comm: httpd Not tainted 2.6.32-279.1.1.el6.i686 #1 这样的标识,说明发生了 oom,关键就是 kill process, 所以可以这样 sudo cat /var/log/messages | grep -i"killed process" 另一种是通过dmesg来查看 dmesg | egrep -i 'killed process' 这个命令查看的 oom 的时间里是时间戳的形式,如果你的 dmesg 没有-T这个时间的选项,那么就需要通过 date -d "1970-01-01 UTC `echo "$(date +%s)-$(cat /proc/uptime|cut -f 1 -d' ')+12288812.926194"|bc ` seconds" 来转换成可读的时间了. oom 的原理 其中涉及到有三个相关文件: /proc/$PID/oom_adj /proc/$PID/oom_score /proc/$PID/oom_score_adj 其中 oom_score 表示最终的分数,该分数越大,越可能被 Killer 杀掉。 而 oom_adj 是调整分数的,可以设置为负值,会对 oom_score减分。 从Linux 2.6.36开始都安装了/proc/$PID/oom_score_adj,此后将替换掉/proc/$PID/oom_adj。即使当前是对/proc/$PID/oom_adj进行的设置,在内核内部进行变换后的值也是针对/proc/$PID/oom_score_adj设置的。可以参见feature-removal-schedule这里 171行. 通过 cat /proc/$PID/oom_score 可以查看进程的得分 打分算法在这里 https://github.com/torvalds/linux/blob/master/mm/oom_kill.c 从上面的 oom_kill.c 代码里可以看到 oom_badness() 给每个进程打分,根据 points 的高低来决定杀哪个进程,这个 points 可以根据 adj 调节,root 权限的进程通常被认为很重要,不应该被轻易杀掉,所以打分的时候可以得到 3% 的优惠(adj -= 30; 分数越低越不容易被杀掉)。我们可以在用户空间通过操作每个进程的 oom_adj 内核参数来决定哪些进程不这么容易被 OOM killer 选中杀掉。比如,如果不想 MySQL 进程被轻易杀掉的话可以找到 MySQL 运行的进程号后,调整 oom_score_adj 为 -15(注意 points 越小越不容易被杀):范围是从-1000 到 1000,参考这里……

阅读全文

graylog日记管理平台使用的那些坑

前言 最近使用 graylog在部署日志平台的时候,踩到很多"坑”,记录一下 日志采集(nxlog) 1.客户端不要做太多的正则计算 graylog 最早推荐的 nxlog 采集客户端,现在貌似有了 beats 的采集方式,不过我没了解,nxlog 采集的话,需要配置Snippets,就是定义输入,输出,处理器的地方,这个地方, Input 模块是在客户端计算的.所以,一定不要进行太多的正则计算.否则会严重影响客户端的 cpu 资源.降低应用程序的性能. 2.开多行一定要慎重 graylog 可以通过配置 <Extension multiline> Module xm_multiline HeaderLine /^\d{0,2}\/\d{0,2}\/\d{0,4}/ EndLine /^\d{0,2}\/\d{0,2}\/\d{0,4}/ </Extension> <Input pcc-esolutions-log> Module im_file File "*.log" SavePos TRUE InputType multiline </Input> 来实现对于类似错误栈这样的信息,将多行采集成一行,但是一定要注意.如果这个正则写错了,或者其他原因,导致,未能正确匹配.会导致 nxlog 客户端占用内存暴涨.原因是为了实现多行采集,会再客户端内存中保存日志内容,直到匹配到行尾.如果未能正确匹配.会一直保存.导致内存泄露. 这时候一般伴随着nxlog 的客户端日志中开始打印: 2016-12-05 18:36:47 ERROR oversized string, limit is 1048576 bytes 这样的信息.表示单条日志超过了1m 最终有一定几率影响客户端应用,被 oom 所杀.不要问我怎么知道的… 3 日志就是太大怎么办. 貌似没办法..只能在 Input 配置中. Exec if $raw_event $raw_event = substr($raw_event, 0, 1040000); 执行类似的来限制,没有尝试过,参考这里:日志大小超长配置 服务端处理(graylog) 1.服务端性能不好的情况下也不要做大量正则 日志处理这部分主要是说 graylog 自身的处理,graylog 是 cpu 密集型的,在收到了 nxlog 经过少量计算的日志后, graylog 其实还提供了 extrator 的功能来解析字段,当时我因为部署了很多应用的日志采集,为了生成一个统一的索引字段,我在extrator写了一个正则,对于所有的消息,根据这个正则找到一个字段,来作为 key(保存成 no), 可能一个流水号,这样我就可以根据 no:xxx 来查询所有相关的日志了. 结果这个正则写了以后, graylog 处理性能急剧下降.开始大量积压消息.无法发送给后端的 es 来做处理.在 graylog 的管理页面,能明显看到 in 是几千, out 是几百..很快 node 节点就废了. 参考:Very slow process message 如果是确定不是 graylog 的问题, output 还是慢,可以尝试修改输出的并发量来解决,改改 graylog 配置中的output_batch_size值. 2.journal如果太多,可能导致graylog 状态 dead 由于我前面的问题,导致 journal 中保存了太多的日志,这样会导致两个问题,1,启动的时候会尝试吧这些日志全部加载 graylog 服务端的内存中.这时候,如果应用内存不够,直接会启动不了报java 的 oom, 2016-12-04T12:25:36.543+02:00 ERROR [ServiceManager] Service JournalReader [FAILED] has failed in the RUNNING state. java.lang.OutOfMemoryError: Java heap space at java.……

阅读全文

graylog中的mongodb配置

接手的一个工具平台,发现 graylog 集群使用了单个的 mongodb 作为数据库,于是需要配置一下集群,来防止数据丢失,毕竟很多配置都在里面. 为了以防万一,先备份一下 graylog 的配置. mongodump -h dbhost -d dbname -o dbdirectory 防止分布式部署的使用搞坏了.之后的恢复可以使用 mongorestore -h dbhost -d dbname --directoryperdb dbdirectory 来恢复.相关说明可以参考这里 之后就可以正式开始了 修改集群名字 在/etc/mongod.conf 中,修改这个值.设置集群使用的集群名称是 graylog,几个机器都配置一下.都先不要启动 replication: replSetName: graylog 然后添加集群配置 启动其中一台,然后通过mongo 命令连接上数据库,依次执行下面的命令.注意,这里有个坑.添加本机的时候,一定要写对外的域名或者 ip.否则会导致无法选主. rs.initiate() rs.add("<hostname>:27017") rs.add("<hostname>:27017") rs.add("<hostname>:27017") rs.conf() 开始启动 这里启动就不用说了. service mongod start 启动就好了. 配置 graylog 集群连接地址 在/etc/graylog/server/server.conf 中配置.mongodb_uri = mongodb://host1,host2,host3/graylog 后面这个 graylog 就是给 graylog 使用的库名,你可以先创建. 之后mongodb 就开始自行同步了. [参考] 高可用的MongoDB集群 ​……

阅读全文

graylog中的字段解析

关于字段解析 一旦 graylog 用在了一个分布式系统上,那么采集的日志格式多种多样,涉及到通过 rules.drl来解析具体的字段.之前的同学的方案是用drools 来完成的.通过一个统一的界面,来给用户生成一些正则规则这种.然后自己写了个转换器转成 Drools 的文件.更新到 graylog 的服务器上.然后重启gralog 应用完成. 实际上, graylog 2之后的版本提供了rules和 pipeline ,这种不需要重启应用,完成这个解析的动作.但是.注意.这个不完善.所以只支持一些简单的语法,无法实现原有的完全转换.所以放弃. 在此过程中.这个rules 有一个比较强大的功能,自动解析 key value 对.需要添加,但是,需要你的日志文件格式里的 key value有空格, 也就是要求必须是 key=value 这样,不能紧挨着逗号这样的..比如你的打印日志是 key=value,key2=value2.那么久无法解析了..这个暂时没看到比较好的办法.估计要改代码.如果你恰好符合.那最好了.……

阅读全文

mac日志批量查询配置

由于公司线下机器非常多,导致每次查日志变得非常痛苦.线下的trace平台大部分时候还是可用的.但是有时候需要本机来批量查询.方案就是批量分发ssh key,实现免登.然后luit实现编码转换,这个主要是公司的机器编码有差异.历史原因. 0. 准备 先要安装pssh,expect,ssh-copy-id. brew install pssh brew install homebrew/dupes/expect brew install ssh-copy-id 另外安装luit的安装参考这里luit安装 1. 生成ssh key ,并批量copy 生成ssh key比较简单.ssh-keygen -t rsa -C "your_email@example.com",直接使用git的ssh key也是可以的.然后保存下面这个脚本为pscopy.sh, #!/bin/bash FILE=`cat ~/host.txt` for ip in $FILE;do expect -c "spawn ssh-copy-id $ipexpect { \"*yes/no*\" {send \"yes\r\";exp_continue} \"*password*\" {send \"pass\r\";exp_continue} \"*password*\" {send \"pass\r\";} } " done 然后执行一下sh pscopy.sh,注意,host.txt要保证存在.格式是user@address.一行一个,中间的paas要改成user的密码,这样就会使用指定的用户密码,自动copy ssh key了. 完成上面的步骤之后,ssh user@address 就可以免登了. 2. 写一个简单的pssh脚本 #!/bin/bash encoding= key= command= file= usage() { echo "Usage: `basename $0` [-f filename] [-c encoding] [-k keyword]" exit 1 } while getopts :f:c:k: opt do case $opt in c) encoding=$OPTARG ;; :) echo "-$OPTARGneeds an argument" ;; k) key=$OPTARG ;; f) file=$OPTARG ;; *) echo "-$optnot recognized" usage ;; esac done if [ -z "$encoding" ]; then #该脚本必须提供-d选项 encoding="gbk" fi if [ -z "$file" ]; then #该脚本必须提供-d选项 file="~/hosts.txt" fi if [ -z "$key" ]; then #该脚本必须提供-d选项 usage fi command="pssh -h $file-P \"find /home/admin/logs/ -name '*.……

阅读全文

修改mac单应用创建线程的限制

最近遇到一个问题,公司的 java 服务端应用,启动后,通过 jstack pid |grep nid -c,可以看到大概创建了2044个线程,然后此时应用就会报错,提示无法创建更多线程, jvm 开始抛错. 查看 mac 的内存,发现还是够的.因为一般认为可创建的线程数=(总内存-其他占用的内存)/线程大小,所以内存够的情况下,应该是能创建的. google 一圈,发现mac 对单线程创建的线程是有限制的.理由应该是为了保持系统稳定性.主要有两个参数 sysctl kern.num_threads 这个可以看一下,说明了系统能够创建的总共的线程,单个应用能够创建的线程是sysctl kern.num_taskthreads,第二个参数就是导致我们创建不出来更多线程的原因, 因为2044+一些 gc 的线程,基本上刚刚达到这个极限. 那么要么改程序,要么改参数.改程序这是不可能的..因为只有 mac 会有这个问题..该参数尝试通过sudo sysctl -w kern.num_taskthreads=4096,修改,会发现提示是只读属性.google 了一圈,无解. 最终意外解决.. 参考这里开启性能模式 nvram boot-args sudo nvram boot-args="serverperfmode=1 $(nvram boot-args 2>/dev/null | cut -f 2-)" 重启 如果想要恢复的话: sudo nvram boot-args="$(nvram boot-args 2>/dev/null | sed -e $'s/boot-args\t//;s/serverperfmode=1//')" 当时各种搜索,加打apple 支持电话.无解.搜索意外看到这个说明,说开启之后,可以支持更多服务应用之类的.猜测应该会改这个值..果然..改完之后,直接重启,这个限制会变成5000..完美解决..理论上,应该通过继续修改这个参数 是可以自定义这个值的.不过还没尝试.……

阅读全文

homebrew缓慢解决方案

mac 下使用 homebrew 作为包管理工具是非常好的. brew 用来安装非 gui 界面的程序. cask 用来安装 gui 界面的程序.但是这两个是使用的源在国外.所以你懂得.. 1.替换 homebrew 默认源 cd /usr/local git remote set-url origin git://mirrors.ustc.edu.cn/brew.git 这里注意记一下以前的默认源.防止以后想换回来.. 默认源是 https://github.com/Homebrew/brew 2.替换homebrew bottles默认源 echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles' >> ~/.bashrc 这里的.bashrc根据自己的情况替换.我是 zsh,就写到.zshrc 文件.……

阅读全文

mac使用全局代理

自从入了 hexo 的坑.这玩意折腾的我不要不要的.各种诡异的问题,不过也顺便搞了搞其他的东西.看了很多相关的代理设置方案.最终沿用 windows 下的策略.最简单高效. mac 下的 ss 代理是只能设置浏览器代理的.对于一些不走 http 代理的.比如终端.或者其他软件.那么就需要将 ss 代理指定给其他软件或者终端使用. 1.有一个 ss 代理 2.安装proxifier,直接 brew cask install proxifier 3.安装好之后,添加Proxies 里面,把 ssh 的信息添加进入 4.添加 Rules, 我为了简单..直接将default 设置成走代理.这样,就啥也不用管了.等 hexo deploy 结束.再关闭proxifier 就行了. 实际使用中.可以先开全局代理.然后知道哪个程序走了代理.需要走代理.然后单独设置即可.软件很好使用. 不得不说, wall 越来越令人难受与不安.……

阅读全文

sourceTree设置使用svn

mac 下面不想安装多个 GUI 的 svn 客户端.所以使用 sourceTree 来做. sourceTree 对于 svn 只能从远程 url 拷贝.不能从本地来.所以在 gui 页面进行添加 但是会发现报错 Can't locate SVN/Core.pm in @INC (you may need to install the SVN::Core module) (@INC contains: 网上搜了一下.原因是 Perl 升级后 版本路径不对.于是执行 sudo ln -s /Applications/Xcode.app/Contents/Developer/Library/Perl/5.18/darwin-thread-multi-2level/SVN /System/Library/Perl/Extras/5.18/SVN sudo ln -s /Applications/Xcode.app/Contents/Developer/Library/Perl/5.18/darwin-thread-multi-2level/auto/SVN/ /System/Library/Perl/Extras/5.18/auto/SVN 这里就是创建两个软连接.以便 sourceTree 识别.这里注意.如果你装了 Xcode 的 CommandLineTools, 而不是完整的 Xcode. 那么你的目录是没有这个原始文件的所以需要执行的 sudo ln -s /Library/Developer/CommandLineTools/Library/Perl/5.18/darwin-thread-multi-2level/SVN /System/Library/Perl/Extras/5.18/SVN sudo ln -s /Library/Developer/CommandLineTools/Library/Perl/5.18/darwin-thread-multi-2level/auto/SVN/ /System/Library/Perl/Extras/5.18/auto/SVN 但是执行的时候还是会报错.因为新版本的 mac系统.已经不允许在 System 目录写文件了.除非关闭安全选项.这就得不偿失了. 但是从stackexchange说法看. mkdir /Library/Perl/5.18/auto sudo ln -s /Library/Developer/CommandLineTools/Library/Perl/5.18/darwin-thread-multi-2level/SVN /Library/Perl/5.18/SVN sudo ln -s /Library/Developer/CommandLineTools/Library/Perl/5.18/darwin-thread-multi-2level/auto/SVN /Library/Perl/5.18/auto/SVN 这个方法也是可以的.就是使用另一个目录作为软连接的目录.测试通过.同理,上面的真实目录根据你装的是 Xcode 还是 CommandLineTools 来替换.记录备用. 参考:http://apple.stackexchange.com/questions/208300/issue-with-creating-a-symbolic-link-inside-system-folder……

阅读全文