Feb16

【原创】如何通过phpstorm查看某一行代码的变更记录

Author: leeon  Click: 950   Comments: 0 Category: 其他  Tag: phpstorm,php,git

多人维护的工程项目,往往对历史代码有些不理解,phpstorm在新版本中集成了一个很有用的功能

“Show History for Selection”

只要我们对有疑问的代码进行框选,然后右键点击git->Show History for Selection ,phpstorm就会去git history中去检查这行代码在历史记录中出现的状态。

Feb15

【原创】最佳PHP框架选择(phalcon,yaf,laravel,thinkphp,yii)

Author: leeon  Click: 1368   Comments: 1 Category: php  Tag: php,yaf,phalcon,laravel,thinkphp,yii

     最近面试了不少人,绝大部分使用的是thinkphp和laravel这两个框架,真正高性能的框架yaf和phalcon反而没有人使用。我认为使用框架主要基于这几点因素:

1. 工程结构规范化

2. 代码格式规范化

3. 功能抽象化

4. 逻辑封装化

5. 底层核心透明化

     tp,laravel,yii的简单实用的上手难度不高,但是复杂封装又各有特点需要深入学习,虽然可以快速通过其丰富的组件功能来构建一个基本的网站,但是后期的学习曲线也比较高。不管是用哪种框架,都是基于MVC模式来设计。本质上都是通过统一的路由管理器来派发不同的控制器任务。本文我将通过直接的性能测评来选出PHP7版本下认为在性能和工程化上最优的PHP框架。

 框架 版本  说明 
 yaf 3.0.4   通过yaf自带的yaf_cg来初始化一个基本工程
 thinkphp 5.0.6   composer创建一个基本工程,关闭debug
 phalcon  3.0.3  通过phalcon-devtools工具创建一个基本工程
 laravel  5.4  composer创建一个基本工程,关闭debug
 yii  2.0.11  yii手工下载basic版本工程,关闭debug

      我们通过将5个工程分别部署成5个网站,并修改里面的首页控制器,均改为输出到页面“hello”字段来评测裸框架下的基准性能。基础测试环境采用负载稳定的树莓派3来运行,并通过另外一台树莓派2来进行ab压力测试。fpm进程设定为static模式,并设定fpm进程数为5个,opcache设为开启状态。

ab运行命令类似如下,并连续采样10次来分析持续压力下的框架稳定性。

ab -k  -c 20 -n500 -q http://127.0.0.1/

压力测试结果如下:

laravel phalcon 原生php yaf thinkphp yii

87.9 670.66 1258.67 1061.76 545.93 61.65

100.4 924.2 1331.67 1126.23 618.78 65.88

81.19 921.87 1352.38 1129.91 608.41 77.84

111.39 930.88 1355.48 1159.62 601.55 79.05

53.89 929.71 1367.68 1165.19 607.24 72.21

94.67 918.72 1482.87 1107 607.24 82

62.21 932.51 1374.17 1130.23 610.72 76.42

85.63 925.01 1674.64 1124.18 609.11 69.82

67.05 913.12 1828.11 1128.22 608.72 75.67

89.21 879.26 1809.36 1159.38 601.18 77.93

     我们可以看到原生的PHP依然是相当强悍的,yaf的性能比phalcon高,这是因为yaf框架只 包含最基本的路由配置加载,并未有任何高级封装,相比phalcon框架丰富的组件,yaf在内存加载启动上必然比phalcon要轻量化。我们可以看到PHP实现的thinkphp性能表现不俗,但lavarel和yii的性能确实有点差强人意了。

    yaf属于超轻量级的c级别裸框架,只集成了基本的视图和路由控制,如果要完成一个中等以上规模的网站的话,还需要集成非常多的第三方类库,如果在线上运营环境中使用,会因为php加载大量的第三方类库而影响到性能。

    phalcon基于c的实现几乎完整的实现了yii,laravel,thinkphp具备的功能特点,同时在性能上完胜了这三个框架,在性能和功能上做了一个比较好的平衡。对于一个可扩展架构的高性能PHP框架而言,phalcon具备了比PHP实现的框架更好的稳定性和开发效率。phalcon虽然在入门门槛上偏高,但是我们只要熟悉了他的框架结构,我们可以很快速的去实现任何web服务业务模型。phalcon具体的介绍将在下一章节中进行介绍。

Feb14

【转载】斗鱼直播平台后端RPC架构浅析

Author: 陈厚道  Click: 812   Comments: 0 Category: 架构  Tag: douyu,斗鱼,rpc

