龚哥哥 爱生活、做自己!
PHP7革新与性能优化
发表于 2015-10-4 | 浏览(1281) | PHP
2015年的PHP技术峰会(PHPCON),鸟哥(惠新宸)的关于PHP7的新特性和性能优化的分享,一切都令人感到激动。鸟哥是国内最权威的PHP专家,他的分享有很多非常有价值的东西,我通过整理分享的PPT和收集相关资料,整理为这篇解读性质的技术文章,希望能给做PHP开发的同学一些帮助。
 
PHP已经走过了20年的历史,直到今天,PHP7都发布了RC版,据说,PHP7正式版应该会在2015年11月份左右发布。PHP7对于上一个系列的PHP5.*,可以说是一个大规模的革新,尤其是在性能方面实现跨越式的大幅提升。

PHP是一种在全球范围内被广泛使用的Web开发语言,PHP7的革新也当然会给这些Web服务带来更深刻的变化。这里引用鸟哥PPT中的一个图表(82%的Web站点有使用PHP作为开发语言):

1.png

(注:一个web站点可以会使用多种语言作为它的开发语言)
(注:本文含有不少从鸟哥PPT里的截图,图片版权归鸟哥所有)
 
我们先看看两张激动人心的性能测试结果图:
Benchmark对比(图片来自于PPT):


2.png

PHP7的性能测试结果,性能压测结果,耗时从2.991下降到1.186,大幅度下降60%。
WordPress的QPS压测(图片来自于PPT):
3.png


而在WordPress项目中,PHP7对比PHP5.6,QPS提升2.77倍。
看完令人激动的性能测试结果对比,我们就进入正题哈。PHP7的新增特性很多,不过,我们会更聚焦于那些主要的变化。
 
一、新增特性和改变
1. 标量类型和返回类型声明(Scalar Type Declarations & Scalar Type Declarations)
PHP语言一个非常重要的特点就是“弱类型”,它让PHP的程序变得非常容易编写,新手接触PHP能够快速上手,不过,它也伴随着一些争议。支持变量类型的定义,可以说是革新性质的变化,PHP开始以可选的方式支持类型定义。除此之外,还引入了一个开关指令declare(strict_type=1);,当这个指令一旦开启,将会强制当前文件下的程序遵循严格的函数传参类型和返回类型。
例如一个add函数加上类型定义,可以写成这样:
4.png


如果配合强制类型开关指令,则可以变为这样:

5.png

如果不开启strict_type,PHP将会尝试帮你转换成要求的类型,而开启之后,会改变PHP就不再做类型转换,类型不匹配就会抛出错误。对于喜欢“强类型”语言的同学来说,这是一大福音。
更为详细的介绍:
PHP7标量类型声明RFC[翻译]
 
2. 更多的Error变为可捕获的Exception
PHP7实现了一个全局的throwable接口,原来的Exception和部分Error都实现了这个接口(interface), 以接口的方式定义了异常的继承结构。于是,PHP7中更多的Error变为可捕获的Exception返回给开发者,如果不进行捕获则为Error,如果捕获就变为一个可在程序内处理的Exception。这些可被捕获的Error通常都是不会对程序造成致命伤害的Error,例如函数不存。PHP7进一步方便开发者处理,让开发者对程序的掌控能力更强。因为在默认情况下,Error会直接导致程序中断,而PHP7则提供捕获并且处理的能力,让程序继续执行下去,为程序员提供更灵活的选择。
例如,执行一个我们不确定是否存在的函数,PHP5兼容的做法是在函数被调用之前追加的判断function_exist,而PHP7则支持捕获Exception的处理方式。
如下图中的例子(截图来源于PPT内):

6.png

3. AST(Abstract Syntax Tree,抽象语法树)
AST在PHP编译过程作为一个中间件的角色,替换原来直接从解释器吐出opcode的方式,让解释器(parser)和编译器(compliler)解耦,可以减少一些Hack代码,同时,让实现更容易理解和可维护。
PHP5:
7.jpg

PHP7:

8.jpg

更多AST信息:
https://wiki.php.net/rfc/abstract_syntax_tree
 
