Giter Site home page Giter Site logo

billfeller.github.io's People

Contributors

wadezhan avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

billfeller.github.io's Issues

Redis/Memcache代理服务Twemproxy简介

作者:zhanhailiang 日期:2014-12-14

简介

twemproxy,也叫nutcraker,是twtter开源的Redis和Memcache代理服务器。

功能

  • Fast.
  • Lightweight.
  • Maintains persistent server connections.
  • Keeps connection count on the backend caching servers low.
  • Enables pipelining of requests and responses.
  • Supports proxying to multiple servers.
  • Supports multiple server pools simultaneously.
  • Shard data automatically across multiple servers.
  • Implements the complete memcached ascii and redis protocol.
  • Easy configuration of server pools through a YAML file.
  • Supports multiple hashing modes including consistent hashing and distribution.
  • Can be configured to disable nodes on failures.
  • Observability through stats exposed on stats monitoring port.
  • Works with Linux, *BSD, OS X and Solaris (SmartOS)

安装

从官网下载安装包编译并安装:distribution tarball:

[root@~/software/nutcracker-0.3.0]# ./configure --prefix=/usr/local/nutcracker-0.3.0
[root@~/software/nutcracker-0.3.0]# make
[root@~/software/nutcracker-0.3.0]# make install
[root@~/software/nutcracker-0.3.0]# cp -R conf /usr/local/nutcracker-0.3.0
[root@~/software/nutcracker-0.3.0]# ln -s /usr/local/nutcracker-0.3.0 /usr/local/nutcracker
[root@~/software/nutcracker-0.3.0]# ln -s /usr/local/nutcracker/sbin/nutcracker /usr/local/bin/nutcracker

配置

twemproxy支持通过YAML语法配置,其支持的指令集如下:

  • listen: The listening address and port (name:port or ip:port) for this server pool.
  • hash: The name of the hash function. Possible values are:
    • one_at_a_time
    • md5
    • crc16
    • crc32 (crc32 implementation compatible with libmemcached)
    • crc32a (correct crc32 implementation as per the spec)
    • fnv1_64
    • fnv1a_64
    • fnv1_32
    • fnv1a_32
    • hsieh
    • murmur
    • jenkins
  • hash_tag: A two character string that specifies the part of the key used for hashing. Eg "{}" or "$$". Hash tag enable mapping different keys to the same server as long as the part of the key within the tag is the same.
  • distribution: The key distribution mode. Possible values are:
    • ketama
    • modula
    • random
  • timeout: The timeout value in msec that we wait for to establish a connection to the server or receive a response from a server. By default, we wait indefinitely.
  • backlog: The TCP backlog argument. Defaults to 512.
  • preconnect: A boolean value that controls if nutcracker should preconnect to all the servers in this pool on process start. Defaults to false.
  • redis: A boolean value that controls if a server pool speaks redis or memcached protocol. Defaults to false.
  • server_connections: The maximum number of connections that can be opened to each server. By default, we open at most 1 server connection.
  • auto_eject_hosts: A boolean value that controls if server should be ejected temporarily when it fails consecutively server_failure_limit times. See liveness recommendations for information. Defaults to false.
  • server_retry_timeout: The timeout value in msec to wait for before retrying on a temporarily ejected server, when auto_eject_host is set to true. Defaults to 30000 msec.
  • server_failure_limit: The number of conseutive failures on a server that would leads to it being temporarily ejected when auto_eject_host is set to true. Defaults to 2.
  • servers: A list of server address, port and weight (name:port:weight or ip:port:weight) for this server pool.

以本文为例,配置一个Redis代理和一个Memcache代理如下:

[root@~/software/nutcracker-0.3.0]# cat /usr/local/nutcracker/conf/nutcracker.yml
alpha:
  listen: 127.0.0.1:22121
  hash: fnv1a_64
  hash_tag: "{}"
  distribution: ketama
  auto_eject_hosts: false
  timeout: 400
  redis: true
  servers:
   - 127.0.0.1:6379:1

beta:
  listen: 127.0.0.1:22122
  hash: fnv1a_64
  distribution: ketama
  timeout: 400
  backlog: 1024
  preconnect: true
  auto_eject_hosts: true
  server_retry_timeout: 2000
  server_failure_limit: 3
  servers:
   - 127.0.0.1:11211:1
   - 127.0.0.1:11212:1

其中,Redis实例 127.0.0.1:6379 和 Memcache实例 127.0.0.1:11211 127.0.0.1:11212 请预先启动好。

/etc/init.d/redis_6379 start
/usr/local/memcached-1.4.20/bin/memcached -d -m 64 -l 127.0.0.1 -p 11211 -u root
/usr/local/memcached-1.4.20/bin/memcached -d -m 64 -l 127.0.0.1 -p 11212 -u root

测试

https://github.com/billfeller/billfeller.github.io/blob/master/code/twenproxyTest.php

启动服务:

[root@/usr/local/nutcracker/conf]# nutcracker -c nutcracker.yml
[Sun Dec 14 20:59:04 2014] nc.c:187 nutcracker-0.3.0 built for Linux 2.6.32-431.23.3.el6.x86_64 x86_64 started on pid 14359
[Sun Dec 14 20:59:04 2014] nc.c:192 run, rabbit run / dig that hole, forget the sun / and when at last the work is done / don't sit down / it's time to dig another one

执行测试脚本:

[root@~/wade/git/billfeller.github.io/code]# /usr/local/php/bin/php twenproxyTest.php 
bool(true)
string(1) "1"
int(1)
bool(false)
bool(true)
int(2)
bool(true)
int(3)
bool(true)
bool(false)

基于Redis bitmap实现签到功能

作者:zhanhailiang 日期:2014-12-21

需求场景

Bitmap 对于一些特定类型的计算非常有效。

假设现在我们希望记录自己网站上的用户的上线频率,比如说,计算用户A上线了多少天,用户B上
线了多少天,诸如此类,以此作为数据,从而决定让哪些用户参加beta测试等活动——这个模式可以使
用SETBIT和BITCOUNT来实现。

比如说,每当用户在某一天上线的时候,我们就使用SETBIT,以用户名作为key,将那天所代表的网站
的上线日作为offset 参数,并将这个offset 上的为设置为1。

举个例子,如果今天是网站上线的第100天,而用户(uid=10086)在今天阅览过网站,那么执行命令SETBIT sign:10086 100 1;如果明天用户(uid=10086)也继续阅览网站,那么执行命令SETBIT sign:10086 101 1,以此类推。

当要计算用户(uid=10086)总共以来的上线次数时,就使用BITCOUNT命令:执行BITCOUNT sign:10086,得出的结果就是用户(uid=10086)上线的总天数。

性能

以上线次数统计例子,即使运行10年,占用的空间也只是每个用户10*365比特位(bit),也即是每个
用户456字节。对于这种大小的数据来说,BITCOUNT的处理速度就像GET和INCR这种O(1)复杂度的
操作一样快。

如果你的bitmap数据非常大,那么可以考虑使用以下两种方法:

1. 将一个大的bitmap分散到不同的key中,作为小的bitmap来处理。使用Lua脚本可以很方便地完成这一工作。
2. 使用BITCOUNT的start和end参数,每次只对所需的部分位进行计算,将位的累积工作(accumulating)放到客户端进行,并且对结果进行缓存(caching)。

代码实现

https://github.com/billfeller/billfeller.github.io/blob/master/code/ISign.php

参考文档:

《Redis.pdf》

TortoiseGit Bad file number 解决方法

TortoiseGit Bad file number 解决方法

作者:zhanhailiang 日期:2015-01-07

直接使用命令行git pull操作正常,如下:

D:\vipshop\mstats\mstats-monitor>git pull
Updating 5050c42..e8b3bd9
Fast-forward
 public/css/app.css              | 30 ++++++++++++++++++
 public/js/page.counts.js        | 68 +++++++++++++++++++++++++++++++++--------
 views/counts.html               |  8 +++++
 views/includes/module_list.html |  3 +-
 4 files changed, 96 insertions(+), 13 deletions(-)

但是使用TortoiseGit pull时报错“/bin/sed: Bad file number”,详情如下:

git.exe pull -v --progress       "origin"

/libexec/git-core/git-sh-setup: line 81: /bin/sed: Bad file number
From http://gitlab.tools.vipshop.com/wade.zhan/mstats-monitor
= [up to date]      master     -> origin/master
C:\Program Files (x86)\Git/libexec/git-core\git-pull: line 268: /bin/tr: Bad file number
Your configuration specifies to merge with the ref 'master'
from the remote, but no such ref was fetched.


git did not exit cleanly (exit code 1) (2090 ms @ 2015/1/7 10:08:05)

根据提示“Your configuration specifies to merge with the ref 'master' from the remote, but no such ref was fetched.”,指的是merge远端引用master,但是fetch不到该引用。

查了下git help pull命令详情:

git pull [options] [<repository> [<refspec>…]]

怀疑是因为缺少参数导致,尝试下手动执行完整命令,如下:

D:\vipshop\mstats\mstats-monitor>git.exe pull -v --progress       "origin" master

