imajax-single,一款全站ajax的博客主题

近半年来,慢慢的制作一款能够适合博客使用的,能够方便阅读的,速度要快主题。灵感来自于wordpress的官方默认主题。

制作缘由

很喜欢wordpress的默认主题twenty-fifteen,但是不是全站ajax,曾经为twenty-fifteen增加过诸多功能,但是使用起来还是特别的不方便,因此就自己制作了一份主题了。

制作过程

断断续续的几个月,有时间就写一点代码,没时间就放着。由于博主现在主要搞后端接口了,所以在前端方面花的功夫就太少了,主题外观感觉看起来中规中矩,不过使用起来应该还是很贴心的。

(更多…)

一致性哈希的php实现

未来项目可能要上memcache集群,memcache集群的key分配完全在客户端完成,服务端不做任何处理,这里对key进行分配节点的最优方式就是使用一致性哈希。

记得以前用mysql进行分库分表的时候,通常会用一个求余作为哈希函数,这样一些id就能对应相应的表了。不过使用mysql的时候,我们不需要考虑这些节点失效问题,以及节点增加或者减少的问题(在此之前应该做好足够的计划和准备),但是对于缓存,通常就比较宽松了,允许节点失效问题,但是普通的hash分配在节点失效之后,大部分的缓存位置都改变了,这显然个灾难,这个时候就要考虑一致性hash了,在增加或者删除节点,只有小部分的key会受影响。

一致性哈希的步骤

  1. 将几个节点(也就是服务器,随便你怎么命名)通过一个hash函数(比如crc32)分别计算出它们的hash值,比如1000,4000,8000,6000,并且排好序,也就是1000,4000,6000,8000
  2. 将key也通过一个hash函数计算出它的hash值,比如1500
  3. 将这个key的hash于节点的hash逐一比较,当这个key的hash小于节点的hash,那么这个节点就是这个key所要储存的节点,如果没有找到,那就存到第一个节点。

ok,就这么简单,其实就是一个区间的问题,服务器节点形成一个区间,然后key节点落在哪个区间,就分配到哪个节点。ok,我想还是这些高大上的介绍看起来更舒服一点,不过一开始就看这个,我都嫌啰嗦。明明几句简短的话就能概括,非要一上来就一堆的balabala

一致性哈希算法(Consistent Hashing)最早在论文《Consistent Hashing and Random Trees: Distributed Caching Protocols for Relieving Hot Spots on the World Wide Web》中被提出。简单来说,一致性哈希将整个哈希值空间组织成一个虚拟的圆环,如假设某哈希函数H的值空间为0-2^32-1(即哈希值是一个32位无符号整形),整个哈希空间环如下:

 

1466754309-6659-274814

 

整个空间按顺时针方向组织。0和232-1在零点中方向重合。

下一步将各个服务器使用Hash进行一个哈希,具体可以选择服务器的ip或主机名作为关键字进行哈希,这样每台机器就能确定其在哈希环上的位置,这里假设将上文中四台服务器使用ip地址哈希后在环空间的位置如下:

 

1466754309-6632-274814

 

接下来使用如下算法定位数据访问到相应服务器:将数据key使用相同的函数Hash计算出哈希值,并确定此数据在环上的位置,从此位置沿环顺时针“行走”,第一台遇到的服务器就是其应该定位到的服务器。

例如我们有Object A、Object B、Object C、Object D四个数据对象,经过哈希计算后,在环空间上的位置如下:

 

1466754309-9412-274814

 

根据一致性哈希算法,数据A会被定为到Node A上,B被定为到Node B上,C被定为到Node C上,D被定为到Node D上。

下面分析一致性哈希算法的容错性和可扩展性。现假设Node C不幸宕机,可以看到此时对象A、B、D不会受到影响,只有C对象被重定位到Node D。一般的,在一致性哈希算法中,如果一台服务器不可用,则受影响的数据仅仅是此服务器到其环空间中前一台服务器(即沿着逆时针方向行走遇到的第一台服务 器)之间数据,其它不会受到影响。

下面考虑另外一种情况,如果在系统中增加一台服务器Node X,如下图所示:

 

1466754309-6874-274814

 

此时对象Object A、B、D不受影响,只有对象C需要重定位到新的Node X 。一般的,在一致性哈希算法中,如果增加一台服务器,则受影响的数据仅仅是新服务器到其环空间中前一台服务器(即沿着逆时针方向行走遇到的第一台服务器) 之间数据,其它数据也不会受到影响。

综上所述,一致性哈希算法对于节点的增减都只需重定位环空间中的一小部分数据,具有较好的容错性和可扩展性。

另外,一致性哈希算法在服务节点太少时,容易因为节点分部不均匀而造成数据倾斜问题。例如系统中只有两台服务器,其环分布如下,

 