4. Native TLS(Native Thread local storage,原生线程本地存储)
PHP在多线程模式下(例如,Web服务器Apache的woker和event模式,就是多线程),需要解决“线程安全”(TS,Thread Safe)的问题,因为线程是共享进程的内存空间的,所以每个线程本身需要通过某种方式,构建私有的空间来保存自己的私有数据,避免和其他线程相互污染。而PHP5采用的方式,就是维护一个全局大数组,为每一个线程分配一份独立的存储空间,线程通过各自拥有的key值来访问这个全局数据组。
而这个独有的key值在PHP5中需要传递给每一个需要用到全局变量的函数,PHP7认为这种传递的方式并不友好,并且存在一些问题。因而,尝试采用一个全局的线程特定变量来保存这个key值。
相关的Native TLS问题:
https://wiki.php.net/rfc/native-tls
 
5. 其他新特性
PHP7新特性和变化不少,我们这里并不全部展开来细说哈。
(1) Int64支持,统一不同平台下的整型长度,字符串和文件上传都支持大于2GB。
(2) 统一变量语法(Uniform variable syntax)。
(3) foreach表现行为一致(Consistently foreach behaviors)
(4) 新的操作符 <=>, ??
(5) Unicode字符格式支持(\u{xxxxx})
(6) 匿名类支持(Anonymous Class)
… …
 
二、跨越式的性能突破:全速前进
1. JIT与性能
Just In Time(即时编译)是一种软件优化技术,指在运行时才会去编译字节码为机器码。从直觉出发,我们都很容易认为,机器码是计算机能够直接识别和执行的,比起Zend读取opcode逐条执行效率会更高。其中,HHVM(HipHop Virtual Machine,HHVM是一个Facebook开源的PHP虚拟机)就采用JIT,让他们的PHP性能测试提升了一个数量级,放出一个令人震惊的测试结果,也让我们直观地认为JIT是一项点石成金的强大技术。
而实际上,在2013年的时候,鸟哥和Dmitry(PHP语言内核开发者之一)就曾经在PHP5.5的版本上做过一个JIT的尝试(并没有发布)。PHP5.5的原来的执行流程,是将PHP代码通过词法和语法分析,编译成opcode字节码(格式和汇编有点像),然后,Zend引擎读取这些opcode指令,逐条解析执行。
9.png

而他们在opcode环节后引入了类型推断(TypeInf),然后通过JIT生成ByteCodes,然后再执行。

10.png

于是,在benchmark(测试程序)中得到令人兴奋的结果,实现JIT后性能比PHP5.5提升了8倍。然而,当他们把这个优化放入到实际的项目WordPress(一个开源博客项目)中,却几乎看不见性能的提升,得到了一个令人费解的测试结果。
于是,他们使用Linux下的profile类型工具,对程序执行进行CPU耗时占用分析。
执行100次WordPress的CPU消耗的分布(截图来自PPT):
11.png

注解:
21%CPU时间花费在内存管理。
12%CPU时间花费在hash table操作,主要是PHP数组的增删改查。
30%CPU时间花费在内置函数,例如strlen。
25%CPU时间花费在VM(Zend引擎)。
 
经过分析之后,得到了两个结论:
(1)JIT生成的ByteCodes如果太大,会引起CPU缓存命中率下降(CPU Cache Miss)
在PHP5.5的代码里,因为并没有明显类型定义,只能靠类型推断。尽可能将可以推断出来的变量类型,定义出来,然后,结合类型推断,将非该类型的分支代码去掉,生成直接可执行的机器码。然而,类型推断不能推断出全部类型,在WordPress中,能够推断出来的类型信息只有不到30%,能够减少的分支代码有限。导致JIT以后,直接生成机器码,生成的ByteCodes太大,最终引起CPU缓存命中大幅度下降(CPU Cache Miss)。
CPU缓存命中是指,CPU在读取并执行指令的过程中,如果需要的数据在CPU一级缓存(L1)中读取不到,就不得不往下继续寻找,一直到二级缓存(L2)和三级缓存(L3),最终会尝试到内存区域里寻找所需要的指令数据,而内存和CPU缓存之间的读取耗时差距可以达到100倍级别。所以,ByteCodes如果过大,执行指令数量过多,导致多级缓存无法容纳如此之多的数据,部分指令将不得不被存放到内存区域。
12.png

CPU的各级缓存的大小也是有限的,下图是Intel i7 920的配置信息:

13.png

因此,CPU缓存命中率下降会带来严重的耗时增加,另一方面,JIT带来的性能提升,也被它所抵消掉了。
 
