2013年5月10日 | 标签:

最近的做一个短信群发的项目,需要用到消息队列。因此开始了我对消息队列选型的漫长路.

为什么选型会纠结呢,直接使用ActiveMQ,RabittMQ,Gearman等流行的消息队列不就可以了吗? 在这个项目中,只有单台服务器,而且我采用了redis来做系统缓存,同时开启了php apc来缓存phalcon model Metadata.如果再开启其他进程,需要很合理的分配各个应用的资源,如果分配不好,极有可能产生浪费,同时还有可能造成应用性能低下.

因此,为了实现项目结构的简单化,同时简化维护,我就打算用Redis来实现,但短信群发过程中,必须要有优先级别的,直接使用Redis的List显然不是太合适,本着这一打算,我还专门google了一下,发现有人使用zset来模拟FIFO,实现LIST中的lpush,rpop操作。

通过Google发现有一个基于Redis的比较不错的消息队列 Resque https://github.com/resque/resque 而此消息队列则是使用ruby语言实现的.我更不想一个项目中使用多种语言了,幸好,马上又发现了基于resque的PHP实现, php-resque https://github.com/chrisboulton/php-resque

Resque还包括很多其他插件以及其他语言的实现,详细列表请看官方列表 https://github.com/resque/resque/wiki/Alternate-Implementations

php-resque本身并没有包括查看消息队列status的用户界面,但我们可以通过命令行查看,同时由于php-resque的消息队列实现和resque中命名一致,可以安装ruby的web界面来进行查看.

我一直使用的是phpredis扩展. php-resque使用Redis Client是 Credis, https://github.com/colinmollenhour/credis ,而Credis的API完全是基于phpredis来封装的,即API一样,前者是C扩展,后者是PHP实现.

促使我最终决定使用Redis及PHP-Resque的一个最要原因是PHP-Resque内置可同时开启多个进程,对于海量数据下发来说非常必要,同时不需要自己再写代码实现多进程或多线程了.

下面具体介绍一下PHP-Resque的安装与使用.

PHP-Resque安装

1.环境需求

  • PHP 5.3+
  • Redis 2.2+
  • Optional but Recommended: Composer

2.安装Composer

$ curl -sS https://getcomposer.org/installer | php
$ mv composer.phar /usr/local/bin/composer

3.安装PHP-Resque

git clone git://github.com/chrisboulton/php-resque.git
cd php-resque
composer install

php-resque的队列实现

所有的消息队列都差不多,有生产者,消费者,还有Task Server.只不过名称不同而已.

生产者:接受用户提交信息,组成消息队列中的一个任务,并将其加入消息队列服务中.

消费者:一般为一个守护进程,从消息队列服务器中取出任务,对任务做出相应的处理.PHP-Resque中的消息者为守护进程+Job Class .即由守护进程从消息队列中取出任务,具体的任务中在任务的生产过程中已经指定了由哪个Job Class来做具体的处理.

Task Server: 消息队列服务器,本处指redis服务.

具体实现

下载安装PHP-Resque后,在php-resque/demo目录中,有类似如下几个文件(我修改测试过,和原有目录不太一样了):

[root@myfc demo]# ll
total 52
-rw-r--r-- 1 root root  113 Apr 17 17:48 bad_job.php
-rw-r--r-- 1 root root  494 Apr 17 17:48 check_status.php
-rw-r--r-- 1 root root 1629 Apr 28 15:43 cli-bootstrap.php
-rw-r--r-- 1 root root  396 Mar 25 10:27 config.ini
-rw-r--r-- 1 root root    6 Apr 18 11:26 index.php
-rw-r--r-- 1 root root  680 Apr 17 17:48 init.php
-rw-r--r-- 1 root root  199 Apr 18 13:13 job.php
-rw-r--r-- 1 root root   78 Apr 17 17:48 long_job.php
-rw-r--r-- 1 root root  325 Apr 28 15:51 MtSend_Job.php
-rw-r--r-- 1 root root   97 Apr 18 12:05 php_error_jobFF.php
-rw-r--r-- 1 root root  382 Apr 18 11:43 queue.php
-rw-r--r-- 1 root root  160 Apr 28 18:09 resque.php
-rw-r--r-- 1 root root   80 Apr 18 13:22 Test_Job.php

生成任务(创建一个Job)

