show databases; (errno: 13 – Permission denied) MySQL填坑记

安全等保要求云服务器有堡垒机,防火墙,有漏洞感知,有安全防护,入口需要有负载,服务器需要有冗余,数据库需要主备…… 同时还要保留5年的所有日志(真叫人头大)。

一系列扫描,修复漏洞Fixed,然后告知在本地在弄一个容灾以及备份机。

嗯,以上是背景,有很多同学过来已经不耐烦了,妈蛋!老子遇见的是 show databases; (errno: 13 – Permission denied) 这个糟心的错误。

恩是的,这个BUG困扰了我一下午。那就梳理一下问题的几个关键点:

首先是起因:本地容灾服务器安装好了各种环境,MySQL数据库版本也统一为5.6,为了以后的日志保存500年,所以讲默认村主路径做了调整,由原来的/var/lib/mysql 调整到/data/mysql 下。然后就是修改mysql.cnf中[mysqld]下的datadir以及socket保存路径。然后就是一通操作 cp -rp /var/lib/mysql/*  /data/mysql   然后确认就是权限,文件夹下的用户属性,用户组属性。这些相比大家都应该踩过了。

然后启动mysql,接下来可能会遇到两个问题:

1.Can’t open the mysql.plugin table. Please run mysql_upgrade to create it.

2.启动成功,登录mysql后使用show databases;的时候 出现errno: 13 – Permission denied,同时你使用 use mysql;切换数据库竟然正常。(这时候你应该有些波澜了)。

解决:首先一遍一遍的确认配置文件,文件夹权限,启动用户,然后每次启动都会都是一样的错误(假如时间超过1小时工程师会崩溃的)

然后就是把你的错误日志一遍一遍的扔进百度,得到的答案永远都是让你确认权限,文件夹属性(不知道他们真的解决了还是抄无脑转载的),然后你开始怀念Google在的日子(怀念一下被GFW封杀的ssh Proxy网站和那上万的会员。)

在无奈之后还是转向了Google,终于找到几点痕迹。

万恶的SELinux和同样坑爹的apparmor

关闭SELinux  使用 setenforce 0  然后永久关闭,修改/etc/selinux/config文件中设置SELINUX=disabled 重启。

如果是 apparmor 修改/etc/apparmor.d/usr.sbin.mysqld文件里面新增:

#这里面写新的datadir目录,写2行,一行r,一行rwk。
/data/mysql/ r,
/data/mysql/** rwk,

然后重启,填完回家。

系统id迁移

最近一段时间原平铝厂的系统发生id重复事件,起因是负载均衡造成的。查找id server 的时候,无意间发现了twitter的id生成器。决定将系统改造一版。

一路走来感觉很艰辛,但是值得了。主表t_pm一万条,级联表t_pm_item十万条。

优化前:

select * from t_pm_1 t left OUTER join t_pm_item_1 tpi on t.kid=tpi.pm_id where t.pm_name like ‘%a%’ limit 501,200;

200 rows in set (1.17 sec)

优化后:

200 rows in set (0.56 sec)

多次执行,时间偏差不大。查询速度提升给力,效果可观,值了!

下面说具体的ID迁移过程:

1.备份库.同时将数据导出 sql.txt

java写个函数:提取sql.txt所有的uuid,替换为newid。

记录替换过程,old_id <–> new_id 替换表。

将sql.txt导入数据库, 记录为新库 ndb .

2.修改java model类

*****特别注意****:将主键、链接键由 uuid String 改为 Long

*****特别注意****:区分model类型: 日期全部用 long , id方式全部为 Long

3.再写一个java函数,读取所有model long类型数据,逐个修改表结构

alter table @table change `@column` `@column` bigint

4.java json 方式向网页发送的 newid 太长 ,18位, js无法识别

需要在 转换json 的时候批量替换 long类型为string类型

5.最后是系统的全流程测试。

需要迁移的伙伴私聊我qq 398479251 发代码。

jquery validationEngine Ajax 动态参数问题

Jquery validationEngine 是个不错的验证插件,不过ajax相对坑较多,列举一个简单的ajax的代码示例

$("#form2").validationEngine({
	scroll : false,
	promptPosition : 'topCenter: -80, 0',
	ajaxFormValidation : true,
	ajaxFormValidationURL:"${path}/mp/user/edit.htm",
	ajaxFormValidationMethod:"post",
	onAjaxFormComplete:doEdit,
	onBeforeAjaxFormValidation:readySubmit
});

可以看到表单使用ajax验证,方式是 POST,验证完成提交的方法是 doEdit();
我们在 表单的代码如下:

checkUserName 的 js代码如下:

"checkUserName" : {//判断用户账号是否可用
  'url' : $("#basePath").attr("val")+'/ajaxCheck/checkUserName.htm', /* 验证程序地址 */
  'extraDataDynamic' : ['#uid'], /* 额外参数 */
  'alertText' : '该用户已经存在',
  'alertTextLoad' : '正在验证是否可用'
}