通过JIT,可以降低VM的开销,同时,通过指令优化,可以间接降低内存管理的开发,因为可以减少内存分配的次数。然而,对于真实的WordPress项目来说,CPU耗时只有25%在VM上,主要的问题和瓶颈实际上并不在VM上。因此,JIT的优化计划,最后没有被列入该版本的PHP7特性中。不过,它很可能会在更后面的版本中实现,这点也非常值得我们期待哈。
 
(2)JIT性能的提升效果取决于项目的实际瓶颈
JIT在benchmark中有大幅度的提升,是因为代码量比较少,最终生成的ByteCodes也比较小,同时主要的开销是在VM中。而应用在WordPress实际项目中并没有明显的性能提升,原因WordPress的代码量要比benchmark大得多,虽然JIT降低了VM的开销,但是因为ByteCodes太大而又引起CPU缓存命中下降和额外的内存开销,最终变成没有提升。
不同类型的项目会有不同的CPU开销比例,也会得到不同的结果,脱离实际项目的性能测试,并不具有很好的代表性。
 
2. Zval的改变
PHP的各种类型的变量,其实,真正存储的载体就是Zval,它特点是海纳百川,有容乃大。从本质上看,它是C语言实现的一个结构体(struct)。对于写PHP的同学,可以将它粗略理解为是一个类似array数组的东西。
PHP5的Zval,内存占据24个字节(截图来自PPT):
14.png

PHP7的Zval,内存占据16个字节(截图来自PPT):

15.png

Zval从24个字节下降到16个字节,为什么会下降呢,这里需要补一点点的C语言基础,辅助不熟悉C的同学理解。struct和union(联合体)有点不同,Struct的每一个成员变量要各自占据一块独立的内存空间,而union里的成员变量是共用一块内存空间(也就是说修改其中一个成员变量,公有空间就被修改了,其他成员变量的记录也就没有了)。因此,虽然成员变量看起来多了不少,但是实际占据的内存空间却下降了。
 
除此之外,还有被明显改变的特性,部分简单类型不再使用引用。
Zval结构图(来源于PPT中):
16.png

图中Zval的由2个64bits(1字节=8bit,bit是“位”)组成,如果变量类型是long、bealoon这些长度不超过64bit的,则直接存储到value中,就没有下面的引用了。当变量类型是array、objec、string等超过64bit的,value存储的就是一个指针,指向真实的存储结构地址。
对于简单的变量类型来说,Zval的存储变得非常简单和高效。
不需要引用的类型:NULL、Boolean、Long、Double
需要引用的类型:String、Array、Object、Resource、Reference
 
3. 内部类型zend_string
Zend_string是实际存储字符串的结构体,实际的内容会存储在val(char,字符型)中,而val是一个char数组,长度为1(方便成员变量占位)。

17.png

结构体最后一个成员变量采用char数组,而不是使用char*,这里有一个小优化技巧,可以降低CPU的cache miss。
如果使用char数组,当malloc申请上述结构体内存,是申请在同一片区域的,通常是长度是sizeof(_zend_string) + 实际char存储空间。但是,如果使用char*,那个这个位置存储的只是一个指针,真实的存储又在另外一片独立的内存区域内。
使用char[1]和char*的内存分配对比:
18.png

从逻辑实现的角度来看,两者其实也没有多大区别,效果很类似。而实际上,当这些内存块被载入到CPU的中,就显得非常不一样。前者因为是连续分配在一起的同一块内存,在CPU读取时,通常都可以一同获得(因为会在同一级缓存中)。而后者,因为是两块内存的数据,CPU读取第一块内存的时候,很可能第二块内存数据不在同一级缓存中,使CPU不得不往L2(二级缓存)以下寻找,甚至到内存区域查到想要的第二块内存数据。这里就会引起CPU Cache Miss,而两者的耗时最高可以相差100倍。
另外,在字符串复制的时候,采用引用赋值,zend_string可以避免的内存拷贝。
 
6. PHP数组的变化(HashTable和Zend Array)
在编写PHP程序过程中,使用最频繁的类型莫过于数组,PHP5的数组采用HashTable实现。如果用比较粗略的概括方式来说,它算是一个支持双向链表的HashTable,不仅支持通过数组的key来做hash映射访问元素,也能通过foreach以访问双向链表的方式遍历数组元素。
PHP5的HashTable(截图来自于PPT):
19.png

