一些总结

为什么要做持续集成 

在敏捷领域中,测试驱动和持续集成被称为敏捷编程的两大基石

对于一个微型程序来说,阶段式的集成或许是最佳方法

易于定位错误。也就是当你的持续集成失败了,说明你新加的代码或者修改的代码引起了错误,这样你很容易的就可以知道到底是谁犯了错误,可以找谁来讨论。
及早在项目里取得系统级的成果。因为代码已经被集成起来了,所以即使整个系统还不是那么可用,但至少你和你的团队都已经可以看到它已经在那了。
改善对进度的控制。这点非常明显,如果每天都在集成,当然每天都可以看到哪些功能可以使用,哪些功能还没有实现。如果你是程序员,你不用在汇报任务的时候说我完成了多少百分比而烦恼,而如果你是项目经理的话,那么你也不再烦恼程序员说完成了编码的50%到底是个什么概念。
改善客户关系。理由同上。
更加充分地测试系统中的各个单元。这也是我们常讲的Daily Build与Smoke Test相结合带来的绝大好处。
能在更短的时间里建造整个系统。这点恐怕要你实施以后才能得出结论。就我们而言,持续集成并没有为每个项目都缩短时间,但却比没有实施时,项目更加可控,也更加有保证。

便于开发流程的管理。比如说,要把一个开发的build提交给测试组作测试,测完满意了,再提交到发布组去发布。

保持随时部署,简化发布流程

有了这些以后,开发工作开始了,我们每天的代码在下班前都提交到subversion里去,第二天,Development Configuration就自动的编译完成了,并且发送通知给我们。我们通常会会开一个Morning Meeting,首先我们会到在QuickBuild的页面上,看到昨天有哪些个改动,测试的状况,比如说哪些测试修正了,哪些测试还没有被修正,哪些source code没有通过代码检查。然后我们会点到具体的报告中去分析,这些报告都可以很容易的打开source code,我们可以直接在上面对各个改动做code review。通常这个工程耗时约30分钟结束。

心跳包机制

   跳包之所以叫心跳包是因为:它像心跳一样每隔固定时间发一次,以此来告诉服务器,这个客户端还活着。事实上这是为了保持长连接,至于这个包的内容,是没有什么特别规定的,不过一般都是很小的包,或者只包含包头的一个空包。

    在TCP的机制里面,本身是存在有心跳包的机制的,也就是TCP的选项:SO_KEEPALIVE。系统默认是设置的2小时的心跳频率。但是它检查不到机器断电、网线拔出、防火墙这些断线。而且逻辑层处理断线可能也不是那么好处理。一般,如果只是用于保活还是可以的。

    心跳包一般来说都是在逻辑层发送空的echo包来实现的。下一个定时器,在一定时间间隔下发送一个空包给客户端,然后客户端反馈一个同样的空包回来,服务器如果在一定时间内收不到客户端发送过来的反馈包,那就只有认定说掉线了。

    其实,要判定掉线,只需要send或者recv一下,如果结果为零,则为掉线。但是,在长连接下,有可能很长一段时间都没有数据往来。理论上说,这个连接是一直保持连接的,但是实际情况中,如果中间节点出现什么故障是难以知道的。更要命的是,有的节点(防火墙)会自动把一定时间之内没有数据交互的连接给断掉。在这个时候,就需要我们的心跳包了,用于维持长连接,保活。

    在获知了断线之后,服务器逻辑可能需要做一些事情,比如断线后的数据清理呀,重新连接呀……当然,这个自然是要由逻辑层根据需求去做了。

    总的来说,心跳包主要也就是用于长连接的保活和断线处理。一般的应用下,判定时间在30-40秒比较不错。如果实在要求高,那就在6-9秒。

心跳检测步骤:

1 客户端每隔一个时间间隔发生一个探测包给服务器

2 客户端发包时启动一个超时定时器

3 服务器端接收到检测包,应该回应一个包

4 如果客户机收到服务器的应答包,则说明服务器正常,删除超时定时器

5 如果客户端的超时定时器超时,依然没有收到应答包,则说明服务器挂了

CGI和CLI的区别

CGI :“公共网关接口”(Common Gateway Interface),HTTP服务器与你的或其它机器上的程序进行“交谈”的一种工具,其程序须运行在网络服务器上。在服务器环境中,为“程序 ”提供标准的接口,通过这个接口,“程序 ”可以对服务器与客户端交换的信息做一些事情 。以CGI方式运行时,web server将用户请求以消息的方式转交给PHP独立进程,PHP与web服务之间无从属关系。纯粹调用--返回结果的形式通讯。而模块方式,则是将PHP做为web-server的子进程控制,两者之间有从属关系。最明显的例子就是在CGI模式下,如果修改了PHP.INI的配置文件,不用重启web服务便可生效,而模块模式下则需要重启web服务。