// Required if redis is located elsewhere
Resque::setBackend('localhost:6379');

$args = array(
    'name' => 'Chris'
);
Resque::enqueue('default', 'My_Job', $args);

其中第一行为连接redis服务

第二行的数组是任务的内容,可随意编写.通过Resque::enqueue 序列化后加入到消息队列中.

最后一行的第一个参数表示 消息队列的名称(可随意标记,比如 email,log等),第二个参数表示取出任务后,由My_Job这个类来处理此条任务.

同时需要说明的是: 在PHP-Resque中也没有数字标识的优化级,但可以通过消息队列名称来实现优化级,具体下面会讲到.

定义Job Class

class My_Job
{
    public function setUp()
    {
        // ... Set up environment for this job
    }

    public function perform()
    {
        // .. Run job
    }

    public function tearDown()
    {
        // ... Remove environment for this job
    }
}

从上面的代码中可以看出,这是一个非常简单的PHP类文件, 方法perform是必须的,主要用来处理任务.其他两个方法可有可无,根据你自己的应用环境看是否需要.

Demo目录中的job.php (修改过)

<?php
class PHP_Job
{
        public function perform()
        {
                sleep(5);
                // fwrite(STDOUT, 'Hello!');
                $p = $this->args['name'];
                echo 'ttime '.$p;
                // print_r(json_decode($p));
                echo "string";
        }
}
?>

从上面的例子可以看出,如果想在Job Class中读取任务的具体内容,可直接使用 $this->args['name']来进行读取.按上面的例子来说,它将输出 Chris

测试消息队列

(1)创建任务

[root@myfc demo]# cd php-resque/demo
[root@myfc demo]# php queue.php PHP_Job
Queued job bcd1cb6f39d72b9b786716f81b757370

queue.php代码如下:

<?php
if(empty($argv[1])) {
        die('Specify the name of a job to add. e.g, php queue.php PHP_Job');
}

require __DIR__ . '/init.php';
date_default_timezone_set('GMT');
Resque::setBackend('127.0.0.1:6379');

$args = array(
        'time' => time(),
        'array' => array(
                'test' => 'test',
        ),
);

$jobId = Resque::enqueue('default', $argv[1], $args, true);
echo "Queued job ".$jobId."\n\n";

此时查看Redis,会发现多了三条数据

resque:queues,  default 
resque:queue:default, {"class":"PHP_Job","args":[{"time":1368167779,"array":{"test":"test"}}],"id":"875234d18af92212a7d60056daeae910"}
resque:job:875234d18af92212a7d60056daeae910:status, {"status":1,"updated":1368167779,"started":1368167779}

注意: “,”逗号前是键名,后面是键值

在开启守护进程以前,请确保PHP_Job存在,PHP_Job为PHP类名,而非PHP文件名. 如果PHP_Job不存在,则此条任务会处理失败.(因为根本不存在处理它的文件)

(2)处理任务

在demo目录中,守护进程是由目录下的resque.php来进行,代码如下:

<?php
date_default_timezone_set('GMT');
require 'bad_job.php';
require 'job.php';
require 'long_job.php';
require 'MtSend_Job.php';

require '../bin/resque';

Job Class需要放到此文件头部引入,当然也可以使用其他方式引入. 上面代码中job.php即是类PHP_Job文件

开启守护进程参数说明:

在上面的代码中,最后一行引入的../bin/resque 其实也是一个php cli程序,代码如下:

#!/usr/bin/env php
<?php

// Find and initialize Composer
$files = array(
  __DIR__ . '/../../vendor/autoload.php',
  __DIR__ . '/../../../autoload.php',
  __DIR__ . '/../../../../autoload.php',
  __DIR__ . '/../vendor/autoload.php',
);

$found = false;
foreach ($files as $file) {
        if (file_exists($file)) {
                require_once $file;
                break;
        }
}

if (!class_exists('Composer\Autoload\ClassLoader', false)) {
        die(
                'You need to set up the project dependencies using the following commands:' . PHP_EOL .
                'curl -s http://getcomposer.org/installer | php' . PHP_EOL .
                'php composer.phar install' . PHP_EOL
        );
}

$QUEUE = getenv('QUEUE');
if(empty($QUEUE)) {
        die("Set QUEUE env var containing the list of queues to work.\n");
}