这个图看起来很复杂,各种指针跳来跳去,当我们通过key值访问一个元素内容的时候,有时需要3次的指针跳跃才能找对需要的内容。而最重要的一点,就在于这些数组元素存储,都是分散在各个不同的内存区域的。同理可得,在CPU读取的时候,因为它们就很可能不在同一级缓存中,会导致CPU不得不到下级缓存甚至内存区域查找,也就是引起CPU缓存命中下降,进而增加更多的耗时。
PHP7的Zend Array(截图来源于PPT):
20.png

新版本的数组结构,非常简洁,让人眼前一亮。最大的特点是,整块的数组元素和hash映射表全部连接在一起,被分配在同一块内存内。如果是遍历一个整型的简单类型数组,效率会非常快,因为,数组元素(Bucket)本身是连续分配在同一块内存里,并且,数组元素的zval会把整型元素存储在内部,也不再有指针外链,全部数据都存储在当前内存区域内。当然,最重要的是,它能够避免CPU Cache Miss(CPU缓存命中率下降)。
Zend Array的变化:
(1) 数组的value默认为zval。
(2) HashTable的大小从72下降到56字节,减少22%。
(3) Buckets的大小从72下降到32字节,减少50%。
(4) 数组元素的Buckets的内存空间是一同分配的。
(5) 数组元素的key(Bucket.key)指向zend_string。
(6) 数组元素的value被嵌入到Bucket中。
(7) 降低CPU Cache Miss。
 
7. 函数调用机制(Function Calling Convention)
PHP7改进了函数的调用机制,通过优化参数传递的环节,减少了一些指令,提高执行效率。
PHP5的函数调用机制(截图来自于PPT):
21.jpg

图中,在vm栈中的指令send_val和recv参数的指令是相同,PHP7通过减少这两条重复,来达到对函数调用机制的底层优化。
PHP7的函数调用机制(截图来自于PPT):
22.png

8. 通过宏定义和内联函数(inline),让编译器提前完成部分工作
C语言的宏定义会被在预处理阶段(编译阶段)执行,提前将部分工作完成,无需在程序运行时分配内存,能够实现类似函数的功能,却没有函数调用的压栈、弹栈开销,效率会比较高。内联函数也类似,在预处理阶段,将程序中的函数替换为函数体,真实运行的程序执行到这里,就不会产生函数调用的开销。
PHP7在这方面做了不少的优化,将不少需要在运行阶段要执行的工作,放到了编译阶段。例如参数类型的判断(Parameters Parsing),因为这里涉及的都是固定的字符常量,因此,可以放到到编译阶段来完成,进而提升后续的执行效率。
例如下图中处理传递参数类型的方式,从左边的写法,优化为右边宏的写法。
23.jpg

三、小结
鸟哥的PPT里放出过一组对比数据,就是WordPress在PHP5.6执行100次会产生70亿次的CPU指令执行数目,而在PHP7中只需要25亿次,减少64.2%,这是一个令人震撼的数据。
在鸟哥的整个分享中,给我最深刻的一个观点是:要注意细节,很多个细小的优化,一点点持续地积累,积少成多,最终汇聚为惊艳的成果。为山九仞,岂一日之功,我想大概也是这个道理。
毫无疑问,PHP7在性能方面实现跨越式的提升,如果能够将这些成果应用在PHP的Web系统中,也许我们只需要更少的机器,就可以支撑起更高请求量的服务。PHP7正式版的发布,令人充满无限憧憬。
 
参考&引用资料:
鸟哥(惠新宸)的分享PPT,http://www.laruence.com/
PHP官方社区,http://php.net/

PDF:PHP7-2015.pdf

阅读全文

PHP标准工厂模式
发表于 2015-9-24 | 浏览(1137) | PHP
<?php
 
//定义接口
interface database
{
    public function connect($param);  //定义接口方法
    public function query($sql);  //定义接口方法
    public function fetch($query);  //定义接口方法
}
 
//接口继承
class mysql implements database
{
    //集成上面 connect 的接口
    public function connect($param)
    {
        echo 'mysql::connect('.$param.')';
    }
     
    //集成上面 query 的接口
    public function query($sql)
    {
        echo 'mysql::query('.$sql.')';
    }
     
    //集成上面 fetch 的接口
    public function fetch($query)
    {
        echo 'mysql::fetch('.$query.')';
    }
}
 
//接口继承
class sqlserver implements database
{
    public function connect($param)
    {
        echo 'sqlserver::connect('.$param.')';
    }
     
