Muxx


  • 首页

  • 归档

  • 标签

  • 关于

  • 搜索

php7源码分析

发表于 2019-07-02

基本变量

php的zval结构体

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
struct _zval_struct {
union {
zend_long lval; /* long value */
double dval; /* double value */
zend_refcounted *counted;
zend_string *str;
zend_array *arr;
zend_object *obj;
zend_resource *res;
zend_reference *ref;
zend_ast_ref *ast;
zval *zv;
void *ptr;
zend_class_entry *ce;
zend_function *func;
struct {
uint32_t w1;
uint32_t w2;
} ww;
} value;
union {
struct {
ZEND_ENDIAN_LOHI_4(
zend_uchar type, /* active type */
zend_uchar type_flags,
zend_uchar const_flags,
zend_uchar reserved) /* call info for EX(This) */
} v;
uint32_t type_info;
} u1;
union {
uint32_t var_flags;
uint32_t next; /* hash collision chain */
uint32_t cache_slot; /* literal cache slot */
uint32_t lineno; /* line number (for ast nodes) */
uint32_t num_args; /* arguments number for EX(This) */
uint32_t fe_pos; /* foreach position */
uint32_t fe_iter_idx; /* foreach iterator index */
} u2;
};

这个新的zval在64位环境下,只需要16个字节,其主要分为两个部分,value和扩充字段。

  • value是一个size_t大小(一个指针大小),可以保存一个指针或者一个long/double
  • 扩充字段又分为u1,u2两个部分,u1是typeinfo,u2是各种辅助字段
    ** typeinfo部分保存了这个zval的类型,扩充辅助字段则会在多个地方使用,比如next,就用在取代hashtable中的原来的拉链指针。

PHP7中的zval, 已经变成了一个值指针, 它要么保存着原始值, 要么保存着指向一个保存原始值的指针。
php7中,引用计数不再是zval的字段,而是被设计在zval的value字段所指向的结构体中

阅读全文 »

cicd

发表于 2019-06-24
1
2
3
4
5
6
7
8
9
10
11
12
13
sudo docker run -d --name gitlab-runner-elk --restart always \
-v /srv/gitlab-runner/config:/etc/gitlab-runner \
-v /var/run/docker.sock:/var/run/docker.sock \
gitlab/gitlab-runner:latest
sudo docker exec -it gitlab-runner-elk gitlab-ci-multi-runner register -n \
--url http://git.intra.weibo.com/ \
--registration-token 2Kpu1BYH1_Jq4QigaTAe \
--executor docker \
--description "docker_elk_runner" \
--docker-image "docker:stable" \
--docker-volumes /var/run/docker.sock:/var/run/docker.sock

redis-cluster

发表于 2019-06-23

Redis-Cluster是一个去中心的分布式Redis存储架构,解决了Redis高可用、可扩展等问题。

集群

redis-cluster采用分片机制,将整个集群分为16384个槽(slot),默认平均分配在集群各个节点上。
每个节点负责维护一部分槽以及槽所映射的键值对
分片算法: slot=CRC16(KEY)%16384

请求流程

将请求发送到任意节点,接收到请求的节点将查询请求转发到正确的节点上执行,即redis会返回转向指令,类似302跳转

一致性

主从节点依然存在数据不一致的问题

容错

​redis-cluster采用replica方式冗余一定节点做slave,当某台主节点fail后在从节点中通过选举算法重新得出主节点。
​如果该节点及其slave节点都fail掉,则整个集群状态变为fail

故障检测

主观下线

集群中每个节点会定期向其他节点发送ping消息,接收节点恢复pong消息作为响应。如果在cluster-node-timeout时间内通信与某台节点ping-pong通信一直失败,则发送节点会认为接收节点存在故障并将接受节点标记为主观下线pfail

客观下线

当某个节点判断另一个节点主观下线后,相应的节点状态会跟随消息在集群内传播。通过gossip消息传播,集群内节点不断收集到故障节点的下线报告。当半数以上持有槽的主节点都标记某个节点是主观下线时,触发客观下线流程

  1. 首先统计有效的下线报告数量,如果小于集群内持有槽的主节点总数的一半则退出
  2. 当下线报告数量大于槽主节点数量一半时,标记对应故障节点为客观下线状态
  3. 向集群广播一条fail消息,通知所有节点将故障节点标记为客观下线,fail消息的消息体只包含故障节点的id

