文章851
标签121
分类10

Redis 事务踩坑

Redis 测试 Demo

<?php
# 原子操作 redis 事务
$redis = new \Redis();
$redis->connect('127.0.0.1', '6379', 3);

// 监控key WATCH  事务开启前监控key
$redis->WATCH('test_hash');

// 开启事务
$redis->MULTI();

// 事务内执行写操作
$redis->set('test_hash', 2);

$redis->set('test_hash', 1);

// 提交事务
$redis->exec();

// 回滚事务
// $redis->discard();

redis 事务 需要通过 redis-cli monitor 监控中看到 正常提交流程

    1544372307.803143 [0 127.0.0.1:37532] "MULTI"
    1544372307.803225 [0 127.0.0.1:37532] "WATCH" "test_hash"
    1544372308.923998 [0 127.0.0.1:37502] "SET" "test_hash" "2"
    1544372312.803550 [0 127.0.0.1:37532] "SET" "test_hash" "1"
    1544372312.803566 [0 127.0.0.1:37532] "EXEC"
    1544372318.742735 [0 127.0.0.1:37502] "get" "test_hash"

如果事务中 中间监控key 发生变动 就会变成

    1544372363.760832 [0 127.0.0.1:37556] "WATCH" "test_hash"
    1544372363.760935 [0 127.0.0.1:37556] "MULTI"
    1544372366.129051 [0 127.0.0.1:37502] "set" "test_hash" "2"
    1544372368.761290 [0 127.0.0.1:37556] "EXEC"

monitor 日志 可以看到 37556 端口实例监控test_hash, 37502 端口实例修改了test_hash exec 仍然提交 但中间没有提交

    "SET" "test_hash" "2"
    "SET" "test_hash" "1"

开发中 PHP demo 操作 exec 返回
成功 :

array(2) {
  [0] =>
  bool(true)
  [1] =>
  bool(true)
}

失败 :

bool(false)

还有个小彩蛋 测试了下 将 test_hash 类型改外其他 hashzset 事务提交也会成功, 成功后将test_hash 改成 string 类型了. 这又点霸道了.

又踩一新坑

Redis 事务开启后 同实例下读操作是不可用的 返回 queue 规避方式就是用其他实例取做读操作, 反正已经watch 了 不用担心读到脏数据;

测试环境 redis 3.2.12

最后 要补充的是 Redis 集群版本不支持事务操作

XHProf 名词解释

2024-10-21T02:12:19.png

2024-10-21T02:12:35.png
XHProf 是一个轻量级的 PHP 性能分析工具,用于分析 PHP 应用程序的性能瓶颈和函数调用情况。它主要用于帮助开发者优化代码,提高应用程序的运行效率。以下是 XHProf 中的一些关键名词及其解释。

1. 性能分析(Profiling)

性能分析是收集程序运行时数据的过程,以识别性能瓶颈和优化点。XHProf 通过监控函数调用、执行时间和内存使用等指标,提供详细的分析报告。

2. 函数调用(Function Call)

在 XHProf 中,函数调用是指程序中对某个函数的执行。XHProf 记录每个函数的调用次数、执行时间和调用的其他函数,以帮助开发者了解代码的执行路径。

3. 调用栈(Call Stack)

调用栈是函数调用的层次结构,用于表示程序执行时函数的调用关系。XHProf 提供的报告中,调用栈可以帮助开发者理解哪些函数调用了其他函数及其相应的执行时间。

4. 执行时间(Execution Time)

执行时间是指函数运行所消耗的时间,通常以毫秒或微秒为单位表示。XHProf 记录每个函数的总执行时间,以及其在调用栈中的相对位置。

5. 内存使用(Memory Usage)

内存使用表示程序在执行过程中消耗的内存量。XHProf 监控每个函数的内存使用情况,帮助开发者识别内存泄漏和高内存消耗的函数。

6. 报告(Report)

XHProf 生成的报告是对性能分析结果的总结,通常包含函数调用的详细信息、执行时间、内存使用情况等。报告可以以可视化的方式展示,帮助开发者快速识别性能瓶颈。

7. 采样(Sampling)

采样是指以一定频率收集程序运行时的数据。在 XHProf 中,采样可以帮助减少性能分析对应用程序运行的影响,同时仍然提供有价值的性能数据。

8. XHProf UI

XHProf UI 是用于展示 XHProf 分析结果的用户界面。它提供了一个易于使用的界面,开发者可以通过该界面查看函数调用的详细信息和性能分析报告。

9. 开销(Overhead)

在性能分析中,开销指的是分析工具本身对被分析程序性能的影响。XHProf 设计为轻量级工具,旨在尽量减少对应用程序的性能影响。

10. 配置(Configuration)

XHProf 的配置是指在使用 XHProf 前需要进行的设置,包括启用 XHProf 扩展、设置数据收集的阈值等。这些配置会影响到性能分析的结果和准确性。

Tcp Rpc 踩坑实践

最近接到需求, 目前项目满足不了, 需要通过中间件实现.
经过讨论和分析, 最后打算 使用 swoole 构建一个 Tcp Rpc 服务.

正常的Rpc 轮子遍地都是 , 但是我们的需求很独特, 需要根据参数 将请求分配至指定 进程. 构建出一套同步堵塞的服务.
场景举例:

修改用户A的资产, 通过参数 `uid` 分配器将 请求发送至固定 进程. 使得用户资产都在单进程内排队更新.