CLI :“ 命令行界面”(Command Line Interface),可在用户提示符下键入可执行指令的界面。CLI则是命令行接口,用于在操作系统命令行模式下执行PHP,比如可以直接在win的cmd或linux的shell模式下直接输入 php a.php 来得到结果。它与CGI模式最大的不同的地方在于既不会输出HTTP头信息(CGI模式除了输出用户能看到的结果外,还会输出用户不能直接看到的HTTP 头信息),抛出的信息也直接以文本方式而不以HTML方式给出,比如新建一个 test.php,写入内容 <?php phpinfo();?> ,在浏览器中可以看到以HTML表格描述的信息,而在命令行输入 php test.php 则会直接看到纯文本的输出。

php-fpm的管理对象是php-cgi。但不能说php-fpm是fastcgi进程的管理器,因为前面说了fastcgi是个协议,似乎没有这么个进程存在,就算存在php-fpm也管理不了他

(fastcgi是一个想法,php-fpm实现了这个想法)

Mysql引擎

InnoDB表的行锁也不是绝对的,假如在执行一个SQL语句时MySQL不能确定要扫描的范围,InnoDB表同样会锁全表,例如update table set num=1 where name like “%aaa%”

  两种类型最主要的差别就是Innodb 支持事务处理与外键和行级锁。而MyISAM不支持.所以MyISAM往往就容易被人认为只适合在小项目中使用。

  作为使用MySQL的用户角度出发,Innodb和MyISAM都是比较喜欢的,如果数据库平台要达到需求:99.9%的稳定性,方便的扩展性和高可用性来说的话,MyISAM绝对是首选。

原因如下:

  1、平台上承载的大部分项目是读多写少的项目,而MyISAM的读性能是比Innodb强不少的。

  2、MyISAM的索引和数据是分开的,并且索引是有压缩的,内存使用率就对应提高了不少。能加载更多索引,而Innodb是索引和数据是紧密捆绑的,没有使用压缩从而会造成Innodb比MyISAM体积庞大不小。

  3、经常隔1,2个月就会发生应用开发人员不小心update一个表where写的范围不对,导致这个表没法正常用了,这个时候MyISAM的优越性就体现出来了,随便从当天拷贝的压缩包取出对应表的文件,随便放到一个数据库目录下,然后dump成sql再导回到主库,并把对应的binlog补上。如果是Innodb,恐怕不可能有这么快速度,别和我说让Innodb定期用导出xxx.sql机制备份,因为最小的一个数据库实例的数据量基本都是几十G大小。

  4、从接触的应用逻辑来说,select count(*) 和order by 是最频繁的,大概能占了整个sql总语句的60%以上的操作,而这种操作Innodb其实也是会锁表的,很多人以为Innodb是行级锁,那个只是where对它主键是有效,非主键的都会锁全表的。

  5、还有就是经常有很多应用部门需要我给他们定期某些表的数据,MyISAM的话很方便,只要发给他们对应那表的frm.MYD,MYI的文件,让他们自己在对应版本的数据库启动就行,而Innodb就需要导出xxx.sql了,因为光给别人文件,受字典数据文件的影响,对方是无法使用的。

  6、如果和MyISAM比insert写操作的话,Innodb还达不到MyISAM的写性能,如果是针对基于索引的update操作,虽然MyISAM可能会逊色Innodb,但是那么高并发的写,从库能否追的上也是一个问题,还不如通过多实例分库分表架构来解决。

  7、如果是用MyISAM的话,merge引擎可以大大加快应用部门的开发速度,他们只要对这个merge表做一些select count(*)操作,非常适合大项目总量约几亿的rows某一类型(如日志,调查统计)的业务表。

InnoDB支持数据行锁定,MyISAM不支持行锁定,只支持锁定整个表。即 MyISAM同一个表上的读锁和写锁是互斥的,MyISAM并发读写时如果等待队列中既有读请求又有写请求,默认写请求的优先级高,即使读请求先到,所以 MyISAM不适合于有大量查询和修改并存的情况,那样查询进程会长时间阻塞。因为MyISAM是锁表,所以某项读操作比较耗时会使其他写进程饿死。

Mysql索引的区别

叶节点包含了完整的数据记录。这种索引叫做聚集索引。因为InnoDB的数据文件本身要按主键聚集,所以InnoDB要求表必须有主键(MyISAM可以没有),如果没有显式指定,则MySQL系统会自动选择一个可以唯一标识数据记录的列作为主键,如果不存在这种列,MySQL自动为InnoDB表生成一个隐含字段作为主键,这个字段长度为6个字节,类型为长整形。

第一个重大区别是InnoDB的数据文件本身就是索引文件。从上文知道,MyISAM索引文件和数据文件是分离的,索引文件仅保存数据记录的地址。而在InnoDB中,表数据文件本身就是按B+Tree组织的一个索引结构,这棵树的叶节点data域保存了完整的数据记录。这个索引的key是数据表的主键,因此InnoDB表数据文件本身就是主索引。