广播fail消息

广播fail消息是客观下线的最后一步,它承担着非常重要的职责

  1. 通知集群内所有节点标记故障节点为客观下线并立即生效
  2. 通知故障节点的从节点触发故障转移流程

注意:容错的过程中集群会短暂down的时间段 集群状态变化ok->fail->ok
节点超时选项:cluster-node-timeout,默认15秒

故障转移

当一个从节点发现自己正在复制的主节点进入下线状态时,从节点将开始对下线主节点进行故障转移

  1. 下线主节点n0的所有从节点中选中其中一个n1(选举)
  2. n1节点执行SLAVEOF NO ONE,成为新的主节点
  3. 新主节点n1节点会撤销所有对n0节点的槽指派,并将这些槽全部指派给自己
  4. 新的主节点n1向集群广播一条PONG消息,这条PONG消息可以让集群中的其他结点立即知道这个节点已经由从节点变成主节点,并且这个主节点已经接管了原本由已下线节点负责处理的槽
  5. 新的主节点开始接收和自己负责的槽有关的命令操作

读写能力优化

redis-cluster中master用于读写,slave节点用于备份。如果不介意读取的是有可能过期的数据,并且对写请求不感兴趣时,看通过readonly命令,将slave设置为可读。

不过redis-cluster中master其实是可以任意扩展的,扩容master其实是比扩容slave效果更好的方式

阅读全文 »

motan剖析之传输协议

发表于 2019-05-10

motan中默认使用motan2作为数据传输协议,实现位于src/github.com/weibocom/motan-go/protocol目录中

其中主要是Message及Header结构体,Header的MsgType中使用按位保留了大量信息,包括

  • 第一位: 是否为request
  • 第二位: 是否使用代理
  • 第三位: 是否oneway(单向调用)
  • 第四位: 是否gzip压缩
  • 第五位: 是否心跳

VersionStatus中使用位保存了version和status信息

使用样例见src/github.com/weibocom/motan-go/protocol/motanProtocol_test.go文件

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
//motan消息头
type Header struct {
Magic uint16
MsgType uint8
VersionStatus uint8
Serialize uint8
RequestID uint64
}
func (h *Header) GetVersion() int //版本
func (h *Header) GetVersion() int
func (h *Header) SetHeartbeat(isHeartbeat bool) //是否心跳
func (h *Header) IsHeartbeat()
func (h *Header) SetGzip(isgzip bool) //设置是否使用gzip
func (h *Header) IsGzip() bool
func (h *Header) SetOneWay(isOneWay bool) //oneway
func (h *Header) IsOneWay() bool
func (h *Header) SetProxy(isProxy bool) //代理
func (h *Header) IsProxy() bool
func (h *Header) SetRequest(isRequest bool) //设置request标识
func (h *Header) isRequest() bool
func (h *Header) SetStatus(status int) error //状态
func (h *Header) GetStatus() int
func BuildHeader(msgType int, proxy bool, serialize int, requestID uint64, msgStatus int) *Header
//motan消息结构体
type Message struct {
Header *Header //消息头
Metadata *motan.StringMap //消息的附加meta信息,motan.StringMap是一个线程安全的map数据结构
Body []byte //消息体 (存储序列化后待传输的数据)
Type int //类型 暂时没使用
}
func (msg *Message) Encode() (buf *motan.BytesBuffer)
func (msg *Message) Clone() interface{}
func Decode(buf *bufio.Reader) (msg *Message, err error)
//将motan协议消息结构转换为motan.Request/Response结构
func ConvertToRequest(request *Message, serialize motan.Serialization) (motan.Request, error)
func ConvertToResponse(response *Message, serialize motan.Serialization) (motan.Response, error)
//将motan.Request/Response结构转换为motan协议消息结构
func ConvertToReqMessage(request motan.Request, serialize motan.Serialization) (*Message, error)
func ConvertToResMessage(response motan.Response, serialize motan.Serialization) (*Message, error)

motan知识整理

发表于 2019-05-10

功能

    服务治理
    高效可靠数据传输

执行流程