1466754309-9865-274814

 

此时必然造成大量数据集中到Node A上,而只有极少量会定位到Node B上。为了解决这种数据倾斜问题,一致性哈希算法引入了虚拟节点机制,即对每一个服务节点计算多个哈希,每个计算结果位置都放置一个此服务节点,称为虚拟 节点。具体做法可以在服务器ip或主机名的后面增加编号来实现。例如上面的情况,可以为每台服务器计算三个虚拟节点,于是可以分别计算 “Node A#1”、“Node A#2”、“Node A#3”、“Node B#1”、“Node B#2”、“Node B#3”的哈希值,于是形成六个虚拟节点:

 

1466754309-9451-274814

 

同时数据定位算法不变,只是多了一步虚拟节点到实际节点的映射,例如定位到“Node A#1”、“Node A#2”、“Node A#3”三个虚拟节点的数据均定位到Node A上。这样就解决了服务节点少时数据倾斜的问题。在实际应用中,通常将虚拟节点数设置为32甚至更大,因此即使很少的服务节点也能做到相对均匀的数据分布。

一致性hash的php实现

实现方式也很简单,就直接上代码了

<?php
class ConsistentHash
{

    /**
     * nodes array
     * @var array
     */
    protected $nodes = array();

    /**
     * virtual nodes
     * @var array
     */
    protected $virtualNodes = array();

    /**
     * sort
     * @var boolean
     */
    protected $isSort = false;

    /**
     * virtual nodes num
     * @var integer
     */
    protected $virtualNodesNum = 10;

    public function __construct()
    {

    }

    public function setVirtualNum($num)
    {
        $this->virtualNodesNum = $num;
    }

    public function addNode($node)
    {
        $this->nodes[] = $node;
        for( $i=0; $i<$this->virtualNodesNum; $i++ ){
            $virtualHash = sprintf("%u",crc32($node.$i));
            $this->virtualNodes[$virtualHash] = $node;
        }
        return true;
    }

    public function addNodes($nodes)
    {
        foreach($nodes as $node){
            $this->addNode($node);
        }
    }

    public function getNode($key)
    {
        if( !$this->isSort ){
            ksort($this->virtualNodes);
            $this->isSort = true;
        }
        $hashKey = sprintf("%u",crc32($key));

        foreach($this->virtualNodes as $hashNode=>$node){
            if( $hashKey < $hashNode ){
                return $node;
            }
        }

        return $this->nodes[0];

    }
}

代码托管在github : https://github.com/cmhc/consistanthash

一个功能完备的url路由:Hcrail

写在前面

功能完备还有待添加,嘿嘿

正文

之前学习了一下composer,正好也缺一个很优雅的 url 路由,于是就来实践一下,这个路由需要php 5.3以上环境支持,因为用到了匿名回调。

代码

<?php
namespace cmhc\Hcrail;

class Hcrail
{

    /**
     * callback function
     * @var callable
     */
    protected static $callback;

    /**
     * match string or match regexp
     * @var string
     */
    protected static $match;

    protected static $routeFound = false;

    /**
     * deal with get,post,head,put,delete,options,head
     * @param   $method
     * @param   $arguments
     * @return
     */
    public static function __callstatic($method, $arguments)
    {
        self::$match = str_replace("//", "/", dirname($_SERVER['PHP_SELF']) . '/' . $arguments[0]);
        self::$callback = $arguments[1];
        self::dispatch();
        return;
    }

    /**
     * processing ordinary route matches
     * @param  string $requestUri
     * @return
     */
    public static function normalMatch($requestUri)
    {
        if (self::$match == $requestUri) {
            self::$routeFound = true;
            call_user_func(self::$callback);
        }
        return;
    }

    /**
     * processing regular route matches
     * @param  string $requestUri
     * @return
     */
    public static function regexpMatch($requestUri)
    {
        //处理正则表达式
        $regexp = self::$match;
        preg_match("#$regexp#", $requestUri, $matches);
        if (!empty($matches)) {
            self::$routeFound = true;
            call_user_func(self::$callback, $matches);
        }
        return;
    }

    /**
     * dispatch route
     * @return
     */
    public static function dispatch()
    {
        if (self::$routeFound) {
            return ;
        }
        $requestUri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
        $requestMethod = $_SERVER['REQUEST_METHOD'];

        if (strpos(self::$match, '(') === false) {
            self::normalMatch($requestUri);
        } else {
            self::regexpMatch($requestUri);
        }

    }

    /**
     * Determining whether the route is found
     * @return boolean
     */
    public static function isNotFound()
    {
        return !self::$routeFound;
    }

}

介绍以及使用

Hcrail

Hcrail是一个简单的PHP路由,代码不到100行