From http://gitlab.tools.vipshop.com/wade.zhan/mstats-monitor
 * branch            master     -> FETCH_HEAD
 = [up to date]      master     -> origin/master
Already up-to-date.

这里就定位到问题,应该缺省参数导致,右键菜单 TortoiseGit->Settings->Git->Edit local .git/config,在[branch "master"]修改remote = origin master,如下图:

git_branch

然后就可以正常使用TortoiseGit pull了:

git.exe pull -v --progress       "origin" master

From http://gitlab.tools.vipshop.com/wade.zhan/mstats-monitor
* branch            master     -> FETCH_HEAD
= [up to date]      master     -> origin/master
Already up-to-date.

Success (2121 ms @ 2015/1/7 10:08:38)

参考文章:

  1. http://blog.csdn.net/renfufei/article/details/41648061

缓存策略优化

作者:zhanhailiang 日期:2014-12-12
需求背景

通常,缓存逻辑是设置一个过期时间,若缓存失效时,就请求后端读取数据并更新缓存。 但是该方案在高qps的场景下会出现问题——在[缓存失效,请求后端读取数并更新缓存)时间段内,所有的请求都会全部透传到后端,该场景对后端将会产生大量请求。所以我们的目标是希望减少这部分请求数。

实现方案
  • 基于概率的实现机制
    • 将cache存储两倍的过期时间 2 * expire,
    • 若请求介在[start,start + expire],则只读缓存即可;
    • 若请求介在(start + expire,start + 2 * expire),则只透传一定比例(factor=10,表示比例为10%)的请求后端读取数据并更新缓存,其它请求继续使用当前缓存;
    • 若缓存已失效,则直接请求后端读取数据;
  • 基于锁的实现机制
    • 将cache存储两倍的过期时间 2 * expire,
    • 若请求介在[start,start + expire],则只读缓存即可;
    • 若请求介在(start + expire,start + 2 * expire),则判断当前是否有请求锁;
      • 若有,则说明已经有请求去后端读取数据,本次请求暂时使用缓存即可;
      • 若无,则设置请求锁,并请求后端读取数据并更新缓存,成功后清除掉请求锁;
    • 若缓存已失效,则直接请求后端读取数据;

代码如下:https://github.com/billfeller/billfeller.github.io/blob/master/code/cache.php

方案评估
  • 从最终结果来看,基于锁的实现机制能最大限度减少后端请求。以factor=10为例,理论上基于概率的实现机制可 以减少90%的请求数,但是基于锁的实现机制在任何场景下都能保证只有一次后端请求。
  • 从实现上看,基于锁的实现机制需要额外的memcached操作,最坏情况下需要3次额外的memcached操作;
结论

方案的选择依赖于数据支撑,需要后端团队提供当前相关接口的并发数再做方案评估。
两种方案都可行,看具体评估。

配置$_SERVER变量值的两种方法

作者:zhanhailiang 日期:2014-12-17

第一,通过配置fastcgi_param来添加服务器变量:

/usr/local/nginx/conf/fastcgi_params

fastcgi_param  SERVER_FLAG       test;

/usr/local/nginx/conf/nginx.conf

location ~ \.php$ {
    root           /usr/local/wwwroot/dokuwiki;
    fastcgi_pass   127.0.0.1:9000;
    fastcgi_index  index.php;
    fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;
    include        fastcgi_params;
}

第二,通过配置php-fpm.conf来添加服务器变量:

/usr/local/php/etc/php-fpm.conf

; 这里配置值"production"可以通过读取Linux环境变量来动态配置
env[SERVER_FLAG2]=production
env[SERVER_FLAG3]=$LINUX_EXPORT_VARIABLE

最后重启php-fpm,nginx:

[root@/usr/local/wwwroot/dokuwiki]# killall php-fpm;
[root@/usr/local/wwwroot/dokuwiki]# export LINUX_EXPORT_VARIABLE=test
[root@/usr/local/wwwroot/dokuwiki]# /usr/local/php/sbin/php-fpm
[root@/usr/local/nginx/conf]# /usr/local/nginx/sbin/nginx -s reload

打印$_SERVER:

{
    "SERVER_FLAG": "test",
    "SERVER_FLAG2": "production",
    "SERVER_FLAG3": "test",
}

浏览历史功能

商品详情页(含美妆单品详情页)上报接口:

请求体:

GET http://m.vip.com/ajaxapi-addProductIdToBH.html?s=1417770095624&productId=39070878

其中,productId表示商品ID

响应体:

    {
        "msg": "成功",
        "ret": 0
    }

浏览历史列表接口
请求体:

GET http://m.vip.com/ajaxapi-queryBH.html?s=1417770095624&lsBHStr=39070878

其中,lsBHStr表示本地商品ID列表,用|分隔

响应体:直接读list字段即可;为空就展示"返回首页"

    {
        "list": [
            {
                "agio": "1.2折",
                "brand_id": "292288",
                "brand_name": "evona女装专场",
                "detailurl": "user-history-product-292288-38988810.html",
                "fav_price": "",
                "market_price": "4190",
                "pms_activetips": "",
                "product_id": "38988810",
                "product_name": "卡其啡色带帽休闲修身长袖长款羽绒服",
                "ptype": "3",
                "sale_out": 1,
                "sell_time_from": "1418090400",
                "sell_time_to": "1418486340",
                "small_image": "http://pic1.vip.com/upload/merchandise/292288/EVONA-DE93341-630-30-5.jpg",
                "small_image2": "http://a.vimage1.com/upload/merchandise/292288/EVONA-DE93341-630-30-5_304x384_80.jpg",
                "special_price": "",
                "stock": "3",
                "type": "3",
                "vipshop_price": "489"
            }
        ],
        "msg": "成功",
        "ret": 0
    }

Robomongo简介

作者:zhanhailiang 日期:2015-01-05

简介

Robomongo是基于Shell的跨平台MongoDB管理工具。Robomongo与MongoDB之间的关系就相当于PHPMyAdmin与MySQL之间的关系。

特性

对MongoDB Shell的完美支持

Robomongo内置V8引擎来驱动mongo命令行工具,所以你通过mongo命令行工具的所有操作都可以通Robomongo来完成。其本身提供语法高亮,自动完成,并且支持不同的结果查询模式(文本,树,或表格),如下图:

robomongo_view_mode

注:可以通过按“Ctrl + Enter”只执行被选中部分查询代码。

多命令行窗口

可以在Robomongo打开多个命令行窗口。

注:可以通过按“Ctrl + T”复制命令行窗口。

支持多结果集查询

Robomongo命令行可以通过编写多条查询语句来一次性获取多个查询结果集,如下图:

robomongo_multiple_results

注:可以通过按“F10”改变结果集的展示方式,即水平和垂直方向的切换。

支持命令自动完成

Robomongo支持对所有的对象和函数的自动完成功能。

注:可以通过输入函数名,然后按“Ctrl + Enter”来获取函数的具体定义,如下图:

robomongo_function

更多阅读

  1. http://www.robomongo.org/
  2. https://github.com/paralect/robomongo-docs
  3. http://mongodb-documentation.readthedocs.org/en/latest/

标准的Base64

作者:zhanhailiang 日期:2014-12-19
算法描述:

Base64要求把每三个8Bit的字节转换为四个6Bit的字节(3_8 = 4_6 = 24),然后把6Bit再添两位高位0,组成四个8Bit的字节,也就是说,转换后的字符串理论上将要比原来的长1/3。

  • 第一个字符通过右移2位获得第一个目标字符的Base64表位置,根据这个数值取到表上相应的字符,就是第一个目标字符。

  • 然后将第一个字符与0x03(00000011)进行与(&)操作并左移4位,接着第二个字符右移4位与前者相或(|),即获得第二个目标字符。

  • 再将第二个字符与0x0f(00001111)进行与(&)操作并左移2位,接着第三个字符右移6位与前者相或(|),获得第三个目标字符。

  • 最后将第三个字符与0x3f(00111111)进行与(&)操作即获得第四个目标字符。

  • 在以上的每一个步骤之后,再把结果与 0x3F 进行 AND 位操作,就可以得到编码后的字符了。

    剩余的字节根据编码规则继续单独转(1变2,2变3;不够的位数用0补全),再用=号补满4个字节。这就是为什么有些Base64编码会以一个或两个等号结束的原因,但等号最多只有两个。因为:
    一个原字节至少会变成两个目标字节
    所以余数任何情况下都只可能是0,1,2这三个数中的一个。如果余数是0的话,就表示原文字节数正好是3的倍数(最理想的情况)。如果是1的话,转成2个Base64编码字符,为了让Base64编码是4的倍数,就要补2个等号;同理,如果是2的话,就要补1个等号。

以上算法描述引用自:http://baike.baidu.com/link?url=lriFEiUvmROqg0a0R0DZS0t8gEmIQRnJ13eSGZuYFFOyUDSrhY824dE7zjTbhSA5rpp2NiDn2-mCoLPbPlY1q_#3_3

算法实现:

从PHP/ext/standard/base64.c中剥离出base64_encode的实现方法,代码如下:

https://github.com/billfeller/billfeller.github.io/tree/master/code/base64

