MySQL datetime类型使用like导致全表扫描的问题总结

最近项目里有一段mysql语句导致了数据库服务器的load过高报警,语句如下:

SELECT
    content
FROM
    communication_log
WHERE
    gmt_create LIKE '2016-12-02%';

explain了这条sql之后可以看出执行计划是全表扫描,查询了882210条记录,字段的索引没有用上,查询的时间为1.23:2be95c40-3efa-4a59-be3c-4437c1744c0a

原因是gmt_create是datetime类型,条件中写了like,会有隐式转换,gmt_create字段需要在比较前转换成String类型,字段的索引将不会被用到,查询变为全表扫描。

解决方法是把原来的SQL改成:
SELECT
    content
FROM
    communication_log
WHERE
    gmt_create BETWEEN '2016-12-02 00:00:00' AND '2016-12-02 23:59:59';

explain的结果,用上了索引只检索给定范围的行,扫描的行数也减少到了108行,查询的时间为0.02:

1b89fe5c-7e16-4a86-8ec5-c6d9c9008167

Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.apache.log4j.Log4jLoggerFactory解决方法

今天在搭建一个项目单元测试环境跑测试用例的时候遇到了致命错误:
Caused by: java.lang.NoClassDefFoundError: Could not initialize class org.apache.log4j.Log4jLoggerFactory
这个是什么情况?
翻看控制台输出信息看到一段:
SLF4J: Detected both log4j-over-slf4j.jar AND slf4j-log4j12.jar on the class path, preempting StackOverflowError.
SLF4J: See also http://www.slf4j.org/codes.html#log4jDelegationLoop for more details.

翻看了上面说的网站提示信息:
The purpose of slf4j-log4j12 module is to delegate or redirect calls made to an SLF4J logger to log4j. The purpose of the log4j-over-slf4j module is to redirect calls made to a log4j logger to SLF4J. If SLF4J is bound with slf4j-log4j12.jar and log4j-over-slf4j.jar is also present on the class path, a StackOverflowError will inevitably occur immediately after the first invocation of an SLF4J or a log4j logger.

意思是slf4j-log4j12是用来代理或者重定向调用使一个SLF4J的日志通过log4j输出,log4j-over-slf4j的目的是将log4j的日志重定向输出到SLF4J,如果它俩在一个class path下造成StackOverflow的错误,因为它俩会陷入一个死循环。如果不明白SLF4J和log4j的同学可以转到:http://www.importnew.com/7450.html 仔细阅读。

于是我寻找了项目的maven依赖,发现有3个依赖中出现了slf4j-log4j12.jar,在每个依赖里加上:

<exclusion>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-log4j12</artifactId>
</exclusion>

最终解决了问题。

再次跑测试用例的时候,还有一堆报错也不见了:
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/Users/wangzhiang/.m2/repository/ch/qos/logback/logback-classic/1.1.3/logback-classic-1.1.3.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/Users/wangzhiang/.m2/repository/org/slf4j/slf4j-log4j12/1.6.1/slf4j-log4j12-1.6.1.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [ch.qos.logback.classic.util.ContextSelectorStaticBinder]

原因是:SLF4J会在编译时会绑定import org.slf4j.impl.StaticLoggerBinder; 该类里面实现对具体日志方案的绑定接入。任何一种基于SLF4J的实现都要有一个这个类。如:slf4j-log4j12-1.6.1提供对log4j的一种适配实现。我的项目中存在logback-classic-1.1.3和slf4j-log4j12-1.6.1两个实现SLF4J的包同时出现,就出现了上面的报错,加上依赖的exclusion去掉slf4j-log4j12即可。

CentOS 6.7下安装vsftpd FTP服务器经验

最近Wordpress从虚拟主机迁移到了VPS上,原来虚拟主机服务商有提供FTP,现在VPS需要自己安装一个FTP服务器来支持Wordpress的插件和主题升级。vsftpd是Linux下比较著名的FTP服务器,我选择它搭建FTP服务器。

 