使用

如果你安装了composer,可以直接用composer吧Hcrail集成到你的项目中去,使用如下代码

require: {
    "cmhc/Hcrail": "dev-master"
}

Hcrail支持普通匹配和正则匹配,如下

普通匹配,匹配首页

use cmhc\Hcrail\Hcrail;

Hcrail::get("/",function(){
    echo 'hello';
});

正则匹配,匹配类似 http://localhost/6666.html 的地址

Hcrail::get("/([0-9]*)\.html",function($args){
    echo $args[1];
});

服务器配置

apache 在根目录建立 .htaccess 文件

RewriteEngine On
RewriteBase /Hcrail

RewriteCond %{REQUEST_FILENAME}% !-f
RewriteCond %{REQUEST_FILENAME}% !-d

RewriteRule ^.*$ index.php [L]

nginx

location / {
    try_files $uri $uri/ /index.php?/$uri;
}

后记

这个我将会在一些项目上来实践,进而发现一些不足,逐渐让这个路由完备起来,但我希望这个路由仍旧越简单越好,保持最基础的功能!

github地址 https://github.com/cmhc/Hcrail

我是一个线程

来自:码农翻身(微信号:coderising)

作者:IBM刘欣

我是一个线程,我一出生就被编了个号: 0x3704,然后被领到一个昏暗的屋子里, 这里我发现了很多和我一模一样的同伴。

我身边的同伴0x6900待的时间比较长, 他带着沧桑的口气对我说:

“我们线程的宿命就是处理包裹。把包裹处理完以后还得马上回到这里,否则可能永远回不来了。”

我一脸懵懂,包裹,什么包裹?

“不要着急,马上你就会明白了, 我们这里是不养闲人的。”

果然,没多久,屋子的门开了, 一个面貌凶恶的家伙吼道:

“0x3704 ,出来!”

我一出来就被塞了一个沉甸甸的包裹,上面还有附带着一个写满了操作步骤的纸。

“快去,把这个包裹处理了。”

“去哪儿处理?”

“跟着指示走, 先到就绪车间”

果然,地上有指示箭头,跟着它来到了一间明亮的大屋子,这里已经有不少线程了, 大家都很紧张,好像时刻准备着往前冲。 (更多…)

shell 变量的定义

shell可以自定义变量,这为shell的编写带来很多方便

定义变量

定义变量时,变量名不加美元符号($),如:

variableName="value"

注意:变量名和等号之间不能有空格,这可能和你熟悉的所有编程语言都不一样

同时,变量名的命名须遵循如下规则。

首个字符必须为字母(a-z,A-Z)。
中间不能有空格,可以使用下划线(_)。
不能使用标点符号。
不能使用bash里的关键字(可用help命令查看保留关键字)。
变量定义举例: (更多…)

用php编写守护进程

在此之前,需要知道守护进程这个概念,知道之后,才可以用php来编写守护进程。那么创建守护进程需要有下面这几个步骤。

1.创建子进程,父进程退出

父进程先与子进程退出,子进程则会被1号进程收养,这个子进程就会成为init的子进程

php使用pcntl_fork()来创建子进程。

pcntl_fork()返回一个整型值,在父进程里面返回的是子进程的id,子进程返回的是0,失败则返回-1。这样我们就可以根据这个来分别控制父进程和子进程执行任务。

2.子进程创建会话

这个是重要的一步,在这一步中该子进程会做这些事情:1.让进程摆脱原会话的控制;2.让进程摆脱员进程组的控制;3.让进程摆脱终端的控制。

为什么要这样?这个在守护进程介绍里面有

php这里使用posix_setsid()来在这个子进程中创建会话,使得这个进程成为会话组组长 (更多…)

chkconfig给linux添加开机自启动服务,chkconfig命令详解

chkconfig命令主要用来更新(启动或停止)和查询系统服务的运行级信息。谨记chkconfig不是立即自动禁止或激活一个服务,它只是简单的改变了符号连接。

使用语法

chkconfig [--add][--del][--list][系统服务] 或 chkconfig [--level <等级代号>][系统服务][on/off/reset]

chkconfig 在没有参数运行时,会显示所有的服务在开机启动状态。如果加上服务名,那么就检查这个服务是否在当前运行级启动。如果是,返回true,否则返回false。如果在服务名后面指 定了on,off或者reset,那么chkconfig 会改变指定服务的启动信息。on和off分别指服务被启动和停止,reset指重置服务的启动信息,无论有问题的初始化脚本指定了什么。on和off开 关,系统默认只对运行级3,4,5有效,但是reset可以对所有运行级有效。

参数用法

