使用GDB调试PHP core dump

2016-03-30 12:20:27 查看评论 2513 人阅读    

最近线上服务器出现了访问不上的情况,查看php-fpm发现大量的WARNING: [pool www] child 11274 exited on signal 31 (SIGSYS) after 0.089068 seconds from start错误,然后php-fpm进程在不断的重启。

查看PHP的错误日记并没有太多可用信息,既然如此那就尝试抓取core dump使用gdb调试看下吧。


关于core dump

我们经常听到大家说到程序core掉了,需要定位解决,这里说的大部分是指对应程序由于各种异常或者bug导致在运行过程中异常退出或者中止,并且在满足一定条件下(这里为什么说需要满足一定的条件呢?下面会分析)会产生一个叫做core的文件。

        通常情况下,core文件会包含了程序运行时的内存,寄存器状态,堆栈指针,内存管理信息还有各种函数调用堆栈信息等,我们可以理解为是程序工作当前状态存储生成第一个文件,许多的程序出错的时候都会产生一个core文件,通过工具分析这个文件,我们可以定位到程序异常退出的时候对应的堆栈调用等信息,找出问题所在并进行及时解决。


core dump默认是不生成的文件,所以首先我们要开启下。

分类: PHP 标签: php core dump gdb

关于订单号的生成

2015-08-14 13:03:02 查看评论 1816 人阅读    

最近面试某公司的时候被问到这个,一开始想法是以流水叠加的方式,借助redis的incr生成一个流水订单号,可以增加前缀。如:2015081400001,后面五位数进行递增。


面试官:如果不想让别人根据订单号来统计流水呢。

这时候第一想法是每日定时生成一批订单,然后存放在redis/mysql,使用的时候进行获取即可。但是仍然无法解决随机获取的问题,随机key的话又要考虑互斥问题。所以想到使用incr的进行random 1-5之间的递增。然后以index去获取order id。


面试官:如果要保证这批订单号都能使用上呢。

对于最后的这个问题当时并没有答得出来。

之后问了下面试官,答题是跟我的思路类似,也是使用incr做index,当时没有想明白。因为按照好我的方式话保证不了随机获取,而且所有的订单号都能获取到。

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

晚上回来之后突然想到,其实思路没问题的,只是纠结在存在redis/mysql是顺序生成的订单号,所以获取的时候也只能顺序获取。mysql倒是有rand()函数,但是性能不好,而且会导致索引失效。 但其实可以生成订单号的时候程序可以进行打乱这批订单号再存储!这样就可以解决这个问题了。

直接上代码

<?php
// 每日生成的最大订单流水号, 可以根据实际应用进行调整
define('NUM', 1000);

// 链接redis
$redis = new Redis();
$redis->connect('127.0.0.1', 6379);

$order = null;
$pre = date('Ymd');

// 生成订单流水数组
$arr = range(0, NUM);

// 数组乱序
shuffle($arr);

$redis->delete('order');

// 插入订单号进入redis
foreach ($arr as $i) {
    $order = $pre . str_pad($i, 5, 0, STR_PAD_LEFT);
    $redis->rPush('order', $order);
}


// 获取订单号
$orders = [];
for($i = 0; $i < 10000; $i++) {
    $orders[] = $redis->lPop('order');
}
var_dump($orders);



分类: 随笔 标签: 订单号生成

[转] 分布式Redis架构设计和踩过的那些坑们

2015-07-12 08:12:13 查看评论 2137 人阅读    

此文根据【QCON高可用架构群】分享内容,由群内【编辑组】志愿整理,转发请注明出处。

      黄东旭,Ping CAP CTO,开源项目Codis的co-author。之前在豌豆荚从事infrastructure相关的工作,现在在创业公司PingCAP,方向依然是分布式存储领域(NewSQL)。


本次分享的内容主要包括五个大部分:

  • Redis、RedisCluster和Codis;

  • 我们更爱一致性;

  • Codis在生产环境中的使用的经验和坑们;

  • 对于分布式数据库和分布式架构的一些看法;

  • Q & A环节。

  Codis是一个分布式Redis解决方案,与官方的纯P2P的模式不同,Codis采用的是Proxy-based的方案。今天我们介绍一下Codis及下一个大版本RebornDB的设计,同时会介绍一些Codis在实际应用场景中的tips。最后抛砖引玉,会介绍一下我对分布式存储的一些观点和看法,望各位首席们雅正。