第一步:安装vsftpd

查看你的服务器是否已经安装vsftpd

rpm -qa | grep vsftpd

如果已经安装就略过下一步yum安装。如果没有安装过就执行以下命令:

yum -y install vsftpd

 

第二步:基于虚拟用户的配置

所谓虚拟用户就是没有使用真实的帐户,只是通过映射到真实帐户和设置权限的目的。虚拟用户不能登录CentOS系统。

1. 修改配置文件

打开/etc/vsftpd/vsftpd.conf,修改该文件原来的配置,如下(这里需要一个一个项目在编辑器里查找并修改,注意YES或NO等配置项后面不要在复制过程中多出不必要的空格):

#设定不允许匿名访问
anonymous_enable=NO

#设定本地用户可以访问。注:如使用虚拟宿主用户,在该项目设定为NO的情况下所有虚拟用户将无法访问
local_enable=YES

#使用户不能离开主目录
chroot_list_enable=YES

ascii_upload_enable=YES

#设定支持ASCII模式的上传和下载功能
ascii_download_enable=YES

#PAM认证文件名。PAM将根据/etc/pam.d/vsftpd进行认证
pam_service_name=vsftpd

以下这些是关于vsftpd虚拟用户支持的重要配置项,默认vsftpd.conf中不包含这些设定项目,需要自己手动添加到/etc/vsftpd/vsftpd.conf中:

#设定启用虚拟用户功能
guest_enable=YES

#指定虚拟用户的宿主用户,CentOS中已经有内置的ftp用户了
guest_username=ftp

#设定虚拟用户个人vsftp的CentOS FTP服务文件存放路径。存放虚拟用户个性的CentOS FTP服务文件(配置文件名=虚拟用户名
user_config_dir=/etc/vsftpd/vuser_conf

 

2. 进行认证

首先,安装Berkeley DB工具,很多人找不到db_load的问题就是没有安装这个包。

yum install db4 db4-utils

然后,创建用户密码文本/etc/vsftpd/vuser_passwd.txt ,注意奇行是用户名,偶行是密码:

wordpress
123456

接着,生成虚拟用户认证的db文件:

db_load -T -t hash -f /etc/vsftpd/vuser_passwd.txt /etc/vsftpd/vuser_passwd.db

随后,编辑认证文件/etc/pam.d/vsftpd,全部注释掉原来语句,再增加以下两句:

auth required pam_userdb.so db=/etc/vsftpd/vuser_passwd
account required pam_userdb.so db=/etc/vsftpd/vuser_passwd

最后,创建虚拟用户配置文件:

mkdir /etc/vsftpd/vuser_conf/
vi /etc/vsftpd/vuser_conf/wordpress  //文件名等于vuser_passwd.txt里面的账户名,否则下面设置无效

内容如下(这里需要注意YES或NO等配置项后面不要在复制过程中多出不必要的空格):

local_root=/home/wwwroot
write_enable=YES
anon_umask=022
anon_world_readable_only=NO
anon_upload_enable=YES
anon_mkdir_write_enable=YES
anon_other_write_enable=YES

 

3. 设置Selinux(可省略)

setsebool -P ftp_home_dir=1   //设置ftp可以使用home目录
setsebool -P allow_ftpd_full_access=1   //设置ftp用户可以有所有权限

 

4. 设置FTP根目录权限

mkdir /home/wwwroot   //创建目录,如果目录已存在请省略
chmod a-w /home
chmod -R 777 /home/wwwroot

最新的vsftpd要求对主目录不能有写的权限所以/home为a-w,主目录下面的子目录再设置777权限。

 

5. 设置防火墙

打开/etc/sysconfig/iptables,添加一句:

-A INPUT -p tcp -m tcp --dport 21 -j ACCEPT

然后保存,并关闭该文件,在终端内运行下面的命令,刷新防火墙配置:

service iptables restart

启动FTP服务器:

service vsftpd start

 

6. 连接FTP服务器

现在你就可以使用FTP工具连接服务器了,建议使用FileZilla工具连接,连接的过程中如果出现报错,你只需要去搜索报错的内容调整服务器的配置就好了。

 

参考文章:http://www.cnblogs.com/xiongpq/p/3384759.html

一次JVM引起的服务器load过高问题排查经历

2016-11-08早上9:25分,公司运维的同事给我报警,称我们团队的一台服务器CPU的压力很大,zabbix的图显示:

1接到警报后,我在该服务器上使用w和top命令查看服务器的load和CPU情况,1分钟的load average在3-5之间,系统在高负荷运转,查看了我们的线上应用系统发现网页打开正常,但一个別列表的查询缓慢,chrome浏览器的network查看http接口的timing在十几秒。这部分列表走的是搜索引擎,我第一反应是会不会是搜索引擎出问题了?

于是我在服务器上查看tomcat日志,获取我们的应用调用搜索引擎的接口和参数,拼装后使用

curl -v '$url'

命令访问,发现访问的速度没有问题。那说明搜索引擎没有问题,那一定是我们的应用从搜索引擎返回值到展示给用户的部分处理有问题。

由于有大量用户反馈系统速度慢,于是我使用jps获取java进程的pid,随后使用:

jmap -dump:format=b,file=crm.bin [pid]

命令dump jvm的信息“保留犯罪现场”,然后重启线上应用。

启动应用后检测到服务器的load渐渐越来越高,最后保持在重启前的样子,于是使用

jstat -gc [pid] 3000

查看服务器每隔3秒的gc情况,发现3秒钟的full gc能够达到两次,jvm的状况十分异常。在启动服务器的这个时间里我利用eclipse MAT工具分析jmap dump文件信息,未诊断出异常。

后来我把原来jvm的Xms参数配置由1024m提高到3072m,发现双机的full gc次数分别稳定在0和2后再也没有full gc过了,但是young GC却十分频繁,3秒钟young GC次数可以达到15-20次。

到底是什么东西这么占内存???我使用jmap -histo pid查看,发现排在第一位的[C对象经常飙升到1个多G然后降到200MB,就是young GC频繁的原因,这通常是String类型的对象存在问题。

随后我使用

top -H -p [pid]

看到了如下结果:

2这一排的PID都占用了大量的CPU资源,于是随机取了一个PID为1077的进程,使用

printf "%x\n" 1077

转换成16进制的数字为435

随后使用jstack工具:

jstack [pid] | less

输出当前的堆栈信息,然后搜索435,发现如下内容:

3这块代码就是调用搜索引擎的代码,它处于RUNNABLE的状态,一直在执行中,说明这段代码一定是追魁祸首!打开代码看看!原来是这样的一段代码:

while ((line = in.readline()) != null) {
    result += line;
}

真相就是:循环里每次对String的操作都会生成新的String对象,不仅效率低下,而且大量浪费有限的内存空间。

将String改成StringBuilder,发布上线后load过高的问题解决。这就解释了为什么一般的页面打开速度正常,而搜索客户列表接口速度缓慢以及为什么char类型的数组占用大量内存。

TypeScript Error TS2304: Cannot find name ‘require’的解决方法

最近在研究ionic framework,在编译项目的时候出现一个报错:

TS2304: Cannot find name 'require'

原因是我们使用了ECharts,在引用它的使用写了这样的一句代码:

// 引入 ECharts 主模块
var echarts = require('echarts/lib/echarts');

require是在ES5的语法里常用的方式,现在我们写typescript了,没有这个玩意儿怎么办?
我找了很久,在github上找到了一个项目:
https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/requirejs/require.d.ts
把项目里的require.d.ts放到ionic的app目录下就解决了这个报错。

↓

CSS3 Powered