上面的场景是很好实现的, 我们也已经在线上运行了一段时间, 基本告别了 过去的mysql 存储用户资产, 并发操作用户资产造成的死锁问题.

重点场景:

两个用户交易资产, 通过参数 `uid`, `bak_uid` 分配器将请求发送到固定 进程.....
显然不现实, 高并发场景下, 两个uid 分配到固定进程, 有些扯淡, 所以需要写个算法提供给两个uid 指定进程 `x`, 并且保证接下来的请求带有之前
的参数都必须都往这个执行进程 `x` 打 

第一个场景 单用户 进程分配方式固定 取模 即可实现

第二个场景 多用户 进程分配方式动态算法 实现 中间坑很多 但也最终实现, 但性能堪忧, 有待测试调优.

说下开发中的坑 技术选型 swoole go

因为是phper 所以默认选 swoole

使用swoole 的 自定义分配方法 dispatch_func 参数 实现 放在在这里相当于所有请求都经过这里, 这是一个分配进程的好地方.

之前使用 dispatch_func 方法 踩了 return -1; 的坑, 结果死循环, 前面文章有提到过.
在调优过程中 通过观察 server->stats 参数如下

   [stats] => Array
    (
        [start_time] => 1544262210
        [connection_num] => 14889
        [accept_count] => 14889
        [close_count] => 0
        [tasking_num] => 0
        [request_count] => 518771
        [worker_request_count] => 5
    )

connection_num 当前连接数 竟然都没有释放

配合 netstat -n | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}' 查看 CLOSE_WAIT

TIME_WAIT 4969
CLOSE_WAIT 13494
ESTABLISHED 1045

果然大量客户端异常断链 导致服务端仍保持连接

问题解决 :

    // 心跳相关                     https://wiki.swoole.com/wiki/page/284.html
    // 'heartbeat_idle_time' => 60,
    // 'heartbeat_check_interval' => 10,
    //  开启 TCP keepalive                          https://wiki.swoole.com/wiki/page/p-tcp_keepalive.html
    'open_tcp_keepalive' => 1,                      // 死连接检测
    'tcp_keepidle' => 60,                           // 单位秒,连接在n秒内没有数据请求,将开始对此连接进行探测。
    'tcp_keepcount' => 6,                           // 探测的次数,超过次数后将close此连接。
    'tcp_keepinterval' => 10,                       // 探测的间隔时间,单位秒。

使用 tcp keepalive 保持连接即可 , 但使用定时ping的方法并不能有效维持连接 1分钟后连接全部断了, 具体原因暂时没时间搞, 但 keepalive 较为消耗性能 最好还是用心跳包, 减少浪费流量及CPU.

未完待续...

Linux命令之pstree - 以树状图显示进程间的关系

pstree 是一个用于显示当前运行的进程及其父子关系的命令行工具。它以树状图的形式展示进程,能够帮助用户更直观地理解进程之间的层级关系。

1. 基本用法

1.1 运行 pstree

在终端中输入以下命令:

pstree

这将显示当前用户的进程树。

1.2 查看所有用户的进程

如果希望查看系统中所有用户的进程,可以使用 -a 选项:

pstree -a

1.3 显示进程 ID

要显示每个进程的进程 ID(PID),可以使用 -p 选项:

pstree -p

1.4 结合其他选项

您还可以结合多个选项使用。例如,显示所有进程及其 PID:

pstree -ap

1.5 指定某个用户的进程

如果想查看特定用户的进程,可以使用 -u 选项,后面跟用户名:

pstree -u username

1.6 过滤特定进程

可以指定进程名称来过滤输出,例如:

pstree -p | grep process_name

2. 示例

2.1 基本树状图

运行 pstree 命令,您可能会看到如下输出:

init─┬─cron
     ├─sshd───sshd───bash───pstree
     └─systemd───systemd-journal

2.2 含 PID 的树状图

使用 pstree -p,输出可能类似于:

init(1)─┬─cron(123)
         ├─sshd(456)───sshd(789)───bash(101112)───pstree(131415)
         └─systemd(161718)───systemd-journal(192021)

2.3 显示所有进程

运行 pstree -a,将显示包含命令行参数的完整进程树:

init─┬─cron
     ├─sshd -D
     └─systemd --system --deserialize 23

TiDB 踩坑

昨天使用 TiDB 查数据发现问题

select FROM_UNIXTIME(created, '%Y%m%d') as dates from `table` 
#返回 20181122

但是

select FROM_UNIXTIME(created, '%Y%m%d') as dates from `table`  union all select FROM_UNIXTIME(created, '%Y%m%d') as dates from `table`
#返回 201811 ..... 后面的 %d 就失效了 

早上问DBA 解释 TiDB 就存在这个问题
解决方案如下 转 字符串

 FROM_UNIXTIME(created, '%Y%m%d')  
# 更换
 CAST(FROM_UNIXTIME(created, '%Y%m%d') AS CHAR)  `day`

又遇见新坑

# 取大于created时间 最近一个ID
SELECT `id` FROM `table` WHERE `created` >= 1542178800 LIMIT 1

一般mysql 下 不需要加order by 默认排序就是 id 正序
但在TiDB 下 这么查 sql 返回的会是一个随机的ID (怀疑分片问题)

养成好习惯 用这类sql 加上 order by id 排下序

">