很久没自己折腾了,准备自己做个淘宝客网站,所以先整好框架和基础后台程序
这套后台是从PHPWind8.7的后台里扒下来的,非常喜欢它的风格和Tab标签形式的内容窗体
MVC框架第三版
后台的主要功能:
权限控制,同一用户可选择多个管理组,权限合并
后台菜单显示与用户的权限有关
在目录 ~/Library/LaunchAgents 下新建redis.plist文件
[codesyntax lang=”xml”]
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>Label</key> <string>com.redis</string> <key>RunAtLoad</key> <true/> <key>ProgramArguments</key> <array> <string>/usr/local/bin/redis-server</string> <string>/usr/local/etc/redis.conf</string> </array> </dict> </plist>
[/codesyntax]
launchctl load ~/Library/LaunchAgents/redis.plist
launchctl start com.redis
同理,memcached,nginx都这么随机启动
CentOS 下SSH无密码登录的配置
最近学习Hadoop。它要求各节点之间通过SSH无密码登录,配置SSH的时候费了一番功夫,记录下来,以备忘。
配置SSH无密码登录需要3步:
1.生成公钥和私钥
2.导入公钥到认证文件,更改权限
3.测试
1.生成公钥和私钥
Shell代码
ssh-keygen -t rsa
默认在 ~/.ssh目录生成两个文件:
id_rsa :私钥
id_rsa.pub :公钥
2.导入公钥到认证文件,更改权限
2.1 导入本机
Shell代码
cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys
2.2 导入要免密码登录的服务器
首先将公钥复制到服务器
Shell代码
scp ~/.ssh/id_rsa.pub xxx@host:/home/xxx/id_rsa.pub
然后,将公钥导入到认证文件,这一步的操作在服务器上进行
Shell代码
cat ~/is_rsa.pub >> ~/.ssh/authorized_keys
2.3 在服务器上更改权限
Shell代码
chmod 700 ~/.ssh
Shell代码
chmod 600 ~/.ssh/authorized_keys
3.测试
ssh host,第一次登录可能需要yes确认,之后就可以直接登录了
[codesyntax lang=”bash”]
#!/bin/sh
PRO_PATH=”/home/sh”
PROGRAM=”rediscache.sh”
while true ; do
PRO_NOW=`ps aux | grep $PROGRAM | grep -v grep | wc -l`
if [ $PRO_NOW -lt 3 ]; then
#echo “exec $PROGRAM”
$PRO_PATH/$PROGRAM 2>/dev/null 1>&2 &
fi
PRO_STAT=`ps aux|grep $PROGRAM |grep T|grep -v grep|wc -l`
if [ $PRO_STAT -gt 0 ] ; then
killall -9 $PROGRAM
./$PROGRAM 2>/dev/null 1>&2 &
fi
sleep 2
done
exit 0
[/codesyntax]
主要功能点
主动缓存,无异常情况下只从redis中取数据,不走mysql
列表的分类、排序
缓存数据中区分正在进行、未开始、已结束
分析sql语句触发redis缓存系统中数据的更新
对关联数据进行同步更新(例 广告中的数据里面有商品信息,当商品发生改变时,触发把广告中的相关商品数据内容也进行同步更新)
针对单个表的缓存数据重建功能
最近看博客统计数据,还是有很多搜索nginx 配置 PATH_INFO 和去掉中间的index.php的关键词,所以把目前自己在用的配置传一份到网上
server
{
listen 80;
server_name ye55.dev;
index index.html index.htm index.php default.html default.htm default.php;
root /home/www/ye55/trunk/www/;
if (!-f $request_filename) {
rewrite ^/(.*)$ /index.php/$1 last;
}
location ~ .*\.php(.*)$
{
fastcgi_pass unix:/tmp/php-cgi.sock;
fastcgi_index index.php;
include fcgi.conf;
fastcgi_split_path_info ^(.+\.php)(.*)$;
include fastcgi_params;
fastcgi_param PATH_INFO $fastcgi_path_info;
}
}
以前在上海的时候,做过一个用redis实现主动列表缓存的方案,但那时生产环境用的是1.0,所以那个列表缓存非常粗糙,只是满足需求而以,但运行得比较稳定,因此redis在实现上是可行的。
加上最近在看redis方面的资料,从头系统过了一遍redis,所以有了改进以前做的主动列表缓存的冲动,计划首先用在现在公司的一个新项目上,如果可行,就可以继续部署到老项目,改进性能。
要实现主动缓存,主要的问题在于以下几点
1. 怎么触发更新、删除、插入数据库时,同步更新redis里的数据
2. redis中数据的存储采用怎么的方式
3. 主动缓存中怎么排序和分类
4. redis意外停止服务的情况下,如果正常提供列表服务
5. 列表缓存应该工作在哪一层,dao ? service ?
6. redis中单个数据失效的情况下怎么剔除
7. 如果减少网络请求,尽量少的命令获取一个分布的数据
目前方案正在设想中,先写下些东西,做下记录,后面再逐步完善!
一,解决mysql数据改变时触发实时更新redis数据,并最少改动现有代码
所以想在加一层 cache 层,使用cache层可以在Controller和service二个层中相互调用。cache中的数据可以来源于dao也可以来源于service层
解决第一个问题,我的想法是,直接在sql执行时,获得sql语句分析sql , 决定是否更新redis中的数据。
二, 做要实现redis主动缓存的相关配置,配置如下
<?php return array( // db_user 表做数据缓存 'db_user' => array( // 定义分类的字段,用于生成多个id索引set 'cate' => array('group_id', 'vip'), // 设定排序所要用到的字段,数字 'sort' => array('sort', 'create_time', 'last_time', 'login_num'), 'callback' => array( 'get' => array('common::getUserService()', 'getOne'), //回调类与方法,用于更新单个数据 //用于当redis数据丢失的情况从mysql中还原数据,需要用于反射来注入数据,有待完善 'getlist' => array('common::getUserService()', 'getList'), ), ), );
主要的意义在配置中告诉程序怎么输出,如果redis失效的情况下,绕过redis缓存系统,直接按回调中的方法从mysql中输出数据。
redis怎么存储缓存数据:
1. 用一个或多个sets 存 id号索引数据。 比如配置中cate字段没有设置,就类型 listcache:db_user:ids
如果配置了cate字段 则出现一组 listcache:db_user:ids:cate:group_id:1 sets来分别存放对应的ID号
2. 另使用一个hash来存储内容,结构因sort配置而变
hset list:cache:db_user:content:id:1 sort 1
hset list:cache:db_user:content:id:1 create_time 122323123
hset list:cache:db_user:content:id:1 last_time 1223231223
hset list:cache:db_user:content:id:1 login_num 20
hset list:cache:db_user:content:id:1 data 用户数据的序列化数据
上面非data用于排序使用
最后获取列表使用 sort 命令
例 sort list:cache:ids BY list:cache:db_user:content:id:*->sort DESC LIMIT 0 10
上面命令用于获取排过序id号数据
也可以直接获取最终的data数据 sort list:cache:ids BY list:cache:db_user:content:id:*->sort GET list:cache:db_user:content:id:*->data DESC LIMIT 0 10
就写到这吧,写得比较混乱。以后再整理些图出来,比较直观!
看起来很简单,递归 + &&运算符,习惯 !$a && $a = true; 这样的语法的比较容易看明白
static public function mkdir($path) { if (!is_dir($path) && self::mkdir(dirname($path))) return mkdir($path); return true; }
更正一下,php5已可以直接mkdir($path, 0777, true);递归生成目录!
给出部分主代码
感谢HaKeem的提醒,程序发现一个bug,以前的代码会发生无法解锁的问题,放出修正后的代码
如果是redis2.2以上版本可以在lock逻辑中加上watch命令,锁定单个key
/** * 加锁 【新的加锁算法,采用redis做锁,redis失效情况下,返回 变量redisErrReturn 设定的值】 * @param string $key 唯一标识 * @param int $expire * @return */ public function lock($key, $expire = 5) { try { list($key, $lockIdKey) = $this->_getLockKey($key); //抢锁,第一个线程抢到,并把过期时间写入锁 if (Common::getQueue()->setnx($key, Common::getTime() + $expire)) return true; //没有抢到锁的线程,判断锁是否异常死锁,如果锁没有过期,返回false if (Common::getQueue()->get($key) > Common::getTime()) return false; //锁因异常死锁并过期的情况下,多个并发线程再次抢锁,getset命令到过期时间,如果未过期,表示锁已被其它线程抢得,返回false if (Common::getQueue()->getset($key, Common::getTime() + $expire) > Common::getTime()) return false; Common::getQueue()->set($lockIdKey, $this->_lockId); return true; } catch (RedisException $e) { // 当捕捉到redis异常时,锁中断,返回变量redisErrReturn $this->_lockStatus = false; return $this->redisErrReturn; } } /** * 给锁进行续期,延长锁的生效周期 * @param string $key * @param int $expire 延时锁失效的秒数 * @param int $triggerTime 触发续期倒计时间 * @return */ public function updateExpire($key, $expire = 3, $triggerTime = 2) { if (!$this->_lockStatus) return true; //当redis失效,中断锁 list($key, $lockIdKey) = $this->_getLockKey($key); $lockId = Common::getQueue()->get($lockIdKey); if ($this->_lockId === null || $lockId != $this->_lockId) return false; $time = Common::getQueue()->get($key); if ($time - $triggerTime <= Common::getTime()) return Common::getQueue()->set($key, $time + $expire); } /** * 解锁 * @param string $key * @return */ public function unlock($key) { if (!$this->_lockStatus) return true; //当redis失效,中断解锁 list($key, $lockIdKey) = $this->_getLockKey($key); $lockId = Common::getQueue()->get($lockIdKey); if ($this->_lockId === null || $lockId != $this->_lockId) return false; Common::getQueue()->del($key); Common::getQueue()->del($lockIdKey); return true; } /** * 清除死锁产生的无用key 默认清除24小时以前的无用key * @param int $cleanTime 默认24小时 */ public function cleanLockKey($cleanTime = 86400) { if ($cleanTime < 3600 || !$keys = Common::getQueue()->keys('PwLock:*')) return false; $i = 0; foreach ($keys as $value) { list($time, $lockId) = explode('|', Common::getQueue()->get($value)); if (Common::getTime() - $time > $cleanTime) { if (Common::getQueue()->del($value)) $i++; } } return $i; } private function _getLockKey($key) { return array('PwLock:' . $key, 'PwLock:' . $key . ':lockId'); }
分卷压缩一个目录:如linux
在linux目录的上层目录:
#tar cvf linux|split -b 2m (已2M大小分卷压缩)
#cat x* > linux.tar (合成分卷压缩包)
或者
#tar czvf linux.tar.gz linux/
#tar czvfp – linux.tar.gz | split -b 2m
#cat x* > linux.tar.gz