# 背景

# 关键设计点

## 模块化

## 资源隔离

## 权限控制

### RPC框架的需求分析和概要设计

#### 发展与现状

- RPC框架指的是能够完成RPC调用的解决方案,除了点对点的RPC协议的具体实现之外,还可以包含服务的发现与注销,提供服务的多台Server的负载均衡、服务的高可用等更多的功能,目前的RPC框架大致有两种不同的侧重方向,一种偏重于服务治理,另一种偏重于跨语言调用。

- 开源的RPC框架介绍:Dubbo、DubboX、Thrift、Motan。其中Dubbo,Dubbox,motan是java生态下的偏向服务治理的RPC框架,Thrift是偏重于跨语言的调用的RPC。

#### RPC框架提供的主要功能

- 服务发现:服务发布、订阅、通知

- 负载均衡:支持一致性Hash、随机请求、轮询、最少连接数优先、低并发优先等分发原则

- 高可用策略:失败重试(FailOver)、快速失败(FailFast)、异常隔离(Server连续失败超过指定次数置为不可用,然后定期进行心跳探测)

- 其他: 调用统计、权限控制、安全、调用链追踪、日志

#### DY RPC框架交互流程1

DY RPC框架中有服务提供方 RPC Server,服务调用方RPC Client,服务注册中心MessageServer三个角色。该框架的RPCServer主要现在用c++写的服务,RPC Client包括php或者RPCServer。

1. RPC Server向MessageServer集群的某个节点B注册服务,并保持长连接。该MessageServe r B节点会通知集群的所有节点。

同时MessageServer B节点也会定时把注册到该节点的RPCServer的服务配置信息同步到 MessageServer集群。

2. RPCClient会连接到MessageServer集群的某个节点A,发起RPC调用。MessageServer A节点会根据RPC调用的参数(服务提供方的ID,GroupID、负载均衡策略等)选择一条合适的

RPC调用链路,比如RPCClient->MessageServerA->MessageServerB->RPCServer,最终到达某个RPCServer,进行函数调用。其中一个RPC调用最多会经过2个MessageServer节点,最少会经过1个MessageServer节点。

3. 当某个RPC Server发生变更时,通过广播的方式,MessageServer集群的所有节点也能比较实时的感知到某个RPCServer发生变更。

TODO RPC流程交互图

#### DY RPC功能模块划分

1. MessageServer在RPC框架这个功能上应该提供的功能,包括服务的注册和发现模块、协议序列化模块、心跳检测模块、负载均衡算法模块,RPC路由模块、失败重试策略模块、超时丢弃策略模块、消息持久化模块。

2. RPCServer要包含RPC治理的组件,主要功能包括RPC的统计、RPC的频率控制、RPC的安全性控制。

##### RPCServer可用性检测模块

每个服务默认都要实现一个类似Ping Pong的 Request和Response,用来给直连RPCServer的MessageServer探测RPCServer是否可用提供依据。不能简单的依赖心跳消息来探测RPCServer是否可用。

##### 负载均衡模块

MessageServer把RPC请求转发给RPCServer Group时,需要支持的负载均衡算法:

1. 随机法(已实现)

2. 轮询法(已实现)目前在生产环境用的这种算法,负载较不均衡。

3. 组内Hash法(已实现)

4. TODO 最少连接法 (最靠谱的负载均衡做法)

斗鱼采用的这些负载均衡算法可以参考这篇微信文章的介绍:http://mp.weixin.qq.com/s/PAOvmzraVlAMECL-PZs2Pg

看服务器响应自己请求的速度就可以判断应该把下一个请求发到哪个服务器端。

具体说是选择活动请求(已经发出去的请求收到响应)数目最少的那个服务端。 只要根据自己以往的调用情况就能做出判断。

5. TODO: 目前的消息系统只支持点到点、点到组。目前还暂不支持点到组内的某个节点的负载均衡算法。

##### 失败重试策略模块

在RPCClient直连的MessageServer上实现RPC失败重试的策略。

- 只有幂等的RPC调用才能重试。

##### 超时丢弃策略模块

在RPCServer的业务层实现超时丢弃的策略,应用场景:发送火箭超时时,客户端提示发送失败,其实是在鱼翅交易服务器出现性能抖动导致。最后的结果就是鱼翅服务器扣除了鱼翅,但是客户端提示发送火箭失败,比较严重的情况是,用户以为提示失败时不会消耗鱼翅,所以不断重新发送火箭。