测试:
[root@~/wade/git/billfeller.github.io/code/base64]# gcc -o base64 base64.c 
[root@~/wade/git/billfeller.github.io/code/base64]# ./base64 "abcd*"
YWJjZCo=
[root@~/wade/git/billfeller.github.io/code/base64]# /usr/local/php/bin/php -r 'echo base64_encode("abcd*").PHP_EOL;'
YWJjZCo=

数据库连接池SQL Relay简介

作者:zhanhailiang 日期:2014-12-27

简介

SQLRelay 是一个持久化的数据库连接池,用来为 Unix 或者 Linux 提供数据库连接池、代理以及负载均衡的功能。

曾在2004淘宝架构迁移充当管理Oracle数据库链接的中间件,请见:

  1. 《淘宝业务发展及技术架构》分享 文字版
  2. 《淘宝业务发展及技术架构》分享 PPT版

连接池示意图:

sqlrelay

负载均衡示意图:

sqlrelay balance

功能特性

  1. 加速数据库驱动的基于 Web 的应用程序
  2. 增加 Web 应用程序的可扩展性
  3. 分布式的访问复制的数据库系统
  4. 对数据库访问进行节流
  5. 从不被支持的平台上访问某个数据库
  6. 可以轻松的对数据库系统进行移植

支持的数据库

  1. Getting Started With Oracle
  2. Getting Started With MySQL
  3. Getting Started With PostgreSQL
  4. Getting Started With Sybase
  5. Getting Started With Microsoft SQL Server 2000 Desktop Engine
  6. Getting Started With IBM DB2
  7. Getting Started With Firebird
  8. Getting Started With SQLite
  9. Getting Started With Microsoft Access
  10. Getting Started With Blackray
  11. Getting Started With ODBC

支持的语言

  1. C++
  2. C
  3. C#
  4. Perl
  5. PHP
  6. Python
  7. Ruby
  8. Java
  9. TCL
  10. Erlang

请见:http://sqlrelay.sourceforge.net/sqlrelay/

本文将讲解如何基于SQL Relay,使用PHP进行Mysql操作。

安装

安装rudiments-0.48:

./configure
make && make install

安装sqlrelay-0.57:

./configure --with-mysql-prefix=/usr/local/mysql --with-php-prefix=/usr/local/php
make && make install

配置php.ini:

extension=sql_relay.so

配置SQL Relay:

[root@~]# cd /usr/local/firstworks/etc/
[root@/usr/local/firstworks/etc]# cp sqlrelay.conf.example sqlrelay.conf

其连接Mysql配置如下:

<?xml version="1.0"?>
<!DOCTYPE instances SYSTEM "sqlrelay.dtd">

<instances>

    <!-- Regular SQL Relay Instance -->
    <instance id="mysqlpool" port="12000" socket="/tmp/mysqlpool.socket" dbase="mysql" connections="3" maxconnections="5" maxqueuelength="0" growby="1" ttl="60" endofsession="commit" sessiontimeout="600" runasuser="nobody" runasgroup="nobody" cursors="5">
        <users>
            <user user="root" password="*****"/>
        </users>
        <connections>
            <connection connectionid="mysqlpool" string="user=root;password=*****;db=test" metric="1" behindloadbalancer="no"/>
        </connections>
    </instance>

</instances>

启动和停止SQL Relay

sqlr-start -id mysqlpool
sqlr-start  --trace -id mysqlpool // 跟踪调用详情
sqlr-stop

注:

1. 关于启动命令的使用,请见:http://sqlrelay.sourceforge.net/sqlrelay/admin/running.html
2. 安装SQL Relay后需要将firstworks/bin/目录添加到环境变量PATH中:

    PATH="/usr/local/firstworks/bin/:$PATH"

测试:

启动SQL Relay后可以看到如下进程:

[root@/usr/local/firstworks/etc]# ps -ef|grep sqlrelay
nobody   26512     1  0 22:26 ?        00:00:00 sqlr-listener -id mysqlpool -config /usr/local/firstworks/etc/sqlrelay.conf
nobody   26519     1  0 22:26 ?        00:00:00 sqlr-scaler -id mysqlpool -config /usr/local/firstworks/etc/sqlrelay.conf
nobody   26520     1  0 22:26 ?        00:00:00 sqlr-connection -id mysqlpool -connectionid mysqlpool -config /usr/local/firstworks/etc/sqlrelay.conf
nobody   26521     1  0 22:26 ?        00:00:00 sqlr-connection -id mysqlpool -connectionid mysqlpool -config /usr/local/firstworks/etc/sqlrelay.conf
nobody   26522     1  0 22:26 ?        00:00:00 sqlr-connection -id mysqlpool -connectionid mysqlpool -config /usr/local/firstworks/etc/sqlrelay.conf
root     26579 18985  0 23:07 pts/3    00:00:00 grep sqlrelay

PHP测试脚本:

<?php
$con = sqlrcon_alloc('mysqlpool', 12000, '/tmp/mysqlpool.socket', 'root', '******', 0, 1);

var_dump(sqlrcon_errorNumber ($con));
var_dump(sqlrcon_dbHostName ($con));
var_dump(sqlrcon_dbIpAddress ($con));

$cur = sqlrcur_alloc($con);

sqlrcur_sendQuery($cur, 'select * from test');

var_dump(sqlrcur_totalRows ($cur));

for ($row=0; $row<sqlrcur_rowCount($cur); $row++) {
    for ($col=0; $col<sqlrcur_colCount($cur); $col++) {
        echo sqlrcur_getField($cur,$row,$col);
    }   
    echo PHP_EOL;
}

sqlrcur_free($cur);
sqlrcon_free($con);

执行输出如下:

int(0)
string(9) "Localhost"
string(9) "127.0.0.1"
int(2)
1
2

参考文章

  1. php+sqlrelay+mysql实现连接池及读写负载均衡
  2. 开源数据库连接池 SQL Relay 的安装配置和应用
  3. SQL Relay官网
  4. Running SQL Relay
  5. Getting Started With MySQL
  6. Programming with SQL Relay using the PHP API
  7. SQL Relay PHP References

美妆单品列表页重构

未登录情况下添加购物车后跳转到登录页面,登录成功后跳回美妆单品列表页自动添加购物车:

// 自动添加购物车
var addCardProduct = {
    "agio": "3.8折",
    "brand_id": "319510",
    "cat_id": "10501004",
    "end_time": "1419782340",
    "end_time_formated": "2天",
    "image": null,
    "img_pre_must": "MZZ-6956497900887",
    "leavings": 11,
    "market_price": "99",
    "merchandise_sn": "6956497900887",
    "num": 1,
    "product_id": "41455743",
    "product_name": "PF79 燕麦舒缓桑蚕丝面膜30g*5p",
    "sale_count": 1246,
    "sale_out": 0,
    "size": 108018131,
    "skuId": 108018131,
    "small_image": "http://a.vimage1.com/upload/merchandise/319510/MZZ-6956497900887-14.jpg",
    "small_image2": "http://a.vimage1.com/upload/merchandise/319510/MZZ-6956497900887-14_262x166_80.jpg",
    "vipshop_price": "38"
};

美妆单品请求

http://m.vip.com/ajaxapi-getBeautyList.html?query=beauty-list-0-1-0-1-2-40&offset=0&limit=40

美妆单品响应体

    {
        "data": [
            {
                "agio": "3.8折",
                "brand_id": "319510",
                "cat_id": "10501004",
                "end_time": "1419782340",
                "end_time_formated": "2天",
                "image": null,
                "img_pre_must": "MZZ-6956497900887",
                "leavings": 11,
                "market_price": "99",
                "merchandise_sn": "6956497900887",
                "product_id": "41455743",
                "product_name": "PF79 燕麦舒缓桑蚕丝面膜30g*5p",
                "sale_count": 1245,
                "sale_out": 0,
                "size": 108018131,
                "small_image": "http://a.vimage1.com/upload/merchandise/319510/MZZ-6956497900887-14.jpg",
                "small_image2": "http://a.vimage1.com/upload/merchandise/319510/MZZ-6956497900887-14_262x166_80.jpg",
                "vipshop_price": "38"
            }
        ],
        "msg": "成功",
        "page": {
            "limit": 40,
            "offset": 0,
            "total": 40
        },
        "result": true,
        "warehouse": "VIP_NH"
    }

git branch分支开发

git branch分支开发

作者:zhanhailiang 日期:2015-01-06

查看当前branch列表

    [root@~/wade/git/billfeller.github.io]# git branch 
    gh-pages
    * master

新建分支

    [root@~/wade/git/billfeller.github.io]# git branch dev

切换分支

    [root@~/wade/git/billfeller.github.io]# git checkout dev 
    Switched to branch 'dev'

切换到新建分支

    [root@~/wade/git/billfeller.github.io]# git checkout -b dev2
    Switched to a new branch 'dev2'

将提交的文件的信息添加到索引库中

    [root@~/wade/git/billfeller.github.io]# git add test.log

将当前文件中所有修改的文件信息添加到索引库

    [root@~/wade/git/billfeller.github.io]# git add .