    public function query($sql)
    {
        echo 'sqlserver::query('.$sql.')';
    }
     
    public function fetch($query)
    {
        echo 'sqlserver::fetch('.$query.')';
    }
}
 
//接口继承
class oracle implements database
{
    public function connect($param)
    {
        echo 'oracle::connect('.$param.')';
    }
     
    public function query($sql)
    {
        echo 'oracle::query('.$sql.')';
    }
     
    public function fetch($query)
    {
        echo 'oracle::fetch('.$query.')';
    }
}
 
class dbfactory
{
    private $objects = array();
    private $classes = array();
 
    public function __construct()
    {
        $this->classes = array(
                'mysql',
                'sqlserver',
                'oracle'
            );
        
        for($i=0; $i<count($this->classes); $i++)
       {
            if(in_array('database', class_implements($this->classes[$i], false)))
           {
                $this->objects[$this->classes[$i]] = new $this->classes[$i];
            } else {
                unset($this->classes[$i]);
            }
        }
    }
 
    public function query($sql, $type = 'mysql')
    {
        // empty 检测变量对象 $this->objects 是否为空
        if(empty($this->objects))
        {
            exit('No class');
        }
        //检测 $this->classes 成员属性数组对象中是否存在 $type 传递过来的值,这里 ! 号 取反,有则 执行 if 外面
        if(!in_array($type, $this->classes))
        {
            exit('NO '.$type.' 没有继承接口');  //没有这个值的时候结束当前函数操作并退出
        }
 
        //下面这句话同等: $object = new mysql();   $object->query($sql);
        $this->objects[$type]->query($sql);  //实例化 类 及调用类里面的方法
    }
}
 
$factory = new dbfactory();
$factory->query('SELECT * FROM member', 'mysql');
echo '<hr/>';
$factory->query('SELECT * FROM member', 'sqlserver');
echo '<hr/>';
$factory->query('SELECT * FROM member', 'oracle');

?>

阅读全文

Git使用教程
发表于 2015-9-17 | 浏览(1223) | 服务器

分支管理架构图

Image

基本操作

拉取分支数据
    默认master分支
        git pull

    指定分支
        git pull origin master

提交数据
    添加到暂停区
        提交当前目录下的所有文件
            git add .

        提交当前仓库所有文件
            git add *

        指定目录或文件
            git add dirname test.php hello.txt

    添加到当前分支
        git commit -m '注释'

    提交到远程仓库
        git push

撤销修改
    git checkout .   # 放弃所有修改
    git checkout test.php   # 放弃test.php文件修改
    git clean -fd   # 放弃新创建的目录或文件

    如果已经添加到暂停区了怎么撤销?两步完成(git add test.php)
        git reset HEAD test.php
        git checkout test.php

版本回退
    回退到上一个版本
        git reset --hard HEAD^

    指定版本号(如果电脑有重启,使用 git reflog)
        git log
            commit 4aa614980a3db998f3f6299f7c22e82f4e248e27
            Author: 龚福祥 <gongfuxiang@gongfuxiangdeMacBook.local>
            Date:   Thu Aug 27 21:47:26 2015 +0800

                gitignore

            commit d496317fc6e0de1697bcebd1dcd0120eaac5b578
            Author: 龚福祥 <gongfuxiang@gongfuxiangdeMacBook.local>
            Date:   Thu Aug 27 21:45:32 2015 +0800

                del temp

            commit 2663f5a91403065f83091087286d9bd7c2368afb
            Author: 龚福祥 <gongfuxiang@gongfuxiangdeMacBook.local>
            Date:   Thu Aug 27 21:31:48 2015 +0800

                dev update

        比如我们回退到 d496317fc6e0de1697bcebd1dcd0120eaac5b578 版本号不用写全,git会自动取找,前几位就行
            git reset --hard d496317fc
                HEAD is now at d496317fc dev update

回退成功后提交到远程仓库
        git push origin master

文件夹/文件管理

文件删除
    git rm test.php

删除文件夹以及文件夹下面的文件
    git rm -r dirname

文件命名
    git mv test.php new_file_name.php

提交到本地仓库
    git commit -m '文件命名'

提交到远程仓库
    git push

分支管理

创建分支
    git branch develop

切换分支
    git checkout develop
        当前分支前面标记一个*号
        * develop
              master

创建分支并且切换到新创建的分支
    git checkout -b develop

