向张小龙致敬

2019年1月9日,微信之父张小龙在微信公开课上做了长达4个小时的演讲,据传当时演讲都没有结束,网上就出来了各种“精华解读”版本。我认为,倘若我们对一个领域停留在大概了解的范畴,也许你可以看一下精华版,但是你不想错过途中的风景,还是亲自完完整整的过吧。

这里我自己做个review,期望若干时间后再看现在的自己,可以说一句“还是年轻”。

所谓的产品经理

张小龙谈论到所谓的业界产品经理,一直拿着KPI做产品,是很难做出来好产品的 。

我很认同,有些所谓的PM,需求自己都弄不清楚,然后就囫囵吞枣的传达给团队成员,在发生意见分歧或者异议的时候经常拿“甲方爸爸这样要求的”,“你不用管,这事儿我来负责”这样的粗暴来强制灌输,有些时候这些PM也弄不清到底对什么负责,这样设计是否有说服力,或者连自己都说服不了就要求产品按照自己的意图完成,因为没有认同感,竟然出现了PM跟RD势不两立的地步,大家互相嘲讽,甚至大打出手。一方嫌弃对方没有责任感,另一方讨厌对方浪费自己时间和生命。甚至演化到公司花钱就是买你的时间这样惊悚的言论。我想在将来的趋势中 ,我更认同购买“服务”或者“能力”这样的说法,公司是一群成年人高效协作的组织架构,时间对每个人都是一样的,只有能力才会影响效率和结果。

你是否足够的热爱?

由于我对工具产品热爱,我甚至会亲自动手写代码来打造出一个Foxmail这样的产品来满足自己的制造欲望。

作为团队的管理者,他们往往使用战术上的勤奋来掩盖自己战略上的懒惰。他们保守陈旧,拒绝变化,不愿意走出自己的舒适区,有很多人是依靠时间的忍耐来换取“活到最后”的胜利,而不是采取自我进化的方式向上攀登。许多人认为从团队成员到团队管理就完成了晋升,走向下一个人生的高坡了,但是这个晋升难道不是角色的转换吗?又有多少人认为这个晋升是作为自己可以划水的起点,仿佛拿到了免死金牌一样。倘若从百岁人生来考虑,这无异于还没起步就放弃了。天呐,30岁出头就产生了从此可以为“年轻人指点人生”的人生导师幻觉了。

不断的学习,进行自我的迭代,最终完成进化。

因为惰性是人共有的特性,没有人愿意主动去学习新知识,去伤脑筋啊。

人和人的努力程度相差太多,还远没到谈论天赋的时候 。好为人师这是共性,若有一个能听从自己教导的“后辈 ”,人生又何尝不是一件开心的事情,那么人生不开心的事情是什么呢?——我想大约就是自己不承认而又不愿意被“别人教导 ”吧, 他们阻止别人进步,尤其是身边的人,使劲指导你,告诉你。你想想身边有没有这样的好心人,天天告你说你应该怎么怎样,对于不听劝阻,或者不听教导的人,报以“傻逼”总结。

所以多一些善良,少一些为人师,不断的学习,遇到事情多想一想别人为什么这样想,为什么这样做,我为什么看不惯,我为什么不认同,不要一上来就说“傻逼”。

毕竟你不要先确定对方打不过你,再说吗?

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,

然后重启,填完回家。

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安装ngxtop

nginx受众很大,可以监控的工具很多,但是对简单粗暴的想知道直观数据的我们来说,ngxtop不可错过。

在centos中yum还不能安装,所以还是人肉安装吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
######
wget http://pypi.python.org/packages/source/s/setuptools/setuptools-0.6c11.tar.gz
tar zxvf setuptools-0.6c11.tar.gz
cd setuptools-0.6c11
python setup.py build
python setup.py install
######
wget https://pypi.python.org/packages/source/p/pip/pip-7.1.2.tar.gz#md5=3823d2343d9f3aaab21cf9c917710196
tar zxvf pip-7.1.2.tar.gz
cd pip-7.1.2
python setup.py install
######
pip install ngxtop

接下来就可以使用了:

ngxtop [options]
ngxtop [options] (print|top|avg|sum) <var>
ngxtop info

一些通用选项:

  • -l : 指定日志文件的完整路径 (Nginx 或 Apache2)
  • -f : 日志格式
  • –no-follow: 处理当前已经写入的日志文件,而不是实时处理新添加到日志文件的日志
  • -t : 更新频率
  • -n : 显示行号
  • -o : 排序规则(默认是访问计数)
  • -a …, –a …: 添加表达式(一般是聚合表达式如: sum, avg, min, max 等)到输出中。
  • -v: 输出详细信息
  • -i : 只处理符合规则的记录

一些内置变量:

  • bodybytessend
  • http_referer
  • httpuseragent
  • remote_addr
  • remote_user
  • request
  • status
  • time_local

 

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