将依据索引库中的内容来进行文件提交

    [root@~/wade/git/billfeller.github.io]# git commit -m 'test'
    [dev2 ce310ee] test
     0 files changed, 0 insertions(+), 0 deletions(-)
     create mode 100644 test.log

查看commit的区别

    [root@~/wade/git/billfeller.github.io]# git diff

合并其它分支到当前分支

    [root@~/wade/git/billfeller.github.io]# git merge dev2
    Updating d509c69..ce310ee
    Fast-forward
     0 files changed, 0 insertions(+), 0 deletions(-)
     create mode 100644 test.log

将branch push到远程分支

    [root@~/wade/git/billfeller.github.io]# git push origin dev2
    Counting objects: 4, done.
    Compressing objects: 100% (2/2), done.
    Writing objects: 100% (3/3), 260 bytes, done.
    Total 3 (delta 1), reused 0 (delta 0)
    To [email protected]:billfeller/billfeller.github.io.git
     * [new branch]      dev2 -> dev2

查看远程分支

    [root@~/wade/git/billfeller.github.io]# git branch -r
      origin/HEAD -> origin/master
      origin/dev2
      origin/master

查看本地和远程分支

    [root@~/wade/git/billfeller.github.io]# git branch -a
      dev
    * dev2
      gh-pages
      master
      remotes/origin/HEAD -> origin/master
      remotes/origin/dev2
      remotes/origin/master

修改branch名

    [root@~/wade/git/billfeller.github.io]# git branch -m dev mdev
    [root@~/wade/git/billfeller.github.io]# git branch -a
    * dev2
      gh-pages
      master
      mdev
      remotes/origin/HEAD -> origin/master
      remotes/origin/dev2
      remotes/origin/master

删除远程分支

    [root@~/wade/git/billfeller.github.io]# git push origin --delete dev2
    To [email protected]:billfeller/billfeller.github.io.git
     - [deleted]         dev2
    [root@~/wade/git/billfeller.github.io]# git branch -a
    * dev2
      gh-pages
      master
      mdev
      remotes/origin/HEAD -> origin/master
      remotes/origin/master

参考文章:

  1. Git入门指南十一:Git branch 分支与合并分支
  2. Git远程分支和refs文件详解
  3. git初体验(三)git分支

Navicat for MySQL Windows下强大的MySQL管理工具

Navicat for MySQL Windows下强大的MySQL管理工具

作者:zhanhailiang 日期:2015-01-21

介绍