针对这种类型的RPC,RPCServer的业务层可以根据RPC的配置规则+RPC发起时间来决定是否直接丢弃该RPC。

##### 消息持久化模块

- 在调用RPC时如果指定可达时,才触发消息持久化的机制。

- 因为RPC的调用链最多需要经过4个节点(RPCClient->MessageServerA->MessageServerB->RPCServer),导致RPC不可达到的情况较为复杂,如果采用自研的方案做消息持久化的话,我们可以假设MessageServer的集群比较稳定,RPCServer较不稳定,所以我们持久化的方案是在和RPCServer直连的MessageServer上实现。

- MessageServer上做持久化具体设计要点:

- 正常流程:

- MessageServer将RPC请求转化为消息,以RPCServer的模块id为Key,将消息存入Redis的队列,我们将这个消息称为MessageData;

- 将RPC请求的MessageID作为Key,Value作为保留字段设计,存入Redis的String,我们将这个数据称为MetaData,同时设置这个Key的过期时间为10分钟(暂定),这个操作和上面的操作作为Redis的一个事务来执行;

- 执行完上面的事务后,直接调用RPC的Response,返回给RPCClient;

- RPCServer集群的某个节点从Redis队列取出MessageData,执行RPCHandler。

- 异常流程1:

- 如果在执行RPCHandler的过程中,RPCServer异常,就只会影响一条MessageData。可以通过一些辅助脚本来做补单,考虑一种策略来实现自动化的补单。

- 异常流程2:

- MessageServerA->MessageServerB网络抖动 或者 MessageServerB->Redis的网络抖动都会导致MessageData不能进入队列;

- 在和RPCClient直连的MessageServerA一段时间(先暂定10s)没有收到RPCResponse,就会触发重试机制,重试的上限次数暂定20次,确保整体重试的时间小于MetaData过期的时间就可以,重试流程进入到MessageServerB节点时,如果是重试RPC,查找Redis队列是否有这个MessageData,如果不存在,则执行正常流程。如果存在,则丢弃本次重试,说明上一次重试已经成功了。

##### 增加RPC追踪链日志

- 在RPCClient直连的个MessageServer上给RPC请求赋予一个Global的RPCID;

- RPCID可以从IDMakerServer集群获得,通过一次获得一批ID来获得良好的性能;

- 在RPC经过的每个节点,都需要有规划统一的格式,并上报给大数据平台;

- 在大数据后台,可以根据RPCID查找整个RPC调用链上的信息。

##### RPC治理组件

- RPC调用统计:每个RPC入口增加统计信息,当rpc进入内部业务函数后也有一次统计,统计信息汇入大数据实时统一日志

- RPC频率控制:某个时间单位内,RPC调用不得超过某个数量;如果有超过,则报警。在频率控制粒度方面,采取如下控制策略和监控策略。

- 每个服务的所有RPC在单位时间内的调用频率控制,超出则报警;

- 某个RPC在单位时间内的调用频率控制,超出则报警;

- 定时统计每个Client来源在每个RPC的调用次数,并按照统一格式上传给大数据平台,大数据平台提供按照Client来源、时间查找RPC调用次数的Top 10的类似功能;

- 大数据平台定时对比RPC的历史调用次数和当前调用次数,超过一定的比例就报警。

- RPC安全策略:

- 可以随时关闭某个RPC、某个服务的所有RPC的安全策略;

- ip验证:给一个ip白名单,这个白名单才能发起RPC调用,不建议按照每个RPC调用单独设置ip白名单

- 口令验证:针对某个RPC、某个服务单独设置密码,对大都数服务都设置成统一的密码,不建议针对每个RPC或者每个服务都单独设置密码。因为除了密码,还有一个摘要认证加密算法才能破解RPC的协议。现在密码是运维维护的,摘要认证加密算法是开发维护的。所以不建议对密码的粒度控制得过细

- RPC手动降级:可以随时关闭某个RPC;也可以根据Client来源关闭某个RPC,但对其他Client来源是开启的。

- RPC自动降级: TODO

- 配置文件格式:参考详细设计文档 by 李明

#### 关键数据结构

1. 服务注册协议

```

struct MC_MsgLoginReqNew : public MessageRoot

{

uint8_t  _version;

DWORD    _uid;

char      _user_name[33];

char      _password[33];      //之前的口令字段依旧不使用

int      _module_id          //模块id

};

```

2.RPCClient Request基本结构,同样包括GroupRPCReq(组内随机调用),GroupRPCReq2(组内hash调用)的

