高性能共享内存 Table
由于 PHP 语言不支持多线程,因此 Swoole 使用多进程模式,在多进程模式下存在进程内存隔离,在工作进程内修改 global 全局变量和超全局变量时,在其他进程是无效的。
设置 worker_num=1 时,不存在进程隔离,可以使用全局变量保存数据
$fds = array();
$server->on('connect', function ($server, $fd){
echo "connection open: {$fd}\n";
global $fds;
$fds[] = $fd;
var_dump($fds);
});
$fds 虽然是全局变量,但只在当前的进程内有效。Swoole 服务器底层会创建多个 Worker 进程,在 var_dump($fds) 打印出来的值,只有部分连接的 fd。
对应的解决方案就是使用外部存储服务:
数据库,如:MySQL、MongoDB
缓存服务器,如:Redis、Memcache
磁盘文件,多进程并发读写时需要加锁
普通的数据库和磁盘文件操作,存在较多 IO 等待时间。因此推荐使用:
Redis 内存数据库,读写速度非常快,但是有 TCP 连接等问题,性能也不是最高的。
/dev/shm 内存文件系统,读写操作全部在内存中完成,无 IO 消耗,性能极高,但是数据不是格式化的,还有数据同步的问题。
除了上述使用存储之外,推荐使用共享内存来保存数据,Swoole\Table 一个基于共享内存和锁实现的超高性能,并发数据结构。用于解决多进程 / 多线程数据共享和同步加锁问题。Table 的内存容量不受 PHP 的 memory_limit 控制
不要使用数组方式读写 Table,一定要使用文档中提供的 API 来进行操作;
数组方式取出的 Swoole\Table\Row 对象为一次性对象,请勿依赖其进行过多操作。
优势
性能强悍,单线程每秒可读写 200 万次;
应用代码无需加锁,Table 内置行锁自旋锁,所有操作均是多线程 / 多进程安全。用户层完全不需要考虑数据同步问题;
支持多进程,Table 可以用于多进程之间共享数据;
使用行锁,而不是全局锁,仅当 2 个进程在同一 CPU 时间,并发读取同一条数据才会进行发生抢锁。
<?php
//创建内存表
$table = new Swoole\Table(1024);//设置内存大小
//内存表增加一行
$table->column('id', Swoole\Table::TYPE_INT);
$table->column('name', Swoole\Table::TYPE_STRING, 64);//字符串需要设置长度
$table->column('age', Swoole\Table::TYPE_INT);
$table->create();
$table->set('test',['id' => 1,'name' => 'xxxx','age' => 30]);
//另一种方案
$table['test2'] = [
'id' => 2,
'name' => 'zzz',
'age' => 31
];
$table->incr('test2','age',2);//增长操作
$table->decr('test','age',3);//原子自减操作。
$table->del('test2');
print_r($table->get('test'));
//获取另一种方法
print_r($table['test2']);
执行结果
Array
(
[id] => 1
[name] => xxxx
[age] => 27
)
Swoole\Table\Row Object
(
[key] => test2
[value] => Array
(
)
)
多进程之间共享数据