把我的blog迁移到了一个新的服务器上了,写篇文章试试好不好使
php gd 库编译
前言
。。。
安装依赖
1 |
yum install -y libjpeg-turbo-devel |
1 |
yum install -y libpng-devel |
1 |
yum install -y freetype-devel |
安装devel的时候会自动安装相应的lib的,所以这样就行;gd支持的更多的libvpx libxpm 这些用不到,就不编译进去了
编译
1 2 |
./configure --with-php-config=/path/to/php-config --with-jpeg-dir=/usr --with-freetype-dir=/usr --with-png-dir=/usr make && make install |
完事儿会有一个gd.so
当有了gd.so后,在其他机器上就没有必要再编译了,直接copy gd.so 自然不好使,因为依赖的库文件可能没有,需要:
1 |
yum install -y libjpeg-turbo |
1 |
yum install -y libpng |
1 |
yum install -y freetype |
注意,这里是不需要devel的
gitlab配置
这里只讨论rpm方式安装的情况
默认的数据目录为: /var/opt/gitlab 有可能这里空间会比较小,可以在 /etc/gitlab/gitlab.rb 里面修改
gitlab 备份恢复与迁移
这里只介绍使用rpm包方式安装时的备份恢复与迁移
转载: http://segmentfault.com/a/1190000002439923
Gitlab 创建备份
使用Gitlab一键安装包安装Gitlab非常简单, 同样的备份恢复与迁移也非常简单. 使用一条命令即可创建完整的Gitlab备份:
1 |
gitlab-rake gitlab:backup:create |
使用以上命令会在/var/opt/gitlab/backups目录下创建一个名称类似为1393513186_gitlab_backup.tar的压缩包, 这个压缩包就是Gitlab整个的完整部分, 其中开头的1393513186是备份创建的日期.
Gitlab 修改备份文件默认目录
你也可以通过修改/etc/gitlab/gitlab.rb来修改默认存放备份文件的目录:
1 |
gitlab_rails['backup_path'] = '/mnt/backups' |
/mnt/backups修改为你想存放备份的目录即可, 修改完成之后使用gitlab-ctl reconfigure命令重载配置文件即可.
Gitlab 自动备份
也可以通过crontab使用备份命令实现自动备份:
1 2 |
sudo su - crontab -e |
加入以下, 实现每天凌晨2点进行一次自动备份:
1 |
0 2 * * * /opt/gitlab/bin/gitlab-rake gitlab:backup:create |
Gitlab 恢复
同样, Gitlab的从备份恢复也非常简单:
1 2 3 4 5 6 7 8 9 |
# 停止相关数据连接服务 gitlab-ctl stop unicorn gitlab-ctl stop sidekiq # 从1393513186编号备份中恢复 gitlab-rake gitlab:backup:restore BACKUP=1393513186 # 启动Gitlab sudo gitlab-ctl start |
Gitlab迁移
迁移如同备份与恢复的步骤一样, 只需要将老服务器/var/opt/gitlab/backups目录下的备份文件拷贝到新服务器上的/var/opt/gitlab/backups即可(如果你没修改过默认备份目录的话). 但是需要注意的是新服务器上的Gitlab的版本必须与创建备份时的Gitlab版本号相同. 比如新服务器安装的是最新的7.60版本的Gitlab, 那么迁移之前, 最好将老服务器的Gitlab 升级为7.60在进行备份.
gitlab 安装
gitlab安装 有麻烦的方法: https://gitlab.com/gitlab-org/gitlab-ce/blob/master/doc/install/installation.md
也有简单的方法: https://about.gitlab.com/downloads/#centos6
yum安装或者脚本安装实在太慢,即使走代理也很慢; 当然,可以:
1 |
nohup yum install -y gitlab-ce & |
如果不小心断网又得从来,不可取。
俺的办法是: 用百度的离线下载功能先把rpm: https://packages.gitlab.com/gitlab/gitlab-ce 下载下来,百度离线下载几分钟就能搞定,然后,再从百度下载rpm,再然后:
1 |
sudo rpm -i gitlab-ce-8.3.4-ce.0.el6.x86_64.rpm |
安装完成后有提示接下来该怎么做,我建议你接下来不要着急配自己的nginx,而是直接enable rpm中自带的nginx
配置文件基本只有一个: /etc/gitlab/gitlab.rb
修改完直接:
1 |
gitlab-ctl reconfigure |
根本不用stop start;
注意:千万不要stop的时候reconfigure,这样总是出错,start状态下直接reconfigure还挺快的
配置见下篇
大并发下的死锁
一直不觉得什么样的代码逻辑才会在小并发下没问题,而在大并发下有问题,今天终于见到了。
今天做一个压力测试,刚刚开始,程序就无法响应了;小伙伴说,重启一个服务吧,我说,还是查查为啥吧,于是发现如下问题:
环境介绍:
- 数据库连接池,限制最多100个链接
- 代码中有一个方法设置了同步(无法多个线程同时执行到该代码,锁等待)
- JAVA多线程环境
代码逻辑为:
- begin 事务
- 执行同步方法
- 同步方法中可以需要执行sql语句,需要一个空闲的数据库连接(该逻辑比较深,不太容易注意到),如果获取不到数据库连接,就等待(如果非要加一个期限的话,实际上是无限期)
- 执行其他sql查询
- 结束
当100个请求同时执行到步骤1的时候,其中一个线程抢先进入了同步方法,但是不幸的是,虽然抢先进入了同步方法,但由于数据库连接已耗尽,只好等待;但是现在其它线程拿着数据库连接却由于等待在同步方法外而无法释放数据库连接,于是,死锁出现。。。
debug过程
由于bug是在高并发下出现的,不宜单步调试,只能从出错的状态中去分析。
第一步: jstack $pid
…. (有N多线程的堆栈就出来了)
第二步: 分析堆栈
很多线程被block,推测:应该有个线程(的堆栈)和别人不太一样; 果然如此
第三步: 参照堆栈和代码,分析得到结果
解决办法:
。。。
Django 初体验
本来没准备去了解python+django,但是工作需要还是了解了一下;从执行效率上来讲,python和PHP基本是同一个级别的语言,我没指望python能有多么好的执行效率,鉴于django是python界赫赫有名的web开发框架,于是就测了一下。
2核8G的cpu下测试django的hello world,大概也就500+的qps。什么?fastcgi?是的,用fastcgi的方式也做了测试,真心没明显变化,fastcgi就真的fast吗?只是相对cgi来讲确实fast了不少,但不是神器。尤其:django的fastcgi实现用的是flup ; flup是纯python实现的,从这一点来讲,还不如PHP,赖好PHP的fastcgi还是C实现的。
django说 1.9 之后不再使用fastcgi了
关于mysql锁的学习
锁的类型: 表锁、页锁、行锁、间隙锁【读锁(共享锁)、写锁(排他锁)】、乐观锁、悲观锁(晕,其实没这么多东西)
mysql.INNODB_LOCKS 这张表记录了发生了锁争用的信息;虽然一个事务正在加了一些锁,如果没有其它session等待这些锁的话,这个表里面也是查不到的哦
但是,A表正在事务中被更新时,如果:
lock tables A write;
虽然被阻塞,但是 mysql.INNODB_LOCKS里面却查不到任何记录! (why: lock tables 不是存储引擎级别的锁)
实例分析:
表结构:
1 2 3 4 5 6 7 8 |
CREATE TABLE `credit_core` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `uid` int(10) unsigned NOT NULL, `app_id` int(10) unsigned NOT NULL, `limit` int(10) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`id`), UNIQUE KEY `uniq_uid_appid` (`uid`,`app_id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 |
sql语句1:
1 2 3 4 |
begin; select * from credit_core where uid=153 and app_id = 1 for update; insert into credit_core(uid, appid, `limit`) values(153, 1, 1000); commit; |
sql语句2:
1 2 3 4 |
begin; select * from credit_core where uid=154 and app_id = 1 for update; insert into credit_core(uid, appid, `limit`) values(154, 1, 1000); commit; |
如果简单认为innodb的锁都是行锁(尤其是select和insert操作的压根儿也不是一行),怎么可能发生死锁呢?
让我们模拟一下,分别在两个session中一行一行地交替执行两个事务,我们发现,确实在insert的时候死锁了
session 1:
1 2 3 4 5 6 7 8 9 10 11 |
mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> select * from credit_core where uid=153 and app_id = 1 for update; Empty set (0.00 sec) mysql> insert into credit_core(uid, app_id, `limit`) values(153, 1, 1000); #这里开始等待锁,第二个session执行到insert时,会发现死锁,然后取消事务并退出,然后,本sql得到锁并成功执行了 Query OK, 1 row affected (15.98 sec) mysql> |
session 2:
1 2 3 4 5 6 7 8 9 |
mysql> begin; Query OK, 0 rows affected (0.00 sec) mysql> select * from credit_core where uid=154 and app_id = 1 for update; Empty set (0.00 sec) mysql> insert into credit_core(uid, app_id, `limit`) values(154, 1, 1000); ERROR 1213 (40001): Deadlock found when trying to get lock; try restarting transaction mysql> |
如果我们不着急去执行session 2中的insert的语句,而是查询一下存在哪些锁,发现如下:
什么是supremum pseudo-record?
supremum pseudo-record :相当于比索引中所有值都大,但却不存在索引中,相当于最后一行之后的间隙锁
解决办法:
1 2 3 4 |
START TRANSACTION; insert into ... on duplicate key update `val`='XX'; commit; |
参看: http://blog.itpub.net/26250550/viewspace-1070422/
问题: 两个select … for update ; 加的是共享锁?否则不能同时两个select语句都能成功执行。还如何查证?
不能简单地说 select … for update 加的是共享锁还是排他锁; 如果select有结果,则加行锁,此时为排他锁; 如果没有结果,则加间隙锁,此时为共享锁(和间隙大小没有关系); 如果没有在事务中,则select for update是不加锁的;
参看: Enabling InnoDB Monitors: https://dev.mysql.com/doc/refman/5.6/en/innodb-enabling-monitors.html
1 |
set GLOBAL innodb_status_output_locks=ON; |
可以查看当前被设置的锁的信息:
1 |
SHOW ENGINE INNODB STATUS\G |
部分信息如下:
1 2 3 4 5 6 7 |
---TRANSACTION 39527, ACTIVE 3 sec 2 lock struct(s), heap size 360, 1 row lock(s) MySQL thread id 37, OS thread handle 0x7f5fb0733700, query id 458 localhost root cleaning up TABLE LOCK table `test`.`credit_core` trx id 39527 lock mode IX RECORD LOCKS space id 132 page no 4 n bits 72 index `uniq_uid_appid` of table `test`.`credit_core` trx id 39527 lock_mode X Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0 0: len 8; hex 73757072656d756d; asc supremum;; |
下面是insert 语句等待时的锁情况:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
mysql> select * from INNODB_LOCKS\G *************************** 1. row *************************** lock_id: 39515:132:4:1 lock_trx_id: 39515 lock_mode: X lock_type: RECORD lock_table: `test`.`credit_core` lock_index: uniq_uid_appid lock_space: 132 lock_page: 4 lock_rec: 1 lock_data: supremum pseudo-record *************************** 2. row *************************** lock_id: 39514:132:4:1 lock_trx_id: 39514 lock_mode: X lock_type: RECORD lock_table: `test`.`credit_core` lock_index: uniq_uid_appid lock_space: 132 lock_page: 4 lock_rec: 1 lock_data: supremum pseudo-record 2 rows in set (0.00 sec) mysql> select * from INNODB_TRX\G *************************** 1. row *************************** trx_id: 39515 trx_state: LOCK WAIT trx_started: 2015-12-25 15:15:50 trx_requested_lock_id: 39515:132:4:1 trx_wait_started: 2015-12-25 15:25:24 trx_weight: 4 trx_mysql_thread_id: 35 trx_query: insert into credit_core(uid, app_id, `limit`) values(153, 1, 1000) trx_operation_state: inserting trx_tables_in_use: 1 trx_tables_locked: 1 trx_lock_structs: 3 trx_lock_memory_bytes: 360 trx_rows_locked: 2 trx_rows_modified: 1 trx_concurrency_tickets: 0 trx_isolation_level: REPEATABLE READ trx_unique_checks: 1 trx_foreign_key_checks: 1 trx_last_foreign_key_error: NULL trx_adaptive_hash_latched: 0 trx_adaptive_hash_timeout: 10000 trx_is_read_only: 0 trx_autocommit_non_locking: 0 *************************** 2. row *************************** trx_id: 39514 trx_state: RUNNING trx_started: 2015-12-25 15:15:40 trx_requested_lock_id: NULL trx_wait_started: NULL trx_weight: 2 trx_mysql_thread_id: 37 trx_query: NULL trx_operation_state: NULL trx_tables_in_use: 0 trx_tables_locked: 0 trx_lock_structs: 2 trx_lock_memory_bytes: 360 trx_rows_locked: 1 trx_rows_modified: 0 trx_concurrency_tickets: 0 trx_isolation_level: REPEATABLE READ trx_unique_checks: 1 trx_foreign_key_checks: 1 trx_last_foreign_key_error: NULL trx_adaptive_hash_latched: 0 trx_adaptive_hash_timeout: 10000 trx_is_read_only: 0 trx_autocommit_non_locking: 0 2 rows in set (0.00 sec) |
学习资料:
关于FTP的主动模式和被动模式
对于主动模式: client 告知server自己的IP:port ,然后server端通过20端口发起数据链路的连接请求。
对于被动模式: server端告知client自己的IP:port, 然后client发起数据链路的连接请求。
参考资料:
nginx 配置之read_timeout
nginx配置文件中有各种timeout,比如:fastcgi_read_timeout ;如果没有一些经验,很可能会认为该配置会限制fastcgi请求的时常,其实不然,不过,很多情况下确实是这样的。
比如,我们将fastcgi_read_timeout 设置为5s,并非fastcgi最大允许执行5s,而是:
当nginx发送完请求,开始从fastcgi读取数据时,当然,这时候fpm一般还没能立即处理完,没法立即返回响应数据,则nginx读不到数据,则开始计时,如果fpm能在5s内响应点儿数据(即使不全也没关系),则nginx就可以读取到该数据,继续尝试读取时,发现又需要等待,则重新开始5s的计时,如果fpm总是能保证5s内响应一部分数据,则nginx愿意一直候着,一旦超过5s读不到数据,nginx就不干了
PHP测试代码:
1 2 3 4 |
<?php while(1){ echo 1;ob_flush();flush();sleep(2); } |
欧了