fetch只会拉取远程分支最新版本,不做merge操作
  git fetch origin test
  git checkout test

查看本地分支
    git branch

查看远程分支
    git branch -a

重命名本地分支名称
    git branch -m develop new_name

推送本地分支到远程
    git push origin develop

删除本地分支
    git branch -d develop

删除远程分支
    git push origin --delete develop
    git push origin :develop   [git v1.7.0之前]

合并某分支到当前分支
    git merge develop

标签管理

创建标签
    git tag v_0.0.1

创建历史版本标签
    查看历史提交的commit id
        git log --pretty=oneline --abbrev-commit
            97ccfa5 test
            4aa6149 gitignore
            d496317 del temp
            2663f5a dev update

    比如要对2663f5a打标签
        git tag v_0.0.1 2663f5a

查看所有标签
    git tag

提交一个标签到远程
    git push origin v_0.0.1

提交所有未提交到远程的标签
    git push origin --tags

删除本地标签
    git tag -d v_0.0.1

删除远程标签
    git push origin --delete tag v_0.0.1
    git push origin :refs/tags/v_0.0.1   [git v1.7.0之前]

获取远程标签
    git fetch origin tag v_0.0.1

暂时提交到缓存

提交修改的数据到缓存
    git stash

查看缓存数据列表
    git stash list

恢复数据并删除缓存数据
    git stash pop

恢复数据不删除缓存数据
    git stash apply

多次stash后可以使用序号恢复
    git stash apply stash@{0}

删除缓存数据
    git stash drop

git使用规范

1;开发不同功能需创建不同分支,如果涉及到多人开发,需提交到远程仓库一起在新的分支中开发。

2;合并分支前打tag标签,版本号明确。

3;提交代码注释写详细

阅读全文

CURL错误77 使用了SSL证书
发表于 2015-9-10 | 浏览(1486) | PHP

解决PHP curl https时error 77(Problem with reading the SSL CA cert (path? access rights?))

服务器环境为CentOS,php-fpm,使用curl一个https站时失败,打开curl_error,捕获错误:Problem with reading the SSL CA cert (path? access rights?)

解决方案:

1. sudo yum install ca-certificates (无论有没有,安装确认一下)

2. 重启php-fpm,这步比较重要,更改底层的东西时一定要重启一下

3. curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);  //关闭curl使用证书

阅读全文

SchoolCMS学校管理系统项目
发表于 2015-9-6 | 浏览(3748) | 开源项目

SchoolCMS 简单而强大的学校内容管理系统、建站更快速!
依托新版SchoolCMS的功能优势和命名空间的特性,官方七年磨一剑,用心打造。更高,更快,更强,建站更简单!

提供的稳健的安全策略,包括备份恢复,容错,防止恶意攻击登陆,网页防篡改等多项安全管理功能,保证系统安全,可靠,稳定的运行。

代码遵循Apache2开源协议,并且免费使用,对商业用户友好。SchoolCMS将成为学校管理系统,另一面国产开源旗舰产品。

官方应用仓库拥有大量的第三方的插件和应用模块、模板主题,众多来自开源社区的贡献,让你的网站完美无缺!


下载地址:http://schoolcms.org/

阅读全文

CentOS设置自动连接网络
发表于 2015-9-1 | 浏览(745) | 服务器

vi /etc/sysconfig/network-scripts/目录下 ifcfg-eth0文件

ONBOOT=					yes 		//自动连接网络
DEVICE=					eth0   		//由eth0来启动
BOOTPROTO=				dhcp   		//获取IP的方式是自动获取,static是固定IP,none是手动
TYPE=					Ethernet 	//网络类型

重启网络

service network restart

阅读全文

MySQL双主_单主_热备份_实时备份
发表于 2015-9-1 | 浏览(1036) | 数据库

6630381670443118394.jpg

两台服务器

主库ip:192.168.1.1
从库ip:192.168.1.2

主库配置、编辑 my.cnf  [mysqld]下添加

server-id=1
log-bin=mysql-bin
relay-log=relay-bin
relay-log-index=relay-bin-index
replicate-do-db=devil #需要备份的数据库
slave_skip_errors = 1062 #忽略错误

#解决互相数据插入自增冲突
auto_increment_offset=1
auto_increment_increment=2

保存重启mysql

从库配置、编辑 my.cnf  [mysqld]下添加