一、 Redis,RedisCluster和Codis


  Redis:想必大家的架构中,Redis已经是一个必不可少的部件,丰富的数据结构和超高的性能以及简单的协议,让Redis能够很好的作为数据库的上游缓存层。但是我们会比较担心Redis的单点问题,单点Redis容量大小总受限于内存,在业务对性能要求比较高的情况下,理想情况下我们希望所有的数据都能在内存里面,不要打到数据库上,所以很自然的就会寻求其他方案。 比如,SSD将内存换成了磁盘,以换取更大的容量。更自然的想法是将Redis变成一个可以水平扩展的分布式缓存服务,在Codis之前,业界只有Twemproxy,但是Twemproxy本身是一个静态的分布式Redis方案,进行扩容/缩容时候对运维要求非常高,而且很难做到平滑的扩缩容。Codis的目标其实就是尽量兼容Twemproxy的基础上,加上数据迁移的功能以实现扩容和缩容,最终替换Twemproxy。从豌豆荚最后上线的结果来看,最后完全替换了Twem,大概2T左右的内存集群。

  Redis Cluster  :与Codis同期发布正式版的官方cluster,我认为有优点也有缺点,作为架构师,我并不会在生产环境中使用,原因有两个:

  • cluster的数据存储模块和分布式的逻辑模块是耦合在一起的,这个带来的好处是部署异常简单,all-in-the-box,没有像Codis那么多概念,组件和依赖。但是带来的缺点是,你很难对业务进行无痛的升级。比如哪天Redis cluster的分布式逻辑出现了比较严重的bug,你该如何升级?除了滚动重启整个集群,没什么好办法。这个比较伤运维。

  • 对协议进行了较大的修改,对客户端不太友好,目前很多客户端已经成为事实标准,而且很多程序已经写好了,让业务方去更换Redisclient,是不太现实的,而且目前很难说有哪个Rediscluster客户端经过了大规模生产环境的验证,从HunanTV开源的Rediscluster proxy上可以看得出这个影响还是蛮大的,否则就会支持使用cluster的client了。

  Codis:和Redis cluster不同的是,Codis采用一层无状态的proxy层,将分布式逻辑写在proxy上,底层的存储引擎还是Redis本身(尽管基于Redis2.8.13上做了一些小patch),数据的分布状态存储于zookeeper(etcd)中,底层的数据存储变成了可插拔的部件。这个事情的好处其实不用多说,就是各个部件是可以动态水平扩展的,尤其无状态的proxy对于动态的负载均衡,还是意义很大的,而且还可以做一些有意思的事情,比如发现一些slot的数据比较冷,可以专门用一个支持持久化存储的server group来负责这部分slot,以节省内存,当这部分数据变热起来时,可以再动态的迁移到内存的server group上,一切对业务透明。比较有意思的是,在Twitter内部弃用Twmeproxy后,t家自己开发了一个新的分布式Redis解决方案,仍然走的是proxy-based路线。不过没有开源出来。可插拔存储引擎这个事情也是Codis的下一代产品RebornDB在做的一件事情。btw,RebornDB和它的持久化引擎都是完全开源的,见https://github.com/reborndb/reborn和https://github.com/reborndb/qdb。当然这样的设计的坏处是,经过了proxy,多了一次网络交互,看上去性能下降了一些,但是记住,我们的proxy是可以动态扩展的,整个服务的QPS并不由单个proxy的性能决定(所以生产环境中我建议使用LVS/HA Proxy或者Jodis),每个proxy其实都是一样的。

640.png


分类: Nosql 标签: codis redis 分布式

[转] MySQL索引原理及慢查询优化

2015-05-20 08:50:37 查看评论 965 人阅读    

