{
"query": {
"match_all": {}
}
}
专注WEB编程开发技术
{
"query": {
"match_all": {}
}
}
MiniFramework 是一款遵循 Apache2 开源协议发布的,支持 MVC 和 RESTful 的超轻量级 PHP 开发框架。MiniFramework 能够帮助开发者用最小的学习成本快速构建 Web 应用,在满足开发者最基础的分层开发、数据库和缓存访问等少量功能基础上,做到尽可能精简,以帮助您的应用基于框架高效运行。
近日,MiniFramework 已经入驻码云 Gitee,在未来的跟新迭代过程中,框架源代码将同时推送到 GitHub 和码云 Gitee 的代码仓库中,两个平台上代码保持同步。
GitHub地址:https://github.com/jasonweicn/miniframework
码云地址:https://gitee.com/jasonwei/miniframework
最近的互联网线上事故发生比较频繁,9月19日网上爆料出顺丰近期发生了一起线上删库事件,在这里就不介绍了。
在这里讲述一下最近发生在我公司的事故,以及如何避免,并且如何处理优化。 该宕机的直接原因是使用 Redis 的 keys * 命令引起的,一共造成了某个服务化项目的两次宕机。
间接原因还有很多,技术跟不上业务的发展,由每日百万量到千万级是一个大的跨进,公司对于系统优化的处理优先级不高,技术开发人手的短缺。
第一次宕机
2018年9月13日的某个点,公司某服务化项目的 RDS 实例连接飙升,CPU 升到 100%,拒绝了其他应用的所有请求服务。
整个过程如下:
我们在项目调优过程中,通常会对代码的运行时间进行统计,以便了解程序运行的性能和效率,这些统计结果将作为代码优化时的重要指标,帮助开发者有针对性的进行调优工作。
MiniFramework 在 1.3.0 版本中,新增了 Debug 类,其中包含有时间统计功能的若干方法,可以非常便捷地帮助开发者实现上述统计需求,下面我们来通过示例代码介绍具体实现方法。
首先,假设我们有一个名为 Index 的 Controller,并且其中包含有一个名为 index 的 Action(MiniFramework下载包中已经包含),我们将代码写在这个 Action 中,如下:
MiniFramework 是一款遵循 Apache2 开源协议发布的,支持 MVC 和 RESTful 的超轻量级 PHP 开发框架。MiniFramework 能够帮助开发者用最小的学习成本快速构建 Web 应用,在满足开发者最基础的分层开发、数据库和缓存访问等少量功能基础上,做到尽可能精简,以帮助您的应用基于框架高效运行。
MiniFramework于2018年9月13日发布1.4.0版本,变化有:
* 新增Log类,用于以日志的形式记录代码运行报错和开发者自定义的调试信息。
* 新增常量LOG_ON,用于控制日志功能的开启和关闭(生产环境建议关闭)。
* 新增常量LOG_LEVEL,用于定义可被写入日志的错误等级。
* 新增常量LOG_PATH,用于定义日志存储路径。
* 新增Debug类的varType方法,用于判断变量类型。
* 改进优化异常控制相关功能。
在开发 Socket 通信时,由于 TCP 协议的特性,在网络状况不佳的情况下,数据传输过程中经常会出现半包或粘包。为解决这一问题,通常我们需要自定义一个通信协议,增加一个 HEADER 部分,并在其中对数据包的长度进行声明,下面分享一段封包和解包的示例代码,可用于 Golang 开发 Socket 时处理数据传输,具体代码如下:
package protocol
import (
"bytes"
"encoding/binary"
)
const (
TCP_HEADER = "TCPHEADER"
TCP_HEADER_LEN = 9
TCP_DATA_LEN = 4
)
// 封包
func Enpack(msg []byte) []byte {
return append(append([]byte(TCP_HEADER), IntToBytes(len(msg))...), msg...)
}
// 解包
func Depack(buffer []byte, readerChannel chan []byte) []byte {
length := len(buffer)
var i int
for i = 0; i < length; i++ {
if length < i + TCP_HEADER_LEN + TCP_DATA_LEN {
break
}
if string(buffer[i:i + TCP_HEADER_LEN]) == TCP_HEADER {
msgLen := BytesToInt(buffer[i + TCP_HEADER_LEN : i + TCP_HEADER_LEN + TCP_DATA_LEN])
if length < i + TCP_HEADER_LEN + TCP_DATA_LEN + msgLen {
break
}
data := buffer[i + TCP_HEADER_LEN + TCP_DATA_LEN : i + TCP_HEADER_LEN + TCP_DATA_LEN + msgLen]
readerChannel <- data
i += TCP_HEADER_LEN + TCP_DATA_LEN + msgLen - 1
}
}
if i == length {
return make([]byte, 0)
}
return buffer[i:]
}
// 整形转换成字节
func IntToBytes(n int) []byte {
x := int32(n)
bytesBuffer := bytes.NewBuffer([]byte{})
binary.Write(bytesBuffer, binary.BigEndian, x)
return bytesBuffer.Bytes()
}
// 字节转换成整形
func BytesToInt(b []byte) int {
bytesBuffer := bytes.NewBuffer(b)
var x int32
binary.Read(bytesBuffer, binary.BigEndian, &x)
return int(x)
}
详见代码:
package main
import (
"fmt"
"net"
)
for _, address := range addrs {
// 检查 ip 地址判断是否回环地址
if ipnet, flag := address.(*net.IPNet); flag && !ipnet.IP.IsLoopback() {
if ipnet.IP.To4() != nil {
fmt.Println(ipnet.IP.String())
}
}
}
阳光部落原创,更多内容请访问http://www.sunbloger.com/
最近在一个基于 Web 的 IM 项目中,我采用异步向服务器发起请求拉取最新的聊天内容,服务器端通过 PHP 处理拉取请求,拉取过程是用 10 次循环查询数据库是否有最新的聊天内容。如发现新内容,则立即向浏览器输出,并结束掉本次请求的进程。在这 10 次的循环中,每次查询数据库后,均通过 Sleep 函数让进程暂停 1 秒,那么这个 PHP 进程可能会在服务器端保持 10 秒。
在测试过程中,我发现当这个拉取请求运行期间,其他向服务器端 PHP 发起的请求,均受到影响,响应变的非常慢。
经过一系列的排查,问题始终得不到解决,但当把代码中涉及到 SESSION 的部分全部跳过时,情况发生了变化,所有 PHP 进程都恢复正常的响应速度了。由此,联想到问题可能出在了 SESSION 阻塞机制上了。
1.部署 MySQL 双主(Master – Master)集群
参考我的博文:《MySQL 双主 Master to Master 架构部署方法》
地址:http://www.sunbloger.com/2018/08/16/604.html
假设已经在 IP 为 192.168.0.1 和 192.168.0.2 的两台主机上部署好了 MySQL 双主集群,接下来我们进行 Keepalived 的部署。
代码如下:
// main
package main
import (
"fmt"
)
func main() {
val := []int{7, 3, 8, 1, 0, 2, 5, 9, 6, 4}
fmt.Println(val)
// 冒泡排序
for i := 0; i < len(val)-1; i++ {
for j := i + 1; j < len(val); j++ {
if val[i] > val[j] {
val[i], val[j] = val[j], val[i]
}
}
}
fmt.Println(val)
}
阳光部落原创,更多内容请访问http://www.sunbloger.com/