--add  增加所指定的系统服务,让chkconfig指令得以管理它,并同时在系统启动的叙述文件内增加相关数据。
--del  删除所指定的系统服务,不再由chkconfig指令管理,并同时在系统启动的叙述文件内删除相关数据。
--level<等级代号>  指定读系统服务要在哪一个执行等级中开启或关毕。
等级0表示:表示关机
等级1表示:单用户模式
等级2表示:无网络连接的多用户命令行模式
等级3表示:有网络连接的多用户命令行模式
等级4表示:不可用
等级5表示:带图形界面的多用户模式
等级6表示:重新启动

(更多…)

第一个shell脚本,hello shell

Linux的Shell种类众多,常见的有:Bourne Shell(/usr/bin/sh或/bin/sh)、Bourne Again Shell(/bin/bash)、C Shell(/usr/bin/csh)、K Shell(/usr/bin/ksh)、Shell for Root(/sbin/sh),等等。不同的Shell语言的语法有所不同,所以不能交换使用。每种Shell都有其特色之处,基本上,掌握其中任何一种 就足够了。在本文中,我们关注的重点是Bash,也就是Bourne Again Shell,由于易用和免费,Bash在日常工作中被广泛使用;同时,Bash也是大多数Linux系统默认的Shell。在一般情况下,人们并不区分 Bourne Shell和Bourne Again Shell,所以,在下面的文字中,我们可以看到#!/bin/sh,它同样也可以改为#!/bin/bash。

你现在可能知道shell是什么了,想学习shell,那我们就开始第一个入门脚本

从hello shell开始,用vim新建一个脚本

vim hello.sh

并且在里面输入下面内容

#!/bin/bash
echo "Hello shell!"

“#!” 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种Shell,这里我们用的是bash,echo命令用于向窗口输出文本。 (更多…)

linux shell 入门

从程序员的角度来看, Shell本身是一种用C语言编写的程序,从用户的角度来看,Shell是用户与Linux操作系统沟通的桥梁。用户既可以输入命令执行,又可以利用 Shell脚本编程,完成更加复杂的操作。在Linux GUI日益完善的今天,在系统管理等领域,Shell编程仍然起着不可忽视的作用。深入地了解和熟练地掌握Shell编程,是每一个Linux用户的必修 功课之一。

Linux的Shell种类众多,常见的有:Bourne Shell(/usr/bin/sh或/bin/sh)、Bourne Again Shell(/bin/bash)、C Shell(/usr/bin/csh)、K Shell(/usr/bin/ksh)、Shell for Root(/sbin/sh),等等。不同的Shell语言的语法有所不同,所以不能交换使用。每种Shell都有其特色之处,基本上,掌握其中任何一种 就足够了。在本文中,我们关注的重点是Bash,也就是Bourne Again Shell,由于易用和免费,Bash在日常工作中被广泛使用;同时,Bash也是大多数Linux系统默认的Shell。在一般情况下,人们并不区分 Bourne Shell和Bourne Again Shell,所以,在下面的文字中,我们可以看到#!/bin/sh,它同样也可以改为#!/bin/bash。

利用vi等文本编辑器编写Shell脚本的格式是固定的,如下:

#!/bin/sh
#comments
Your commands go here

首行中的符号#!告诉系统其后路径所指定的程序即是解释此脚本文件的Shell程 序。如果首行没有这句话,在执行脚本文件的时候,将会出现错误。后续的部分就是主程序,Shell脚本像高级语言一样,也有变量赋值,也有控制语句。除第 一行外,以#开头的行就是注释行,直到此行的结束。如果一行未完成,可以在行尾加上”,这个符号表明下一行与此行会合并为同一行。 (更多…)

memcacheq的安装与使用

1、安装libevent

官网:http://www.libevent.org/

$ wget https://github.com/downloads/libevent/libevent/libevent-2.0.21-stable.tar.gz --no-check-certificate
$ tar -zxvf libevent-2.0.21-stable.tar.gz
$ cd libevent-2.0.21-stable
$ ./configure --prefix=/usr/local/libevent
$ sudo make && make install

2、安装 BerkeleyDB

官网:http://www.oracle.com/technetwork/products/berkeleydb/downloads/index.html(下载需要登录)

安装:

$ wget http://download.oracle.com/berkeley-db/db-6.0.30.tar.gz
$ tar -zxvf db-6.0.30.tar.gz (根据自身的情况解压到目录)
$ cd db-6.0.30/build_unix
$ ../dist/configure --prefix=/usr/local/berkeleyDB
$ sudo make && make install

安装完成之后:

$ export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/libevent/lib:/usr/local/berkeleyDB/lib

或者:

$ vim /etc/ld.so.conf

添加:

/usr/local/libevent/lib
/usr/local/berkeleyDB/lib

并执行:

$ /sbin/ldconfig

(更多…)