MySQL凭借着出色的性能、低廉的成本、丰富的资源,已经成为绝大多数互联网公司的首选关系型数据库。虽然性能出色,但所谓“好马配好鞍”,如何能够更好的使用它,已经成为开发工程师的必修课,我们经常会从职位描述上看到诸如“精通MySQL”、“SQL语句优化”、“了解数据库原理”等要求。我们知道一般的应用系统,读写比例在10:1左右,而且插入操作和一般的更新操作很少出现性能问题,遇到最多的,也是最容易出问题的,还是一些复杂的查询操作,所以查询语句的优化显然是重中之重。
本人从13年7月份起,一直在美团核心业务系统部做慢查询的优化工作,共计十余个系统,累计解决和积累了上百个慢查询案例。随着业务的复杂性提升,遇到的问题千奇百怪,五花八门,匪夷所思。本文旨在以开发工程师的角度来解释数据库索引的原理和如何优化慢查询。

一个慢查询引发的思考

select
   count(*) 
from
   task 
where
   status=2 
   and operator_id=20839 
   and operate_time>1371169729 
   and operate_time<1371174603 
   and type=2;

系统使用者反应有一个功能越来越慢,于是工程师找到了上面的SQL。
并且兴致冲冲的找到了我,“这个SQL需要优化,给我把每个字段都加上索引”
我很惊讶,问道“为什么需要每个字段都加上索引?”
“把查询的字段都加上索引会更快”工程师信心满满
“这种情况完全可以建一个联合索引,因为是最左前缀匹配,所以operate_time需要放到最后,而且还需要把其他相关的查询都拿来,需要做一个综合评估。”
“联合索引?最左前缀匹配?综合评估?”工程师不禁陷入了沉思。
多数情况下,我们知道索引能够提高查询效率,但应该如何建立索引?索引的顺序如何?许多人却只知道大概。其实理解这些概念并不难,而且索引的原理远没有想象的那么复杂。

分类: MySQL 标签: mysql 索引 优化 慢查询

[转] VRRP协议介绍

2015-04-03 11:51:58 查看评论 1010 人阅读    

1. 前言


VRRP(Virtual Router Redundancy Protocol)协议是用于实现路由器冗余的协议,最新协议在RFC3768中定义,原来的定义RFC2338被废除,新协议相对还简化了一些功能。


2. 协议说明

2.1 协议

VRRP协议是为消除在静态缺省路由环境下的缺省路由器单点故障引起的网络失效而设计的主备模式的协议,使得在发生故障而进行设备功能切换时可以不影响内外数据通信,不需要再修改内部网络的网络参数。VRRP协议需要具有IP地址备份,优先路由选择,减少不必要的路由器间通信等功能。

VRRP协议将两台或多台路由器设备虚拟成一个设备,对外提供虚拟路由器IP(一个或多个),而在路由器组内部,如果实际拥有这个对外IP的路由器如果工作正常的话就是MASTER,或者是通过算法选举产生,MASTER实现针对虚拟路由器IP的各种网络功能,如ARP请求,ICMP,以及数据的转发等;其他设备不拥有该IP,状态是BACKUP,除了接收MASTER的VRRP状态通告信息外,不执行对外的网络功能。当主机失效时,BACKUP将接管原先MASTER的网络功能。

配置VRRP协议时需要配置每个路由器的虚拟路由器ID(VRID)和优先权值,使用VRID将路由器进行分组,具有相同VRID值的路由器为同一个组,VRID是一个0~255的正整数;同一组中的路由器通过使用优先权值来选举MASTER,优先权大者为MASTER,优先权也是一个0~255的正整数。

VRRP协议使用多播数据来传输VRRP数据,VRRP数据使用特殊的虚拟源MAC地址发送数据而不是自身网卡的MAC地址,VRRP运行时只有MASTER路由器定时发送VRRP通告信息,表示MASTER工作正常以及虚拟路由器IP(组),BACKUP只接收VRRP数据,不发送数据,如果一定时间内没有接收到MASTER的通告信息,各BACKUP将宣告自己成为MASTER,发送通告信息,重新进行MASTER选举状态。