server-id=2
log-bin=mysql-bin
relay-log=relay-bin
relay-log-index=relay-bin-index
replicate-do-db=devil #需要备份的数据库
slave_skip_errors = 1062 #忽略错误

#解决自增冲突
auto_increment_offset=2
auto_increment_increment=2

保存重启mysql

主库配置、进入mysql控制台执行

mysql -uroot -proot

stop slave;

change master to master_host='192.168.1.2',master_user='root',master_password='root';

开启配置
start slave;

查看警告
Show warnings;

查看配置状态
show slave status\G

	以下两项yes表示状态配置成功,如果error有错误根据提示解决:
	Slave_IO_Running: Yes
    Slave_SQL_Running: Yes

从库配置、进入mysql控制台执行

change master to master_host='192.168.1.1',master_user='root',master_password='root';

stop slave;

start slave;

Show warnings;

show slave status\G

以下两项yes表示状态配置成功,如果error有错误根据提示解决:
	Slave_IO_Running: Yes
    Slave_SQL_Running: Yes

如果以上顺利通过,则可以进行测试了。以下是可能遇到的问题。

日志冲突解决

查看所有二进制日志
SHOW MASTER LOGS;

清空所有二进制日志
RESET MASTER;

网络连接失败

Last_IO_Errno: 1130
1;一般是防火墙开启,拒绝3306端口。或者是配置错误,如用户名或密码
2;还有可能是主库备份帐号的访问权限,进入主库mysql控制台
  use mysql;
  select * from user where user='root';
  update user set host = '%' where user ='root';
  flush privileges;

如果不使用root用户,可以创建一个备份用户

grant replication slave,replication client on *.* to '用户名'@'可执行操作的ip' identified by '密码';

阅读全文

jQuery的基本选择器使用
发表于 2015-9-1 | 浏览(757) | 前端

废话不多说,直接上代码,将所有 赋值到一个 html 文件中即可测试,// 表示注释

jquery-1.8.3.min.js 这个jQuery 下载地址,

下载地址:http://code.jquery.com/jquery-1.8.3.min.js

<!DOCTYPE html
<html>
    <head>
        <meta charset="UTF-8" />
        <title>jQuery 属性选择器</title>
        <script type="text/javascript" src="./jquery-1.8.3.min.js"></script>
        <script type="text/javascript">
            //$(document).ready(function() { 会选中全部
            $(document).ready(function() {
                //点击 button 按钮就会调用
                $('button').click(function() {
                    //$('#dd').css('color', '#F00');
                    //$('.cc').css('font-size', '38px');  //单个

                    //同时选作多个设置颜色
                    //$('#dd, .cc').css('color', '#0ff');

                    //会选择 ul 下的所有子元素,多级
                    //$('.ul span').css('color', '#F00');

                    //只会选择 ul 下的子元素,孙元素不会被选中
                    //$('.ul > span').css('color', '#F00');

                    //选作 class iia 紧的挨着的下一个元素
                    //$('.iia + li').css('color', '#F00').css('font-size', '38px');

                    //下面有两个iib 这样子的话,就会选中两个,最后一个和跟最后一个键紧挨着的一个
                    //$('.iib + li').css('color', '#F00');
                    //当选择下一个紧挨着的一个元素不存在时,则不会生效
                    //$('#iic + li').css('color', '#F00');

                    //意思class iia 下面的所有子 li 元素。逗号,则不一样的元素
                    //$('.iia ~ li,p').css('color', '#F00');

                    // 选中html标签中 属性为 id 的所有元素
                    //$('[id]').css('color', '#F00');

                    // 选中html标签中 属性为 for 的所有元素
                    //$('[for]').css('color', '#F00');

                    // 选中html标签中 属性为 asdf 的所有元素,可以应用于自定义属性
                    //$('[asdf]').css('color', '#F00');

                    //选中属性 for 等于 aaa 的所有元素
                    //$('[for="aaa"]').css('color', '#F00');

                    //选中 class 属性值为 php 的所有元素
                    //$('[class="php"]').css('color', '#F00');

                    //选中 class 不为 php 的元素。
                    //$('[class != "php"]').css('color', '#F00');

                    //选中 class 为 i 字母开头的元素
                    //$('[class ^= "i"]').css('color', '#F00');

                    //选中 class 以 b 字母结束的元素
                    //$('[class $= "b"]').css('color', '#F00');

                    //选中 class 包含 f 字母的所有元素
                    //$('[class *= "f"]').css('color', '#F00');

                    //选中 标签中必须包含 class 和 id 属性等于 iic 的元素
                    //$('[class][id = "iic"]').css('color', '#F00');

                    //选中标签中同时包含 class 属性值为 gege 和 id 属性值为 gg 的元素
                    //$('[class = "gege"][id = "gg"]').css('color', '#F00');

                    //选中 class ul,中间的空格表示下一及,后代选择器,下 class 的值为 iid 和 id 值为 bod 的元素
                    $('.ul [class = "iid"][id = "bod"]').css('color', '#F00');
                });
            });

        </script>
    </head>
    <body>
        <button>按钮 1</button>
        <button>按钮 2</button>
        <div id="dd">div dd</div>
        <div class="cc">div cc</div>
        <div class="cc">div cc2</div>

        <ul class="ul">
        <span>你是我的uuuullll</span>
            <li class="iia" id="good">苹果手机aagood 2</li>
            <li class="iib">安卓手机12bbb</li>
            <li class="iibf">软件开发2bbb</li>
            <li id="iic" class="php" asdf="fff">程序员2ccc</li>
            <p>p看看 ppp</p>
            <span>
                <li class="iid" id="bod" for="ccc">嘻嘻嘻嘻</li>
                <li id="good">哈哈哈哈哈good 2</li>
            </span>
        <li class="df">l滴滴滴滴
            <span>spspsp</span>
        </li>
        </ul>
        <label for="aaa" class="gege" id="gg">l乐乐乐乐</label>
        <li class="iid" id="bod" for="ccc">嘻嘻嘻嘻2222222</li>
    </body>