Navicat for MySQL[是一款强大的 MySQL 数据库管理和开发工具,它为专业开发者提供了一套强大的足够尖端的工具。Navicat for MySQL 基于Windows平台,为 MySQL 量身订作,提供类似于 phpMyAdmin 的用户管理界面工具。

使用说明

  1. 下载并安装,Navicat for MySQL
  2. 连接数据库;
    navicat_create_link
  3. 连接成功后即可对该DB做所有有权限的操作;

更多阅读

  1. http://www.navicat.com.cn/
  2. http://www.navicat.com.cn/whatisnavicat
  3. Robomongo Windows下强大的MongoDB管理工具

[翻译]中级Git用户的25个使用技巧(下)

[翻译]中级Git用户的25个使用技巧(下)

译者:zhanhailiang 日期:2015-01-21

原文链接:25 Tips for Intermediate Git Users

存储内容到Stashes, Index和文件系统

10. 暂存区

丢弃暂存区的所有操作:

$ git stash
# Do something...
$ git stash pop

11. 交互式添加修改到暂存区

$ git add -i
           staged     unstaged path


*** Commands ***
  1: status      2: update   3: revert   4: add untracked
  5: patch       6: diff     7: quit     8: help
What now>  

12. Storing/Retrieving from the File System

略.

查看git日志

13. 查看操作日志

查看最近提交的操作日志:

$ git log -p

只查看最近修改的文件列表:

$ git log --stat

14. 搜索日志

查询指定作者的更新日志:

$ git log --author=Andy

通过搜索提交的注释关键字过滤日志:

$ git log --grep="Something in the message"

查询指定文件的修改日志:

$ git log lib/foo.rb

查看分支feature/132与分支feature/145,其各自与master分支的区别:

$ git log feature/132 feature/145 ^master

也可以查询指定时间段内(该时间格式支持ActiveSupport style)的操作日志:

$ git log --since=2.months.ago --until=1.day.ago

15. 查看指定版本的相关信息

$ git show 12a86bc38 # By revision
$ git show v1.0.1 # By tag
$ git show feature132 # By branch name
$ git show 12a86bc38^ # Parent of a commit
$ git show 12a86bc38~2 # Grandparent of a commit
$ git show feature132@{yesterday} # Time relative
$ git show feature132@{2.hours.ago} # Time relative

16. Selecting a Range

查看本地仓库未推送的修改日志:

$ git log origin/master..new
# [old]..[new] - everything you haven't pushed yet

回滚与错误修复

17. 回滚修改

直接回滚到本地仓库最近的版本:(若你的修改未提交过)

$ git reset HEAD lib/foo.rb

回滚到本地仓库最近的版本:(若你的修改提交过)
如果你要回滚到最后一次提交之前的版本:
$ git commit --amend
如果你要回滚前已经提交多次代码:
$ git checkout feature132
$ git reset --hard HEAD~2

18. 分支操作

master提交了三次修改,现在希望将最近三次修改移动分支experimental,并取消master分支最近三次的修改:

$ git branch experimental   # Creates a pointer to the current master state
$ git reset --hard master~3 # Moves the master branch pointer back to 3 revisions ago
$ git checkout experimental

19. Interactive Rebasing

略.

20. Cleaning Up

略.

其它注意事项

21. 查看上次查询的SHA-1记录日志

$ git reflog
$ git log -g # Same as above, but shows in 'log' format

22. 分支命名

$ # Generate a changelog of Release 132
$ git shortlog release/132 ^release/131
$ # Tag this as v1.0.1
$ git tag v1.0.1 release/132

23. 查询指定文件的各行编辑日志

$ git blame FILE

24. Database Maintenance

略.

25. 重建一个已丢失败的分支

$ git branch experimental SHA1_OF_HASH

浏览历史开发总结

总结

产品

功能开发过程发现从细节上看,很多细节不够细腻:

  1. 浏览历史排序逻辑,目前只是按最近浏览时间进行排序,并没有更多维度的排序(如将已售罄的商品置底);
  2. 对客户端本地存储的商品ID数据,目前客户端只能清除超过20个商品的场景,并没有自动清除已过期的商品ID;

优化目标:快速迭代,小步快跑;

开发

缺乏后端数据层的支持;目前读取浏览历史列表时是通过遍历商品ID调用商品详情接口来获取相关商品信息,上限需要发20次HTTP请求才能完成调用;

优化目标:是否考虑在需求评审阶段就拉上后端团队共同完成评审和方案评估;

尝试Redis集成Lua方案,实现添加浏览历史记录功能;但是包括开发阶段发现的慢查询日志和DBA的建议,都否定掉使用该方案,其中原因如下:

  1. slowlog;
  2. monitor不方便;
  3. twenproxy不完全支持Redis eval指令;
  4. Lua对服务器造成的额外开销;

前后端开发分离,包括异步上报浏览历史,异步读取浏览历史,对性能和体验都做了比较好的考虑;但是也间接增加了协作沟通的成本;

测试

浏览历史是第一个尝试测试团队的性能测试方案的项目,从出发点来说,其实是很好的点,但在实际操作时遇到了很多问题(第一次,难免有点紧张):

性能测试标准不明确;产品提出性能测试需求时不知道是要做什么,包括实施性能测试需要实现模拟用户行为,如登录,选择分仓,浏览商品行为,到最终上报商品ID性能测试和浏览历史查询性能测试,其中涉及m域,mlogin域大量的业务逻辑,需要大量时间协助测试人员完成业务逻辑模拟实现;

优化目标:明确性能测试方案标准和各项指标。


部署

因为配置WAP_REDIS_HOST,WAP_REDIS_PORT环境变量需要全域重启php-fpm,nginx,运维认为风险很高(特别是年终时期),所以暂时改成通过后台网站配置来实现配置。目前网站配置有很多人有操作权限(包括产品开发测试等),不能避免人为的失误操作。

优化目标:如果不可避免的情况下需要通过后台来实现配置,需要管理后台支持更细粒度的权限控制——比如针对不同的配置项支持不同权限级的配置,理想情况下,实现对不同角色的每个操作实现权限控制;

新人专享优惠券领券业务逻辑

新人专享优惠券领券业务逻辑

请求体:

http://m.vip.com/ajaxapi-bindCoupon.html?fCouponId=12082

其中,fCouponId参数通过data-fCouponId获取;

响应体:

{
    "ret": 0,
    "data": {
        "coupon_id": 12082,
        "coupon_name": "下载APP新会员专享券100-10",
        "coupon_sn": "KXR9KDTRXK66QQE",
        "begin_time": 1420771486,
        "end_time": 1421030686,
        "use_limit": "100",
        "coupon_type": 2,
        "coupon_field": 5,
        "coupon_source": "站内活动页面领取",
        "limit": 800000,
        "active": 104,
        "rest": 799896
    }
}

其中:

ret 0   领券成功
    -1  活动已过期
    -2  用户未登录
    -3  非新客用户AB
    -4  已领券
    -5  前端参数有误
    -6  接口异常
    -97 已领券
    -98 券已领完
    -99 接口异常

PHP curl报错“Problem (2) in the Chunked-Encoded data”解决方案

作者:zhanhailiang 日期:2015-01-23

本地环境:

系统版本:Microsoft Windows 6.1.7601
PHP版本:PHP 5.3.29
php_curl.dll扩展版本:7.35.0

Windows环境下遇到一个很奇怪的问题,使用PHP curl发送请求报错:

错误码:56
错误信息:Problem (2) in the Chunked-Encoded data

但是使用浏览器直接访问又正常,怀疑是php_curl.dll扩展本身的bug,解决方案如下:

在PHP curl头部添加HTTP版本信息即可解决:

curl_setopt($curl, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);

即可修复该问题。

mysqlnd扩展简介

作者:zhanhailiang 日期:2015-01-01

MySQL Native Driver简称mysqlnd,作为libmysqlclient替代品于PHP5.3.0版本引入。之前,MySQL数据库扩展mysql,mysqli,PDO MYSQL都是通过libmysqlclient实现与MySQL Server的通信。引入mysqlnd,这三个扩展都可以通过mysqlnd实现与MySQL Server的通信。

其较libmysqlclient的通信原理对比如下图:

mysqlnd

优点

  1. mysqlnd更容易编译;因为它是php源码树的一个组成部分;而基于libmysqlclient编译,意味着需要在本地安装MySQL;
  2. mysqlnd和php内部机制结合更紧密,是优化过的mysql驱动;
  3. mysqlnd更节省内存,从测试结果来看,比传统的mysql扩展节省40%的内存;
  4. mysqlnd更快;
  5. mysqlnd提供了丰富的性能统计功能;
  6. mysqlnd通过MySQL Native Driver Plugin API特性来充当MySQL Proxy,实现负载均衡,监控和性能优化
  7. mysqlnd使用了PHP license以避免不必要的版权纠纷;

安装

./configure --prefix=/usr/local/php-5.3.29-production --with-mysql=mysqlnd --with-mysqli=mysqlnd --with-openssl --with-pdo-mysql=mysqlnd --enable-fpm --enable-mysqlnd
make && make install

测试

[root@/usr/local]# /usr/local/php-5.3.29-production/bin/php -ini|grep mysqlnd
Configure Command =>  './configure'  '--prefix=/usr/local/php-5.3.29-production' '--with-pear' '--with-iconv=/usr/local/' '--with-mysql=mysqlnd' '--with-mysqli=mysqlnd' '--with-openssl' '--with-libxml-dir' '--with-curl' '--with-pdo-mysql=mysqlnd' '--disable-fileinfo' '--enable-fpm' '--enable-mysqlnd' '--with-mcrypt' '--enable-mbstring'
Client API version => mysqlnd 5.0.8-dev - 20102224 - $Id: 731e5b87ba42146a687c29995d2dfd8b4e40b325 $
Client API library version => mysqlnd 5.0.8-dev - 20102224 - $Id: 731e5b87ba42146a687c29995d2dfd8b4e40b325 $
mysqlnd
mysqlnd => enabled
Version => mysqlnd 5.0.8-dev - 20102224 - $Id: 731e5b87ba42146a687c29995d2dfd8b4e40b325 $
Client API version => mysqlnd 5.0.8-dev - 20102224 - $Id: 731e5b87ba42146a687c29995d2dfd8b4e40b325 $

更多阅读

  1. mysqlnd
  2. mysqlnd plugins

[翻译]中级Git用户的25个使用技巧(上)

[翻译]中级Git用户的25个使用技巧(上)

译者:zhanhailiang 日期:2015-01-17

原文链接:25 Tips for Intermediate Git Users

基本技巧

1. 安装git后,需要配置用户名和邮箱:

$ git config --global user.name "Some One"
$ git config --global user.email "[email protected]"

2. git是基于指针的

git中的一切都以文件形式存储,举例:

  1. 每创建一次提交动作,git其实将创建一个文件(.git/refs),其中包含提交注释和相关信息(用户名,邮箱,时间,之前的提交等),并将其与一个树结构文件(.git/objects)关联。这个树结构文件包含对象列表。这些对象或块就是实际提交的修改内容。这些对象以SHA-1哈希命名。
  2. 在git中,branch,tags也是以文件存储(.git/refs/heads),其中存储的是指向当前提交的哈希值。
  3. HEAD(.git/HEAD)也是一个包含指向当前分支提交的哈希值的文件。

3. Two Parents

在git中查看合并提交信息,你将看到Two Parents,其中第一个Parent指向当前分支,第二个Parent指向你想合并的分支。

4. 合并冲突

和svn一样,当遇到合并冲突,需要手动修改<<<<, ====, >>>>部分的内容。

$ git diff --merge
diff --cc dummy.rb  
index 5175dde,0c65895..4a00477  
--- a/dummy.rb
+++ b/dummy.rb
@@@ -1,5 -1,5 +1,5 @@@
  class MyFoo
    def say
-     puts "Bonjour"
 -    puts "Hello world"
++    puts "Annyong Haseyo"
    end
  end

服务器,分支,标签

5. 远程服务器

git中最重要的特性之一是可以支持分布式仓库,从而避免SVN中心式的弊端。你可以在本地汪厍多个读远程服务器,也可以添加多个写远程服务器。

$ git remote add john [email protected]:johnsomeone/someproject.git

如果想获取远程服务器信息,如下:

# shows URLs of each remote server
$ git remote -v 

# gives more details about each
$ git remote show name 

也可以通过以下命令获取本地分支和远程分支的区别:

$ git diff master..john/master

也可以查看本地HEAD的修改:

$ git log remote/branch..
# Note: no final refspec after ..

6. 标签

git支持两种类型的标签:

  1. 一个指向某个提交的指针;

    $ git tag to-be-tested

  2. 一个指向标签对象的指针,其包含自身信息和历史。

    $ git tag -a v1.1.0 # Prompts for a tag message

7. 创建分支

$ git branch feature132
$ git checkout feature132

等价于:

$ git checkout -b feature132

8. 合并分支

$ git checkout master
$ git merge feature83 # Or...
$ git rebase feature83

合并分支分为merge和rebase两种方式:

  1. merge tries to resolve the changes and create a new commit that blends them.
  2. rebase tries to take your changes since you last diverged from the other branch and replay them from the HEAD of the other branch.

可以通过以下命令查看哪些分支包含独立的修改:

# Shows branches that are all merged in to your current branch
$ git branch --merged

# Shows branches that are not merged in to your current branch
$ git branch --no-merged

9. 远程分支

提交本地当前分支修改到远程服务器:

$ git push origin twitter-experiment:refs/heads/twitter-experiment
# Where origin is our server name and twitter-experiment is the branch

删除远程服务器的分支:

$ git push origin :twitter-experiment

查看所有远程分支的信息:

$ git remote show origin

待续......

ab压力测试

环境配置:
系统:CentOS release 5.8 (Final)
CPU:8核 Intel(R) Xeon(R) CPU E5-2430 0 @ 2.20GHz
内存:32GB
网卡:1000 Mbps

C:\Program Files (x86)\Apache Software Foundation\Apache2.2\bin>ab.exe -n 1000 -
c 10 -C "WAP[revision]=touch" -C "WAP[hd]=1" -C "WAP_product_preheating_referer=
http%3A%2F%2Fm.vip.com%2Fpreheating-brand-301810-0-0-0-0-0-1-40.html" -C "m_vipr
uid=58788556" -C "WAP_preheat_brand_return_url=a%3A0%3A%7B%7D" -C "WAP%5BremindS
how%5D=1" -C "m_vip_province=104104" -C "WAP[p_area]=%25E5%25B9%25BF%25E4%25B8%2
59C" -C "WAP[p_wh]=VIP_NH" -C "WAP[hide_wh_tip]=1" -C "time_offset=3" -C "wap_so
urce=wap" -C "warehouse=VIP_NH" -C "WAP_cart_history=1" -C "WAP_ID=9ff2476288ee0
4fcbffe2785f51b603b3b5ebdbe" -C "m_new_index=1" -C "WAP[show]=1" -C "WAP[brd_lst
_addtocart]=308297" -C "WAP_brand_return_url=a%3A5%3A%7Bi%3A0%3Bs%3A69%3A%22http
%3A%2F%2Fweibo.com%2Fbillfeller%2Fprofile%3Frightmod%3D1%26wvr%3D6%26mod%3Dperso
nnumber%22%3Bi%3A1%3Bs%3A27%3A%22http%3A%2F%2Fm.vip.com%2Findex.html%22%3Bi%3A2%
3Bs%3A17%3A%22http%3A%2F%2Fm.vip.com%2F%22%3Bi%3A3%3Bs%3A100%3A%22http%3A%2F%2Fm
.vip.com%2Findex.php%3Fm%3Dspecial%26p%3D%2Fte%2Fpermanent%2Fs8900_nh_index.php%
26h%3Dmzt.vip.com%26wapid%3Dmzt_8900%22%3Bi%3A4%3Bs%3A17%3A%22http%3A%2F%2Fm.vip
.com%2F%22%3B%7D" -C "WAP[back_act]=%2Fproduct-308297-40225817.html" -C "WAP_rec
_product_id=40225817" -C "WAP_rec_brand_id=308297" -C "WAP_referer_url=http%3A%2
F%2Fm.vip.com%2Fbrand-308297-0-0-0-1-0-1-20.html" -C "mars_pid=116" -C "mars_cid
=1418638667918_e0a48b526d042c1c682e5c440b10d3b0" -C "mars_sid=6ec2bbb831359468f4
64ba2ae0a63d39" -C "visit_id=4C43ACFB3D5E82D9D4552BB098E43692" -C "WAP_u_new=new
" -C "m_vipruid=58788556" -C "wap_consumer=C12" "http://m.vip.com/ajaxapi-addPro
ductIdToBH.html?s=1418696408150&productId=40225817"
This is ApacheBench, Version 2.3 <$Revision: 655654 $>
Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/
Licensed to The Apache Software Foundation, http://www.apache.org/

Benchmarking m.vip.com (be patient)
Completed 100 requests
Completed 200 requests
Completed 300 requests
Completed 400 requests
Completed 500 requests
Completed 600 requests
Completed 700 requests
Completed 800 requests
Completed 900 requests
Completed 1000 requests
Finished 1000 requests

Server Software: nginx/1.2.4
Server Hostname: m.vip.com
Server Port: 80

Document Path: /ajaxapi-addProductIdToBH.html?s=1418696408150&productId
=40225817
Document Length: 40 bytes

Concurrency Level: 10
Time taken for tests: 29.207 seconds
Complete requests: 1000
Failed requests: 2
(Connect: 0, Receive: 0, Length: 2, Exceptions: 0)
Write errors: 0
Non-2xx responses: 2
Total transferred: 985882 bytes
HTML transferred: 40240 bytes
Requests per second: 34.24 [#/sec] (mean)
Time per request: 292.071 [ms] (mean)
Time per request: 29.207 [ms] (mean, across all concurrent requests)
Transfer rate: 32.96 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 1 2.8 0 31
Processing: 63 279 673.3 118 8996
Waiting: 63 273 673.5 114 8996
Total: 63 280 673.3 118 8996

Percentage of the requests served within a certain time (ms)
50% 118
66% 132
75% 140
80% 146
90% 168
95% 2098
98% 2139
99% 3109
100% 8996 (longest request)

其中,各个参数表示:

  • Server Software: Web服务器版本信息(若Web服务器设置不显示则为空)
  • Server Hostname: Web服务器地址
  • Server Port: Web服务器端口
  • Document Path: 请求路径
  • Document Length: 测试请求响应长度
  • Concurrency Level: 并发数
  • Time taken for tests: 本次压力测试所花费的总时间数
  • Complete requests: 成功的请求数
  • Failed requests: 失败的请求数
  • Write errors: 写入失败的次数
  • Total transferred: 本次压力测试的总数据传输量(包括响应头和响应体)
  • HTML transferred: 本次压力测试的总数据传输量(仅计算响应体)
  • Requests per second: 平均每秒可响应多少请求
  • Time per request: 平均每個请求所花费的时间(单位: 毫秒)
  • Time per request: 平均每個请求所花费的时间,跨所有同时连接数的平均值(单位: 豪秒)
  • Transfer rate: 从ab到Web Server之間的网络传输速度

MySQL Proxy简介

作者:zhanhailiang 日期:2014-12-31

MySQL Proxy是介于MySQL Client端和MySQL Server端之间的中间件,可以监测、分析或改变它们的通信。由于其MySQL Proxy实现MySQL C/S通信协议,所以其对应用是透明,即应用把MySQL Proxy当成MySQL Server,只需要将原先直连的MySQL host:port修改成MySQL Proxy host:port即可;

其主要应用场景:

  1. 充当MySQL连接池。
  2. 通过Lua监测、分析或改变SQL DML,如连接控制,过滤,实现读写分离和负载均衡。其中,MySQL Proxy实现“读写分离”的基本原理是让主数据库处理事务性查询,让从库处理SELECT查询。数据库复制被用来把事务性查询导致的变更同步到集群中的从库。

接下来介绍如何安装与使用MySQL Proxy。

1. 下载二进制包进行安装

下载源码包,获取Lua测试脚本

wget http://cdn.mysql.com/Downloads/MySQL-Proxy/mysql-proxy-0.8.5.tar.gz
tar zxvf mysql-proxy-0.8.5.tar.gz

下载二进制包,安装

wget http://cdn.mysql.com/Downloads/MySQL-Proxy/mysql-proxy-0.8.5-linux-glibc2.3-x86-64bit.tar.gz
tar zxvf mysql-proxy-0.8.5-linux-glibc2.3-x86-64bit.tar.gz
mv mysql-proxy-0.8.5-linux-glibc2.3-x86-64bit /usr/local/
cd /usr/local/
ln -s mysql-proxy-0.8.5-linux-glibc2.3-x86-64bit mysql-proxy

2. 配置

添加环境变量到~/.bashrc

PATH=/usr/local/mysql-proxy/bin:$PATH

创建MySQL Proxy配置文件 /usr/local/mysql-proxy/etc/master.conf, 注意将master.conf文件权限修改成0660

[mysql-proxy]
log-file = /var/log/mysql-proxy.log
log-level = message
proxy-backend-addresses = 127.0.0.1:3306

3. 测试

启动Mysql Proxy,添加--daemon将以守护进程方式运行,默认MySQL Proxy监听4040端口:

mysql-proxy --defaults-file=/usr/local/mysql-proxy/etc/master.conf --proxy-lua-script=/root/software/mysql-proxy-0.8.5/examples/tutorial-query-time.lua

通过MySQL客户端直连MySQL Proxy即可:

[root@~/software/mysql-proxy-0.8.5/examples]# /usr/local/mysql/bin/mysql --host=127.0.0.1 --port=4040 -u root -p
Enter password: 
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 65
Server version: 5.5.39-log MySQL Community Server (GPL)

Copyright (c) 2000, 2014, Oracle and/or its affiliates. All rights reserved.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

测试Lua脚本,测试脚本test.php如下:

$db = mysql_connect('127.0.0.1:4040', 'root', '******');
if (!$db) {
    exit(-1);
}

mysql_select_db('test', $db);
$result = mysql_query('SELECT * FROM test.test', $db);

while ($row = mysql_fetch_assoc($result)) {
    var_dump($row);
}

执行test.php:php test.php,其输出如下:

array(1) {
  ["id"]=>
  string(1) "1"
}
array(1) {
  ["id"]=>
  string(1) "2"
}

查看MySQL Proxy日志如下:

[root@/usr/local]# mysql-proxy --defaults-file=/usr/local/mysql-proxy/etc/master.conf --proxy-lua-script=/root/software/mysql-proxy-0.8.5/examples/tutorial-query-time.lua
we got a normal query: SELECT * FROM test.test
query-time: 0.3ms
response-time: 0.31ms

4. 更多阅读

  1. MySQL Proxy
  2. Appendix A MySQL Proxy FAQ
  3. 转MySQL Proxy的几篇文章

vim忽略大小写查找配置

作者:zhanhailiang 日期:2014-12-17

默认 vim 的查找是区分大小写,可通过以下两种方式实现忽略大小写查找

set ic?
noignorecase

1 指令设定:

:set ic(ignorecase 的缩写) 忽略大小写
:set noic(noignorecase 的缩写) 不忽略大小写

输入以上指令, 此后每次查找都是按当前配查找,如果想一直有效,可以将其写入配置文件.vimrc

set ic

2 查找符号设定:

/\CREDIS_HOST 区分大小写的查找
/\credis_host 不区分大小写的查找

这个操作只针对当前的查找有效

HTTPS下请求HTTP时客户端不带Referer头部

作者:zhanhailiang 日期:2015-01-08

今天,测试发现在
https://mlogin.vip.com/user-login.html?back_act=http%3A%2F%2Fm.vip.com%2Fuser.html
下上报监控数据
http://mstats.vip.com/v1/timing/m?_t=1420647129290&p2=240&p4=377&t0=0&t1=63&t2=474&t3=642&t4=1&t6=411&t7=919&t8=3&t9=1059
老是报412:

GET http://mstats.vip.com/v1/timing/m?_t=1420647129290&p2=240&p4=377&t0=0&t1=63&t2=474&t3=642&t4=1&t6=411&t7=919&t8=3&t9=1059 412 (Precondition Failed)

看了监控平台的代码,返回状态码412是因为监控平台需要通过Referer头部来判断平台,但是该次请求却无Referer头部:

GET /v1/timing/m?_t=1420647129290&p2=240&p4=377&t0=0&t1=63&t2=474&t3=642&t4=1&t6=411&t7=919&t8=3&t9=1059 HTTP/1.1
Host: mstats.vip.com
Connection: keep-alive
Pragma: no-cache
Cache-Control: no-cache
Accept: image/webp,*/*;q=0.8
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/39.0.2171.95 Safari/537.36
DNT: 1
Accept-Encoding: gzip, deflate, sdch
Accept-Language: en-US,en;q=0.8
Cookie: m_vip_province=104104; WAP[p_wh]=VIP_NH; warehouse=VIP_NH; wap_A1_sign=1; wap_consumer=A1; mars_pid=105; mars_cid=1420628456366_8d67e997a179843a61b1d3151d6bb9db; mars_sid=a4148eed668a36b75d29c288580f7099; visit_id=628ED24779611F6233FA107A22B83450

确实请求头没有Referer头部,原来是因为HTTP协议规定:

Clients SHOULD NOT include a Referer header field in a (non-secure) HTTP request if the referring page was transferred with a secure protocol.

参考文章:

  1. [原]HTTPS 与 Referer 头部丢失的问题

LINUX 查看硬件配置命令

系统

# uname -a # 查看内核/操作系统/CPU信息
# head -n 1 /etc/issue # 查看操作系统版本
# cat /proc/cpuinfo # 查看CPU信息
# hostname # 查看计算机名
# lspci -tv # 列出所有PCI设备
# lsusb -tv # 列出所有USB设备
# lsmod # 列出加载的内核模块
# env # 查看环境变量

资源

# free -m # 查看内存使用量和交换区使用量
# df -h # 查看各分区使用情况
# du -sh <目录名> # 查看指定目录的大小
# grep MemTotal /proc/meminfo # 查看内存总量
# grep MemFree /proc/meminfo # 查看空闲内存量
# uptime # 查看系统运行时间、用户数、负载
# cat /proc/loadavg # 查看系统负载

磁盘和分区

# mount | column -t # 查看挂接的分区状态
# fdisk -l # 查看所有分区
# swapon -s # 查看所有交换分区
# hdparm -i /dev/hda # 查看磁盘参数(仅适用于IDE设备)
# dmesg | grep IDE # 查看启动时IDE设备检测状况

网络

# ifconfig # 查看所有网络接口的属性
# iptables -L # 查看防火墙设置
# route -n # 查看路由表
# netstat -lntp # 查看所有监听端口
# netstat -antp # 查看所有已经建立的连接
# netstat -s # 查看网络统计信息

进程

# ps -ef # 查看所有进程
# top # 实时显示进程状态

用户

# w # 查看活动用户
# id <用户名> # 查看指定用户信息
# last # 查看用户登录日志
# cut -d: -f1 /etc/passwd # 查看系统所有用户
# cut -d: -f1 /etc/group # 查看系统所有组
# crontab -l # 查看当前用户的计划任务

服务

# chkconfig --list # 列出所有系统服务
# chkconfig --list | grep on # 列出所有启动的系统服务

程序

# rpm -qa # 查看所有安装的软件包

其他常用命令整理如下:

查看主板的序列号:dmidecode | grep -i 'serial number'
用硬件检测程序kuduz探测新硬件:service kudzu start ( or restart)
查看CPU信息:
    cat /proc/cpuinfo
    dmesg | grep -i 'cpu'
    dmidecode -t processor
查看内存信息:
    cat /proc/meminfo
    free -m
    vmstat
查看板卡信息:cat /proc/pci
查看显卡/声卡信息:
    lspci |grep -i 'VGA'
    dmesg | grep -i 'VGA'
查看网卡信息:
    dmesg | grep -i 'eth'
    cat /etc/sysconfig/hwconf | grep -i eth
    lspci | grep -i 'eth'
查看PCI信息:lspci (相比cat /proc/pci更直观)
查看USB设备:cat /proc/bus/usb/devices
查看键盘和鼠标:cat /proc/bus/input/devices
查看系统硬盘信息和使用情况:fdisk & disk – l & df
查看各设备的中断请求(IRQ):cat /proc/interrupts
查看系统体系结构:uname -a
查看及启动系统的32位或64位内核模式:
    isalist –v
    isainfo –v
    isainfo –b
查看硬件信息,包括bios、cpu、内存等信息:dmidecode
测定当前的显示器刷新频率:/usr/sbin/ffbconfig –rev \?
查看系统配置:/usr/platform/sun4u/sbin/prtdiag –v
查看当前系统中已经应用的补丁:showrev –p
显示当前的运行级别:who –rH
查看当前的bind版本信息:nslookup –class=chaos –q=txt version.bind
查看硬件信息:dmesg | more
显示外设信息, 如usb,网卡等信息:lspci
查看已加载的驱动:
    lsnod
    lshw
查看当前处理器的类型和速度(主频):psrinfo -v
打印当前的OBP版本号:prtconf -v
查看硬盘物理信息(vendor, RPM, Capacity):iostat –E
查看磁盘的几何参数和分区信息:prtvtoc /dev/rdsk/c0t0d0s 
显示已经使用和未使用的i-node数目:
    df –F ufs –o i 
    isalist –v

对于“/proc”中文件可使用文件查看命令浏览其内容,文件中包含系统特定信息:

主机CPU信息:Cpuinfo 
主机DMA通道信息:Dma 
文件系统信息:Filesystems 
主机中断信息:Interrupts 
主机I/O端口号信息:Ioprots 
主机内存信息:Meninfo 
Linux内存版本信息:Version
备注: proc – process information pseudo-filesystem 进程信息伪装文件系统

有限状态机的实现

有限状态机的实现

作者:zhanhailiang 日期:2015-01-24

什么是有限状态机

一个有限状态机是一个设备,或是一个设备模型,具有有限数量的状态,它可以在任何给定的时间根据输入进行操作,使其从一个状态变换到另一个状态,或者是促使一个输出或者一种行为的发生。一个有限状态机在任何瞬间只能处在一个状态。

即有限状态机背后的概念是要把一个对象的行为分解成为易于处理的“块”或状态。典型的例子,墙上的灯是一个非常简单的有限状态机,它有两种状态:开或关。状态之间的变换是通过你手指的输入产生的。向上按开关,产生从开到关的状态变换,向下按开关,产生从开到关的状态变换。

关闭状态:没有相应的输出或行动(除非考虑灯泡不亮也是一种行动);
开启状态:允许电流流过开关并通过灯泡丝点亮你的房间。

状态机的实现

使用switch语句来表达状态的代码如下:

switch ($state) {
    case STATE_RUNAWAY : // 逃跑状态
        // 躲避敌人
        // 若安全,进入巡逻状态
        break;
    case STATE_PATROL :  // 巡逻状态
        // 巡逻
        // 若遇到比自己强的敌人,进入逃跑状态
        // 若遇到比自己弱的敌人,进入攻击状态
        break;
    case STATE_ATTACK : // 攻击状态
        // 若攻击比自己强的敌人,进入逃跑状态
        // 否则取其首级
        break;
    // etc...
}

使用switch实现的有限状态机,随着更多的状态和条件的加入,将导致代码流程象意大利面条一样难以理解并且产生调试恶梦。

接下来使用状态变换表表示以上示例状态变换关系

当前状态 条件 状态变换
逃跑 安全 巡逻
攻击 比故人弱 逃跑
巡逻 受到威胁并比敌人强 攻击
巡逻 受到威胁并比敌人弱 逃跑

接下来使用状态设计模式实现以上的有限状态机。它提供了一种优雅的方式来实现状态驱动行为。

请见:

<?php
// vim: set expandtab cindent tabstop=4 shiftwidth=4 fdm=marker:

/**
 * @file     RunnerTest.php
 * @version  1.0
 * @author   wade
 * @date     2015-01-24 19:57:53
 */

/**
 * 有限状态机实现demo
 */

interface State {
    public function execute(Troll $troll);
}

class Troll {
    private $uid;
    private $_curState = NULL;

    public function __construct($uid) {
        $this->uid = $uid;
    }

    public function Update() {
        if ($this->_curState instanceof State) {
            $this->_curState->execute($this);
        }
    }

    public function changeState(State $state) {
        $this->_curState = $state;
    }

    public function isPatrolState() {
        return TRUE;
    }

    public function patrol() {
        echo sprintf("%d is patroling!\n", $this->uid);
    }

    public function isAttackState() {
        return TRUE;
    }

    public function attack() {
        echo sprintf("%d is attacking!\n", $this->uid);
    }

    public function isRunawayState() {
        return TRUE;
    }

    public function runaway() {
        echo sprintf("%d is running away!\n", $this->uid);
    }
}

class PatrolState implements State {
    public function execute(Troll $troll) {
        if ($troll->isPatrolState()) {
            $troll->patrol();
        } else {
            // todo
        }
    }
}

class AttackState implements State {
    public function execute(Troll $troll) {
        if ($troll->isAttackState()) {
            $troll->attack();
        } else {
            // todo
        }
    }
}

class RunawayState implements State {
    public function execute(Troll $troll) {
        if ($troll->isRunawayState()) {
            $troll->runaway();
        } else {
            // todo
        }
    }
}

$uid = 10001;
$troll = new Troll($uid);

$PatrolState = new PatrolState();
$troll->changeState($PatrolState);
$troll->Update();

$AttackState = new AttackState();
$troll->changeState($AttackState);
$troll->Update();

$RunawayState = new RunawayState();
$troll->changeState($RunawayState);
$troll->Update();

查看输出如下:

[root@~/wade/git/billfeller.github.io/code]# /usr/local/php/bin/php RunnerTest.php 
10001 is patroling!
10001 is attacking!
10001 is running away!

广告位功能优化

请求体:

GET http://m.vip.com/ajaxapi-queryAdList.html?s=1418038239498&zoneId=75&f=channel

其中,

zoneId参数通过$('#wrapper_banner').data('zoneid');读取;
f参数通过$('#wrapper_banner').data('f');读取;

响应体:判断list即可;

{
    "list": [
        {
            "url": "product-292734-39355252.html"
        }
    ],
    "msg": "成功",
    "ret": 0
}

Xshell操作快捷键说明

作者:zhanhailiang 日期:2014-12-14

Alt+Enter 全屏切换
Ctrl+Inset 复制
Shift+Insert 粘贴
Alt+Insert 粘贴所选择的文本

预热商品列表预加载接口定义

请求体:

GET ajaxapi-getPreheatingProducts.html?query=308698-0-0-0-1-0-2-40&offset=40&limit=40 

其中,

query参数通过location.href截断preheating-brand-(.*?).html获取即可;
offset参数,略;
limit参数,略;

响应体:

{
    "data": [
        {
            "agio": "7.1折",
            "brand_id": "308698",
            "cat_id": "10501012",
            "fav_price": "",
            "icons": [],
            "is_warmup": "1",
            "m_mobile_show": "0",
            "market_price": "3627",
            "max": -1,
            "min": -1,
            "product_id": "39885370",
            "product_name": "精研祛斑大礼盒",
            "ptype": -1,
            "sale_out": "0",
            "saled": -1,
            "sequence": "43",
            "small_image": "http://sp.vip.com/upload/merchandise/259398/sk2-2014091907-5.jpg",
            "small_image2": "http://a.vimage1.com/upload/merchandise/259398/sk2-2014091907-5_304x384_80.jpg",
            "special_price": "",
            "standard": "0",
            "stock": -1,
            "vipshop_price": "2580"
        },
        ...
    ],
    "msg": "成功",
    "page": {
        "limit": 40,
        "offset": 40,
        "total": 24
    },
    "result": true
}

数据存储选型方案评估标准RDBMS or KV

作者:zhanhailiang 日期:2014-12-11

本文主要介绍常见的数据存储方案及相应选型的评估标准的介绍。

Guideline:针对不同应用场景,针对性选择存储方式。

1. 数据存储方案

SQL:

MySQL 5.5/5.6/MariaDB(对于Dev绝大多数场景下透明);
Oracle|MS SQL暂不考虑;

NoSQL:

Memcached 1.4.21;
Redis 2.8;
MongoDB 2.6.6;
Hbase 0.96/0.98;

#2. 评估标准

RDBMS:(MySQL):

  • 要求数据持久化存储;用户提交数据就不能丢失;
  • 要求事务保证;
  • 应用复杂,数据结构复杂,数据一致性要求高;
  • 分布式实现时复杂度高,分库分表代价较大。
  • 适合需要严格事务保证的OLTP类系统和MIS类系统;

典型场景:

以电商网站为例,
所有后端子系统(比如ERP,物流,财务,仓储,人事,VIS等);
网站核心数据存储(比如用户,商品,库存,购物车,订单);

KV(Memcache/Redis):

  • 数据结构简单;只是按照简单的Key来查询和update记录;
  • 数据不需要持久化存储(persistent on disk), 是secondary data;一般不是用户直接写入;(比如由后端job生成,可以由应用实现双写)
  • 不需要transaction事务支持;
  • 可能有很高的QPS/TPS(for example, 10k+ query/transaction per second);
  • 有非常高的响应速度要求(<1ms typically),以redis为例,同机房操作一般都是几十微秒级别;

典型场景:

各类计数器;
各类cache层(商品列表页,各类配置信息,商品描述信息等);

Analytics Platform:

Hadoop:ETL;科学分析;
GP:BI分析;各类报表;
Hbase:在线系统;OLAP分析;
DocDB:应用相对简单,数据结构相对复杂,支持快速开发,非事务类处理的信息处理系统。如知识问答、社区等;

#3. 性能优化

已有系统碰到性能瓶颈时,优化次序依次为:

  • 容量评估
  • 性能优化(系统优化,代码逻辑优化,SQL优化)
  • 硬件升级(从低端硬件到高端硬件,从低端存储到高端存储)
  • 垂直拆分(按照不同的模块拆分数据库)
  • 水平拆分(对某个模块,在系统里面再也跑不动,就需要对该模块按照主键或者其他逻辑拆分)

附录:

尝试使用github.com issues工具写博客,挺爽的!
对应github.com链接:#4

基于Redis bitmap实现开关配置功能

作者:zhanhailiang 日期:2014-12-21

bitmap api

SETBIT key offset value
对key所储存的字符串值,设置或清除指定偏移量上的位(bit)。
位的设置或清除取决于value参数,可以是0也可以是1。
当key不存在时,自动生成一个新的字符串值。
字符串会进行伸展(grown)以确保它可以将value保存在指定的偏移量上。
当字符串值进行伸展时,空白位置以0填充。
offset参数必须大于或等于0,小于2^32(bit映射被限制在512MB之内)。
返回值: 指定偏移量原来储存的位。
Warning: 对使用大的offset的SETBIT操作来说,内存分配可能造成Redis服务器被阻塞。
Warning: 当生成一个很长的字符串时,Redis 需要分配内存空间,该操作有时候可能会
造成服务器阻塞(block)。在2010年的Macbook Pro上,设置偏移量为536870911(512MB内
存分配),耗费约300毫秒,设置偏移量为134217728(128MB内存分配),耗费约80毫秒,
设置偏移量33554432(32MB内存分配),耗费约30毫秒,设置偏移量为8388608(8MB内存分配),
耗费约8毫秒。

GETBIT key offset
对key 所储存的字符串值,获取指定偏移量上的位(bit)。
当offset比字符串值的长度大,或者key不存在时,返回0。
返回值:字符串值指定偏移量上的位(bit)。

需求场景

在很多业务场景中,我们都需要针对很多功能实现配置,比如以下场景:

  1. 新增某个功能, 希望有开关可以控制是否开启该功能;
  2. 游戏上线某个新功能,希望引导用户去打开该功能,需要诱导用户,比如打开该功能,可以获取XX奖励,此时需要标记位来记录领奖记录;

代码实现

https://github.com/billfeller/billfeller.github.io/blob/master/code/IBit.php

基于Node.js的跨平台工具LivePool简介

基于Node.js的跨平台工具LivePool简介

作者:zhanhailiang 日期:2015-01-05

简介

LivePool 是一个基于 NodeJS,类似 Fiddler 支持抓包和本地替换的 Web 开发调试工具,是 Tencent AlloyTeam 在开发实践过程总结出的一套的便捷的 WorkFlow 以及调试方案。

特性

  • 基于 NodeJS, 跨平台
  • 支持 http 抓包和本地替换调试,Https/WebSockets 直接代理转发(暂不支持本地替换)
  • 便捷的 UI 管理界面,跟 Fiddler 类似,降低学习成本
  • 可以脱离 UI 后台运行,适应于某些不需要抓包,只需要使用替换和简单路由的场景
  • 基于项目的替换规则管理,方便高效,规则支持拖曳排序
  • 支持基于请求路径的本地文件替换,支持基于请求路径的路由转发(host 配置)
  • 替换类型支持:文件/文件夹替换,combo合并替换,qzmin替换(批量combo),delay延时等
  • 支持自动设置系统代理
  • 支持规则过滤,只显示关注的请求
  • 提供构建 http get/post 请求界面,方便接口调试
  • 特色功能:模拟gprs/3g等低网速(mac only)
  • 特色功能:支持离线站点到本地,并自动代码格式化

安装

  1. 安装Node.js,http://nodejs.org
  2. 安装livepool
    D:\Users\wade.zhan>npm install livepool -g
  1. 运行livepool
    D:\Users\wade.zhan>livepool
    =========================================
    livepool is running, port: 8090
    liveapp ui is ready, port: 8002
    connect:t5k2_rmpy1DZIMReAAAA
    disconnect:t5k2_rmpy1DZIMReAAAA
    connect:DqzEMagEAF5bxCcoAAAB
    [https connect error]: accounts.google.com:443
    [https connect error]: accounts.google.com:443
    disconnect:DqzEMagEAF5bxCcoAAAB

使用

  1. 将浏览器的代理设置为 http://127.0.0.1:8090, chrome 可以通过 switchsharp 进行
    switchsharp
  2. 打开浏览器,http://127.0.0.1:8002
  3. 打开需要调试页面地址,如 http://m.vip.com
    livepool_capture

更多阅读

  1. 项目官网:http://rehorn.github.io/livepool
  2. github: https://github.com/rehorn/livepool
  3. Readme: https://github.com/rehorn/livepool/blob/master/README.md
  4. http://www.alloyteam.com/2014/07/nodejs-debug-proxy-livepool/

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.