2.2 MASTER选举
如果对外的虚拟路由器IP就是路由器本身配置的IP地址的话,该路由器始终都是MASTER;
否则如果不具备虚拟IP的话,将进行MASTER选举,各路由器都宣告自己是MASTER,发送VRRP通告信息;
如果收到其他机器的发来的通告信息的优先级比自己高,将转回BACKUP状态;
如果优先级相等的话,将比较路由器的实际IP,IP值较大的优先权高;
不过如果对外的虚拟路由器IP就是路由器本身的IP的话,该路由器始终将是MASTER,这时的优先级值为255。

2.3 协议状态机
VRRP协议状态比较简单,就三种状态,初始化,主机,备份机。

blob.png

分类: Linux 标签: vrrp

[转]Go 程序的性能调试问题

2015-03-30 06:10:13 查看评论 2701 人阅读    

假设你手上有个Go语言编写的程序,你打算提升它的性能。目前有一些工具可以为此提供帮助。这些工具能帮你发现包括CPU、IO和内存在内多种类型的热点。所谓热点,是指那些为了能显著提升性能而值得你去关注的地方。有时候这些工具还能帮助你发现程序中主要的性能瑕疵。举个例子,你没必要每次执行SQL查询前都对SQL语句进行参数化解析,你可以将这个准备过程在程序启动时一次完成。再举个例子,当前某个算法的复杂度是O(N²),但其实存在一个复杂度是O(N)的解决方案。为了能发现这些问题,需要理智地检查你在优化分析器中获取到的信息。比如上面提到的第一个问题,你会注意到相当长的时间被花费在了对SQL语句的准备上。

了解针对性能的不同边界因素也是比较重要的。比方说,如果一个程序使用100 Mbps带宽的网络进行通信,而目前已经占用了超过90 Mbps的带宽,为了提升它的性能,你拿这样的程序也没啥办法了。在磁盘IO、内存消耗和计算密集型任务方面,也有类似的边界因素。

将这点牢记在心,让我们看看有哪些工具可以用。

注意:这些工具会彼此互相影响。例如,对内存使用优化分析器会导致针对CPU的优化分析器产生误差,对goroutine阻塞使用优化分析器会影响调度器跟踪等等。为了获得更加精确的信息,请在隔离的环境中使用这些工具。

注意:本文描述的用法基于Go语言发布的1.3版。


CPU 分析器

Go 运行时包含了内建的CPU分析器,它用来展示某个函数耗费了多少CPU百分时间。这里有三种方式来使用它:

1. 最简单的是用"go test"的-cpuprofile选项。例如下面的命令:

$ go test -run=none -bench=ClientServerParallel4 -cpuprofile=cprof net/http

将会分析所给的基准并将结果写入"cprof"文件中。

然后:

$ go tool pprof --text http.test cprof

将会打印耗费最多CPU时间的函数列表。

这里有几种可用的输出形式,最实用的有 --text, --web 和 --list。运行 "go tool pprof" 来得到完整的列表。

这个选项最明显的缺点是它只能用来做测试。

2. net/http/pprof 包。这是网络服务器的理想解决方案。你可能仅仅需要导入net/http/pprof,然后使用下面的方法收集分析结果:

$ go tool pprof --text mybin http://myserver:6060:/debug/pprof/profile

3. 手动收集. 你需要导入 runtime/pprof 然后再main函数中添加下面的代码:

1   if *flagCpuprofile != "" {
2       f, err := os.Create(*flagCpuprofile)
3       if err != nil {
4           log.Fatal(err)
5       }
6       pprof.StartCPUProfile(f)
7       defer pprof.StopCPUProfile()
8   }

分析结果会被写入指定的文件中,像第一种方式一样使之可视化。

这里有一个使用 --web 选项来实现可视化的例子:

cpu profile


[转]DBA专家门诊一期:索引与sql优化问题汇总

2015-01-06 15:52:00 查看评论 1409 人阅读    

              这是从阿里云论坛上转载的一篇文章,是阿里大牛在论坛上解答问题的帖子汇总。


              非常感谢大家踊跃参加DBA专家门诊一期:索引与sql优化,很多云友都提出了己的问题,门诊主任医师玄惭对大家提的问题一一作了解答。现已整理好这些问题,分享在此,欢迎来拿,绝对干货! 篇幅较长,耐心细看! 
