2017年,小视频分享成为风口的小猪,人工智能大行其道,然而并未见到什么特别的效果,所有最有意义的都在于推荐。
手机方面,因为人脸解锁的流行,看上去第一次让深度学习的东西落了地。
业务方面,国内似乎已经慢了,各大厂家纷纷出海,印度、印尼成了新的“”。
另外,传统业务新零售热起来了。
1.明年将会是科技企业海外IPO的集中年。
2.人民日益增长的物质文化需要会导致继续出现人性丑陋的事件。
3.企业海外开花,主战场移动到印度印尼。
4.类似线上抓娃娃机的项目继续兴起。
5.AI开始落地。
6.房价可能会冷却到下半年后大涨。
7.更加封闭,不论是网络还是经济。
8.CRS影响基本悄无声息。
9.python更加流行。
10.人民币进入7时代。
1.国内污染比2016更加严重且封口更紧。- 准,帝都附近受北风影响,似乎是好点的。
2.公共安全事件再一次出现。- 准,杭州保姆纵火案,别以为不是公共安全事件,涉及所有消防、物业,不敢多想。
3.微信支付在国内全方位超越支付宝。- 一般准,没有全方位,至少是大范围。
4.小米生态链企业要雄起一两个(出名或者IPO)。- 准,紫米和华米 都挺出名了。
5.人工智能的项目依旧不产生实际超大收益。- 准。
6.电子支付开始作为大鱼抢占的关键制高点。- 一般准。
7.开始有国产手机厂商关门或被并购。- 准,乐视手机。
8.直播行业常态化,变成所有应用都有的功能,收益下滑。- 准
9.云公司推出人工智能平台。- 准
10.人民币到7.2。- 差点准,这个太难了。
明年见!
由于上个月推出第一篇《生娃指北》https://www.54chen.com/blog/2017/07/14/born-in-beijing/ 后,收到了广大人民群众的反馈,特更新第二篇-采购篇。
看表
物品名 | 品牌名 | 备注 |
---|---|---|
奶瓶150ml | comotomo | |
玻璃奶瓶150ml | betta | |
塑料250ml | betta | |
宽口奶瓶250ml | 布朗博士 | |
宽口奶瓶150ml | 布朗博士 | |
婴儿车 | SilverCross | 大气好用,主流车型 |
婴儿车 | 好孩子口袋车 | 折起来很小,但是还没用过就送人了 |
婴儿车 | quintus伞车 | |
奶粉 | 德国爱他美白金版一段 | 出生入量不如喝了两次 |
沐浴露 | 加州宝宝 | |
保湿乳液 | 加州宝宝 | |
驱蚊液 | 加州宝宝 | |
抚触油 | 妙思乐 | |
维生素D3 | Ddrops | 母乳宝宝出生2周后开始补d3促进钙吸收 |
西甲硅油 | little remedies | 解决肠绞痛莫名哭闹放屁的 |
盐水滴鼻剂 | little remedies | 买了没用过 |
乳钙 | bioland | 半岁前只吃D3,乳钙半岁后考虑吃 |
安抚奶嘴×4 | 苏维妮 | 利器,必备 |
安抚奶嘴链*1 | 苏维妮 | |
指甲刀 | 苏维妮 | 从小剪指甲,否则自己抠自己 |
梳子 | 苏维妮 | |
餐具套装 | 苏维妮 | |
勺子 | 苏维妮 | |
安抚玩具 | jellycat邦尼兔、小熊 | 用处不大 |
安抚巾 ×2 | 麦侬贝儿 | 流口水啃这个比啃手强 |
婴儿床 | 可优比 | 早买散味 |
餐椅 | 可优比 | |
床垫 | 可优比 | |
腰凳 | 可优比 | 能扶坐了才有用 |
牙胶 | 苏维小鹿 | 不知道为啥,一咬就哭 |
牙胶 | banana | 同上 |
牙胶 | comotomo×2 | |
保温壶 | tiger | 尚未启封 |
耳温枪 | 博朗 | 慎用,不如传统水银温度计准,要高0.5度 |
料理棒 | 博朗 | |
洗衣液 | 佬甘尼克 | |
奶瓶清洁剂 | 佬甘尼克 | |
玩具清洁剂 | 佬甘尼克 | |
洗衣皂 | 韩宁 | 很好用,可以多买 |
湿纸巾×40 | 韩国顺顺儿 | |
护臀膏 | 地球妈妈 | 预防宝宝红PP |
侧切喷雾 | 地球妈妈 | |
鞣酸软膏 | 北医三院 | 宝宝容易淹脖子,大腿根,抹抹就好 |
痱子粉 | 和光堂 | |
桃子水 | 贝亲 | 好用,点赞 |
驱蚊器 | vape | |
驱蚊贴 | 小合光堂 | |
紫草膏 | 小蜜蜂 | |
消锅 | 小白熊 | |
洗澡盆 | stokke | |
纸尿裤 | 大王天使 | 大一点才能用拉拉裤,拉拉裤穿起来容易 |
拉拉裤 | 大王天使 | |
连体衣×6 | 英氏 | |
包被 | 英氏 | |
奶瓶夹 | 英氏 | |
袜子 | 英氏 | |
上下衣×2 | 英氏 | 千万不要买59cm,穿不了几天就小了,宝宝衣服大两码没关系 |
绵柔巾 | 全棉时代 | 搞活动多买 |
纱布浴巾×2套 | 全棉时代 | |
口水巾×2套 | 全棉时代 | |
产褥垫×2包 | 全棉时代 | 医院其实有备 |
一次性隔尿垫×2包 | 全棉时代 | 同上 |
一次性内裤×5包 | 全棉时代 | 同上 |
收腹缠带 | 全棉时代 | 没用 |
防溢乳垫 | 全棉时代 | |
棉签 | 棉花秘密 | |
绵柔巾 | 棉花秘密 | 洗屁股用,没有全棉时代的好,掉絮 |
防溢乳垫 | 棉花秘密 | |
健身架 | 费雪 | |
床铃 | 费雪 | |
米兔早教机 | 小米 | |
夜灯 | 小米 | |
恒温水壶 | 小米 | 不冲奶粉,没什么用 |
宝宝晾衣架×25 | 淘宝 | |
宝宝洗脸盆+屁屁盆 | 淘宝 | 跟护士学会水龙头清洗后盆没什么用 |
围栏 | ifam | |
回力车 | B.toys | 玩具 |
跳跳大河马 | B.toys | 玩具 |
拨浪鼓×2 | hape | 玩具 |
哺乳枕 | 良良 | |
凉席×2 | 良良 | |
防吐垫 | 淘宝 | 一个斜三角形的垫子,娃躺上面是斜着的,不吐 |
dha | 挪威小鱼 | 如果妈妈吃,宝宝可半岁后在吃 |
妈妈营养片 | swisse钙片、惠氏dha 佬新章维生素片 | |
安全座椅+提篮 | cybex | |
哺乳文胸 | 美德乐 、妈妈喂 | |
乳头霜 | Lansinoh | |
吸奶器 | Lansinoh | |
储奶袋 | Lansinoh | |
集奶器 | 淘宝 | 巨推荐,吸奶器不如这个 |
婴儿理发器 | 好孩子 | |
宝宝护肚围 | 淘宝 | 就是一圈软布 |
保温箱 | tgbox | 用来运奶的 |
黑白卡、早教卡 | 淘宝 | |
尿布台 | 淘宝 | 没用 |
手持吸尘器 | 戴森 | 有用,吸床 |
This is a quick guide explaining how to run GUI app in docker on mac osx.
#brew cask install xquartz
#brew install socat
socat TCP-LISTEN:6001,reuseaddr,fork UNIX-CLIENT:\"$DISPLAY\" &
#ifconfig
You can see en0 en1 en2 and so on,choose a right one which has the right IP addrass.
step 4.run docker
docker run -it -e XAUTHORITY=/tmp/xauth -v ~/.Xauthority:/tmp/xauth -e DISPLAY=$(ifconfig en3 | grep 'inet '|awk '{print $2}'):1 --net host --volume=$(pwd):/workspace fastercnn /bin/bash
attention: You must modify the DISPLAY,replace the “ifconfig en*” by the one which choosed in step 3.
Good luck!
本篇纯属扯淡,技术性极高,学好社会流程之后,可以节省很多时间,也能有效减少被看不起的机会。
1.准生证
这是俗称,自从放开二胎后,变名为《生育登记服务单》。这个高级,有官方网站 http://syz.bjchfp. ,填写对了居委会就会给你打电话。完了你自己下载打印就可以了。
2.母子健康档案(也有人叫做 建卡)
由卫生主管的社区卫生服务中心(这TM是个事业单位吧?),他们资料后,给你媳妇发3个册子:《母子健康档案》、《儿童保健记录》俗称体检本(有些地方要等娃生了才给)、《儿童保健健康教育手册》这本基本没卵用。
3.医院建档
建档是指,你媳妇怀上了,决定要去哪个医院产检和生产,这个医院要同意,首先要建立档案,简称建档。
step 1.想生个娃了,上网站登记,准备打印准生证。
step 2.一不小心怀上了,且大于42天,注意42天!
step 3.带上医院验血、B超之类的能证明怀了的(验孕试纸不行)东西,和各种身份证明(具体打电话问居委会问卫生服务中心),办理母子健康档案。
step 4.带上母子健康档案,排队挂号OR牛&金钱去你媳妇心宜的医院。
step 5.为期十几次的产检后,生啦。
step 1 里必须确定好居委会名称。
step 2 里42天是很多社区的龟腚,小于这个时间人家懒得理你。
step 3 人家会问你一堆的资料,提前打好电话。
step 4 越好的医院,越不可以排队排到,牛是个不错的选择,但是不靠谱的牛更麻烦,因为错过了一两天,医院就满了,不收你了。三院顺产没有无痛。(感谢伟俊提供信息)
step 5 产检排队很浪费时间,四维立体B超那个对医学来讲毛用没有,有医院靠这赚钱。
社区疫苗建档环节,需要证件:母子健康档案(健康档案和疫苗建档不在一个地方的一定要办迁出,由健康档案发证的社区医院盖戳)、出生后第一次打卡介苗和乙肝的疫苗证明、居住证明(暂住证,房本,社区开具的居住证任一)、父母双方身份证。(感谢现奎提供信息)
1.预产期
就是你媳妇怀孕时间到多久要生的时间,每回的B超单子上都有,一般来讲都有2个值,一个是B超观测的时间,一个是计算时间。一般来说,计算时间39周之后就可以生了,39周后是越早出来越安全(因为后面越长越大啦),41周再不出来,医生就要采取措施了。
2.羊水早破
好像是个医学名词吧,是一种很危险的情况,比如在家里出现这个情况,你家娃有在妈妈肚子里羊水提前破了,娃就有窒息的危险。所以说要医院离家近一点。
3.入盆
有经验的老医生摸一把就知道入了,入了之后,羊水早破的风险就低一些了,因为即使破了,羊水也不会流这么快,你家娃的头顶着的。
4.母乳喂养
一出生的娃第一件事情不是喂奶瓶,是吸妈妈的奶,对大人小孩都有帮助。另外,母乳喂养是社会可持续发展的关键。而且,还能省一大笔奶粉钱。
5.疸
生理性疸是一开始没有,过三四天出现,再过几天得不行,然后一两个星期就没了。没别的办法,多吃多拉多晒太阳。
期间有很多次产检,公立医院可能会排队很长时间,私立医院是个不错的选择,和睦家什么的都可以在天猫上买618的价格还算是划算。
预产期最后两个星期,家里一定要有多的人,不可留孕妇一人在家。
三院人太多,顺的不给无痛。(感谢伟俊提供信息)
1.出院诊断证明
这个是医院的标准流程最后一环,一般住完院、付完钱,都会给出院诊断证明。
2.出生证
没错,就是传说中的出生证,一般出生后一个星期,医院都有专门的地方统一办。
3.听力筛查单、卡介苗接种证、首针乙肝
这三个,一般都是在孩子出生后当天和一周内,全部备齐了,打或者没打,都得给个纸条的。
4.疫苗本
绿片的,全称《免疫疫苗接种证》,一般是在社区卫生服务中心办理的,满1月时打第二针乙肝时就正好办了。
因为之前你办过《母子健康档案》,所以社区卫生服务中心是有你记录的,他们看时间差不多了,你家应该生了,就会打你电话,然后让你去交本本。
这里有个关键的地方,如果没有《儿童保健记录本》,以后上学的时候很麻烦(按目前看),所以一定要问社区要。
昌平的做法,去办体检的时候,他们帮你保管了,如果你要去海淀,可以找他们自己再取出来。
1.发烧
半岁内的娃,发烧38.5是个界限,38.5以上,要用退热剂(泰诺林),38.5以下,用温水擦胳肢窝脖子四肢(隔个半小时擦一次就行了,别不停的擦)。
建议不要一发烧就跑医院,目前大多数三甲医院被家长们烦死了,都把儿科急诊给关掉了。
和睦家崔玉涛名医指点:发烧第三天再去医院。因为前几天验血都看不出来啥原因发的烧。
2.睡前哭
入睡困难,简单说是要快。当发现娃有要睡觉的意思了(揉眼睛、打呵欠),就弄他睡觉去。别等人家暗示了半天还在让人家不睡,后面又想睡觉又睡不着,宝宝心里不苦才怪。
3.吐奶
吐啊吐的就习惯了,4个月之前,都这个样子。能做的事情就是,吃完奶前半小时,别把他抱来抱去的,只保持一个姿势,拍咯。放肩上大人半躺到沙发,是个非常舒服的姿势。
4.入量够不够
看小便次数,一天小便十次以上且不,说明不饿了。
5.洗澡
新生儿多洗澡没坏处,天天洗都行,不要天天用沐浴露。网上找下婴儿抚触和排气视频,最有用的两项技能。
[更新了 三院因为人太多顺产没有无痛 -伟俊提供信息 2017.7.17]
[更新了 办理疫苗档案时需要的手续-现奎提供信息 2017.7.17]
[长期持续更新,最后更新时间2017.7.17]
Caffe is a deep learning framework made with expression, speed, and modularity in mind. It is developed by Berkeley AI Research (BAIR) and by community contributors.
The official website is http://caffe.berkeleyvision.org/ .
It is easy to install it with python 2 and Ubuntu.But it is hard to install it with python 3 and centOs.
Here are some records when I install it with Anaconda python3 on centos7.
Prior to installing, have a glance through this blog and take note of the details for your platform.
$cat /etc/redhat-release
CentOS Linux release 7.*.* (Core)
$python --version
Python 3.4.3 :: Anaconda 2.3.0 (64-bit)
$pip --version
pip 7.0.3 from /home/work/anaconda3/lib/python3.4/site-packages (python 3.4)
$sudo yum install gflags-devel glog-devel lmdb-devel openblas-devel leveldb-devel snappy-devel opencv-devel hdf5-devel
Fist of all,download the dependencies.
$git clone --depth 1 https://github.com/BVLC/caffe.git
$wget http://sourceforge.net/projects/boost/files/boost/1.59.0/boost_1_59_0.tar.gz/download
$wget 'https://github.com//protobuf/releases/download/v3.3.0/protobuf-cpp-3.3.0.tar.gz'
$wget 'https://github.com//protobuf/releases/download/v3.3.0/protobuf-python-3.3.0.tar.gz'
Install the dependencies:
1.python libs:
$cd caffe/python
$for req in $(cat requirements.txt) pydot; do /usr/bin/pip install $req -i https://pypi.mirrors.ustc.edu.cn/simple; done
If you are not in China,remove the -i url parameter.
2.pb libs:
$cd ../..;tar zxvf boost_1_59_0.tar.gz;tar zxvf protobuf-cpp-3.3.0.tar.gz;tar zxvf protobuf-python-3.3.0.tar.gz
$cd protobuf-3.3.0/
$./configure
$make && make install
$cd python/
$python setup.py build
$python setup.py install
$sudo ln -s /usr/local/lib/libprotobuf.so.13.0.0 /usr/lib64/libprotobuf.so.13
3.boost libs:
$cd boost_1_59_0/
$./bootstrap.sh
$./b2 cxxflags="-I /home/work/anaconda3/include/python3.4m/"
$sudo ./b2 install --prefix=/usr cxxflags="-I /home/work/anaconda3/include/python3.4m/"
The last step:
$cd caffe
$git checkout -b 1.0
$vim Makefile.config
change the config like this:
BLAS := open
BLAS_INCLUDE := /usr/include/openblas
PYTHON_INCLUDE := /home/work/anaconda3/include \
/home/work/anaconda3/include/python3.4m \
/home/work/anaconda3/lib/python3.4/site-packages/numpy/core/include
PYTHON_LIBRARIES := boost_python3 python3.4m
$make
$make pycaffe
$export PYTHONPATH=$PYTHONPATH:/home/work/soft/src/caffe/python
$cd caffe
$make test && make runtest
Good luck!
以下是神经网络训练中经常会遇到的一些概念,进行了收集总结,供需要时查阅。
按偏差平方和最小的原则选取拟合曲线,并且采取二项式方程为拟合曲线的方法,称为最小二乘法。
它通过最小化误差的平方和寻找数据的最佳函数匹配。
利用最小二乘法可以简便地求得未知的数据,并使得这些求得的数据与实际数据之间误差的平方和为最小。
参考tf.train.GradientDescentOptimizer
梯度下降(GD)是最小化风险函数、损失函数的一种常用方法,随机梯度下降和批量梯度下降是两种迭代求解思路。
学习率是GD中最关键的参数,了每个梯度的大小,大了会反复振荡,小了会计算困难。
参考keras.optimizers.SGD
为了解决GD里学习率的选择问题,SGD用随机的办法来减少计算学习率的次数。
SGD伴随的一个问题是噪音较多,使得SGD并不是每次迭代都向着整体最优化方向。
keras.optimizers.SGD(lr=0.01, momentum=0.0, decay=0.0, nesterov=False)
参数:
lr:大于0的浮点数,学习率
momentum:大于0的浮点数,动量参,它模拟的是物体运动时的惯性,即更新的时候在一定程度上保留之前更新的方向,同时利用当前batch的梯度微调最终的更新方向。这样一来,可以在一定程度上增加稳定性,从而学习地更快,并且还有一定摆脱局部最优的能力,这个值在0-1之间,在训练开始时,由于梯度可能会很大,所以初始值一般选为0.5;当梯度不那么大时,改为0.9。
decay:大于0的浮点数,每次更新后的学习率衰减值
nesterov:布尔值,确定是否使用Nesterov动量-为true时,启用执行简单的梯度下降步骤。
SGD通常训练时间更长,容易陷入鞍点,但是在好的初始化和学习率调度方案的情况下,结果更可靠。
参考keras.optimizers.Adagrad
不建议修改keras Adagrad算法任何参数。
会在学习的过程中自动调整 learning rate, 对于出现频率低的参数使用较大的 learning rate, 出现频率高的参数使用较小的 learning rate. 因此, 这种方法对于训练数据比较稀疏的情况比较适用. AdaGrad 可以提高 SGD 的鲁棒性。
Adagrad 的缺点是,在深度学习中, 这种方法导致学习率的调整太激进, 因此常常过早结束了学习过程。
参考keras.optimizers.RMSprop
RNN网络经常使用此算法,在keras里,推荐全部默认参数,除了学习率之外。
RMSProp是一个非常高效的算法, 但是目前并没有发表。他改进了AdaGrad算法,也是一种自动调整学习率的算法。
参考 keras.optimizers.Adadelta
不建议修改keras的默认参数。
AdaGrad 方法比较激进, 会过早结束优化过程, AdaDelta 的目的就是为了解决这个问题. 在 AdaGrad 中对 learning rate 进行 normalize 的参数是使用之前所有时间得到的梯度的累积, AdaDelta 的是通过设置窗口 w, 只使用部分时间的梯度累积.
参考keras.optimizers.Adam
adam算法来自于RMSprop的改进,论文中推荐的超参数为 eps=1e-6,bata1=0.9,beta2=0.999,keras参考此设置,也不建议修改。其效果相当于SGD+Nesterov Momentum再加上bias的纠正机制。
在大部分实践过程中,数据比较稀疏的情况下,此算法比较通吃。
参考keras.optimizers.Adamax
是adam的一个变种,他对学习率变化的上限提供了更简单的范围。
参考keras.optimizers.Nadam
不推荐修改默认参数值。
Nadam对学习率有了更强的约束,同时对梯度的更新也有更直接的影响。一般而言,在想使用带动量的RMSprop,或者Adam的地方,大多可以使用Nadam取得更好的效果。
[后续为激活函数]
参考keras激活函数activation-sigmoid。
由于函数图像很像一个“S”型,所以该函数又叫 sigmoid。广义逻辑回归曲线可以模仿一些情况人口增长( P )的 S 形曲线。起初阶段大致是 指数增长 ;然后随着开始变得饱和,增加变慢;最后,达到成熟时增加停止。 函数。用于估计某种事物的可能性。可以用来回归,也可以用来分类,主要是二分类。它不像SVM直接给出一个分类的结果,而是这个样本属于正类或者负类的可能性是多少,当然在多分类的系统中给出的是属于不同类别的可能性,进而通过可能性来分类。
参考tf.nn.softmax
如果不是在[0,1]中取值,而是在K个类别中取值,这时问题就变为一个多分类问题。
sigmoid函数只能分两类,而softmax能分多类,softmax是sigmoid的扩展。
sigmoid将一个real value映射到(0,1)的区间(当然也可以是(-1,1)),这样可以用来做二分类。
而softmax把一个k维的real value向量(a1,a2,a3,a4….)映射成一个(b1,b2,b3,b4….)其中bi是一个0-1的常数,然后可以根据bi的大小来进行多分类的任务,如取权重最大的一维。
tanh 网络的收敛速度要比sigmoid快。因为 tanh 的输出均值比 sigmoid 更接近 0,可降低所需的迭代次数。
与传统的sigmoid激活函数相比,ReLU能够有效缓解梯度消失问题,从而直接以监督的方式训练深度神经网络,无需依赖无监督的逐层预训练,这也是2012年深度卷积神经网络在ILSVRC竞赛中取得里程碑式突破的重要原因之一。
ReLU随着训练的推进,部分输入会落入硬饱和区,导致对应权重无法更新。这种现象被称为“神经元死亡”。
ReLU还经常被“诟病”的一个问题是输出具有偏移现象,即输出均值恒大于零。偏移现象和 神经元死亡会共同影响网络的收敛性。
PReLU是ReLU 和 LReLU的改进版本,具有非饱和性。RReLU是一种非确定性激活函数,其参数是随机的。这种随机性类似于一种噪声,能够在一定程度上起到正则效果。
融合了sigmoid和ReLU,左侧具有软饱和性,右侧无饱和性。右侧线性部分使得ELU能够缓解梯度消失,而左侧软饱能够让ELU对输入变化或噪声更鲁棒。ELU的输出均值接近于零,所以收敛速度更快。
maxout网络能够近似任意连续函数,且当w2,b2,…,wn,bn为0时,退化为ReLU。Maxout能够缓解梯度消失,同时又规避了ReLU神经元死亡的缺点,但增加了参数和计算量。
softplus 是对 ReLU 的平滑逼近的解析函数形式。
类似tanh的非线性函数,很少被用到。
[后续为损失函数]
用来评价训练数据的好坏函数。
MSE = mean_squared_error 均方差:参数估计值与参数真值之差平方的期望值。最小二乘法的误差度量办法。而在实际应用中,通常会使用均方差(MSE)作为一项衡量指标。
对于回归任务,一般都提供了mse损失函数(基于树的模型除外)。
MAE = mean_absolute_error 平均绝对误差
MAPE = mean_absolute_percentage_error 相对百分误差
在现实数据中,往往会存在异常点,并且模型可能对异常点拟合得并不好,因此提高评价指标的鲁棒性至关重要,于是可以使用中位数来替代平均数,如MAPE。
MSLE = mean_squared_logarithmic_error 对MSE加一层对数的优化
KLD = kullback_leibler_divergence KL散度 从预测值概率分布Q到真值概率分布P的信息增益,用以度量两个分布的差异。
cosine = cosine_proximity 即预测值与真实标签的余弦距离平均值的相反数。
binary_crossentropy(亦称作对数损失,logloss) softmax作为最后一层常用的是代价函数是他。对数损失函数(logarithmicloss function) 或对数似然损失函数(log-likelihood loss function)都是他。
categorical_crossentropy:亦称作多类的对数损失,注意使用该目标函数时,需要将标签转化为形如(nb_samples, nb_classes)的二值序列。
sparse_categorical_crossentrop:如上,但接受稀疏标签。注意,使用该函数时仍然需要你的标签与输出值的维度相同,你可能需要在标签数据上增加一个维度:np.expand_dims(y,-1)。
http://keras-cn.readthedocs.io/en/latest/other/objectives/
http://sebastianruder.com/optimizing-gradient-descent/index.html
http://blog.csdn.net/viewcode/article/details/8794401
http://blog.jobbole.com/88521/
http://blog.csdn.net/u014422406/article/details/52805924
http://shuokay.com/2016/06/11/optimization/
http://blog.csdn.net/xiaozhuge080/article/details/52688613
http://www.cnblogs.com/zhangbojiangfeng/p/6362963.html
http://www.qingpingshan.com/bc/jsp/126064.html
http://blog.csdn.net/u014595019/article/details/52562159
http://blog.csdn.net/mao_xiao_feng/article/details/53242235?locationNum=9&fps=1
在直播软件中,典型的过程是A用户充值,送花给B用户,B用户提现。
正是有这样一条变现的道路,无数盗刷、退款、36技术的黑产人盯上了直播,报道见到映客的损失一度到了300万人民币(本文价值至少300万了:P)。外链https://www.douban.com/group/topic/89441680/
本文介绍利用keras+tensorflow,快速完成一个神经网络,从工程角度看深度学习带来的实际作用。
1.先升级pip
chenzhen$ pip install --upgrade pip
2.安装keras
chenzhen$ pip install keras
...
installing collected packages: numpy, scipy, six, theano, pyyaml, keras
Successfully installed keras-1.2.1 numpy-1.12.0 pyyaml-3.12 scipy-0.18.1 six-1.10.0 theano-0.8.2
3.安装tensorflow
chenzhen$ export TF_BINARY_URL=https://storage.apis.com/tensorflow/mac/cpu/tensorflow-1.0.0rc2-py2-none-any.whl
chenzhen$ pip install --upgrade $TF_BINARY_URL
...
Installing collected packages: funcsigs, pbr, mock, wheel, pyparsing, packaging, appdirs, setuptools, protobuf, tensorflow
Found existing installation: wheel 0.24.0
Uninstalling wheel-0.24.0:
Successfully uninstalled wheel-0.24.0
Found existing installation: setuptools 18.0.1
Uninstalling setuptools-18.0.1:
Successfully uninstalled setuptools-18.0.1
Successfully installed appdirs-1.4.0 funcsigs-1.0.2 mock-2.0.0 packaging-16.8 pbr-1.10.0 protobuf-3.2.0 pyparsing-2.1.10 setuptools-34.1.1 tensorflow-1.0.0rc2 wheel-0.29.0
4.检查安装是否成功
chenzhen$ python -c "import keras; print keras.__version__"
Using TensorFlow backend.
1.2.1
5.检查配置是否正确
chenzhen$ cat ~/.keras/keras.json
{
"image_dim_ordering": "tf",
"epsilon": 1e-07,
"floatx": "float32",
"backend": "tensorflow"
}
6.安装h5py 用来保存权重数据
chenzhen$ pip install h5py
...
Installing collected packages: h5py
Successfully installed h5py-2.6.0
7.安装 scikit-learn 用来写代码自动计算最优超参
chenzhen$ pip install scikit-learn
...
Installing collected packages: scikit-learn
Successfully installed scikit-learn-0.18.1
8.安装hyperas 用来自动计算最优超参
pip install hyperas
首先拿线上两天的数据,一天用来训练,一天用来测试。
数据都是csv的,根据过去的经验,一个用户给另一个用户刷钱,能拿到的数据项有:
1.是否白名单 2.是否签约 3.粉丝数量 4.是否入库 5.播放次数 6.播放时长 7.充值总次数 8.关注数量 等8个数据
所有数据均为数字,再在9位上加上0表示正常1表示有问题的用户(有问题的用户是通过之前不正常的充值靠人肉挑的)。
chenzhen$ cat deep.py
from keras.models import Sequential
from keras.layers import Dense
import numpy
dataset = numpy.loadtxt("0207.csv", delimiter=",")
X = dataset[:,0:8]
Y = dataset[:,8]
dataset2 = numpy.loadtxt("0208.csv", delimiter=",")
Z = dataset2[:,0:8]
Q = dataset2[:,8]
# 输入8个参数,隐藏层12个神经元,先用relu激活,输出用sigmoid激活
model = Sequential()
model.add(Dense(12, input_dim=8, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
# loss用mse 优化用Adamax 准确率衡量
model.compile(loss='mse', optimizer='Adamax', metrics=['accuracy'])
# 训练100次,每次取60行
history = model.fit(X, Y, nb_epoch=100, batch_size=60)
# 测试数据
loss, accuracy = model.evaluate(Z, Q)
print("\nLoss: %.2f, Accuracy: %.2f%%" % (loss, accuracy*100))
# 保存下来训练好的模型供线上使用
# serialize model to JSON
model_json = model.to_json()
with open("model.json", "w") as json_file:
json_file.write(model_json)
# serialize weights to HDF5
model.save_weights("model.h5")
print("Saved model to disk")
chenzhen$ cat run.py
from keras.models import Sequential
from keras.layers import Dense
from keras.models import model_from_json
import numpy
dataset2 = numpy.loadtxt("0208.csv", delimiter=",")
Z = dataset2[:,0:8]
Q = dataset2[:,8]
# load json and create model
json_file = open('model.json', 'r')
loaded_model_json = json_file.read()
json_file.close()
loaded_model = model_from_json(loaded_model_json)
# load weights into new model
loaded_model.load_weights("model.h5")
print("Loaded model from disk")
# test data
loaded_model.compile(loss='mse', optimizer='Adamax', metrics=['accuracy'])
score = loaded_model.evaluate(Z, Q, verbose=0)
print "for test %s: %.2f%%" % (loaded_model.metrics_names[1], score[1]*100)
# prediction probabilities里有预测的结果,需要启动一个简单的server对外服务即可。
probabilities = loaded_model.predict(Z)
predictions = [float(round(x)) for x in probabilities]
accuracy = numpy.mean(predictions == Q)
print("Prediction Accuracy: %.2f%%" % (accuracy*100))
前面讲了工程使用的步骤,里面的参数都是随便写的,准确率大约60%,现在来讲如何让预测更加准确。
test1是认好训练50次每次10条效果最好。
chenzhen$ python test1.py
Best: 0.696000 using {'nb_epoch': 50, 'batch_size': 10}
test2确认好优化器使用Adam效果最好。
chenzhen$ python test1.py
Best: 0.686000 using {'optimizer': 'Adam'}
test3是优化器使用SGD时,确认里面的两个参数。
chenzhen$ python test3.py
Best: 0.654000 using {'learn_rate': 0.001, 'momentum': 0.8}
test4是初化类型。
test5是激活函数类型。
test6是dropout层的参数。
test7是隐藏层神经元数量确定。
相关的python代码见后。
上面一种调优办法有点麻烦,要一个一个试。
Hyperas可以一次性完成。
chenzhen$ python testh.py
Evalutation of best performing model:
192/200 [===========================>..] - ETA: 0s[0.35499999999999998, 0.64500000000000002]
Hyperas的执行结果直接保存了model,简单粗暴。代码见后。
前面的模型,都比较简单,只定义了两三层,输入8个参数输出1个参数,然后有15个神经元的隐藏层,在testh.py里的调整参数时,增加了一些Activation层。
要在工程上使用,还得上到分布式tensorflow上,进行更多的训练,以达到测试集的准确率更高。
然后将保存下来的model,使用run.py里的逻辑,做成线上server,提供预测判断服务。
预测的同时,要提供人工抽检反复训练,将判断错和判断漏的,都加入到训练的过程中去,做成定时过程,才能满足需要。
另外不得不提的一点:将输入的数字归一化到0-1之间,对BPNN网络的训练效率会大大提升。
上述所有代码均在 https://github.com/54chen/deep 。
2016年,以映客为的个人直播行业从无到有,小视频行业如火如荼,GIF快手渗透到二三线城市,简单来讲,麻雀虽小也是赚钱的。
相比而言,在移动互联网发展高峰到了顶点的时间点,微信和支付宝的支付相争才是年头大戏。
汇总一句话,2016年,移动互联网大盘已定,大鱼只抢支付,小鱼小虾只走垂直方向,未来也机会多多。
个人方面,过去一年一直在各国支付和提现中了解细节,做一些收钱发钱的事情,关键还有一些如何防止黑产渗透到系统中进行套现的处理。映客没能处理好这个细节,一个月被人套现上百万。
1.国内污染比2016更加严重且封口更紧。
2.公共安全事件再一次出现。
3.微信支付在国内全方位超越支付宝。
4.小米生态链企业要雄起一两个(出名或者IPO)。
5.人工智能的项目依旧不产生实际超大收益。
6.电子支付开始作为大鱼抢占的关键制高点。
7.开始有国产手机厂商关门或被并购。
8.直播行业常态化,变成所有应用都有的功能,收益下滑。
9.云公司推出人工智能平台。
10.人民币到7.2。
明年见!
1.阿黎应该是要回来小米了。-准
2.服务器行业应该不会出现啥大的热门技术了。-一般准,人工智能不算啥新技术,但的确又热了。
3.的移动网络可能会有改善。-一般准,移动网络好了不少,2g用户少了许多。
4.c/s结构的好用的框架开始出现。-准,微信开源的框架。
5.进入资本冬天,各种小公司不好融资。-不准,热钱还是很多,很多小伙伴都创业去了。
6.国内的污染进一步加剧。-准,的天数越来越多。
7.安全生产事故再一次出现。-准,江西电厂74死。
8.造开始追求品质。-一般准,良心新国货厂商开始关注品质。
9.更多的有钱人。-一般准,这条随着6的加剧而增加。
10.人民币汇率到7。-不准,只到6.9,没到7。
近期多半时间在支付相关的业务上,特此记录一下接触到的各家情况,尽可能本着客观公正的态度进行点评(实在受不了的渠道才偏主观,见谅)。
国内支付不用说,主要是微信、支付宝,另外不得不提到的还有苹果IAP、小米支付。
分几部分, IAP主要在马来西亚、台湾等地使用的人不少(没接当地支付渠道的情况下)。paypal作为海外支付宝的角色,在很多外汇不管制的很方便。印度的话,商务不靠谱程度超乎想象,还是要提一提这几家mobikwiki、paytm。印尼、新马泰地区使用的话,讲一讲coda和doku。
排名是分先后的,把微信排在第一,表明了在我心中,他的江湖地位已经稳固。
1) 接入方面
如果是第一次接他们的用户付款,平台、公众平台、商户平台 三个的名字可以搞晕你。特别是当你发现平台的openid和公众账号的openid不是一个的时候,他们的文档会告诉你使用unionid,然后你会SB地发现线上的数据根本就TMD没有unionid,根本就TMD没有unionid!没有unionid!(重复三遍以示重要)然后,你不得不让所有的用户退出登录重新进来。
总结一下三个平台的关系:平台可以得到app里的openid,确认用户的身份; 公众平台可以得到在微信里打开h5的openid,也能确认用户的身份,如果要与前一个身份对应上,需要在平台做关联,然后产生一个相等的unionid; 商户平台和平台、公众平台有绑定关系,绑定后,才能收款的对应关系,然后(注意了!敲黑板!这里是重点!)服务号认证后才可申请微信支付,申请服务费:300元/次,然后(还是重点!)定期会过期,重新交钱。
如果要实现app提现的功能(万能的直播app必备功能),之前有人用公众号发红包的api来实现,但这前提要求先关注公众号。最佳实践还是他们企业付款的api,当然了,这个api推出时间不长,一定要注意两个返回码,一个叫return_code,一个叫result_code,必须两个都是success才是真的成功!(敲黑板!!!)呵呵!
另外一个不得不提的就是,如果你的服务器有ipv6支持,他们的域名dns会各种打圈,以至于请求慢到了5-10秒还不返回,对此参考这篇文章https://www.54chen.com/blog/2016/06/18/wexin-resolve-slowly/%EF%BC%8C%E6%88%96%E8%80%85%E5%85%B3%E9%97%AD%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%9A%84ipv6%E3%80%82
2) 坏账
微信的欺诈性订单基本没有,有纠纷的也比较少,目测主要是他们的垫付金额比较高,对商家基本无感(双手点赞!)。
3) 用户使用方面
微信支付因为微信的存在,比支付宝要方便,1000块以下的钱,还是微信方便,国内小R用户大量集中在这里。
4) 靠谱度评分
综合而言,给个最高分,4.5分(满分5分)。
江湖上曾经的老大,现在略下降排名,天天搞朋友圈。
1) 接入方面
中规中举,没毛病。
2) 坏账
欺诈性订单没有,纠纷也没有,老牌支付,数据积累不少,坏人进不来。
3) 用户使用方面
大R全在这里,因为微信支付的上限只有3000每天,所以超出额度的大R都会选择支付宝。
4) 靠谱度评分
4.4,比微信少一分,就因为支付宝最近总在那个圈里瞎JB搞。
这里要推荐小米应用内支付。
1) 接入方面
推荐的点在于,你只要接一个sdk,微信+支付宝+小米钱包,全都有了。
2) 坏账
同前。
3) 用户使用方面
基本上就是微信+支付宝+小米 用户,都适用。
4) 靠谱度评分
4分,差1分满分,是为了自己家的不要骄傲。
这个渠道很变态又不得不用。
1) 接入方面
如果app涉及到支付购买虚拟物品,苹果应用商店规定必须使用IAP,否则不通过。
接入的时候,严谨的服务器(注意!不要在客户端验证!)验证步骤是:1.有receipt字段 2.有bundle_id 3.in_app有值 4.有transaction_id 5.有prodution_id 6.bundle_id是本app 7.验transaction_id与app订单号是否相等 8.transaction_id是否使用过 9.订单号里的价格是否相等。(这里是重点!)
另外,一个比较重要的防丢单的地方(又是重点!),因为苹果不提供server to server的notify机制,一旦用户端网络不好的时候,很容易出现钱被扣了没发货的情况。这个时候,客户端要使用ios提供的机制,收到应用的回调,重新向服务器发送check订单的请求。
2) 坏账
快别提了,苹果的坏账率一度能到96%,\cry~~
如果你的app有提现功能(一般直播类打赏类软件必备功能),自己琢磨怎么风控吧(下次有机会再专门讲这里),否则会血本无归。
3) 用户使用方面
在大,访问佬服务器,使用体验你可以想象,转菊花打不开什么的是常事。关键服务这么烂,无耻的苹果要分30%的提成!
4) 靠谱度评分
1分,要不是苹果app store的原因,才不会用这么烂的支付。(希望苹果的员工能看到)
比支付宝还要老牌的国际范支付。
1) 接入方面
人家有server to server的notify,还是比较靠谱的。
有个查订单的接口,千万不要被坑了,里面有有个叫state的字段,如果订单支付有问题,他们在第二个state字段里不会是completed,千万不要只用第一个state(血泪史!)。
处理问题太慢了,一个被刷的案例,一个多星期还没有人来响应。。。商务找商务,再到开发查问题,损失都已经造成了。你能进得来才是怪事。
2) 坏账
用他们的支付,老外欺诈的很少,反而是国人在上面捣鼓退单提现挣钱。
paypal的风控体系是完善的,能提前预防一些订单。
然而万能的社会工程学成员,经常会在他们平台提起申诉,要求退款,然后你就会花大量的精力和他们提供证据,证明发货,而他们的审判也不一定会判断成给钱或不给,不可知性很强(这里也是重点,就是说他们的坏账率不固定!)。
3) 用户使用方面
海外用的人不少,除了个别外汇管制不行。
4) 靠谱度评分
3分,虽然是老牌的支付,还是没有支付宝牛逼。
这个不起眼的支付,居然可以这样。
1) 接入方面
这里,没有查询订单接口,没有server to server api。只有一个RSA的验证签名过程。
重点一,一定要在服务器验证,不要在客户端验证,不要把私钥放在客户端。
重点二,客户端代码要混淆(虽然也没啥卵用)。
重点三,android developer网站一定要用英文版,中文的翻译版本不知道是哪年翻译的了,好多东西没有。https://developer.android.com//play/billing/billing_integrate.html 最后一段,讲了要在服务器做的事情(ras x.509 balabala…)。(大量的单机游戏直接就在本地做这个验证了,这真是一个路不拾遗的好时代~~~)
重点四,漏单处理,客户端要在本地主动查询拥有的货品状态,主动commit,与苹果不同,手工的要多一点。
重点五,注意android市场的版本号不要太低,如果用户在其他渠道拿到一个版本号更大的包,是不能支付成功的!
2) 坏账
刷的人一大把一大把的,但是,人家牛逼啊,基本都能拦住。
不过不得不说的是,他们48小时可以无条件退款(虽然只有一两次到底几次不知道的机会。。。),机器学习就是牛!!
3) 用户使用方面
主要是海外有android play商店的地方,国内也有一少部分人用,但是连不上~~(因为)
4) 靠谱度评分
3.5分,比paypal都要靠谱。
印度人民大开挂。
1) 接入方面
之前在印度,大家是基本不用银行卡的,\笑cry~~
阿里投资了paytm,是当地最大的,mobikwik是个新出来的。技术接入相对简单,完全继承和学习了支付宝。
接入最大的问题是商务。外国公司是不能直接收他们的货币的,所以很长很长的商务周期后,才能开始接入,很长很长的周期后才能上线(截止发稿前,还是开发测试完成未上线)。
而且,印度人民是不乐意看到app有请求发向的(可以),请自觉怎么。
2) 坏账
未知。
3) 靠谱度评分
0分,根据印度人民的不靠谱程度,最低分其实是-1。
印尼和新马泰一带,遍布了华人的足迹。
1) 接入方面
印尼人民很有意思,线上线下的结合很普遍,他们在线上创建的订单,居然愿意跑一趟711去付现金。
接入来讲,很流行的小额支付主要是靠手机运营商代扣(分成50%以上!)。
稍微大额一点(大于相当人民25块),就会线上创建订单,便利店+ATM付款了。
codapay集成了一堆的支付方式,要实现的只有计算他们的301地址的签名的一段逻辑(意味着基本没有native的sdk)。
2) 坏账
他们坏账自己承担(民风纯朴,哪有啥坏账)。
3) 靠谱度评分
codapay2分,doku 2.1分,他两都是当地的支付商家,doku的接口多一些,多0.1分。
这是小米大树系列第三部分,前两部分见:
https://www.54chen.com/blog/2016/08/06/mi2/ 《小米大树part2:测试之痛》
https://www.54chen.com/blog/2016/08/01/mi1-dot-5/ 《小米大树part1.5:基础架构之痛答疑》
https://www.54chen.com/blog/2016/07/29/mi/ 《小米大树part1:基础架构之痛》
一直想写一系列的笔记,记录整个小米六年的研发工作中实际遇到的困难,以及这一大群人如何不可避免的走向大公司氛围,又如何慢慢打破定势。
作为开发人员,实在是难以启齿吐槽产品经理,以至于很久没有补上第三篇。--题记
十年前的互联网公司,大多数还没有这个岗位。如今人人都是产品经理的年代,烂大街的灵光一现的点子,不知所谓的需求描述,不着边际的实际作,无人问津的后续跟进,直接造就了产品太烂、进度缓慢的各种局面。
A君是产品,从业多年,下过海创过业,身经百战。
A:我们的用户经常在这里出现了问题,我觉得要把这里拿掉,做成xxx的。
开发B:好啊,我觉得也是。
一个月过去了,A君遇到用户投诉,问B:当时说过的xxx怎么没有做啊?
B一脸懵B:纳尼,我以为你只是随口说说。
好的产品,不会提一句话需求,落实到文档到交互到协调到执行,才是好产品。
C君刚从某211高等学府毕业,茫然投身于产品事业,从业一段时间发现开发同学很懒,需求经常被开发追问为什么。
一次偶然机会C君发现只要说需求来自x总,开发基本不再问,效率很高,久而久之,来自y总、来自z总就成了基本功了。
C:这个需求是z总提的,我也不知道为什么。
开发D:z总提的,你也需要知道为什么呀,z总也是用户,你这样的实现是不是真的解决了用户的问题?不要做传话筒。
好的产品,不会把老板的需求挂在嘴边,会进一步挖掘用户真正的需求,据理力争。
产品E君,身兼数职,事情太多。
E:这个需求的详细文档在xxx,分析也比较清楚,开发时间也已经给出,剩下就看大家的了。
然后就没有然后了。
一段时间过去了,无人再问津。
突然有一天有人问起,xxx需求怎么还没做出来。
做出来了,因产品太忙无人验收这个需求,一直没有合主干。。。
一个好的产品,绝不会忘记自己提过的需求。
x功能,由于对系统架构改动太大,迟迟没有动工。
产品对需求丝毫不让步,和开发天天讨论不休,却没有结论。
产品F:这个需求只是为了试一试,谁也不知道有没有人用,我们先按简单的方案来搞吧。
一个好的产品,一定会区分“试一试需求”和“all in需求”,并且提前告知开发。
一个y功能,不知道哪个产品君提出的,开发做完了,由于赶时间测试也马虎通过了。
线上发现了问题,回滚,重新改逻辑,重新找bug,重新上线,浪费了大量的人员和时间。
这一点,是产品的意识问题,互联网产品如果承担一部分测试工作(我们叫做验收功能),从越早环节发现问题影响越小、成本越低。
黑猫白猫,好产品坏产品,只要是从用户出发的产品,都不孬。
痛点太多,竟无从下笔。–题记
一直想写一系列的笔记,记录整个小米六年的研发工作中实际遇到的困难,以及这一大群人如何不可避免的走向大公司氛围,又如何慢慢打破定势,苦于自己拖延症影响,现在才开始总结。
共分三个部分:基础架构之痛、测试之痛、产品进度之痛。本篇是第二部分。
2010年,来自各大公司的ABCD君,都拥有良好的软件工程习惯,测试代码行行见血。即便如此,依旧不能耽搁产品的节奏,于是开始找来专门的测试人员。
E君从事开发测试多年,测试经验丰富,开发只要给个连接服务的框架就可以开工,属于给了原子弹就能上天型。
F君则一直专注在手工测试上,产生一些稀奇古怪的作方法来帮助找出问题。
A:“我们可以放弃单元测试,只搞好冒烟测试bvt,每日对线上和测试环境发起测试。”
E:“没问题,给我们测试时间,一定可以完成覆盖。”
然后一直时间不够,就在缺少开发测试和覆盖不全的矛盾中度过了两三年。
经常会出现一种情况,新功能上线了,忘记通知测试……或者通知了测试没有人力来写测试代码…
测试工程师一直被赶着,本身招聘价位低于开发,再加上稍微能力强一点的测试工程师就想着转为开发,测试这个活就越来越没有动力了,从而矛盾开始加剧了,直到有一天,暴发。
D:“开发的屁股要自己擦!”
E:“测试只提供测试框架技术支持!”
F:“手工测试要提前预约!”
A:“MD现在真大公司!”
于是很多项目,急于上线,没有测试,这些项目都由开发打了保票,所以可以直接上线,当然了,开发也不是万能的,同时也不乏上去线就挂了的。
A:“为啥这个项目上线就挂了?”
B:“因为有个逻辑有瓶颈,线上压力一大就挂了,测试环境没压力看不出来。”
C:“为啥没考虑做压力测试?”
D:“项目太杂乱,模块太多,关系不清,很难做压力测试的环境。”
E:“给我们两个月时间搭环境,做压力测试!”
两个月过去了,压力测试环境卡在了某个基础环境上,迟迟不能解决。算了,不能测不测了。反正我们灰度上线也是一种压测办法…
就这样,度过了一天又一天。
四五年后,并没有发生实质性变化。每当开发工程师回头看自己的代码时,经常会被自己吓到,真的有一种刀尖上跳舞的感觉。
一旦大家被自己吓到,想到需要测试的时候,还没开始想办法立马会被错综复杂的服务吓退。
就这样在胆颤心惊中度过一年又一年。
改变这一切的都是细节。
在上一篇( https://www.54chen.com/blog/2016/07/29/mi/ )里提到的基础设施的改进后,模块之间服务之间抽象的很简单,只关心超时-被调用方承诺的最大服务时长,超过为不可用。
在超时确立后,压力测试变得简单,要压测一个服务,只需要将下游服务全部故意超时掉(办法有很多种,比如调度到一个不存在的地方去等超时),此时可以得到此服务的最差表现下的压力情况,这个数据完全可以供线上参考使用。
解决了压力测试的问题之后,我们延用了原来bvt的思路,依旧对服务进行最外围的功能覆盖测试,每次上线前,都依赖bvt的结果进行判断能否上线,不同在于,我们对整体服务的接入逻辑进行了分类,重要的地方提前准备用例,后期加的地方可以慢一点跟进。
一切在向好的方向变化,虽然测试资源也是时不时紧张一下。
一句话概括:测试工作不能省也不能推。测试没做好,开发占六成因素,测试占四成。
上周末发了第一篇,在微博收到了许多朋友的反馈,可能是写得匆忙,没能完整描述,特加1.5,专门针对各位的问题进行答疑。
原文地址:《小米大树part1:基础架构之痛》| https://www.54chen.com/blog/2016/07/29/mi/
Q:@浩松 …为啥我觉得博主还是没有找到原因。这个东西就和为什么要统一度量衡统一文字集权虽然不同地方的方言可能有差别一样的,和有没有腾讯的人一点关系都没有啊
A:其实我想表达的,并非是统一度量衡这个问题,发展过程中,大家的度量衡其实是统一的。而更大的问题是,度量衡本身不科学,我们大多数时间在监控一个服务自身的qps\percentile等数值,却没有一个可用性的数值来监控和报警,这是根本点。
Q:@咩罗 花式吹腾讯…
A:完全是个无心之举,但从腾讯过去从来不参加开源到现在一点一点放出来技术细节,的确要高于行业水平。回忆一下,已经很久没有遇到QQ大规模故障了。
Q:@沧落海 我靠,git,memcache都能拿来说
A:为什么不能拿来说,git现在是十岁多,我在讲的五六年前的事情,国内还在流行svn,我们的团队还有人连svn都没用过。而memcache,我们引入的实际上是zookeeper和memcache的合体解决方法,做到自动化配置。
Q:@辩图识人生 引入C基础架构,排除gc影响,提高吞吐。–现在基础平台以c为主?
A:只是部分,因为小米还是没有CTO这样的行政岗位,有基础的团队自己会跑在前面,并不强求全公司的基础架构都发生改变。
Q:@Easy 页面的行间距调一下吧……看着好诡异……
A:这是个好问题,顺手调了一下,不知道大家感觉如何。
《小米大树part2:测试之痛》大约周末有功夫写,写完就发。大概会记录当时我们如何做不了单元测试、如何做冒烟测试、如何在压力测试上失败,以及如何不测试。
无知和弱小不是生存的障碍,傲慢才是。 --《三体》
一直想写一系列的笔记,记录整个小米六年的研发工作中实际遇到的困难,以及这一大群人如何不可避免的走向大公司氛围,又如何慢慢打破定势,苦于自己拖延症影响,现在才开始总结。
共分三个部分:基础架构之痛、测试之痛、产品进度之痛。本篇是第一部分。
2010年,第一批服务器工程师来自五湖四海,有金山、微软、、百度、人人,唯独,没有来自最大互联网公司-腾讯。
A君(人物纯属虚构,以求表达效果)从业数年,经验丰富,说:“我觉得我们可以用一些php,简单好招人”,于是开始这样干了。
B君说:“我们还可以用一些java,招人也不太难,现成的东西多”,于是这样作了。
C君说:“的thrift也不错,我们需要一个这样的rpc框架”,于是用上了thrift。
D君说:“与客户端最简单,还是用http请求吧,加上json,调起来方便”,于是就http+json了。
E君和F君带来了先进的海外大公司经验,大家都深信不疑。
G君带来了maven,H君带来了git,I君带来了zookeeper,J君带来了memcache,K君带来了scribe,L君带来了hadoop,M君带来了HBase,N君带来了spring。。。
两年之后,诸君磨合成了以java为核心,诸多语言为辅助,看上去哪哪都大厂的基础体系。并且大家都认为可以为各兄弟无脑使用了。
两年之后,人多事杂,诸君分为多个,多个都在共用着这一整套基础架构。
有一天,X君在调用Y君的接口出现了速度突然变慢了一倍,从10ms的速度变成了100ms(因为基础架构里没有可用性的计算,X君也是在用户投诉说最外层的API慢,分析之后才发现只有可能是这里慢了)。
X:“Y啊,你的服务不稳定啦,怎么慢了10倍,影响我们的服务啦”。
Y:“不对啊,从基础架构里提供的counter看,我们的服务一切正常,99.9%的请求,都在5ms返回了”。
X:“真的是你这边慢了,你再查查吧”。
Y:“可能是网络有问题吧,我们的服务真的没有问题”。
X无可奈何,Y也觉得自己没有过错,转身,X抱怨了一句:“TMD现在怎么这么官僚啊”。Y也莫名其妙:“草,A这的人太找茬了”。
Z君在网络,从交换机上看了一下图,“网络一切正常”。
这个技术问题就这样没有了结论。
上述的场景在一天又一天演进,慢慢形成了所谓的大公司氛围,除非同一的人遇到了问题,很难将一个问题查到根本原因。
而X君遇到的问题,也没有专家团队可以帮忙解决,因为当年引入技术的专家们,分散在各个,在为各自的方向努力,根本无暇顾及。
靠前人拼凑出来的基础架构里,多年过去也没有可用性这样直接抽象的数据和监控报警。
根本的原因,是基础架构里,没有一个CTO的角色,从技术上进行抽象思考,从行政上强迫统一。
腾讯的前CTO张志东应该是个牛逼的人,带领老一辈的技术高人们,没有这么多开源的项目可以借用,所有的东西都要靠自己来抽象。
在没有开源行业的这个大保障(大包袱),腾讯的基础架构抽象得出奇的自然,再经过几代人的修补,已经坚不可破。
而X君这次遇到的问题,痛点在于:1.基础架构里的监控数据无法表达X君、Y君服务的可用性。2.Y君所参考的基础架构里的自身监控数据也无法认同X君说自己的服务不稳定的现实。3.X君和Y君,都没有意识到,网络也是服务的一环,而不是交给硬件和网络维护。4.X和Y君都在使用java,典型的gc问题就可能导致双方的数据全部不可靠。
在第四五年的时候,已经开始有在打破上述的常规:
1.引入C基础架构,排除gc影响,提高吞吐。
2.主动调用方以承诺最大延时得出可用性数据描述被动调用方服务稳定性,并且双方达成一致。
3.除非有明确的原因分析结果,绝不把问题抛向相关团队。
4.每个环节,都有可用性数据,包括客户端。
一句话概括,对于互联网业务,可用性就是一切。
有朋友在阿里云主机实现微信支付逻辑时,发现api.mch.weixin.qq.com的解析实在是太慢了。
因此出现了手动修改/etc/hosts的情况,当然了,哪天微信支付要是换个机房肯定要挂。
我们的机房也有相似的同题,专门记录一下。
代码里用curl来请求微信,经常超时,这时使用wget试验:
[root@01 tmp]# wget api.mch.weixin.qq.com
--2016-06-18 14:51:03-- http://api.mch.weixin.qq.com/
Resolving api.mch.weixin.qq.com... 域名解析很久不出来
给wget加上-4,强制使用ipv4,如果很快,那基本上确定是ipv6惹的祸了。
[root@01 tmp]# wget -4 api.mch.weixin.qq.com
--2016-06-18 17:03:52-- http://api.mch.weixin.qq.com/
Resolving api.mch.weixin.qq.com... 123.151.71.149, 123.151.79.109
Connecting to api.mch.weixin.qq.com|123.151.71.149|:80... connected.
专门写个代码来测试ipv6的解析,用到系统函数getaddrinfo:
#include <stdio.h>
#include <string.h>
#include <netdb.h>
#include <iostream>
#include <sys/types.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
using namespace std;
int main() {
struct addrinfo hints,*answer,*curr,*p;
int error;
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_INET6;//AF_UNSPEC; // use AF_INET6 to force IPv6
hints.ai_socktype = SOCK_STREAM;//SOCK_DGRAM; // SOCK_STREAM
if ((error = getaddrinfo("api.mch.weixin.qq.com", NULL, &hints, &answer)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(error));
return 1;
} else cout <<"Success with a URL\n";
char ipstr[16];
for (curr = answer; curr != NULL; curr = curr->ai_next) {
inet_ntop(AF_INET,&(((struct sockaddr_in *)(curr->ai_addr))->sin_addr),ipstr, 16);
printf("%s\n", ipstr);
}
freeaddrinfo(answer);
return 0;
}
包含头文件
netdb.h
函数原型
int getaddrinfo( const char hostname, const char service, const struct addrinfo *hints, struct addrinfo **result );
参数说明
hints:可以是一个空指针,也可以是一个指向某个addrinfo结构体的指针,调用者在这个结构中填入关于期望返回的信息类型的暗示。举例来说:如果指定的服务既支持TCP也支持UDP,那么调用者可以把hints结构中的ai_socktype成员设置成SOCK_DGRAM使得返回的仅仅是适用于数据报套接口的信息。而是否ipv6则由ai_family决定。
result:本函数通过result指针参数返回一个指向addrinfo结构体链表的指针。
返回值:0——成功,非0——出错
ai_family为ipv6时,只会寻找ipv6的解析结果,一般域名也没设置。ai_family为AF_UNSPEC时,会先ipv6再ipv4的,而api.mch.weixin.qq.com这个域名的ipv6解析出奇的慢(qq.com却不慢,原因见后)。
如果是curl,c可以强制指定ipv4,使用curl_easy_setopt(curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
其他语言的也参考此法。
https://github.com/54chen/dns_test
nslookup -query=AAAA api.mch.weixin.qq.com -debug 是找不到解析的(指定的AAAA就是ipv6),然后会发现一个SOA声明和他的上级weixin.qq.com有一个ipv6的CNAME,到了minorshort.weixin.qq.com,而这域名又是没有ipv6的解析的。
目测ipv6找解析时是在这个SOA和CNAME的地方打圈了,微信的同学们是不是考虑让大伙好过一点,把这些个域名的ipv6设置去掉。
dig @ns-tel1.qq.com weixin.qq.com AAAA
weixin.qq.com. 43200 IN SOA ns-tel1.qq.com. webmaster.qq.com. 1293502040 300 600 86400 300
这里记录了一种简单的办法,在遇到写c/c++找不到答案时的最简单找代码办法。
方法是:找php怎么解决,大把的答案,然后看php源代码是怎么用c实现的。
我们server端在对接 play的时候,遇到了ras加密来验证参数的实现,官方也没有什么c的参考代码,java和php的网上倒是能找到一堆。
java的实现和本文要说的内容无关,只是随带一列:
public static boolean verify(String publicKey, byte[] data, String sign) throws Exception {
// 解密由base64编码的公钥
byte[] keyBytes = Base64.decodeBase64(publicKey);
System.out.println(keyBytes.length);
// 构造X509EncodedKeySpec对象
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
// KEY_ALGORITHM 指定的加密算法
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
// 取公钥匙对象
PublicKey pubKey = keyFactory.generatePublic(keySpec);
Signature signature = Signature.getInstance("SHA1WithRSA");
signature.initVerify(pubKey);
signature.update(data);
// 验证签名是否正常
return signature.verify(Base64.decodeBase64(sign));
}
php的实现比较多,随便找了一个,没有验证过:
<?php
$public_key = file_get_contents(dirname(__FILE__).’/rsa_public_key.pem’);
$pkeyid = openssl_pkey_get_public($public_key);
$data = ‘abc’;
$sign = ‘WkMaSsx9Fbj9/YyjoM1X0SLYvaFbsz9VmMaxc42fXxamEEIj5AfqQLrygEZRq0gkLNT4heIwOiSWEAWbfD4imaERKk07ANXEtZJ9jPJvyvg70IVvaYMKAr7bX0dJXmYw4aHnkcWR1kz27Drr6fxPmchB9WCsRmi4VfhVoF1+HRFOp28nIVReGRcbwbW1/bcMisXbitirz9Wq396vY88GUSgbgNdhFXX/kzjRBTjnG+CIhXq4HPdOWovqtPhQoxmK55+V+vxNZk9OPPHHaN3vVswk062NOs2/05yNVObL+PWeg/m43buXYalmkrwEhemdGfjIdNEoSO2D4gikvm43cg==’;
$sign = base64_decode($sign);
if ($pkeyid) {
$verify = openssl_verify($data, $sign, $pkeyid, OPENSSL_ALGO_MD5);
openssl_free_key($pkeyid);
}
var_dump($verify);
?>
看到上面的php代码,关键的几个函数有:openssl_pkey_get_public openssl_verify
然后转战最新的php源代码,https://github.com/php/php-src/blob/80f91fd9d513b83ca88345a2a8c76523e0164789/ext/openssl/openssl.c 。
别问为什么可以定位到这个文件的,github可以直接搜一个库里的源文件。
忽略一切以zend、zval开头的逻辑,直接找上面关键的函数。
于是就找到了关键的头文件:
/* OpenSSL includes */
#include <openssl/evp.h>
#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include <openssl/dh.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/crypto.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/conf.h>
#include <openssl/rand.h>
#include <openssl/ssl.h>
#include <openssl/pkcs12.h>
关键的一行key生成代码:
key = PEM_read_bio_PrivateKey(in, NULL,NULL, passphrase);
关键的核心逻辑:
EVP_VerifyInit (&md_ctx, mdtype);
EVP_VerifyUpdate (&md_ctx, data, data_len);
err = EVP_VerifyFinal(&md_ctx, (unsigned char *)signature, (unsigned int)signature_len, pkey);
EVP_MD_CTX_cleanup(&md_ctx);
if (keyresource == NULL) {
EVP_PKEY_free(pkey);
}
这么些核心代码都找到了,还不会抄吗?
通过上面的过程,进行自己的组装,已经再简单不过了,为了让写c/c++的同学们快速得到 play的rsa验证代码,特别贴一下:
int verifiedByRsaPublicKey(const string& publicKey, const string& signature, char* message) {
char *chPublicKey = const_cast<char *>(publicKey.c_str());
BIO* mem_bio = NULL;
if ((mem_bio = BIO_new_mem_buf(chPublicKey, -1)) == NULL) { //从字符串读取RSA公钥
BIO_free(mem_bio);
return -3;
}
EVP_PKEY *publicRsa = PEM_read_bio_PUBKEY(mem_bio, NULL, NULL, NULL);
unsigned int slen = signature.length();
EVP_MD_CTX md_ctx;
EVP_VerifyInit(&md_ctx, EVP_sha1());
EVP_VerifyUpdate(&md_ctx, message, strlen(message));
int err = EVP_VerifyFinal(&md_ctx, (unsigned char*) signature.data(), slen, publicRsa);
EVP_MD_CTX_cleanup(&md_ctx);
EVP_PKEY_free(publicRsa);
return err;
}
通过php的解决方案去找到php的实现,是写c/c++同学们不可不学的一招。
This is a simple solution when you do not know how to develop with c/c++.
The solution is,it will have lots of answer ho to do with php in ,and then look up the desgin in the source codes of php.
We need to verify the parameters by RSA when we devlop the Play apps.There is not any reference codes with c/c++.There are so many java or php examples in the internet.
It no connection with what we are talking about.Just BTW:
public static boolean verify(String publicKey, byte[] data, String sign) throws Exception {
// 解密由base64编码的公钥
byte[] keyBytes = Base64.decodeBase64(publicKey);
System.out.println(keyBytes.length);
// 构造X509EncodedKeySpec对象
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
// KEY_ALGORITHM 指定的加密算法
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
// 取公钥匙对象
PublicKey pubKey = keyFactory.generatePublic(keySpec);
Signature signature = Signature.getInstance("SHA1WithRSA");
signature.initVerify(pubKey);
signature.update(data);
// 验证签名是否正常
return signature.verify(Base64.decodeBase64(sign));
}
There are too many php examples.Find one without checking:
<?php
$public_key = file_get_contents(dirname(__FILE__).’/rsa_public_key.pem’);
$pkeyid = openssl_pkey_get_public($public_key);
$data = ‘abc’;
$sign = ‘WkMaSsx9Fbj9/YyjoM1X0SLYvaFbsz9VmMaxc42fXxamEEIj5AfqQLrygEZRq0gkLNT4heIwOiSWEAWbfD4imaERKk07ANXEtZJ9jPJvyvg70IVvaYMKAr7bX0dJXmYw4aHnkcWR1kz27Drr6fxPmchB9WCsRmi4VfhVoF1+HRFOp28nIVReGRcbwbW1/bcMisXbitirz9Wq396vY88GUSgbgNdhFXX/kzjRBTjnG+CIhXq4HPdOWovqtPhQoxmK55+V+vxNZk9OPPHHaN3vVswk062NOs2/05yNVObL+PWeg/m43buXYalmkrwEhemdGfjIdNEoSO2D4gikvm43cg==’;
$sign = base64_decode($sign);
if ($pkeyid) {
$verify = openssl_verify($data, $sign, $pkeyid, OPENSSL_ALGO_MD5);
openssl_free_key($pkeyid);
}
var_dump($verify);
?>
The key functions are openssl_pkey_get_public and openssl_verify in the codes above mentioned.
Go to the newest php source codes, https://github.com/php/php-src/blob/80f91fd9d513b83ca88345a2a8c76523e0164789/ext/openssl/openssl.c
Dont ask me how to find the file.You can search the file in a project at Github.
Ignore all the codes start with zval and zend.Go to the codes which include the key functions.
And then there is the key header file:
/* OpenSSL includes */
#include <openssl/evp.h>
#include <openssl/bn.h>
#include <openssl/rsa.h>
#include <openssl/dsa.h>
#include <openssl/dh.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <openssl/crypto.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <openssl/conf.h>
#include <openssl/rand.h>
#include <openssl/ssl.h>
#include <openssl/pkcs12.h>
The key codes generated pkey:
key = PEM_read_bio_PrivateKey(in, NULL,NULL, passphrase);
The core logic:
EVP_VerifyInit (&md_ctx, mdtype);
EVP_VerifyUpdate (&md_ctx, data, data_len);
err = EVP_VerifyFinal(&md_ctx, (unsigned char *)signature, (unsigned int)signature_len, pkey);
EVP_MD_CTX_cleanup(&md_ctx);
if (keyresource == NULL) {
EVP_PKEY_free(pkey);
}
All of the codes are ready,cant you copy?
It is easy to merge the codes above mentioned.
To get the codes faster for any other people,there are the codes about play Ras verifying:
int verifiedByRsaPublicKey(const string& publicKey, const string& signature, char* message) {
char *chPublicKey = const_cast<char *>(publicKey.c_str());
BIO* mem_bio = NULL;
if ((mem_bio = BIO_new_mem_buf(chPublicKey, -1)) == NULL) { //从字符串读取RSA公钥
BIO_free(mem_bio);
return -3;
}
EVP_PKEY *publicRsa = PEM_read_bio_PUBKEY(mem_bio, NULL, NULL, NULL);
unsigned int slen = signature.length();
EVP_MD_CTX md_ctx;
EVP_VerifyInit(&md_ctx, EVP_sha1());
EVP_VerifyUpdate(&md_ctx, message, strlen(message));
int err = EVP_VerifyFinal(&md_ctx, (unsigned char*) signature.data(), slen, publicRsa);
EVP_MD_CTX_cleanup(&md_ctx);
EVP_PKEY_free(publicRsa);
return err;
}
Is is a good solution for c/c++ developer.You can find the answer in php at first,go to see the c source codes of php at last.
2010年的时候,我们开始最早的一波做小米的服务器的同学,基本都很少互联网经验,七拼八凑的把米聊上了线,这么多年过去了,很多技术框架沉淀到了公司各处团队中去了。
今天再来看,其实有很多细节,当时真的没考虑(现在也是坑)。
一个典型的架子,是nginx+resin/tomcat,然后在nginx上设置weight=1 max_fails=3 等等。
在上线的时候,并没有平滑过度的手段(比如修改一下所有nginx配置拿掉一台之类的),所有的上线都是有损的。
庆幸的是,移动互联网native的app,断个一两秒的不服务用户感觉不出来。
线上故障的情况,不出意外就是一个模块和另一个模块之间发生了什么问题。
过去的几年,我们始终没考虑过抽象出来这种数据。
我们的监控数据全部是以单独一个模块自身的访问数据(qps、响应时长等),常见的问题是别人说访问你慢,访问老失败,你自己一看数据觉得还挺好。
如果当时没有paoding-rose,我想我们会考虑做成一个标准的tcp server,中间用pb传输到手机。
这样做的好处,在应对不好的移动网络的时候,http束手束脚,而tcp却得多。
这一点我同样要点名嘲笑一个微博的客户端,在一样的坑里。
如果当时选的是php,我想我们线上的服务在很多年后需要重启的会很少(由于nio或者其他什么泄漏之类的,最后服务就假死了,重启就能管很长时间)。
当然了,现在来看,更倾向于选c/c++,至少老老实实的写不会有太大的坑,跑起来也稳定。
用mysql没有什么错,使用方便,实现业务快。
在中期要做多IDC容灾的时候,没办法了,实在是关系太复杂了,做不了。
如果当时我们全部有key-value的,将大量的mysql做的事情放在业务代码里来,做多IDC简直是小菜一碟。
而多IDC在一个互联网业务来看,上量了之后又是多么重要的一件事情。
在需要削峰的项目上使用mq无可厚非,但是一个项目到处都在用mq的时候,简直是灾难(想一想,一个大系统,调用谁不清楚,谁在调用也不清楚,只知道自己在消费什么对象)。
后期的时候,要想知道一个模块正在被谁调用基本无从查询了,因为这些开源的mq,根本不会考虑实际运维中的需求,出发点全部是如何快速的使用。
细节有点多,坑都还在(还有一些坑已经爬出来了就不列在这里了),依旧有后继的团队和项目在坑里,如果一个项目立志要做大做强,还是一开始就跳出这些坑吧。
We deployed MILIAO server, which was a sketchy version patched together, in 2010.The first team members that developed at XIAOMI sever-side were less experience in the internet field.
The techlonogy frameworks have broadcasted to every team in XIAOMI after all these years.
And now for a look at the techlonogy details,it was thought too little at that time.
A typical case is nginx worked with resin or tomcat,and there is a configration like ‘weight=1 max_fails=3’ in nginx.
There is not graceful when deploying the service.We dont have any load-balance tool.
It is a relief that the users do not know out of service at the native app.
No surprisingly,there is something wrong between one model call another one when it is out of service online.
We have not thought about the model-call traffice data in the pass years.
We have too many data like QPS and percentile but all of them are made by the servce be called rather than the caller.
One question that frequently comes up was that looks all good by data but not good by the caller.
Without pading-rose framework,I think we would develop a tcp server,which transfer data by protobuffer.
It is better for Chinese network enviroment,because the tcp one is more free than the http one.
The Weibo app is also designed by http.
I think the service online is not need restarted now if we had choose php at that time.
Now I prefer c/c++.It is less problem.
It is not wrong that a project is designed by mysql.It is easy and quick.
But it is difficult when you want to take the service to multi-IDC.It is impossible.
Mult-IDC is a easy thing,if we have designed the service by key-value store.The logic must be done in project rather than in mysql.
This is so important when your project have became greater.
It is doesnot matter that a peakedness project is designed by mq.It must be a disaster that a usual project is designed by mq everywhere.
It is difficult to find the calling relationship.
There are too many details.To avoid the wrong thing if your service will be greater.
前些天看到了老板的二十年前的文章《程序人生》,地址在这里 http://t.cn/RqPJYHU ,深有感触,于是也萌发了写一写的想法,看看二十年后,自己的认识是否会有所改变,当然了,即便作为职业码农近十年,很多观点依然不能构成一种完整且保证正确的人生观。
如果一定要用几个词来形容程序员的人生观,我想那应该是:坚定、乐观、冷静、钻研。
//如果不能坚定地知道自己喜欢计算机这个事情,早就干点别的什么去了,码农这个事情常人看来无味极了。
与上一辈程序员相比,时代留给这一辈的机会不同,裕兴、小霸王、步步高成为我们很早就启蒙计算机知识的最佳方式,从小学或者初中起,脑洞大开。
在接触过的好朋友中,凡是从小接触计算机的,在初中高中已经基本可以完成一些诸如pascal\c\basic\asp之类的流行技能。他们大多干过如下的事情:1.做个人网站 2.帮教务处做报课系统 3.维护学校bbs(当然了,雷老板是这事情的鼻祖了) 4.接些外包小系统赚点外快。
上述这些枯燥的事情中,每件事情,都需要投入极大的兴趣,不计得失,才能取得一点点的成就感。如果没有坚定的想法,多半都半途而废了。
//如果不是乐观的态度,早被遇到的困难和歧视折磨死了。
一个同学,在大连做外包行业的开发工作,毕业后干了两年到了结婚生子的年龄了,什么积蓄也没有,对整个行业失望至极,完全没有方向,回家随便找了个商场当起了销售员。
比起老板阳春白雪的干上一辈子程序的想法,更多看到的是程序员还在温饱线上挣扎的现实。
别说是国内流行的35岁前转管理岗这种说法,光是吃不饱一个问题,不够乐观的程序员,早就已经放弃了这个行业。
对于乐观的人来说,这些都不是事。十年前我在金山实习的时候,工资才够付房租,吃饭还得想办法[笑cry]。
//遇到困难,冷静地战胜困难,是程序员的兴奋点。
有很多事情,程序员并不担心,这是思维上的习惯。
曾经有过这样的同事,遇到bug找不出来,急得像热锅上的蚂蚁,思维已经完全顾不上想解决的办法,只剩下着急。
如果不够冷静,只会让事情更糟。
//浪费一次调查到问题根本原因的机会,就是浪费生命。
这是职业习惯,许多时候程序员要靠这种钻研的过程来吸收新的知识。
许多人反而容易放弃一次可以轻松得到的学习机会,认为很多问题出现了,可能是什么什么原因,然后就结束了。
钻研的习惯要靠很多年才能养成,还要花费大量的时间和精力,要成为人生观的一项,很是艰难。
但在程序员的人生观里,这都是很正常的事情。
与老板的程序人生相比,本文主要是说的一个纯粹程序员的人生观。然而,要在社会立足,专业的程序员肯定不如专业的企业家或者小老板靠谱。
所以,摆在程序员面前的两条路:1.用专业的程序员态度慢慢积累财富,离开这个,去物质丰富的发达继续程序人生。2.用我老板的程序人生思路,不要沉浸在程序员的世界里,抬头看看社会需要什么,约三五好友,完成需求,转而进入了"企业家程序人生"行列。
在c++中使用protobuf的时候,大多数元素,我们可以直接set_xxx,如果有嵌套进去一个对象,会有set_allocated_xxx的方法和mutable_xxx的方法。
这里有一个坑。
首先,看pb定义:
package test;
message a{
required uint32 aa = 1;
}
message b{
required a aaa = 1;
}
如果使用set_allocated_aaa,同时传入了一个定义好的a,而不是new的a,如下:
void bad_case(){
a aa;
b bb;
aa.set_aa(1);
bb.set_allocated_aaa(&aa);
}
编译的时候不会有错误,一运行就出问题了:
*** glibc detected *** ./test.run: double free or corruption (out): 0x00007fffc65ade20 ***
下面的写法,不会有问题:
int good_case1(){
a* aa = new a();
b bb;
aa->set_aa(1);
bb.set_allocated_aaa(aa);
return 0;
}
下面的写法,也不会有问题:
void good_case2(){
a aa;
b bb;
aa.set_aa(1);
bb.mutable_aaa()->MergeFrom(aa);
}
在pb生成的对象中,析构函数统一都要进行对象的delete作:
b::~b() {
// @@protoc_insertion_point(destructor:test.b)
SharedDtor();
}
void b::SharedDtor() {
if (this != default_instance_) {
delete aaa_;
}
}
通过定义得到的一个变量,只在栈上临时生成,在函数生命周期后自动清理,而将地址给了一个pb后,执行结束时会进行手动delete,从而导致了double free。
通过new得到的一个对象,放在堆上,手动delete才会清理。
good_case2正确的原因,是因为mutable_aaa的代码里new了一个a。
inline ::test::a* b::mutable_aaa() {
set_has_aaa();
if (aaa_ == NULL) aaa_ = new ::test::a;
// @@protoc_insertion_point(field_mutable:test.b.aaa)
return aaa_;
}
使用pb的set_allocated_xxx要小心,没有显式allocate的东西不要往里传。
文中涉及的代码地址:https://github.com/54chen/test
马上过年了,先祝大家新快乐、万事如意!
一群错综复杂的服务,如何去衡量质量,如何去快速找到问题,如何每个环节都有“眼线”?
yammer的metrics项目,可能算是大家用得最多的一个了,可以算qps,可以算99.9%的请求时长。
这些在线上故障的发现和定位有用吗?够用吗?
通过线上的事故积累,答案是,故障的发现,仅通过一个qps和percentile的绝对值来报警,误报非常高,真正的故障往往被掩盖。:(
经过前辈们的探索,下面的实践的确是最佳的:
1.服务抽象为主调方和被调方。
2.提前商定好超时,以一分钟为单位计算成功率。
3.连续三分钟的成功率低于三个九,报警。
实践中从来没有误报过。:)
服务在告诉监控系统成功率的时候,随带就告诉了系统,是因为1(超时)、2(用户不存在)、3(xx服务不响应)、4(存储异常)等等。
出现故障的时候,报警直接会告诉你,“90%原因是超时”,连服务器上的日志都不用去看!
通过抽象的数据,我们可以再按照每天的成功率进行统计,“天三个九”的要求会低于“分钟三个九”(不信你算一下)。
日报里大致会标出 A->B 99.1% B->C 98.9% C->D 99%,很明显了,D服务有问题了,导致上面每一层都有问题。
再单独看C->D抽象返回的结果统计,1占88% 2占1%等等,定位为超时原因。
然后看看具体出问题的时间点是否有其他的异常日志,如果没有,则是需要扩容了(增加处理线程OR增加机器)。
文中系统真实存在,童叟无欺,实现简单并未开源,小米同学可以使用,如有欲望邮件联系我。
2015年,是一直在学习的一年,来自腾讯小伙伴们的多年经验要在一年里吸收,包括方式方法技术方案,着实不是一件容易的事情。
在这一年大部分时间,都在围绕着用户的网络问题进行着努力,让问题从出现到解决成为闭环,环环相扣,直到找不到漏洞所在。
汇总一句话,2015是充实忙碌的一年,也是完全解开了前三年的一些技术疑问的一年。
生活方面,这一年搬了新家,学习了装修的过程,端午在在塞班了解了一下苦逼的帝国人民都是如何浪费生命的,年底又去了一趟大连办档案,然后在小米满了五年,签了第一份无固定期劳动合同。
展望2016,可能会有以下十件大事:
1.阿黎应该是要回来小米了。
2.服务器行业应该不会出现啥大的热门技术了。
3.的移动网络可能会有改善。
4.c/s结构的好用的框架开始出现。
5.进入资本冬天,各种小公司不好融资。
6.国内的污染进一步加剧。
7.安全生产事故再一次出现。
8.造开始追求品质。
9.更多的有钱人。
10.人民币汇率到7。
明年见!