第二个与MyISAM索引的不同是InnoDB的辅助索引data域存储相应记录主键的值而不是地址。换句话说,InnoDB的所有辅助索引都引用主键作为data域。

聚集索引这种实现方式使得按主键的搜索十分高效,但是辅助索引搜索需要检索两遍索引:首先检索辅助索引获得主键,然后用主键到主索引中检索获得记录。

知道了InnoDB的索引实现后,就很容易明白为什么不建议使用过长的字段作为主键,因为所有辅助索引都引用主索引,过长的主索引会令辅助索引变得过大。再例如,用非单调的字段作为主键在InnoDB中不是个好主意因为InnoDB数据文件本身是一颗B+Tree,非单调的主键会造成在插入新记录时数据文件为了维持B+Tree的特性而频繁的分裂调整,十分低效,而使用自增字段作为主键则是一个很好的选择。

Mysql覆盖索引

覆盖索引,如果where条件的列和返回的数据在一个索引中,那么不需要回查表,那么就叫覆盖索引。,必须是从第一个开始覆盖,

多线程和多进程

多进程和多线程其实是作用是相同的。区别是

1.    线程是在同一个进程内的,可以共享内存变量实现线程间通信

2.    线程比进程更轻量级,开很大量进程会比线程消耗更多系统资源

多线程也存在一些问题:

1.    线程读写变量存在同步问题,需要加锁

2.    锁的粒度过大会有性能问题,可能会导致只有1个线程在运行,其他线程都在等待锁。这样就不是并行了

3.    同时使用多个锁,逻辑复杂,一旦某个锁没被正确释放,可能会发生线程死锁

4.    某个线程发生致命错误会导致整个进程崩溃

HashTabel碰撞

哈希表(或散列表),是将键名key按指定的散列函数HASH经过HASH(key)计算后映射到表中一个记录,而这个数组就是哈希表。这里的HASH指任意的函数,例如MD5、CRC32、SHA1或你自定义的函数实现。

理想情况下HashTable的性能是O(1)的,性能消耗主要集中在散列函数HASH(key),通过HASH(key)直接定位到表中的记录。
而在实际情况下经常会发生key1 != key2,但HASH(key1) = HASH(key2),这种情况即Hash碰撞问题,碰撞的概率越低HashTable的性能越好。当然Hash算法太过复杂也会影响HashTable性能(HashTable碰撞)

PHP数组中,键名可以为数字或字符串类型。而在内核中只允许数字索引,对于字符串索引,内核采用了time33算法将字符串转换为整型(是对字符串的每个字符转换为ASCII码乘上33并且相加得到的结果)

键名为数字时:内核中哈希表的散列函数就是简单的h & ht->nTableMask,其中h代表PHP中设置的索引号,nTableMask等于哈希表分配的长度-1。

键名为字符串时:与数字索引相比,只是多了一步将字符串转换为整型。用到的算法是time33

HashTable碰撞:PHP中使用一个叫Backet的结构体表示桶,同一哈希值的所有桶被组织为一个单链表。(先根据哈希值找到位置,然后再判断原始key是否相同,如果不相同,找单链表下一个元素)

PHP哈希表最小容量是8(2^3),最大容量是0×80000000(2^31),并向2的整数次幂圆整(即长度会自动扩展为2的整数次幂,如13个元素的哈希表长度为16;100个元素的哈希表长度为128)

防hashTable碰撞攻击(构造一个大数组,键值产生的哈希值都相同,然后post提交这个数组)在>=PHP5.3.9的版本中增加了一个配置项max_input_vars,用于标识一次http请求最大接收的参数个数,默认为1000。但如果是json方式提交,并不能防止攻击。

一般来说有两种方式,一是限制每个桶链表的最长长度;二是使用其它数据结构如红黑树取代链表组织碰撞哈希(并不解决哈希碰撞,只是减轻攻击影响,将N个数据的操作时间从O(N^2)降至O(NlogN),代价是普通情况下接近O(1)的操作均变为O(logN))

 

PHP变量在内存中的存储方式

函数传参时是赋值操作,只是其存储在不同的符号表(函数符号表),并且引用计数加2,而不是加1。原因是函数栈也包含了这个变量容器的引用。

当函数结束时,函数的符号表将被销毁。在销毁的过程中,Zend引擎将遍历符号表中的每个变量,并将其refcount的值减少。当变量容器的refount的值变为0,这个变 量容器将会被销毁

在PHP5.3之后,引入了新的垃圾收集机制,引用计数和引用的字段名改为refcount__gc和is_ref__gc

符号表是指当前php页面中,所有变量名称的集合

几种进程间的通信方式

# 管道( pipe ):管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
# 有名管道 (named pipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。
# 信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
# 消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
# 信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
# 共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
# 套接字( socket ) : 套解口也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同及其间的进程通信。

猜你喜欢

转载自my.oschina.net/u/3646190/blog/1577387