```

struct MC_RPC_Req_New : public MessageRoot< MCT_RPC_Req_New, MC_RPC_Req_New >

{

uint8_t _version;        // 版本号

int64 _rpc_global_id;    // 每次调用需要从idMakderServer获得唯一id,RPC追踪链需要依赖该id来识别

int _rpc_option;          // 包括RPC可达,重试,超时丢失等标志,不可叠加

int32 _user_data;          // 自定义用户数据

int _rpc_retry_count;      // 0表示第一次请求,每重试一次+1

int _invoker_id;          // 调用者的ID

int _invoker_moudule_id;  // 调用者的模块id

uint32_t _invoker_ip;      // 调用者的ip

int _call_token;        //调用标识,由调用者设置,返回结果时必须携带此token,否则调用者无法区分是哪一次调用

int _recvier_id;      // 接收者的serverID

uint32_t _req_time    // 请求时间戳

int64_t _random_num;  // 随机数 没有口令配置此项可以不填

uchar _password[32];  // 口令,由 随机数+ 模块id+ 函数名+ 配置文件的口令+ 时间戳 的字符串 一次md5获得,服务器使用同字段md5对比校验,没有口令配置此项留空即可

char _func_name[128]; //函数名

char _text_data[1];  //SttEncoding存储函数体,包括函数名、参数名/参数值

};

```

> _rpc_global_id,_invoker_moudule_id,_invoker_ip这个由调用方直连的第一个MessageServer直接赋值

> _version,_req_time,_random_num,_password,由RPCClient生成,RPCServer校验

> _rpc_retry_count,表示重试的次数,这个由调用方直连的第一个MessageServer发起重试策略时+1

> _rpc_option,包括RPC可达,重试,超时丢弃等标志,现在不可叠加,以后可支持叠加,常见的场景是:

1. RPCClient不太关注返回结果的、关键数据更新类的RPC,建议指定RPC可达。

2. RPCClient非常关注返回结果提示,但又不支持重试的(非幂等RPC),建议指定超时丢弃标志

3. RPCClient非常关注返回结果提示,该RPC又支持幂等,建议指定重试标志

4. _user_data:根据不同的RPC标志,可以指定特定的含义.比如指定最大重试次数或者超时丢弃的时间

> GroupRPCReq(组内随机调用),GroupRPCReq2(组内hash调用)的数据结构也需要同时更新。

3. RPCServer Response基本结构

```

struct RPC_RespNew

{

uint8_t _version;      // 版本号

int64 _rpc_global_id;  // RPC全局唯一id

int recvier_id;        // 接收者的ID;如果是按组接收,此值由MessageServer修改为具体的接收者ID

int invoker_id;        // 调用者的ID

int call_token;        //调用标识,由调用者设置,返回结果时必须携带此token,否则调用者无法区分是哪一次调用

char text_data[1];      //SttEncoding存储调用结果

}

```

#### 以送火箭场景为场景描述架构重构的思路

1. php调用发送火箭RPC接口给鱼翅交易服务器,鱼翅服务器完成RPC调用,并且是把这个消息发送给所有的ChatRoom。

2. 鱼翅交易服务器把发送火箭这个RPC封装成NetMessage通过ChatRoom发送给RoomMaster,RoomMaster找到人气值前50的房间,并向人气值前50的房间的ChatRoom发送火箭广播的NetMessag,ChatRoom再把广播消息发送给MessageRepeater

3. ChatRoom通过NetMessage把发送火箭这个消息事件发送给排行榜服务器

4. ChatRoom通过NetMessage把发送火箭这个消息事件发送给经验服务器

5. ChatRoom发送创建红包RPC给红包服务器

目前的业务流程的主要弊端如下:

1. ChatRoom和大都数服务耦合非常紧密,据我了解,c++的各个小组经常存在同时维护ChatRoom的情况。

2. 同样,新增一个和送火箭相关的服务,ChatRoom也需要增加相关接口。

3. ChatRoom通过RPC、NetMessage和其他业务交互时,如果网络出现抖动或者其他业务在维护或者不稳定时,都会导致数据的丢失,比较影响用户的体验。

针对送火箭这个业务流程,我个人认为比较优雅的架构(新架构)如下:

1. php调用发送火箭RPC接口给鱼翅交易服务器,鱼翅服务器完成RPC调用

2. 鱼翅交易服务器把发送火箭这个RPC封装成消息事件,发送给消息队列服务器。