可以看到有个参数“extraDataDynamic”,这个是可以在表单中关联验证的,例如判断账号:因为自己的账号本身就存在,如果这里不做关联判断,是无法提交的,
因为文档大部分参数是“extraData”,直到看了源码才发现这块,以后大家躲一躲吧。

var errorSelector = rules[i + 1];
var rule = options.allrules[errorSelector];
var extraData = rule.extraData;
var extraDataDynamic = rule.extraDataDynamic;

使用jvisualvm 监控服务器VM

最近业务服务器在早上并发时出现地区性无法响应问题,初步推断是内存爆掉,导致swap交换不过来了,为了寻找占用内存的怪兽,使用jvisualvm协助监控。

环境JDK1.8,在jdk下的bin目录提供了很多优秀的工具,例如:jvisualvm

然后在服务端启动jstatd。在当前目录下心间jstatd.all.policy文件

grant codebase "file:${java.home}/../lib/tools.jar" {  
   permission java.security.AllPermission;  
};

命令启动:

./jstatd -J-Djava.security.policy=jstatd.all.policy -J-Djava.rmi.server.hostname=192.168.1.233

然后本地使用jvisualvm连接吧:)
69eaf9d5-5de0-42ee-a938-fcd5fbf50c4f

微信订阅号获取用户openID

一天时间,某企业需要搞一次活动,微信一天内需要上线,达到扩大宣传,吸粉的目的。

困境:

一天不到的时间

微信只有认证过的订阅号

订阅号管理员找不到了

没有法办,只能硬顶。拦截器拦截初次访问用户,生成永久Ucode来标识用户。

结果:活动顺利上线,页面PV20W+,

出现了问题:

1.刷票

处理:识别屏蔽,限制微信端打开。

结果:取关人数上升,遭到恶意举报,然后活动页面被微信暂停了 ?

======================

困境:活动被禁跳了,又一次短时间上线继续活动

优势:微信号管理员找回来了

换了思路,更换了新域名,取消了微信人工连接,采用了订阅号开发者模式。

新问题:订阅号不能通过网页获取用户openID,WTF。

心中飘过一万个草尼马。

新方案:微信号新增“活动入口”按钮,动态回复入口消息,第一次进入的时候绑定openID。

窃喜ing,

现在关注人数飙升。

总结,建议采用服务号来搞活动。

BTW:由于技术过硬,曾经在高速运转的系统中升级核心模块等,玩的就是心跳~

Spring boot 部署服务

Spring Boot 出来之后,大家都振臂高呼,一些反应慢的还有些摸不着头脑,剩下的一群喷子……算了不说了

就说spring boot 有什么用吧,随着越来越多的人不停的嘲讽Java是如何的落后,如何的缓慢,就像一个老态龙钟的老人,弄的好多从业Javaer人心惶惶,这里还是不扯淡了,有一件事能做好也能做好另一件事,大家都不用纠结了。

先说Spring boot 有什么好处,首先它构建在spring 上,开发建立在spring上面,减少了很多配置,可以自己集成容器启动,这个在业界不停的讨论是否还需要容器来运行程序这个论调上算是Spring帮java扳回一城。

那么接下来就是如何玩了,当你在eclipse+maven的环境中开发完你的微服务,接下来部署开始打jar包,我推荐把依赖copy到单独的文件夹,这样在你的MANIFEST.MF 已经帮你搞定MainClass和classpath的问题,剩下就是自己指定所需要的配置文件位置

一个简单的启动参考: java -jar easyzhxSwap.jar –spring.config.location=/Users/72/Desktop/application.properties

如何优化?你猜?你再猜!

Jfinal中事务测试

昨天跟波总了解了下事务的处理,今天写个Test备忘一下。

在控制层中使用事务,简单的代码展示

@Before({POST.class , Tx.class})
public void saveWxSetting(){
log.info("saveWxSetting");
SysConfig sys1 = new SysConfig();
sys1.setId(PKUtil.getPK());
sys1.setKey("1");
sys1.setVal("1");
sys1.save();
SysConfig sys2 = new SysConfig();
sys2.setId(PKUtil.getPK());
sys2.setKey("1");
sys2.setVal("1");
sys2.save();
renderText("");
}

其中key为唯一所以,事务生效。
后来探讨了下static方法是用与测试,代码有些变化:
在业务层增加:

public static boolean test(SysConfig sys){
return sys.save();
}

控制层:

@Before({POST.class , Tx.class})
	public void saveWxSetting(){
		log.info("saveWxSetting");
		SysConfig sys1 = new SysConfig();
		sys1.setId(PKUtil.getPK());
		sys1.setKey("1");
		sys1.setVal("1");
		SysConfig.test(sys1);
		SysConfig sys2 = new SysConfig();
		sys2.setId(PKUtil.getPK());
		sys2.setKey("1");
		sys2.setVal("1");
		SysConfig.test(sys2);
		renderText("");
	}

测试依旧OK:)
后台回到业务层,意味着取消控制层的事务

@Before(POST.class)
	public void saveWxSetting(){
		log.info("saveWxSetting");
		SysConfig sys1 = new SysConfig();
		sys1.setId(PKUtil.getPK());
		sys1.setKey("1");
		sys1.setVal("1");
		SysConfig sys2 = new SysConfig();
		sys2.setId(PKUtil.getPK());
		sys2.setKey("1");
		sys2.setVal("1");
		SysConfig.test(sys1,sys2);
		renderText("");
	}
///
@Before(Tx.class)
	public static boolean test(SysConfig sys1,SysConfig sys2){
		return sys1.save()&&sys2.save();
	}

显然是失败了:( 因为:你这是业务层 aop 实现的事务,注意要用一下 Duang.duang(…) 去触发

如果在业务层中调用,代码变为:

@Before({POST.class})
	public void saveWxSetting(){
		log.info("saveWxSetting");
		SysConfig sys1 = new SysConfig();
		sys1.setId(PKUtil.getPK());
		sys1.setKey("1");
		sys1.setVal("1");
		SysConfig sys2 = new SysConfig();
		sys2.setId(PKUtil.getPK());
		sys2.setKey("1");
		sys2.setVal("1");
		SysConfig sys = Duang.duang(SysConfig.class);
		sys.test(sys1, sys2);
		renderText("");
	}
 
@Before(Tx.class)
	public boolean test(SysConfig sys1,SysConfig sys2){
		return sys1.save()&&sys2.save();
	}
 
测试下来  Dung 和 Enhancer 效果一样:)

yum 安装mysql5.7

曾经mysql落入oracle之手,原作者开创了MariaDB,此后不久各大Linux厂商纷纷转投MariaDB阵营(oracle可见多不得人心)。

随着Oracle发布mysql5.7开始支持原生json,大家又开始蠢蠢欲动了,因为之前的源都已经指向mariaDB,所以不得不采用rpm来安装,但是门槛相对傻瓜式的yum复杂一些,好在mysql提供源方便安装了

环境:centos 6.5 64bit

源地址:http://dev.mysql.com/downloads/repo/yum/

接下来不说了,继续吧

centos 安装memcached

官方的教程很简单

Debian/Ubuntu: apt-get install libevent-dev Redhat/Centos: yum install libevent-devel

wget http://memcached.org/latest
tar -zxvf memcached-1.x.x.tar.gz
cd memcached-1.x.x
./configure && make && make test && sudo make install

不过必要的准备还是的有的吧

yum -y install gcc
yum -y install gcc-c++ libstdc++-devel
yum -y install zlib-devel

然后按照官方搞定吧

启动参数
-p 设置TCP端口号(默认不设置为: 11211)
-U UDP监听端口(默认: 11211, 0 时关闭)
-l 绑定地址(默认:所有都允许,无论内外网或者本机更换IP,有安全隐患,若设置为127.0.0.1就只能本机访问)
-d 以daemon方式运行
-u 绑定使用指定用于运行进程
-m 允许最大内存用量,单位M (默认: 64 MB)
-P 将PID写入文件,这样可以使得后边进行快速进程终止, 需要与-d 一起使用

启动命令:例如:memcached -d -u root

使用jodd发送邮件设置发件人问题

使用odd mail的好处就是不用自己实现各种协议,还可以轻松搞定问题,发送邮件就是一件小事儿了,但是有时候需要设置一下发件人,生的人家都是 各种公司CEO的,到我们这都是 devp@sxnuoyun.com  之类的low掉渣渣。

无奈E文差,网速更差,jodd mail 说的蛮简单,以至于没找见怎么设置发件人字段了,干脆去猜吧,看着哪个像点哪个

Email email = new Email();

email.setFrom(new MailAddress(FROMEMAIL));

65E26EA5-7591-4B7B-B622-50DBD2440DEC

手感不错,猜的蛮准, 使用xxxx <email> 格式自动截取发件人:)