Redis初步使用总结

项目组里一直没有使用Redis,经过对Redis的简单了解,我就觉得这么神奇好用的玩意儿,不去用它真的是与IT社会脱轨。再者,看看外面的PHP面试,对Redis、Memcached的要求可不仅仅是说会用就行了,要掌握原理、数据结构、两者不同应用场景,特别是高流量下的优化处理。


聊聊自己曾经开发的小功能,现在回想,用了Redis,不管是效率还是代码的简洁度,都会有个大提升。

①  同步返回结果,异步请求第三方

            

图1

            

图2

需求是:APP发起请求,由于第三方通道的同步返回特别慢,避免用户等待时间过久,所以同步返回APP请求已提交的信息,通过另外的页面记录告知此次请求的结果。异步请求第三方通道,判断同步结果,若成功继续进行查询,查询结果可能会是等待,需要一直查询直到结果为成功或失败,结果都正常则更新A表的指定字段。

在初步请求成功的前提下,第三方会有个异步回调,这里当时有点疑问,既然有回调,为什么要搞那么麻烦前面还要查询,后来发现因为要更新失败的情况啊~接着继续调另外的第三方接口,同样判断同步结果,再进行查询,一直查一直查。

听Java的开发同事说,他是用死循环一直查询,直到有结果。当然我不知道Java的内部机制是怎么样的,如果PHP死循环查询,要是对方服务器出问题了,刚好这时候用户并发请求也多,这不是要让服务器崩溃嘛,我们可不能因为别人的问题搞蹦自己呢,后来就设置查个20次好了。

那么在这个初步请求过程里,异步逻辑必不可少,由于另外一套代码是Java开发的,内部使用一个子线程非常方便。而PHP不管使用哪种运行模式,感觉都没有有效的方法。

 

查找相关资料,发现CURL拓展可以通过HTTP请求的方式,实现另类的伪异步。设置CURLOPT_TIMEOUT这个参数可以让请求脚本忽略等待。这存在不少问题,比如增加一个HTTP请求,相当于用户请求一次占用了两次请求的资源,要是并发大,直接把性能砍了一半;而且必须最小等待1秒钟,既然想用异步,这1秒的等待是毫无意义的;虽然说服务器HTTP请求本身出错几率极低,同样的在并发大的情况下,要是运行出错,没有任何补救机制。

另外考虑过,使用crontab命令定时执行PHP脚本,查询表内是否存在需要处理的数据。但是要查询的是流水表,数据量相当大,也要考虑定时器时间和请求未执行完成,下个请求冲突等等情况。

后来慢慢了解Redis之后,使用list结构,可以比较方便的解决这个问题。在每次APP请求时,将某个指定字段值添加在尾部,取出数据时先取头部,类似队列的方式,先进先出。创建一个或多个PHP的常驻脚本(这也是个学问),用while(true)走循环,内部使用BLPOP方法取LIST的元素,保证了没有元素的时候,能够堵塞不至于占用太多系统资源。

②  使用Redis生成唯一字段和统计数据

前段时间公司有个外包项目,刚开始多个人一起参与,这种情况下自己写代码,相对要参考他人的想法,后来在比较赶巧的情况下这项目派我去出差了,在后续的新需求和改bug过程中,也就慢慢转移到我一个人这。

在出差途中,甲方对API接口进行压测检验,在TPS仅仅20-30笔/秒的情况下,订单号出现重复。其实这个问题我有担心过,因为各种随机数也好,代码实现的唯一字符串也好,大部分是基于某个时间因子来生成,那么重复是非常可能的事情。

最之前订单号有用时间戳+rand随机数的方式,可能一直没出过问题,也就没有重视,有次就发现由于相同的订单号,导致状态被异常修改,这里说下rand的规则也是用时间作为随机因子来生成随机数。后来建议了使用用户某个唯一性的字段切割一部分填充订单号。

在新的项目中,考虑过这问题,使用了如下代码:

