首页
留言
友情链接
壁纸
更多
关于
Search
1
dockerfile怎么执行shell脚本(利用tail -f /dev/null命令防止container启动后退出)
5,017 阅读
2
channel常见的异常总结
4,276 阅读
3
支付宝支付配置开发流程
1,431 阅读
4
HTTP 协议中的Content-Encoding
1,287 阅读
5
Laravel底层原理(二) —— 契约(Contracts)
950 阅读
PHP
composer
laravel
swoole
Docker
Linux
Go
随笔
mysql
nginx
Search
标签搜索
kratos
golang
微服务
gopher
PHP
Docker
dockerfile
通道
go
defer
alipay
支付
git
phpstorm
IDEA
web安全
漏洞
socket
设计原则
依赖注入
Royal
累计撰写
51
篇文章
累计收到
0
条评论
首页
栏目
PHP
composer
laravel
swoole
Docker
Linux
Go
随笔
mysql
nginx
页面
留言
友情链接
壁纸
关于
搜索到
51
篇与
Royal
的结果
2023-07-08
PHP设计模式遵循6大原则
单一职责原则(SRP) 一个类只负责一个职责,避免一个类承担过多的职责,提高类的可复用性、可维护性和可扩展性。 开放封闭原则(OCP) 对扩展开放,对修改封闭。在不修改原有代码的情况下,通过扩展来实现新的功能。里氏替换原则(LSP) 子类可以替换父类并且可以在不改变程序正确性的前提下工作。即,在任何使用父类对象的地方,都可以使用子类对象替换。依赖倒置原则(DIP )高层模块不应该依赖低层模块,它们都应该依赖于抽象。抽象不应该依赖于具体实现,具体实现应该依赖于抽象。接口隔离原则(ISP) 客户端不应该依赖于它不需要的接口。一个类对另一个类的依赖应该建立在最小的接口上。迪米特法则(LoD) 一个对象应该与其他对象之间保持最少的耦合。一个类应该尽可能少地了解其它类,只与直接的朋友通信。
2023年07月08日
11 阅读
0 评论
0 点赞
2023-07-07
FFI扩展调用C的so动态库
什么是FFI? 此扩展允许在纯PHP中加载共享库(.DLL或.so),调用C函数以及访问C数据结构,而无需深入了解Zend扩展API。这个扩展需要安装 libffi libffi-devel库,编译安装步骤具体步骤就不说了(phpize、configure、make、make install四部曲),另外此扩展要求PHP版本必须是(PHP 7 >= 7.4.0, PHP 8),安装完通过php -m就可以看到下面的模块。FFI的API都有哪些?FFI::addr— 创建指向C数据的非托管指针FFI::alignof— 获取对齐方式FFI::arrayType— 动态构造一个新的C数组类型FFI::cast— 执行C类型转换FFI::cdef— 创建一个新的FFI对象FFI::free— 释放非托管数据结构FFI::isNull— 检查FFI \ CData是否为空指针FFI::load— 从C头文件加载C声明FFI::memcmp— 比较内存区域FFI::memcpy— 将一个存储区复制到另一个FFI::memset— 填充内存区域FFI::new— 创建一个C数据结构FFI::scope— 在预加载期间使用解析的C声明实例化FFI对象FFI::sizeof— 获取C数据或类型的大小FFI::string— 从内存区域创建一个PHP字符串FFI::type— 从C声明创建FFI \ CType对象FFI::typeof— 获取FFI \ CData的FFI \ CTypeFFI怎么用? 直接上例子,下面就是通过一个实例来说明FFI怎么调用C的动态库函数。首先通过FFI::cdef创建一个FFI对象,定义我们动态库中的常量、结构体、函数、以及通过地址加载我们的动态库。 define('ECCref_MAX_BITS', 512); define('ECCref_MAX_LEN', (ECCref_MAX_BITS + 7) / 8); define("SGD_SM3", 0x00000001); $this->ffi = FFI::cdef(<<<EOH // 定义结构体 typedef struct ECCrefPublicKey_st{ unsigned int bits; unsigned char *x; unsigned char *y; } ECCrefPublicKey; // 定义打开设备函数 int SDF_OpenDevice(void **phDeviceHandle); // 定义创建会话句柄函数 int SDF_OpenSession(void *hDeviceHandle, void **phSessionHandle); // 定义生成随机数函数 int SDF_GenerateRandom(void *hSessionHandle, unsigned int uiLength, unsigned char *pucRandom); // 定义杂凑运算初始化函数 int SDF_HashInit(void *hSessionHandle, unsigned int uiAlgID, ECCrefPublicKey *pucPublicKey, unsigned char *pucID, unsigned int uiIDLength); EOH , '/home/sangshuaidong/sdk/libcsapi.so');#加载动态库然后,我们在方法中进行调用c函数。public function openDevice() { $deviceHandlePtr = FFI::new("void*[1]"); $result = $this->ffi->SDF_OpenDevice($deviceHandlePtr); if ($result == 0) { $this->deviceHandle = $deviceHandlePtr[0]; return true; } else { return false; } } public function openSession() { $sessionHandlePtr = FFI::new("void*[1]"); $result = $this->ffi->SDF_OpenSession($this->deviceHandle, FFI::addr($sessionHandlePtr)); if ($result == 0) { $this->sessionHandle = $sessionHandlePtr[0]; return true; } else { return false; } } // 获取16位随机数 public function generateRandom($length) { $randomBuffer = FFI::new("unsigned char[$length]"); $result = $this->ffi->SDF_GenerateRandom($this->sessionHandle, $length, $randomBuffer); if ($result == 0) { $randomHex = bin2hex(FFI::string($randomBuffer, $length)); return $randomHex; } else { return false; } } // hash杂凑运算初始化 public function hashInit($algID = "SGD_SM3", $length = 0) { $result = 0; if ($algID === 'SGD_SM3') { $publicKey =$this->ffi->new("ECCrefPublicKey"); $publicKey->bits = 0; $unsignedCharType = FFI::arrayType(FFI::type('unsigned char'), [ECCref_MAX_LEN]); $publicKey->x = FFI::cast('unsigned char*', FFI::new($unsignedCharType)); $publicKey->y = FFI::cast('unsigned char*', FFI::new($unsignedCharType)); $result = $this->ffi->SDF_HashInit( $this->sessionHandle, SGD_SM3, FFI::addr($publicKey), FFI::addr(FFI::new("unsigned char")), $length ); } else { // 其他算法的处理,根据实际情况进行设置 } if ($result == 0) { return true; } else { return false; } } 最后,我们通过执行可执行程序可以看到成功输出!
2023年07月07日
269 阅读
0 评论
1 点赞
2023-06-21
线上服务怎么部署golang应用程序
编译我们的golang项目并生成可执行程序(二进制文件)go build main.go我们需要考虑将应用程序作为系统服务运行。为此,我们需要编写一个systemd服务文件。在/etc/systemd/system/目录中,使用vim或nano等编辑器创建一个新文件,文件名称为devcloud.service,当然您也可以为其取其他的名称在devcloud.service文件中,添加以下内容:[Unit] Description=devcloud After=syslog.target After=network.target [Service] # Modify these two values and uncomment them if you have # repos with lots of files and get an HTTP error 500 because # of that ### #LimitMEMLOCK=infinity LimitNOFILE=100000 LimitNPROC=100000 Type=forking # 如果要启动的命令是一个daemon进程, 这里的值设置为forking User=root Group=root # WorkingDirectory,程序的运行目录 WorkingDirectory=/home/goproject/src # ExecStart,程序的启动命令,必须为绝对路径,若WorkingDirectory有变动,ExecStart路径对应也要变动 ExecStart=/home/goproject/src/main Restart=always ExecStop=/bin/kill -9 $(pidof main) # Some distributions may not support these hardening directives. If you cannot start the service due # to an unknown option, comment out the ones not supported by your version of systemd. # ProtectSystem=full # PrivateDevices=yes # PrivateTmp=yes # NoNewPrivileges=true [Install] WantedBy=multi-user.target注释:常见的Type类型有以下这些:在Systemd配置文件中,常见的Type选项的取值有以下几种类型:simple:默认类型。当该服务以Type=simple启动时,Systemd会认为启动命令是简单的,不会进一步检查进程的状态。Systemd仅仅启动命令,并认为启动完成后服务已经就绪。forking:当服务启动时,Systemd会认为启动命令会派生(fork)出一个子进程,并认为服务在子进程就绪后才完成启动。此类型的服务会在主进程退出后仍然继续运行。oneshot:适用于只执行一次任务的服务。当服务启动时,Systemd会等待命令执行完成,然后认为服务已经完成启动。dbus:适用于通过DBus启动的服务。notify:适用于服务启动完成后向Systemd发送通知的情况。idle:适用于服务在空闲状态时启动的情况。exec:仅执行一次命令,不会认为服务在命令执行完成后就绪。以上是常见的Type选项的取值类型。根据您的需求和服务的特性,选择适合的Type选项来定义服务的启动类型。保存文件后,使用以下命令启动新的系统服务并将其添加到自动启动中:systemctl start devcloud systemctl enable devcloud执行以上命令后,您的服务应该已经在Linux服务器上成功运行并自动启动,可以使用以下命令查看服务启动状态:systemctl status devcloud重启/停止服务systemctl restart devcloud systemctl stop devcloud
2023年06月21日
222 阅读
0 评论
0 点赞
2022-10-11
SSH通过免密登录实现程序远程批量部署
需求最近在部署程序的时候发现,一共三个语言,6台设备,每台设备3个模块,每个模块3种语言,总共6台设备下来要部署54个程序,工作重复繁琐不说,很容易出现漏部署或者错误,想到了使用一键脚本部署程序的方式,把程序的tar包和shell脚本分别通过统一入口放置,在入口处执行脚本,分别把tar包和执行脚本远程发送到对应的机器和对应的模块上去执行,这样就不用一个一个模块上传程序,再操作,因此想到了一种方式ssh免密登录的方式,通过一台机器去连接到其他所有要部署的机器上,把程序传输过去,前提是这些机器必须是在同一网段内,如果是在一个交换机下面,必须是在同一vlan下面。好了废话不多说,接下去第一步实现免密登录。实现免密登录免密登录很简单,网上一搜很容易就能知道怎么做,我们看下过程:客户端生成公私钥此客户端就是我们要统一放置程序的地方,需要部署的机器我们称之为服务端,本地客户端生成公私钥:(一路回车默认即可)ssh-keygen上面这个命令会在用户目录.ssh文件夹下创建公私钥cd ~/.ssh ls上传公钥到服务端我们随机选择一台机器作为服务端,然后把第一步生成的公钥复制一份传到服务端,然后把公钥内容写入到authorized_keys文件内cat id_rsa.pub >authorized_keys可以看到客户端写入到服务器的 id_rsa.pub (公钥)内容。测试下免密登录ssh root@10.21.4.155第一次需要输入yes才能访问!可以看到我们的免密登录功能做好了,剩下的就是怎么把我们的程序,脚本发送过去,批量执行的问题了。实现一键部署我们做了一个ci.sh的一键部署脚本,所有的程序tar包和部署脚本放在了deploy目录,执行ci.sh就可以了#!/bin/bash set -e ####################################################################### # #4、#5、#6的相应模块的调试口ip left2="10.21.4.121" left2_2="10.21.4.122" right2="10.21.4.124" schedule2="10.21.4.123" executor2_5="10.21.4.125" executor2_6="10.21.4.126" executor2_7="10.21.4.127" left3="10.21.4.131" left3_2="10.21.4.132" right3="10.21.4.134" schedule3="10.21.4.133" executor3_5="10.21.4.135" executor3_6="10.21.4.136" executor3_7="10.21.4.137" # 部署的时候指定执行体被复制到板卡的哪个目录 function help_info() { echo "help" } ####################################################################### script_dir=$(cd "$(dirname "$0")"; pwd) script_name=$(basename $0) script_path=$script_dir/$script_name real_script_path=$(readlink -f `which $script_path`) real_script_dir=$(dirname $real_script_path) image_dir=$real_script_dir/deploy wip="30.30.30.23" bip="192.168.1.46" machine_num=0 ip="0.0.0.0" isw=0 isb=0 isdeploy=0 com=0 lange=0 short_opts="b:w:n:i:dc:l:h" ARGS=`getopt -o ${short_opts} -n 'switch.sh' -- "$@"` if [[ $? != 0 ]]; then echo "Terminating..." exit 1 fi #将规范化后的命令行参数分配至位置参数($1,$2,...) eval set -- "${ARGS}" while true do case "$1" in -w) isw=1 wip=$2 shift 2 ;; -b) isb=1 bip=$2 shift 2 ;; -n) machine_num=$2 shift 2 ;; -d) isdeploy=1 shift 1 ;; -c) com=$2 #echo $com shift 2 ;; -l) lange=$2 #echo $lange shift 2 ;; -h) help_info shift 1 ;; --) module=$2 shift 2 break ;; *) echo "Internal error!" exit 1 ;; esac done ############################################################ #处理剩余的无法识别的参数 unknown_arg=$@ for arg in $unknown_arg do echo "unknown argument $arg" done if [[ ${#unknown_arg} -ne 0 ]];then exit 127 fi ############################################################ function deploy() { #将命令行指定的密码机号和模块号映射成具体的模块ip,存放在executor变量中 local executor=$(eval echo \$executor$1_$2) local language=$3 #echo $executor if [[ $language = "java" ]];then ssh -t root@$executor "systemctl stop scheduleClient" if [[ $2 -eq 5 ]];then scp -r $image_dir/java/deploy-java-com$2.sh root@$executor:/home/ scp -r $image_dir/java/de_ht_nt.tar root@$executor:/home/ ssh -t root@$executor "cd /home/ && chmod u+x deploy-java-com$2.sh && ./deploy-java-com$2.sh" elif [[ $2 -eq 6 ]];then scp -r $image_dir/java/deploy-java-com$2.sh root@$executor:/home/ scp -r $image_dir/java/ub_ng_nt.tar root@$executor:/home/ ssh -t root@$executor "cd /home/ && chmod u+x deploy-java-com$2.sh && ./deploy-java-com$2.sh" elif [[ $2 -eq 7 ]];then scp -r $image_dir/java/deploy-java-com$2.sh root@$executor:/home/ scp -r $image_dir/java/ce_ht_nt.tar root@$executor:/home/ ssh -t root@$executor "cd /home/ && chmod u+x deploy-java-com$2.sh && ./deploy-java-com$2.sh" fi ssh -t root@$executor "systemctl start scheduleClient" elif [[ $language = "php" ]];then ssh -t root@$executor "systemctl stop scheduleClient" if [[ $2 -eq 5 ]];then scp -r $image_dir/php/deploy-php-com$2.sh root@$executor:/home/ scp -r $image_dir/php/centos_apache_ci.tar root@$executor:/home/ ssh -t root@$executor "cd /home/ && chmod u+x deploy-php-com$2.sh && ./deploy-php-com$2.sh" elif [[ $2 -eq 6 ]];then scp -r $image_dir/php/deploy-php-com$2.sh root@$executor:/home/ scp -r $image_dir/php/debian_nginx_ci.tar root@$executor:/home/ ssh -t root@$executor "cd /home/ && chmod u+x deploy-php-com$2.sh && ./deploy-php-com$2.sh" elif [[ $2 -eq 7 ]];then scp -r $image_dir/php/deploy-php-com$2.sh root@$executor:/home/ scp -r $image_dir/php/ubuntu_apache_ci.tar root@$executor:/home/ ssh -t root@$executor "cd /home/ && chmod u+x deploy-php-com$2.sh && ./deploy-php-com$2.sh" fi ssh -t root@$executor "systemctl start scheduleClient" elif [[ $language == "python" ]];then ssh -t root@$executor "systemctl stop scheduleClient" if [[ $2 -eq 5 ]];then scp -r $image_dir/python/deploy-python-com$2.sh root@$executor:/home/ scp -r $image_dir/python/cm_un_env_v1.tar root@$executor:/home/ ssh -t root@$executor "cd /home/ && chmod u+x deploy-python-com$2.sh && ./deploy-python-com$2.sh" elif [[ $2 -eq 6 ]];then scp -r $image_dir/python/deploy-python-com$2.sh root@$executor:/home/ scp -r $image_dir/python/cm_ca_env_v1.tar root@$executor:/home/ ssh -t root@$executor "cd /home/ && chmod u+x deploy-python-com$2.sh && ./deploy-python-com$2.sh" elif [[ $2 -eq 7 ]];then scp -r $image_dir/python/deploy-python-com$2.sh root@$executor:/home/ scp -r $image_dir/python/cm_dn_env_v1.tar root@$executor:/home/ ssh -t root@$executor "cd /home/ && chmod u+x deploy-python-com$2.sh && ./deploy-python-com$2.sh" fi ssh -t root@$executor "systemctl start scheduleClient" elif [[ $language -eq 0 ]];then ssh -t root@$executor "systemctl stop scheduleClient" #部署php if [[ $2 -eq 5 ]];then scp -r $image_dir/php/deploy-php-com$2.sh root@$executor:/home/ scp -r $image_dir/php/centos_apache_ci.tar root@$executor:/home/ ssh -t root@$executor "cd /home/ && chmod u+x deploy-php-com$2.sh && ./deploy-php-com$2.sh" elif [[ $2 -eq 6 ]];then scp -r $image_dir/php/deploy-php-com$2.sh root@$executor:/home/ scp -r $image_dir/php/debian_nginx_ci.tar root@$executor:/home/ ssh -t root@$executor "cd /home/ && chmod u+x deploy-php-com$2.sh && ./deploy-php-com$2.sh" elif [[ $2 -eq 7 ]];then scp -r $image_dir/php/deploy-php-com$2.sh root@$executor:/home/ scp -r $image_dir/php/ubuntu_apache_ci.tar root@$executor:/home/ ssh -t root@$executor "cd /home/ && chmod u+x deploy-php-com$2.sh && ./deploy-php-com$2.sh" fi #部署python if [[ $2 -eq 5 ]];then scp -r $image_dir/python/deploy-python-com$2.sh root@$executor:/home/ scp -r $image_dir/python/cm_un_env_v1.tar root@$executor:/home/ ssh -t root@$executor "cd /home/ && chmod u+x deploy-python-com$2.sh && ./deploy-python-com$2.sh" elif [[ $2 -eq 6 ]];then scp -r $image_dir/python/deploy-python-com$2.sh root@$executor:/home/ scp -r $image_dir/python/cm_ca_env_v1.tar root@$executor:/home/ ssh -t root@$executor "cd /home/ && chmod u+x deploy-python-com$2.sh && ./deploy-python-com$2.sh" elif [[ $2 -eq 7 ]];then scp -r $image_dir/python/deploy-python-com$2.sh root@$executor:/home/ scp -r $image_dir/python/cm_dn_env_v1.tar root@$executor:/home/ ssh -t root@$executor "cd /home/ && chmod u+x deploy-python-com$2.sh && ./deploy-python-com$2.sh" fi #部署java if [[ $2 -eq 5 ]];then scp -r $image_dir/java/deploy-java-com$2.sh root@$executor:/home/ scp -r $image_dir/java/de_ht_nt.tar root@$executor:/home/ ssh -t root@$executor "cd /home/ && chmod u+x deploy-java-com$2.sh && ./deploy-java-com$2.sh" elif [[ $2 -eq 6 ]];then scp -r $image_dir/java/deploy-java-com$2.sh root@$executor:/home/ scp -r $image_dir/java/ub_ng_nt.tar root@$executor:/home/ ssh -t root@$executor "cd /home/ && chmod u+x deploy-java-com$2.sh && ./deploy-java-com$2.sh" elif [[ $2 -eq 7 ]];then scp -r $image_dir/java/deploy-java-com$2.sh root@$executor:/home/ scp -r $image_dir/java/ce_ht_nt.tar root@$executor:/home/ ssh -t root@$executor "cd /home/ && chmod u+x deploy-java-com$2.sh && ./deploy-java-com$2.sh" fi ssh -t root@$executor "systemctl start scheduleClient" fi } #machine_num、com、lange function exe() { local mchi_num=$1 local com_num=$2 local lang=$3 local all_mchi_num="2 3" local mchi_isexist=`expr index "$all_mchi_num" $mchi_num` #isexit为0,不存在,非0存在 local all_com_num="5 6 7" local com_isexist=`expr index "$all_com_num" "$com_num"` if [[ $mchi_num == "all" ]];then for i in $all_mchi_num do for((j=5;j<=7;j++)) do deploy $i $j 0 #echo $i $j done done elif [[ $mchi_isexist -ne 0 && $com_isexist -ne 0 ]];then deploy $mchi_num $com_num $lange #echo $mchi_num $com_num $lange elif [[ $mchi_isexist -ne 0 && $com_num -eq 0 ]];then #echo $mchi_num $com_num $lange deploy $mchi_num 5 $lange deploy $mchi_num 6 $lange deploy $mchi_num 7 $lange fi } function left() { echo "function left" } function sche() { echo "function sche" } function cmn() { local mchi_num=$1 local com_num=$2 local executor=$(eval echo \$executor$1_$2) local left=$(eval echo \$left$1) local left2=$(eval echo \$left$1_2) local schedule=$(eval echo \$schedule$1) local right=$(eval echo \$right$1) local all_mchi_num="2 3" local mchi_num_isexist=`expr index "$all_mchi_num" $mchi_num` #isexit为0,不存在,非0存在 if [[ $mchi_num_isexist -eq 0 ]];then echo "nothing done!!!" exit 127 fi if [[ $com_num -eq 1 ]];then scp -r $image_dir/cmnmod/web_left.tar root@$left:/home/ scp -r $image_dir/cmnmod/web_left.sh root@$left:/home/ ssh -t root@$left "cd /home/ && chmod a+x web_left.sh && ./web_left.sh" elif [[ $com_num -eq 2 ]];then scp -r $image_dir/cmnmod/csm_left.tar root@$left2:/home/ scp -r $image_dir/cmnmod/csm_left.sh root@$left2:/home/ ssh -t root@$left2 "cd /home/ && chmod a+x csm_left.sh && ./csm_left.sh" elif [[ $com_num -eq 3 ]];then scp -r $image_dir/cmnmod/dispatch.tar root@$schedule:/home/ scp -r $image_dir/cmnmod/dispatch.sh root@$schedule:/home/ ssh -t root@$schedule "cd /home/ && chmod a+x dispatch.sh && ./dispatch.sh" elif [[ $com_num -eq 4 ]];then scp -r $image_dir/cmnmod/right.tar root@$right:/home/ scp -r $image_dir/cmnmod/right.sh root@$right:/home/ ssh -t root@$right "cd /home/ && chmod a+x right.sh && ./right.sh" elif [[ $com_num -eq 5 ]];then scp -r $image_dir/cmnmod/executor1.sh root@$executor:/home/ scp -r $image_dir/cmnmod/executor1.tar root@$executor:/home/ ssh -t root@$executor "cd /home/ && chmod a+x executor1.sh && ./executor1.sh" elif [[ $com_num -eq 6 ]];then scp -r $image_dir/cmnmod/executor2.sh root@$executor:/home/ scp -r $image_dir/cmnmod/executor2.tar root@$executor:/home/ ssh -t root@$executor "cd /home/ && chmod a+x executor2.sh && ./executor2.sh" elif [[ $com_num -eq 7 ]];then scp -r $image_dir/cmnmod/executor3.sh root@$executor:/home/ scp -r $image_dir/cmnmod/executor3.tar root@$executor:/home/ ssh -t root@$executor "cd /home/ && chmod a+x executor3.sh && ./executor3.sh" elif [[ $com -eq 0 ]];then scp -r $image_dir/cmnmod/web_left.tar root@$left:/home/ scp -r $image_dir/cmnmod/web_left.sh root@$left:/home/ ssh -t root@$left "cd /home/ && chmod a+x web_left.sh && ./web_left.sh" scp -r $image_dir/cmnmod/csm_left.tar root@$left2:/home/ scp -r $image_dir/cmnmod/csm_left.sh root@$left2:/home/ ssh -t root@$left2 "cd /home/ && chmod a+x csm_left.sh && ./csm_left.sh" scp -r $image_dir/cmnmod/dispatch.tar root@$schedule:/home/ scp -r $image_dir/cmnmod/dispatch.sh root@$schedule:/home/ ssh -t root@$schedule "cd /home/ && chmod a+x dispatch.sh && ./dispatch.sh" scp -r $image_dir/cmnmod/right.tar root@$right:/home/ scp -r $image_dir/cmnmod/right.sh root@$right:/home/ ssh -t root@$right "cd /home/ && chmod a+x right.sh && ./right.sh" executor=$(eval echo \$executor$1_5) scp -r $image_dir/cmnmod/executor1.sh root@$executor:/home/ scp -r $image_dir/cmnmod/executor1.tar root@$executor:/home/ ssh -t root@$executor "cd /home/ && chmod a+x executor1.sh && ./executor1.sh" executor=$(eval echo \$executor$1_6) scp -r $image_dir/cmnmod/executor2.sh root@$executor:/home/ scp -r $image_dir/cmnmod/executor2.tar root@$executor:/home/ ssh -t root@$executor "cd /home/ && chmod a+x executor2.sh && ./executor2.sh" executor=$(eval echo \$executor$1_7) scp -r $image_dir/cmnmod/executor3.sh root@$executor:/home/ scp -r $image_dir/cmnmod/executor3.tar root@$executor:/home/ ssh -t root@$executor "cd /home/ && chmod a+x executor3.sh && ./executor3.sh" fi } if [[ $module == "left" ]];then echo "function left" elif [[ $module == "right" ]];then echo "right" elif [[ $module == "cmn" ]];then cmn $machine_num $com elif [[ $module == "sch" ]];then echo "sche" elif [[ $module == "exe" ]];then exe $machine_num $com $lange fi
2022年10月11日
208 阅读
0 评论
0 点赞
2022-09-15
记一次线上socket_read的坑
先来看下问题:测试的时候发现三个执行体只有php的执行体所在的板卡CPU占用率居高不下,java和python的则正常,由于服务正在被多人测试,导致登录界面加载很慢,验证码刷新不出等问题。排查:通过排查发现,左括号输出日志,报了8080超时,8080端口为php的服务,而此时拟态大屏在频繁发送数据请求,而右括号服务没有正常响应,导致执行体的客户端一直在等待接收数据,因为执行体作为TCP客户端跟右括号建立通信时需要接收指定的长度才会断开连接,但是使用了socket_set_nonblock非阻塞模式设置,所以如果没有接收到数据就会跳出外层for循环,一直持续4分钟的时间,这样就会导致cpu资源被for循环全部占用。我们先来看下有问题的代码:我们知道socket_read,socket_recv,socket_accept均为默认的阻塞模式,什么是阻塞模式,就是当程序运行到此函数时,会一直读取服务端发来的数据,直到接收满2048个字节的(最大设置65535)长度才会继续往下运行,否则就停留在此处,交由操作系统和底层网络接管程序,一直监听,直到超时为止,所以问题就来了,在这个代码中由于把read设置成了socket_set_nonblock($socket);非阻塞模式,也就是说当运行到这里时,由于右括号服务已经挂了所以不会发送数据,自然而然也不会读到数据,由于又没有超时设置,所以很快就往下继续运行了,跳出本次循环,继续下次循环,这个时间是很短暂的,也就是说当有括号不发数据时,执行体一直在运行for循环,自然而然cpu就飙上去了,直到手动设置的超时4分钟结束才中断连接,也就是这4分钟内其他服务都不能访问!!虽然CPU升高是由于右括号的服务异常,继而导致php执行体服务运行不正常最终导致的,但是我们还是要尽量避免由于别的模块或者服务不正常导致自己的服务出问题继而瘫痪整个系统的情况。要尽量把异常缩小在可控范围内。解决知道问题所在了,那么就很好解决了,可以通过以下方式进行修改:设置为非阻塞模式,并增加读取数据超时时间设置;socket_set_option($socket,SOL_SOCKET,SO_RCVTIMEO,array("sec"=>10, "usec"=>0 ) );记住:一定要注释掉非阻塞改为阻塞,不然即使加了阻塞超时设置也不会生效,因为本质是非阻塞,非阻塞就是死循环。增加多路复用阻塞:假如我一定要用非阻塞设置该怎么办呢?办法很多,那就是在read前面加多路复用阻塞:参数 描述read 指向一组等待可读性检查的套接字write 指向一组等待可写性检查的套接字except 指向一组等待错误检查的套接字tv_sec 用来设置select()的等待时间,秒tv_usec两者组成了 用来设置select()的等待时间,微妙这种方式也很好理解,就相当于在read非阻塞模式前加了阻塞判断,select来监听read的数据。当读取出来数据为空时会一直读,直到10s为止,可以理解为比sleep()更高级点,PHP的socket_select函数也是调用系统的select函数实现的。PHP中socket_select()函数传入的read和write数组是引用传入的,所以每次调用socket_select()后read和write或者except数组中会包含最新的可以使用的资源数组。传入的是要监视的,而调用socket_select后得到的是可以用的。多路是指多个客户端连接socket,复用就是指复用少数几个进程,多路复用本身依然隶属于同步通信方式,只是表现出的结果看起来像异步,这点值得注意.目前多路复用有三种常用的方案,依次是:select,最早的解决方案poll,算是select的升级版epoll,目前的最终解决版,解决c10k问题的功臣使用其他方式其实该问题的本质还是解决死循环过程中CPU过高的问题,只不过我们改为阻塞,就避免了程序死循环过程中被过多占用CPU资源的问题,我们其实可以直接暴利一点使用sleep(),判断当接收不到数据时 就sleep来释放资源,不过这种方式过于暴利,会影响性能,你要知道循环一次sleep1毫秒 循环10000次就是10s 不可想象!!总结 通过以上总结,我们在使用socket通信时,如果对并发量要求不高,尽量使用阻塞模式,由于我们使用了负载均衡,所以对单机并发量不是特别要求。阻塞的socket函数在调用send,recv,connect,accept等函数时,如果特定的条件不满足,就会阻塞其调用线程直至超时,非阻塞的socket恰恰相反。非阻塞模式一般用于需要支持高并发多QPS的场景(如服务器程序),但是正如前文所述,这种模式让程序的执行流和控制逻辑变得复杂;相反,阻塞模式逻辑简单,程序结构简单明了,常用于一些特殊场景中。应用场景一:某程序需要临时发送一个文件,文件分段发送,每发送一段,对端都会给予一个响应,该程序可以单独开一个任务线程,在这个任务线程函数里面,使用先send后recv再send再recv的模式,每次send和recv都是阻塞模式的。应用场景二:A端与B端之间的通信只有问答模式,即A端每发送给B端一个请求,B端比定会给A端一个响应,除此之外,B端不会向A端推送任何数据,此时A端就可以采用阻塞模式,在每次send完请求后,都可以直接使用阻塞式的recv函数接收应答包。
2022年09月15日
290 阅读
0 评论
1 点赞
1
...
3
4
5
...
11