3. 红包服务器、经验服务器、排行榜服务器、RoomMaster都通过订阅的方式订阅到了发送火箭这个消息。这些服务器按照自己的业务规则处理该消息事件!

4. RoomMaster找到人气值前50的房间,并向人气值前50的房间的ChatRoom发送火箭广播的NetMessag,ChatRoom再把广播消息发送给MessageRepeater。

新架构的优点如下:

1. ChatRoom和其他服务已经完全解耦。

2. 如果新增一个和送火箭相关的服务,鱼翅服务器的逻辑也不用调整。新增的服务只需要订阅送火箭的消息队列就可以了。

3. 消息队列服务器是一个稳定的第三方服务,基本是不用维护的。其他比如红包服务器、经验服务器、排行榜服务器的不稳定,都不会导致数据的丢失。

老框架迁移到新框架下的推进计划:

1. 先挑选送火箭这个业务进行重构,其他业务流程仍然兼容老的RPC的通信方式;

2. 逐步梳理c++组的业务流程,挑选业务流程逐一进行重构;

3. 第一个业务流程的重构预估时间大概在3周左右,后面的每个业务流程重构预估在1周左右,在3-4个月的时间内梳理完所有流程。

## 当前底层框架可以优化的点

1. MessageServer集群可以优雅的增加、删除、修改(同时删除、增加来实现)节点,现在修改某个节点的ip需要重启整个集群?

2. 把弹幕的MessageServer集群和RPC的MessageServer集群分离

3. 协议序列化框架改成ProtoBuffer,可以逐个协议升级

4. MessageServer的通信链路自动检测,防止出现某个节点异常之后很久才发现

## 统一日志

**TODO:本周5和c++组讨论之后再确定**

## 近期之内主要的工作项

WorkItem | 优先级 | 备注

---|---|---

Feb10

【原创】采用xhgui及tideways搭建PHP性能监控平台

Author: leeon  Click: 1256   Comments: 0 Category: php  Tag: xhgui,xhprof,tideways,php

      xhprof扩展已经三年多没有更新了,PHP7是没法直接使用xhprof来进行性能分析了。好在tideways出品了一款xhprof的进化版php性能分析插件,可以完美支持php7程序。网上关于如何使用tideways和xhgui搭建性能分析平台的教程已经有了很多,部署的话可以参考借鉴这篇文章https://segmentfault.com/a/1190000007580819,但是在搭建过程中还是遇到了一些问题,需要说明一下。

   1. 当git clone https://github.com/perftools/xhgui.git xhguid的源后,注意你的php代码中必须安装mogondb的扩展,否则在php install的时候会出现调用composer安装第三方库失败,composer下载的vendoer资源也是需要依赖pecl的mogondb库的。这点在官方的配置文档中并没有提及。

  2. xhgui在配置nginx的时候官方文档也有些问题,需要注意这里

这里需要修改成:

        location / {

                 try_files $uri $uri/ /index.php?$query_string;

        }

如果不修改这个配置,xhgui里面集成的slim框架无法正常解析到路由数据。
 3.xhgui里面集成的slim框架有一个轻微语法出错,会导致php7下warning级别错误,请修复vendor\slim\views\Slim\Views\Twig.php文件的render方法,父类定义了第二个参数,但继承的类中没有指定导致warning报错,将第二个参数添加上即可:
public function render($template, $data = NULL)

xhgui属于无侵入式的代码性能监控方案,对于现有的代码不需要原先xhprof那样在代码中埋点指定xprof的文件路径,我们仅仅需要在对应的项目工程nginx配置中加入如下的代码:

[code="plain"]
fastcgi_param TIDEWAYS_SAMPLERATE "25";
fastcgi_param PHP_VALUE "auto_prepend_file=/usr/local/nginx/html/xhgui/external/header.php";
[/code]

第二行配置请根据自己的xhgui存放路径进行填写。

分类

标签

归档

最新评论

ligaofeng在11:55:22评论了
file_get_contents超时问题的解决方法
我也不知道叫个啥好在00:59:46评论了
shell中使用while循环ssh的注意事项
司马成空在16:14:13评论了
【原创】ZendStudio中格式化HTML代码错位问题修正
Owen在22:56:46评论了
【原创】MyBatis Generator使用小记
waltye在23:38:05评论了
【原创】武汉互联网公司介绍[2016年8月更新版]

我看过的书

链接

其他

访问本站种子 本站平均热度:6010 c° 本站链接数:27 个 本站标签数:428 个 本站被评论次数:87 次