public static function getOrderNo(){
    $orderNo = date('YmdHis') . substr(implode(NULL, array_map('ord',str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
    $tot = 9;
    for ($i=1 ;$i<=5; $i++) {
        srand(self::getMicroseconds());
        $orderNo = substr_replace($orderNo, rand(0, $tot--), -$i, 1);
    }
    return $orderNo;
}
//获取毫秒数
public static function getMicroseconds() {
    $utimestamp = sprintf("%.10f", microtime(true)); // 带微秒的时间戳
    $timestamp = floor($utimestamp); // 时间戳
    $microseconds = round(($utimestamp - $timestamp) * 10000000000); // 微秒
    return $microseconds;
}

第一句代码参考了网上的文章,本质在于uniqid()方法。

uniqid():基于以微秒计的当前时间,生成一个唯一的 ID

当时也有点怀疑,就像刚刚说的,只要是基于时间生成,即时是微妙,都会有几率重复,只是这个几率被逐步的降低了。然后本地测试简单测试了下,还真发现就重复了,几率并没有预想的低,于是参考了另外非后端同事意见,对单个字符用随机数去做替换,每次rand前新定义随机因子,微妙的多位数,这几率总该低了吧。

解释了这么多,其实没啥用,因为压测一进行就重复了。寻找解决的方法倒不复杂,网上查查,他人意见参考,那就上Redis呗。往常由于自己对新技术的深层次原理、优化了解不深等其他原因,不一定有机会使用很多东西,而这次嘛,业务需求给予机会,也推动我进步。

过程其实就很简单,光使用keyvalue方式就好,设置一个自增序列,每次使用incr方法,获取自增后的值,同时设置自定义的到期时间和到达指定值的初始化,只要每次请求能够得到一个唯一的值,那么订单号什么的都是小意思。在我认识中,redis是单进程的,并发应该不会产生重复,(瞎猜的,等待后续研究)。根据结果得到结论,到目前为止,订单号没有任何一次重复了,如果到了某天并发量增了一个数量级发现重复,那我应该也能基于Redis或其他技术想出新办法了。

在其他的请求中,要统计不少的数据结果做判断。有个主要功能业务,接口每次请求,要查询流水表来统计某个数据做限制,这咋说呢,肯定不靠谱了。后来兜兜转转,又加上点新需求,我说既然都用了Redis,全部让棒棒的PHP处理了吧~

 

总结一下来说呢,Redis的初步使用,并发情况下的唯一性很好,key到期时间失效很好,数据高性能存储和获取很好。另外作为初学者其实要担心的问题不多,在流量慢慢增涨的情况下,可能要开始考虑高可用、资源占用等问题,在这个从低到高过程中,要有自信自己能够掌握会Redis深层次的知识。

后续担心PHP连接会不会太多,占用太多进程数;pconnectconnect又有啥区别等等,这又是另外的学习故事了。

 



本周我们使用 Redis 进行了一些实例操作,并进行了相关笔记记录。 首先,我们了解了 Redis 的基本概念和特点。Redis 是一种高性能的键值存储系统,它以内存为主存储方式,可以实现快速的读写操作,同时还提供了多种数据结构的支持,如字符串、哈希、列表、集合等,能够满足不同场景下的存储需求。 在实践中,我们首先进行了 Redis 的安装和配置。我们按照官方文档的指引,下载并安装了 Redis,然后对其进行了简单的配置,包括设置监听端口、配置密码等。同时,我们还学习了一些常用的命令,如 SET、GET、DEL 等,以及相关的配置文件参数的含义。 接着,我们进行了一些基本操作的练习。比如,我们通过命令向 Redis 中新增了一些键值对,并进行了查询和删除操作。我们还尝试了一些 Redis 的高级特性,如使用哈希结构存储和获取数据,并使用列表结构实现了简单的消息队列。 此外,我们还了解了 Redis 的持久化机制。Redis 提供了两种持久化方式,分别是 RDB(快照)和 AOF(追加式文件),可以将内存中的数据定期或根据日志保存到硬盘中,以防止数据丢失。 总结而言,本周我们对 Redis 进行了初步的学习和实践。我们了解了 Redis 的基本概念、安装配置以及常用操作命令,并进行了简单的实例操作。通过这些学习,我们对 Redis使用有了一定的了解,并在后续的工作中可以更好地应用它来解决实际问题。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值