我们将赠送每位提问者每人一本凌云杂志第四期,请各位以论坛短消息形式将姓名、电话、地址发送给管理员xiaofanqie。
 
  
啊里新人(Q1):索引我一般都是只有主键,这玩意儿,是不是越少越好? 
玄惭(A1):在日常的业务开发中,常见使用到索引的地方大概有两类:  
第一类.做业务约束需求,比如需要保证表中每行的单个字段或者某几个组合字段是唯一的,则可以在表中创建唯一索引;  
比如:需要保证test表中插入user_id字段的值不能出现重复,则在设计表的时候,就可以在表中user_id字段上创建一个唯一索引:  
CREATE TABLE `test` (  
  `id` int(11) NOT NULL AUTO_INCREMENT,  
  `user_id` int(11) NOT NULL,  
  `gmt_create` datetime DEFAULT NULL,  
  PRIMARY KEY (`id`),  
  UNIQUE KEY `uk_userid` (`user_id`)  
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;  
 

分类: MySQL 标签: mysql 优化 索引

centos6 下安装nginx1.7.9+php5.6.4+mysql

2015-01-06 08:55:39 查看评论 5466 人阅读    

        该文章是由于我在docker安装LNMP环境时出现的,原型是张宴大哥这篇文章:http://zyan.cc/nginx_php_v7/,只是做了一些软件升级变更。


1. 安装关联库

# mkdir -p /data/tgz
# cd /data/tgz
# yum install wget
# yum install pcre
# yum install openssl*
# yum install tar
# yum -y install gcc gcc-c++ autoconf libjpeg libjpeg-devel libpng libpng-devel freetype freetype-devel libxml2 libxml2-devel zlib zlib-devel glibc glibc-devel glib2 glib2-devel bzip2 bzip2-devel ncurses ncurses-devel curl curl-devel e2fsprogs e2fsprogs-devel krb5 krb5-devel libidn libidn-devel openssl openssl-devel openldap openldap-devel nss_ldap openldap-clients openldap-servers make gd gd2 gd-devel gd2-devel

# ulimit -SHn 65535
# wget ftp://ftp.csx.cam.ac.uk/pub/software/programming/pcre/pcre-8.36.tar.gz
# tar zxvf pcre-8.36.tar.gz
# cd pcre-8.36
# ./configure --prefix=/data/apps/pcre
# make && make install
# cd ../


分类: Linux 标签: lnmp

[转]通过telnet连接查看memcache服务器

2015-01-06 05:50:16 查看评论 883 人阅读    

memcache作为一款优秀的进程外缓存,常常被运用于高并发系统架构中。这里主要谈谈怎么通过telnet工具,查看memcache运行状况并对其key进行管理维护。假设memcache安装目录:/usr/local/memcached

          
1、启动memcache

# /usr/local/memcached/bin/memcached -d -m 512  -u root -l 192.168.119.70 -p 12000 -c 512 -P /usr/local/memcached/memcached.pid

启动参数详解
 -d:以守护进程方式启动。如果该参数没有指定,当按ctrl+c命令结束,memcache自动关闭
 -m:分配给memcache使用的最大内存数 单位是m,默认是64m
 -u: 指定运行memcache的用户
 -l: 指定监听的ip地址
 -p: 指定监听的tcp端口号,可以通过-u指定udp端口.默认是11211
 -c: 最大并发连接数
 -P: 报错进程id的文件
 memcache 启动之后,我们就可以通过telnet连接memcache,对其进行简单操作管理。


2、telnet连接memcache

# telnet 192.168.119.70 12000

blob.png


分类: Nosql 标签: memcache telnet

Docker创建centos的LNMP镜像

2014-12-28 17:54:23 查看评论 15664 人阅读    

        前段时间重装了系统,今天刚好有时间,就用docker安装一个lnmp开发环境,下面是我的安装笔记。


 1. 安装docker

        这个就不说了,不会的可以看下我之前的文章《Docker介绍及安装》。


    1)启动docker

# service docker start


分类: Linux 标签: docker 镜像 lnmp