客户端执行流程
    初始化
    调用
        pre_clusterfilter
        lb选出endpoint
        ha调用
        pre_filter
        真正ep执行
        post_filter
        post_clusterfilter

        客户端metric记录请求时间 通过PXX(默认90),使用backuprequest降低长尾请求,消峰

主要模块

filter 过滤器
ha ha策略
lb lb调度策略


ha
    failover 失败重试
    backuprequest 双发重试

filter
    filter
        AccessLogFilter
        MetricsFilter
        CircuitBreakerFilter
        FailfastFilter
        TracingFilter
        RateLimitFilter
    clusterFilter
        clusterAccessFilter
        ClusterCircuitBreakerFilter
        ClusterMetricFilter
        lastClusterFilter
cluster和endpoint
    单个服务的集群用cluster表示,集群中最小粒度是endpoint,cluster由多个endpoint构成

protocol
    传输协议
serialize
    序列化协议

不同机房使用不同的group
不理解trace采集点设置的位置有什么关联
motan中注册的是服务 服务是一种资源 对服务可以调用各种方法

从传输与控制角度

grpc入门

发表于 2019-05-10

gRPC是一个高性能、通用的开源PRC框架,由Google主要面向移动应用开发并基于HTTP/2协议标准而设计,基于ProtoBuf
特点:

  • 跨语言通信
  • 基于HTTP/2标准设计,在移动端上表现更好
  • 使用pb序列化,效率高
    (Protocol Buffers)序列化协议开发,且支持众多开发语言。

简单描述下pb
优点:

  • 没有xml或json的字段名,数据体积更小,读写更快
  • 向下兼容性好

缺点:

  • 可读性较差
    >

    pb与其他序列化协议对比
    20190510155745438262407.png

官方入门教程

php 官方自动化测试方法

发表于 2019-05-09

├── Makefile
├── phpt
│ └── test.phpt
└── run-tests.php

Makefile文件

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
base_dir=./
top_builddir=${base_dir}
top_srcdir=${base_dir}
TESTS=${base_dir}/phpt
#PHP_EXECUTABLE=/usr/local/php/bin/php
PHP_EXECUTABLE=/usr/bin/php
EGREP = /bin/grep -E
CC = cc
PHP_TEST_SETTINGS = -d 'open_basedir=' -d 'output_buffering=0' -d 'memory_limit=-1'
all:
@echo
@echo "You should run 'make test'."
@echo
test:
-@if test ! -z "$(PHP_EXECUTABLE)" && test -x "$(PHP_EXECUTABLE)"; then \
INI_FILE=`$(PHP_EXECUTABLE) -d 'display_errors=stderr' -r 'echo php_ini_loaded_file();' 2> /dev/null`; \
if test "$$INI_FILE"; then \
cp "$$INI_FILE" $(top_builddir)/tmp-php.ini; \
else \
echo > $(top_builddir)/tmp-php.ini; \
fi; \
TEST_PHP_EXECUTABLE=$(PHP_EXECUTABLE) \
CC="$(CC)" \
$(PHP_EXECUTABLE) -n -c $(top_builddir)/tmp-php.ini $(PHP_TEST_SETTINGS) $(top_srcdir)/run-tests.php -n -c $(top_builddir)/tmp-php.ini $(TESTS); \
rm $(top_builddir)/tmp-php.ini; \
else \
echo "ERROR: Cannot run tests without CLI sapi."; \
fi
.PHONY: all test

参考

动态追踪利器-Systemtap

发表于 2019-04-24

Tracer

strace 用于跟踪程序运行时的系统调用,UNIX-LIKE系统上相同效果的工具是truss
dtrace可以通过D语言在任意指定系统调用处设置探针,系统调用发生时触发探针处设置的逻辑,这种逻辑可以通过脚本文件的形式动态加载,由于这种灵活性我们叫它动态追踪,UNIX-like系统上相同效果工具是dtruss

Say this five times fast: strace, ptrace, dtrace, dtruss

SystemTap使用技巧

动态追踪
实现方式: 探针
特点:
非侵入
一般是针对操作系统内核的
常用工具
DTrace
SystemTap
Perf

1…8910…29
Mu

Mu

230 日志
53 标签
© 2021 Mu
由 Hexo 强力驱动
主题 - NexT.Pisces