</html>

阅读全文

CentOS安装memcached服务
发表于 2015-9-1 | 浏览(605) | 服务器

1;yum安装

yum -y install memcached

2;验证是否安装成功,如果输出一些帮助信息表示安装成功

memcached -h

3;将memcache加入启动列表

chkconfig --level 2345 memcached on

4;配置Memcache

vi /etc/sysconfig/memcached
文件中内容如下
PORT=”11211″ 端口
USER=”root” 使用的用户名
MAXCONN=”1024″ 同时最大连接数
CACHESIZE=”64″ 使用的内存大小
OPTIONS=”" 附加参数

5;启动memcached

启动:service memcached start
关闭:service memcached stop
重启:service memcached restart

加入系统启动项
  echo "service memcached start" >> /etc/rc.local 

6;分配空间(11211 端口号可以自定义设置)

memcached -p 11211 -m 512 -d -u root start

7;连接memcached

telnet 121.199.44.203 11211

阅读全文

php安装memcache和memcached扩展
发表于 2015-9-1 | 浏览(923) | 服务器

安装php memcache

wget http://pecl.php.net/get/memcache-3.0.6.tgz
tar -zxvf memcache-3.0.6.tgz
cd memcache-3.0.6
/data/soft/php/bin/phpize (如果不知道phpize在什么位置,可以用find / -name phpize查找)
./configure –enable-memcache –with-php-config=/data/soft/php/bin/php-config –with-zlib-dir
make
make install

记录下安装成功后的提示,类似于:
Installing shared extensions: /data/soft/php/modules/
把这个地址记录下来

在php.ini文件里面添加扩展

vim /data/soft/php/bin/php.ini
添加 extension=memcache.so

最后验证一下是否安装完成

php -m|grep memcache
应该会显示memcache

到这里php memcach安装完成

安装php memcached扩展

1、先安装 memcached 依赖库 libmemcached

wget https://launchpad.net/libmemcached/1.0/1.0.18/+download/libmemcached-1.0.18.tar.gz
tar -zxvf libmemcached-1.0.18.tar.gz
cd libmemcached-1.0.18
./configure --prefix=/usr/local/libmemcached --with-memcached
make
make install

现在安装php memcached扩展

wget http://pecl.php.net/get/memcached-2.2.0.tgz
tar -zxvf memcached-2.2.0.tgz
cd memcached-2.2.0
/data/soft/php/bin/phpize
./configure --enable-memcached --with-php-config=/data/soft/php/bin/php-config --with-libmemcached-dir=/usr/local/libmemcached --disable-memcached-sasl

在php.ini文件里面添加扩展

vim /data/soft/php/bin/php.ini
  添加 extension=memcached.so

最后验证一下是否安装完成

php -m|grep memcached
应该会显示memcached

到这里php memcachd安装完成

阅读全文

TOP