$REDIS_BACKEND = getenv('REDIS_BACKEND');
$REDIS_BACKEND_DB = getenv('REDIS_BACKEND_DB');
if(!empty($REDIS_BACKEND)) {
        if (empty($REDIS_BACKEND_DB)) 
                Resque::setBackend($REDIS_BACKEND);
        else
                Resque::setBackend($REDIS_BACKEND, $REDIS_BACKEND_DB);
}

$logLevel = 0;
$LOGGING = getenv('LOGGING');
$VERBOSE = getenv('VERBOSE');
$VVERBOSE = getenv('VVERBOSE');
if(!empty($LOGGING) || !empty($VERBOSE)) {
        $logLevel = Resque_Worker::LOG_NORMAL;
}
else if(!empty($VVERBOSE)) {
        $logLevel = Resque_Worker::LOG_VERBOSE;
}

$APP_INCLUDE = getenv('APP_INCLUDE');
if($APP_INCLUDE) {
        if(!file_exists($APP_INCLUDE)) {
                die('APP_INCLUDE ('.$APP_INCLUDE.") does not exist.\n");
        }

        require_once $APP_INCLUDE;
}

$interval = 5;
$INTERVAL = getenv('INTERVAL');
if(!empty($INTERVAL)) {
        $interval = $INTERVAL;
}

$count = 1;
$COUNT = getenv('COUNT');
if(!empty($COUNT) && $COUNT > 1) {
        $count = $COUNT;
}

$PREFIX = getenv('PREFIX');
if(!empty($PREFIX)) {
    fwrite(STDOUT, '*** Prefix set to '.$PREFIX."\n");
    Resque_Redis::prefix($PREFIX);
}

if($count > 1) {
        for($i = 0; $i < $count; ++$i) {
                $pid = Resque::fork();
                if($pid == -1) {
                        die("Could not fork worker ".$i."\n");
                }
                // Child, start the worker
                else if(!$pid) {
                        $queues = explode(',', $QUEUE);
                        $worker = new Resque_Worker($queues);
                        $worker->logLevel = $logLevel;
                        fwrite(STDOUT, '*** Starting worker '.$worker."\n");
                        $worker->work($interval);
                        break;
                }
        }
}
// Start a single worker
else {
        $queues = explode(',', $QUEUE);
        $worker = new Resque_Worker($queues);
        $worker->logLevel = $logLevel;

        $PIDFILE = getenv('PIDFILE');
        if ($PIDFILE) {
                file_put_contents($PIDFILE, getmypid()) or
                        die('Could not write PID information to ' . $PIDFILE);
        }

        fwrite(STDOUT, '*** Starting worker '.$worker."\n");
        $worker->work($interval);
}

从上面的代码可以看出,在命令行启动守护进程时,可以传递一些环境变量.而 ../bin/resque通过getenv函数来获取环境变量.

支持的环境变量有:

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

QUEUE – 這个是必要的,会決定 worker 要執行什麼任務,重要的在前,例如 QUEUE=default,notify,mail,log 。也可以設定為 QUEUE=* 表示執行所有任務。

APP_INCLUDE – 这也可以说是必要的,因為 Resque 的 Job 都是写成PHP类,那 worker 執行的時候當然要把物件的檔案引入進來。可以設成 APP_INCLUDE=require.php 再在 require.php 中引入所有 Job 的 Class 文件即可。

COUNT – 設定 worker 數量,預設是1 COUNT=5 。

REDIS_BACKEND – 設定 Redis 的 ip, port。如果沒設定,預設是連 localhost:6379 。

LOGGING, VERBOSE – 設定 log, VERBOSE=1 即可。

VVERBOSE – 比較詳細的 log, VVERBOSE=1 debug 的時候可以開出來看。

INTERVAL – worker 檢查 queue 的間隔,預設是五秒 INTERVAL=5 。

PIDFILE – 如果你是開單 worker,可以指定 PIDFILE 把 pid 寫入,例如 PIDFILE=/var/run/resque.pid 。

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

启动守护进程:

QUEUE=* APP_INCLUDE=require.php COUNT=5 VVERBOSE=1 php resque.php

QUEUE=* 表明处理所有的消息队列,此时则没有优化级别.如果需要优化级别,可以按先后顺序列出,如 QUEUE=mail1,mail2,mail3

