2020年5月9日星期六

oracle云服务器申请

oracle之前提供了免费的云服务器,据说是终身免费的。不过之前申请后用了一段时间居然被删除了!当时也没想再用,因为速度也不快,不过现在有需要把它重新用起来,于是就重新申请了一个来搭建fq的服务。
oracle的云服务器创建还是比较简单,不过有个坑的地方是有两个地方的防火墙设置,设置ok后才能使用。
第一个地方:云服务器的子网里面有设置防火墙,需要在入站规则里面把服务的端口打开。
第二个地方:在云主机上面,需要把iptables对应的端口打开。
root@instance-xxx:/home/ubuntu# iptables -L
Chain INPUT (policy ACCEPT)
target     prot opt source               destination
ACCEPT     all  --  anywhere             anywhere             state RELATED,ESTABLISHED
ACCEPT     icmp --  anywhere             anywhere
ACCEPT     all  --  anywhere             anywhere
ACCEPT     udp  --  anywhere             anywhere             udp spt:ntp
ACCEPT     tcp  --  anywhere             anywhere             state NEW tcp dpt:ssh
REJECT     all  --  anywhere             anywhere             reject-with icmp-host-prohibited
可以看到没有打开我们的服务端口,需要增加一条INPUT规则:
iptables -i INPUT 2 -m tcp --dport 10086 -j ACCEPT

注意不要添加到最后面,-i INPUT 2 即添加到第二条规则。然后就可以访问我们的服务了。

2017年11月8日星期三

分布式锁的使用

最近项目碰到一个问题,涉及到分布式锁的使用,场景:多个客户端同时上传文件,server可能同时写文件,由于腾讯云的文件系统(COS:对象存储)对同时多个相同文件上传时,会移动其中一个文件,导致会有一个写失败,因此需要server在写的时候用锁来避免竞争。

同事一开始想的方案是直接用个文件来做锁:任何一个server收到上传请求的时候,会创建一个文件(名字用上传文件名来命名),多个server同时创建文件时,只会有一个创建成功,这样就可以锁住了。然后锁失败的server就反复读这个文件,直到获得锁的一端处理完数据,删除这个文件为止。

这个方案还是有一些问题的:比如如果获取锁的一方挂了,就会导致锁一直不会被销毁,这样其他server就会上传不了文件了。

对于分布式锁,之前用得最多的就是zk了,这次又重新复习了一下分布式锁的内容,网上有几篇文章说的比较好的:
分布式锁的几种实现方式:http://www.hollischuang.com/archives/1716,这篇文章谈到了分布式锁的几个要求:
这把锁要是一把可重入锁(避免死锁)
这把锁最好是一把阻塞锁(根据业务需求考虑要不要这条)
有高可用的获取锁和释放锁功能
获取锁和释放锁的性能要好
其实主要是避免死锁,和阻塞,失效时间,性能问题还在其次。文章还对几种锁:数据库锁,缓存锁,zk做了分析。从结论和我们实际应用来看,还是zk比较靠谱一点。

还有一篇文章谈到了redis做分布式锁的问题,里面对锁的机制和问题也做了很深入的分析。
http://zhangtielei.com/posts/blog-redlock-reasoning.html 。最开始我们也考虑过用redis做分布式锁,但是过期时间很不好设置。最后也放弃了redis作为分布式锁的方案。

我们最后用了什么方案呢?没用redis,也没用zk,只是做了简单的重试,这样就基本解决了问题。之所以用这个方案,一个时间成本考虑,一个是从现状分析:并发的情况不多,出现冲突的时候可以重试一下。所以说在分布式领域,有时候很难有完美的技术解决方案,但是根据实际情况可以采用更灵活的方案来解决问题。

2016年7月20日星期三

Redis 内存容量优化