APP_INCLUDE=require.php 文件中,可以引入其他的一些Job Class或其他辅助类,当然也可以直接在 demo/resque.php中引入

启动守护进程后:

[root@myfc demo]# QUEUE=*  COUNT=5 VVERBOSE=1 php resque.php
#!/usr/bin/env php
*** Starting worker myfc:22143:*
*** Starting worker myfc:22144:*
** [07:25:09 2013-05-10] Registered signals
*** Starting worker myfc:22145:*
** [07:25:09 2013-05-10] Registered signals
** [07:25:09 2013-05-10] Registered signals
*** Starting worker myfc:22146:*
** [07:25:09 2013-05-10] Registered signals
*** Starting worker myfc:22148:*
** [07:25:09 2013-05-10] Registered signals
[root@myfc demo]# ** [07:25:09 2013-05-10] Checking default
** [07:25:09 2013-05-10] Found job on default
** [07:25:09 2013-05-10] got (Job{default} | ID: 875234d18af92212a7d60056daeae910 | PHP_Job | [{"time":1368167779,"array":{"test":"test"}}])
** [07:25:09 2013-05-10] Forked 22163 at 2013-05-10 07:25:09
** [07:25:09 2013-05-10] Processing default since 2013-05-10 07:25:09
** [07:25:09 2013-05-10] Checking default
** [07:25:09 2013-05-10] Sleeping for 5
** [07:25:09 2013-05-10] Checking default
** [07:25:09 2013-05-10] Sleeping for 5
** [07:25:09 2013-05-10] Checking default
** [07:25:09 2013-05-10] Sleeping for 5
** [07:25:09 2013-05-10] Checking default
** [07:25:09 2013-05-10] Sleeping for 5
ttime 1368167779string** [07:25:14 2013-05-10] done (Job{default} | ID: 875234d18af92212a7d60056daeae910 | PHP_Job | [{"time":1368167779,"array":{"test":"test"}}])
** [07:26:29 2013-05-10] Checking default
** [07:26:29 2013-05-10] Checking default
** [07:26:29 2013-05-10] Sleeping for 5
** [07:26:29 2013-05-10] Sleeping for 5
** [07:26:34 2013-05-10] Checking default
** [07:26:34 2013-05-10] Checking default
** [07:26:34 2013-05-10] Sleeping for 5
** [07:26:34 2013-05-10] Sleeping for 5
** [07:26:34 2013-05-10] Checking default
** [07:26:34 2013-05-10] Sleeping for 5
** [07:26:34 2013-05-10] Checking default
** [07:26:34 2013-05-10] Checking default
** [07:26:34 2013-05-10] Sleeping for 5
** [07:26:34 2013-05-10] Sleeping for 5
** [07:26:39 2013-05-10] Checking default
** [07:26:39 2013-05-10] Checking default
** [07:26:39 2013-05-10] Sleeping for 5
** [07:26:39 2013-05-10] Sleeping for 5
** [07:26:39 2013-05-10] Checking default
** [07:26:39 2013-05-10] Sleeping for 5
** [07:26:39 2013-05-10] Checking default
** [07:26:39 2013-05-10] Checking default
** [07:26:39 2013-05-10] Sleeping for 5
** [07:26:39 2013-05-10] Sleeping for 5

可以看出,已经成功取出任务,并使用PHP_Job处理.然后守护进程一直在运行,等待处理新的任务

此时看一下进程文件:

[root@myfc sop]# ps -aux|grep php
root     22143  0.0  0.0 310700 11496 pts/2    S    15:25   0:00 php resque.php
root     22144  0.0  0.0 310700 11580 pts/2    S    15:25   0:00 php resque.php
root     22145  0.0  0.0 310700 11496 pts/2    S    15:25   0:00 php resque.php
root     22146  0.0  0.0 310700 11496 pts/2    S    15:25   0:00 php resque.php
root     22148  0.0  0.0 310700 11496 pts/2    S    15:25   0:00 php resque.php

查看任务的状态

在生成任务的时候,使用 $token = Resque::enqueue('default', 'My_Job', $args, true); 生成一个任务,第四个参数设置为true,会返回任务的JobID,通过JobID可以查看任务的状态.

$status = new Resque_Job_Status($token);
echo $status->get(); // Outputs the status

类文件Resque_Job_Status中定义了所有类型任务状态

Resque_Job_Status::STATUS_WAITING - 等待被取出处理
Resque_Job_Status::STATUS_RUNNING - 任务正在被处理
Resque_Job_Status::STATUS_FAILED - 任务处理失败
Resque_Job_Status::STATUS_COMPLETE - 任务处理完成

事件触发接口 暂时没用到,可查看官方文档

本来想把选型,使用,以及整合Phalcon写到一篇文章中,看来太长,还是分开吧.抽空把集成到Phalcon以及消息队列实际应用写一下.

 

参考文档:

http://avnpc.com/pages/run-background-task-by-php-resque

http://blog.hsatac.net/2012/01/php-resque-introduction/

http://kamisama.me/2012/10/12/background-jobs-with-php-and-resque-part-4-managing-worker/

https://github.com/kamisama/Fresque

http://stackoverflow.com/questions/11814445/what-is-the-proper-way-to-setup-and-use-php-resque

2013年5月7日 | 标签:

经历多个beta发布版本后,Phalcon 1.1正式发布!

此版本增加了一些新的功能,修正以及改善了目前的组件,大大提升了性能。我们一直在不断的寻找性能与功能之间的最佳平衡,建立一个可靠的PHP框架,使之表现更加出色。

此版本主要更新的功能特点如下:

QueryBuilder Paginator(QueryBuilder 分页组件)
在版本1.1之前,框架中只能使用ModelResultset 和 NativeArray两种内置分页方式,这个版本开始提供QueryBuilder的分页方式,使用SQL语句的LIMIT/OFFSET子句来获得请求结果集,以便处理大型的数据集。

use Phalcon\Paginator\Adapter\QueryBuilder;

$builder = $this->modelsManager->createBuilder()
      	->columns('id, name')
  	->from('Robots')
  	->orderBy('name');

$paginator = new Paginator(array(
	"builder" => $builder,
	"limit"=> 10,
	"page" => 1
));

$page = $paginator->getPaginate();

关于此分页组件,我曾在版本v0.8时,在phalcon issue中提出改进意见
详见:https://github.com/phalcon/cphalcon/issues/319

同时还有其他用户也提出了相应的意见,详见:

http://forum.phalconphp.com/discussion/129/paginating-large-amounts-of-data,同时在此贴中很好的讨论了关于Mysql大数据集分页及排序的讨论。

另一点值得注意的是,在此版本中,使用QueryBuilder Paginator的同时,相应的执行两条SQL语句,一条是查询取得将要使用的数据集,另一条是执行SQL SELECT count,同时返回total_pages和total_items两个值,使用起来相当方便,关于此特性,也是1.1版本中新加入的,详见我在官方论坛上的贴子: http://forum.phalconphp.com/discussion/272/when-i-use-new-phalcon-paginator-adapter-querybuilder-it-execute

Beanstalkd Queuing client(Beanstalkd消息队列)
此版本还内置加入了高性能的消息队列Beanstalkd消息队列的客户端实现:

<?php

//Connect to the queue
$queue = new Phalcon\Queue\Beanstalk(array(
    'host' => '192.168.0.21'
));

//Insert the job in the queue (simple)
$queue->put(array('proccessVideo' => 4871));

//Insert the job in the queue with options
$queue->put(
    array('proccessVideo' => 4871),
    array('priority' => 250, 'delay' => 10, 'ttr' => 3600)
);

while (($job = $queue->peekReady()) !== false) {

    $message = $job->getBody();

    var_dump($message);

    $job->delete();
}

如果你不清楚Beanstalkd是什么的话,(我也刚知道这个:))那么你一定听说过Gearman, RabbitMQ,SquirrelMQ , HTTPSQS等
同时这里有几篇关于Beanstalkd的介绍及使用文章:

http://www.igvita.com/2010/05/20/scalable-work-queues-with-beanstalk/

http://miliwo.com/w/739/14535

http://www.blogjava.net/Skynet/archive/2009/10/30/300325.html

同时再为大家介绍一款比较不错的消息队列,那就是基于Redis的Resque 。关于消息队列选型以及Resque的文章稍后有空单独写一下。

Encryption (加密)
此版本还实现了基于PHP mcrypt库的加密/解密类。

//Create an instance
$encryption = new Phalcon\Crypt();