在上一篇blog中(http://wadeling.blogspot.com/2016/07/redis.html),提到接手的一个redis服务,这个redis服务一开始是完全用string类型来存储key值,导致需要的内存容量非常的大。而且咨询使用方,有可能业务量还要几倍的上涨,而我们现在的机器只有16G内存,就算加内存,内存压力也太大了。于是有了内存优化的想法。
查询了网络上的一些优化文章,通过实验,发现还是有不少优化效果。具体思路就是把string类型的数据转成hash来存,同时保证每个hashkey里面的filed个数在一定范围内,这样redis会把hash的内存做优化处理,减小了内存的使用量。经过实验,100万个key,采用string类型存储,需要88M的内存,如果用hash来存,只需要45M内存。
优化方案如下:
1.查看redis的hash设置
通过cli方式查看:config get hash-max-ziplist-entries,值是512.
config get hash-max-ziplist-value,值是64.
即每个hashkey里面的field数目为512一下,value长度是64字节以内时,redis会对内存做优化。
2.对10万个key做分hash存储

//把md5字符串转成整数,具体方法是取前面8个字符,用base_convert转成10进制
$md5int = $this->md5str_to_int($md5str);

//3000为估算,即最后会有3000个hashkey,每个hashkey里面大概有300多个field,满足要求
$key = $md5int % 3000;

//hset来存入
$ret = $this->redis->hSet($key,$md5str,$value);


参考:
redis内存容量优化
Redis内存优化案例
instagram使用redis内存优化
redis官方内存优化方案

2016年7月12日星期二

redis内存容量估算

最近刚接手一个redis服务,由于是内部使用,所以在redis前端封装了一层代理,用于内部协议和redis协议的转化,并不复杂。但是使用方刚使用两天,就发现内存爆量了。具体现象是redis返回的错误:OOM command not allowed when used memory > 'maxmemory',使用方给出的请求量是:5000万key,每个key40字节(string类型),每个value8字节,这样算下来只要2.4G内存啊,怎么一下内存就爆了。
我也是刚接触redis,只好研究了一番,还好网上有一篇文章,详细说明了redis的容量估算问题,简单的说就是redis占用的内存除了业务数据之外,还有redis自己的数据结构也会占用一部分内存,所以实际占用内存会大于业务数据的。链接在此:http://www.searchdatabase.com.cn/showcontent_55189.htm
根据文章提供的公式,结合使用方提供的数据,估算的容量如下:
1.首先是计算公式:
string类型的内存大小 = 键值个数 * (dictEntry大小 + redisObject大小 + 包含key的sds大小 + 包含value的sds大小) + bucket个数 * 4

2.根据使用方提供的数据,占用的redis内存容量如下:
dictEntry大小: 16 字节
redisObject大小:16字节
key:40字节, sds对象:9 字节。总共是49字节,按jemalloc分配机制会占用到64字节。
value:8字节,sds对象:9字节,总共是17字节,按jemalloc分配机制会占用到32字节。
以上的内存占用量为:
 (16 + 16 + 64 + 32)* 5000*1000*10 = 6.4G

bucket个数大概为6000万(5000万向上取整到2的n次方,即2的26次方,6000多万)
bucket大小:6000万*4 = 240M左右。

所以总容量为6.4G左右,而redis的配置里面maxmemeroy只配置了4G,难怪要报错了。修改配置后,运行正常了。
从redis里面也可以看到峰值使用内存为6.44G, 和计算出来的容量是吻合的.











2016年6月29日星期三

PHP SSH2 的各种问题

最近两天,不断碰到php ssh2的问题,总结下来有几个:
1.PHP Warning: ssh2_scp_send(): Failed copying file
 此问题出现在传大文件的时候
2.PHP Warning: ssh2_exec(): Unable to request a channel from remote host
 连接某台机器的时候,执行shell命令的时候。其他机器没问题。

对于第一个问题,测试机上没问题(php ssh2 扩展版本为0.11.3),生产环境有问题(php ssh2 版本为 0.11.0),所以更新生产环境为0.11.3。但是测试还是有问题,百思不得其解。
后面再更新为0.13 stabel版本,ssh2_scp_send 不再报错了,但是传文件后发现文件md5结果不一样!又再google一番,在ssh2_scp_send之后增加一句:ssh2_exec($con, 'exit');这样才ok了。
但是在测试的时候,发现另外一个新的问题:
php: symbol lookup error: /usr/local/php/lib/php/extensions/no-debug-zts-20100525/ssh2.so: undefined symbol: libssh2_session_set_timeout
然后 nm ssh2.so |grep libssh2_session_set_timeout,发现这个函数是引用的外部实现。那这个函数在哪个so里面呢?找了一下,在libssh2.so.1里面,但是为啥没找到呢。
和运维同学想了半天,最后发现/etc/ld.so.conf.d/libssh2.conf 这个文件里面没有把 libssh2.so.1的路径包含进去,最后修改libssh2.conf文件,增加 /usr/local/libssh2/lib,这下ok了。

总结:碰到过两次php扩展版本的问题,之前碰到过memcache的问题,也是用的beta版本导致很多问题。这次也是一样。所以以后任何的扩展,都要仔细检查是否是stable版本的。

2016年3月31日星期四

php foreach reference 导致的问题

今天碰到一个奇怪的问题,在一个php脚本中写了一个foreache循环,遍历一个数组,同时修改数组里面的元素。大致就是这样:
foreach ($a as $key => &$value) {
   $value['ttt'] = '123';
}
forearch ($a as $key => $value) {

}
结果第二次循环的时候,数组最后一行数据居然没有了。
第一次循环完dump出来的数组又是对的,但是其中一行有点奇怪,大概是这样:
 &array(1) {
    [0]=>
    &array(20) {
      ["sampleID"]=>'aaa'
    }
 }
和这个有没有关系呢?搜了一圈,找到原因了。
这篇解释得很清楚:
php foreach reference
解决方法就是在使用引用完后要unset一下。php manual也有说明
php:foreach

2016年2月23日星期二

“Illegal double … value found during parsing” 错误

刚刚碰到的一个问题,数据提交时报"Illegal double '20160221E0259700' value found during parsing"错误。但是程序运行了一段时间,怎么会报错呢?查了一下,带"E"的串会被PHP认为是double变量,而要更新的这个字段是一个varchar类型,所以导致错误。
之前为啥没报错呢,因为代码太搓:update strid=2016123456,这样就没报错,实际上应该是update strrid='201612345'。坑啊!