$key = 'le password';
$text = 'This is a secret text';

$encrypted = $encryption->encrypt($text, $key);

echo $encryption->decrypt($encrypted, $key);

Assets Management(静态资源管理)
此组件简化了添加静态资源文件的方式,如添加javascript,css等文件,然后输出到视图。

//Add some local CSS resources
$this->assets
	->addCss('css/style.css')
	->addCss('css/index.css');

//and some local javascript resources
$this->assets
	->addJs('js/jquery.js')
	->addJs('js/bootstrap.min.js');

在视图模板文件中这样写:

<html>
    <head>
        <title>Some amazing website</title>
        <?php $this->assets->outputCss() ?>
    </head>
    <body>

        <!-- ... -->

        <?php $this->assets->outputJs() ?>
    </body>
</html>

关于此组件的实现,我在1.1版本之前也发布相应的帖子,详见 http://forum.phalconphp.com/discussion/91/view-file-struct-volt-inheritance-association 十分幸运,此功能在1.1版本做为内置功能实现了。

Exception mode in ORM Validations(在ORM验证中使用抛出异常)
在默认情况下,验证creating/updating的成功与否,通过使用方法save()/create(),update时返回布尔值true,false来进行验证这一操作是否成功。现在,你可以改变这种行为,使用异常:

use Phalcon\Mvc\Model\ValidationFailed;

try {

	$robot = new Robots();
	$robot->name = 'Bender';
	$robot->save();

} catch (ValidationFailed $e) {
	echo 'Reason: ', $e->getMessage();
}

Hostname routing
Phalcon\Mvc\Router 现在实现了基于hostname的路由方式:

$router = new Phalcon\Mvc\Router();

$router->addGet('/api/robots', array(
	'module' => 'api',
	'controller' => 'robots',
	'action' => 'index'
))->setHostName('api.phalconphp.com');

还可以使用组的方式:

$group = new Phalcon\Mvc\Router();

$group->setHostName('api.phalconphp.com');

$groop->addGet('/api/robots', array(
	'module' => 'api',
	'controller' => 'robots',
	'action' => 'index'
));

$groop->addGet('/api/robots/{id}', array(
	'module' => 'api',
	'controller' => 'robots',
	'action' => 'show'
));

$router->mount($group);

Use Controllers in Mvc\Micro (在Mvc\Micro中使用Controller)
为了更好的组织Micro应用程序,现在你可以创建一个类文件作为控制器:

$collection = new Phalcon\Mvc\Micro\Collection();

//Use direct instantiation
$collection
	->setPrefix('/posts')
	->setHandler(new PostsController());

//Lazy instantiation
$collection
	->setPrefix('/posts')
	->setHandler('PostsController', true);

$collection->get('/', 'index');

$collection->get('/edit/{id}', 'edit');

$collection->delete('/delete/{id}', 'delete');

$app->mount($collection);

1.1.0版本还包括其他一些细微的改动,Bug修复和稳定性方面的改进,具体变化可以查看完整的CHANGELOG

最后,我需要补充一点官方日志发布中没提到的,那就是 Phalcon\CLI\Console

此组件在1.1.0版本中进行了行为改变,以至于我的项目出现了问题,详见我在issue的提问 https://github.com/phalcon/cphalcon/issues/601

V0.7 版本中文文档: http://phalcon.5iunix.net  (v0.7)

同时欢迎志同道合的兄弟一起完善更新中文文档,另我向作者要来了 http://china.phalconphp.com 域名,找志同道合的朋友一起推广促进Phalcon在国内的发展。

2013年5月7日 | 标签:

Linux 禁ping和开启ping操作
# echo 1 > /proc/sys/net/ipv4/icmp_echo_ignore_all
如果要恢复,只要:
# echo 0 > /proc/sys/net/ipv4/icmp_echo_ignore_all
即可,挺方便,不要去专门使用ipchains或者iptables了。

或者用以下方法也可以,异曲同工

以root进入Linux系统,然后编辑文件icmp_echo_ignore_all
vi /proc/sys/net/ipv4/icmp_echo_ignore_all
将其值改为1后为禁止PING
将其值改为0后为解除禁止PING
转自:https://www.akii.org/linux-ban-ping-and-open-way.html

2013年4月28日 | 标签:

myisam

innodb

merge

csv

FEDERATED

archive

Falcon

seqdb

handler-socket

xtradb

mariadb

q4m

2013年4月26日 | 标签: , ,

两台电脑安装的都是fedora18 x64,一直使用的是ibus五笔,包括wubi-hangfeng,wubi-jidian,wubi-wnwb等。

近一段时间以来,不是英文字母不能输入半角,就是标点无法输入半角。前一段时间查了一下,在google code上找到了切换方式,使用 CTRL+  . (dot)

正常使用一段时间后,使用此方式只能切换标点符号的全角半角,英文的始终是全角。

最杯具的是,我不清楚 fsdafsd这种字符是什么字符,不得已到oschina动弹上问了一下,回答的还真快,这是全角的英文。

知道是什么编码后就容易google了嘛,查到以下几篇文章。

http://code.google.com/p/ibus/issues/detail?id=1549

http://www.dengguibao.cn/blog/114

经过实验,得出最后结果:

想要切换标点的全角半角,使用的是 ctrl+. (dot)

切换英文的全角半角,使用的是 shift+ space

输入法不好用,工作起来很费劲的嘛,这下爽多了。不过说实在的,linux下有点太自由,没有统一的管理者,各种ibus engine和ibus经常会出现各种不兼容。

2013年4月24日 | 标签:

http://www.flotcharts.org/

Attractive JavaScript plotting for jQuery
Flot is a pure JavaScript plotting library for jQuery, with a focus on simple usage, attractive looks and interactive features.
Works with Internet Explorer 6+, Chrome, Firefox 2+, Safari 3+ and Opera 9.5+
2013年4月22日 | 标签:

在天朝,敏感词问题是个比较大的问题,而且还非常多,如果用substr之类的函数查找,效率显然是不行的。

http://hellohank.iteye.com/blog/1327903 (这篇文章可以好好看一下)
http://blog.csdn.net/lyflower/article/details/5890132 这也有一篇介绍DFA算法的文章

我安装的是以下扩展

https://github.com/wulijun/php-ext-trie-filter

关键词过滤扩展,用于检查一段文本中是否出现敏感词,基于Double-Array Trie 树实现。

需要先安装 libdatrie-0.2.4 or later,下载地址为 http://linux.thai.net/%7Ethep/datrie/datrie.html

安装datrie

$ tar zxvf libdatrie-0.2.4.tar.gz
$ cd libdatrie-0.2.4
$ make clean
$ ./configure --prefix=$LIB_PATH
$ make
$ make install

我个人在安装过程在遇到了 undefined reference to `libiconv’ 的问题。

可以使用如下参数避免,前提就你已经安装过libiconv.

./configure LDFLAGS=-L/usr/local/lib LIBS=-liconv --prefix=/usr/local/libdatrie

安装成功后,继续安装php扩展trie-filter

$ $INSTALL_PHP_PATH/bin/phpize
$ ./configure --with-php-config=$INSTALL_PHP_PATH/bin/php-config --with-trie_filter=$LIB_PATH
$ make
$ make install

PHP示例代码

<?php
$arrWord = array('word1', 'word2', 'word3');
$resTrie = trie_filter_new(); //create an empty trie tree
foreach ($arrWord as $v) {
    trie_filter_store($resTrie, $v);
}
trie_filter_save($resTrie, __DIR__ . '/blackword.tree');

$resTrie = trie_filter_load(__DIR__ . '/blackword.tree');

$arrRet = trie_filter_search($resTrie, 'hello word2');
print_r($arrRet); //Array(0 => 6, 1 => 5)
echo substr('hello word2', $arrRet[0], $arrRet[1]); //word2

$arrRet = trie_filter_search($resTrie, 'hello word');
print_r($arrRet); //Array()

trie_filter_free($resTrie);

这还有一篇神仙兄用PHP代码实现的一个类

http://syre.blogbus.com/logs/44107784.html

2013年4月18日 | 标签:

搜索,你懂的

好吧,假如你建了一个web站点或者是一个应用程序,你就可能会需要添加搜索功能(因为这太有必要了),而事实上让搜索跑 起来是有难度的,我们不仅想要搜索的速度快,而且还要安装方便(最好是无痛安装),另外模式定义要非常自由(schema free),可以通过HTTP以JSON格式的数据来进行索引,服务器必须是一直可用的(HA高可用,这个不能丢),从一台机器能够扩展到成千上万台,然 后搜索必须是实时的(real-time),使用起来一定要简单、支持多租户,我们需要一整套的解决方案,并且是为云构建的。

“让搜索更简单”,这是我们的宣言,“并且要酷,像盆景一样”

elasticsearch 的目标是解决上面的所有问题以及更多。她是开源的(Apache2协议),分布式的,RESTful的,构建在Apache Lucene之上的的搜索引擎.

模式自由(Schema Free) & 面向文档的 (Document Oriented)

搜索引擎的数据模型属于模式自由以及数据库是面向文档的,以目前#nosql的发展趋势来看,使用这种数据模型来构建应用程序已经被证明是非常高效的。

elasticsearch 的模型基于 JSON, 事实上,在近些年,它俨然已经成为数据呈现的一个标准,此外,通过JSON,可以非常简单的表示半结构化的数据,同样的,大多数编程语言都会优先支持JSON数据的解析.

先来看几个简单的例子,都是创建索引的。(ps:curl是一个linux下的处理HTTP请求的一个工具,你可以使用fiddler或者其他类似的工具来执行elasticsearch提供的RESTful接口)。

Continue reading “elasticsearch – – Open Source, Distributed, RESTful, Search Engine , ElasticSearch 官方站点中文版(开源、分布式、RESTful的搜索引擎)” »

2013年4月16日 | 标签:

vim

2013年4月16日 | 标签:

转自: http://software.intel.com/zh-cn/blogs/2010/07/20/400004478
关于多进程和多线程,教科书上最经典的一句话是“进程是资源分配的最小单位,线程是CPU调度的最小单位”,这句话应付考试基本上够了,但如果在工作中遇到类似的选择问题,那就没有这么简单了,选的不好,会让你深受其害。
经常在网络上看到有的XDJM问“多进程好还是多线程好?”、“Linux下用多进程还是多线程?”等等期望一劳永逸的问题,我只能说:没有最好,只有更好。根据实际情况来判断,哪个更加合适就是哪个好。
我们按照多个不同的维度,来看看多线程和多进程的对比(注:因为是感性的比较,因此都是相对的,不是说一个好得不得了,另外一个差的无法忍受)。
01
看起来比较简单,优势对比上是“线程 3.5 v 2.5 进程”,我们只管选线程就是了?
呵呵,有这么简单我就不用在这里浪费口舌了,还是那句话,没有绝对的好与坏,只有哪个更加合适的问题。我们来看实际应用中究竟如何判断更加合适。
1)需要频繁创建销毁的优先用线程
原因请看上面的对比。
这种原则最常见的应用就是Web服务器了,来一个连接建立一个线程,断了就销毁线程,要是用进程,创建和销毁的代价是很难承受的
2)需要进行大量计算的优先使用线程
所谓大量计算,当然就是要耗费很多CPU,切换频繁了,这种情况下线程是最合适的。
这种原则最常见的是图像处理、算法处理。
3)强相关的处理用线程,弱相关的处理用进程
什么叫强相关、弱相关?理论上很难定义,给个简单的例子就明白了。
一般的Server需要完成如下任务:消息收发、消息处理。“消息收发”和“消息处理”就是弱相关的任务,而“消息处理”里面可能又分为“消息解码”、 “业务处理”,这两个任务相对来说相关性就要强多了。因此“消息收发”和“消息处理”可以分进程设计,“消息解码”、“业务处理”可以分线程设计。
当然这种划分方式不是一成不变的,也可以根据实际情况进行调整。
4)可能要扩展到多机分布的用进程,多核分布的用线程
原因请看上面对比。
5)都满足需求的情况下,用你最熟悉、最拿手的方式
至于“数据共享、同步”、“编程、调试”、“可靠性”这几个维度的所谓的“复杂、简单”应该怎么取舍,我只能说:没有明确的选择方法。但我可以告诉你一个选择原则:如果多进程和多线程都能够满足要求,那么选择你最熟悉、最拿手的那个。
需要提醒的是:虽然我给了这么多的选择原则,但实际应用中基本上都是“进程+线程”的结合方式,千万不要真的陷入一种非此即彼的误区。

第 1 页,共 24 页12345...1020...最旧 »