TP3.2 中使用 PHPMailer 发送邮件
Redis作为缓存使用,在值大小为1k的情况下,可以支持到每秒近十万次的set操作,可见redis的运行效率是非常的高的。但是为什么我们还会有的时候会遇到redis的瓶颈呢?一般来说,都是因为我们没有对redis的所有的操作有一个全面直观的了解。
Redis运行模式
Redis是运行在单线程下的,也就是说,一个redis实例最多也就只能占用一个cpu,当redis实例线程运行所使用的cpu到达100%后,就无法进行更多的操作了,甚至从操作系统层面就开始拒绝连接了。然后我们就遇到了最迷茫的事情,为什么我设置了很多的连接,但是都无法连接到redis服务呢,原因大抵如此。
Redis在执行一个操作的时候,其他所有的操作,包括系统的,后台的等等,都会出现阻塞,一旦有阻塞,就会出现返回变慢的情况。
虽然说redis的运行时非常快的,但是也会受到很多其他因素的影响,在分析过程中,要注意都有什么耗时的操作在霸占cpu(依旧是单线程的问题),这些操作能不能分解,这些操作能不能再做缓存,这些操作是否是必要的,在优化处理时都应该考虑这样的问题。
总而言之,redis是以单线程来应对上层多线程的调用,在编码过程中,使用到redis就要考虑到这一层。
Redis操作中需要规避的一些问题
Redis提供了比较多的数据结构,让单纯的kv结构更加丰富,但随之而来的问题就是,数据结构越是复杂,操作时间越长,记住redis只能单线程!
当然,redis就是为了大量快速地读写一些数据而生的,放心大胆地去用,不然搭建一个redis干嘛呢?
为了放心地使用redis,下面列举一些需要特别注意,必要时要规避这些操作。这些操作有时会很慢,但是具体有多慢呢?我们不能用通常的模式去理解,如果说这个操作只需要10ms呢?是否算慢呢?当一个操作需要10ms时,这个redis的实例,在1s中只能执行100次同样的操作,这样算快还是慢呢?当redis的调用量上来以后,这个操作就成了系统的瓶颈了。
SISMEMBER
这个操作是查看集合中的成员。在集合较大的情况下,会变得比较慢。所以,一般不要直接返回整个集合中的成员,而是采用标准的调用方式SISMEMBER key member,查看集合是否具有该成员,从而避免大量的无用的数据处理。
SINTER
返回一个集合的全部成员,该集合是所有给定集合的交集。当两个巨大的集合进行交集的运算,其效果也可以是毁灭性的。
LPUSH & RPUSH
在队列头部/尾部插入一串key。这个操作本身并无什么大问题,但是我们又考虑到redis是一个单线程,那么我们一次性插入了大量的值,就会造成阻塞,那么就有必要把这一次操作分散为多次的操作,循环去做了,虽然觉得循环会耗时,但是在没有读写分离的情况下,这种处理方式总归是比直接阻塞redis要来得好的。建议一次性增加200个左右为佳。但是这也受限于key值的大小。具体的问题具体分析,在调试和测试中要注意这部分的耗时,可以控制在10ms以内即可(redis默认超过10ms的操作对于redis是慢的)。
MSET & MGET
批量设置和获取一串key的值。此操作与上面的也是一样的,要考虑到整体的耗时,在需要的时候要做到循环设置/获取,标准也是尽量控制一次操作在10ms以内。
KEYS
KEYS操作,查询并枚举redis中与给定规则相符的key。此物为大杀器,看似每个操作只需要40-70ms,在编码和功能性的测试中,根本无法感知到其带来的恶果,因为70ms实在是很难感知到到底有多长,但是用另一个指标来衡量,就很明显看出来了。取平均值,假设KEYS操作耗时50ms,那么一个redis实例的qps只有可怜的20,还是在不做其他动作的情况下。
此处要着重说明之前的一个线上问题的解决,就是因为KEYS操作引起,最后调用者临时做了读写分离,并且将redis的实例拉到了恐怖的21个才勉强支持起线上的调用量,堪称本司有史以来最豪华redis,并且这个还是在用户数没有暴增的情况下。
所以切记,KEYS是禁止使用的!(后续再新机房中的redis会直接改掉这个操作,具体怎么再来调用KEYS操作,我就不告诉你!)
CONFIG GET & CONFIG SET
非管理人员,禁止使用!
Redis需要注意的操作其实并不多,并且很多情况下,根本不会造成压力,但是这些情况都是需要在编码时注意的,去衡量并正确高效地使用redis。记住一句,我们是单线程!我们是运行在毫秒级别的服务!
Redis的设计中需要注意的
Redis本身没有强的模式,在使用中,所有人都可以随意地设置redis的存储,那么我们要如何才能高效地使用redis呢?有一些问题就需要在存储的设计时要注意了。
Key的命名要简短,且有意义。Key在redis中也是要占用空间的,并且内存是很宝贵的,所以要节约使用。当key名有意义,那么在程序的逻辑处理过程中,就有可能直接获得key名,从而直接去获取到相应的value了。
Value值不宜过大。当value在1k的时候,redis可以支持到10w/s左右,那当value的大小达到10k,那么redis就只能支持到1w/s左右了。可见value的大小对于redis的效率还是很有影响的。所以,每个key的value值要尽量精简,哪怕是冗余一些多余的key也不要制造一个超级大的key因为那样的话,还不如使用其他的存储来得实惠了。
返回的数据要尽量紧凑,小型。虽然redis没有对客户端做什么限制,但是他是预留了功能的,可以在一次请求超过了多久,或者是总数据量超过多少,还有就是规定时间内发送数据超过多少的情况下,就可以直接杀死链接,没有任何返回,也没有任何道理。所以要注意,只返回有用的东西。
对于list要活学活用。我们不能做KEYS,那么当我们又需要将某种类型的KEY进行计数的时候,我们就应该去使用list了。将一些相关的key都存放于一个list中,我们就可以轻松地使用LLEN来获取到list的长度,其效果可以抵消一部分KEYS的应用场景了。对于list也并不是万灵药,虽然在很多情况下,list可以消耗更少的资源来做到和key相同的效果,但是也要注意,list不适宜过长,要做到可控。
Set(集合)的运用,与list类似,就不多描述了,参见一下redis的命令列表吧。这也是一种非常有用的数据结构。
对于list和set还是要说两句,正因为有了这样的数据结构,我们得以用更小的代价管理更加庞大的key。
要用SETEX去设置key的过期时间。Redis本身就是一个缓存,只是一个缓存,在需要持久化的场景下,不要妄想能在redis中做的存储大量的值。所以redis中尽量存储一些不需要持久化的东西,并且如果关联到持久化的数据的话,最好能有缓存载入的脚本,能手工载入一些缓存数据,在出现整个redis集群完全崩溃的情况下可以减少crash到数据库的时间。
我们是单线程!又说到这个话题了,redis就是个单线程,我觉得也不太可能改造了。那么我们怎么来应对大量并发呢?
其实并不是没招,招有的是。
方法一,我们可以使用队列,将请求放入队列中,再取出处理,将大量的并发序列化,持续地,高效地在redis中处理。
方法二,读写分离。在有可能的情况下一定要具备读写分离功能。当序列化后依然无法响应大量的并发,那么我们就需要做读写分离了。这样只要在量上来时,多拉实例,并添加到负载均衡即可了。
要为分布式做好准备。现在本司在redis的分布式上选型是twemproxy,在分布式的情景下,很多操作会受到限制,所以,当可以预见到redis在将来会增长到需要做分布式的场景下,就需要注意了,在编码中就要有意去规避这些操作,以减少将来修改的成本。
如何去界定一个redis是否需要做成分布式,建议当redis的数据量超过15G时就需要更换为分布式,当redis的数据量达到8G,并且有增长的趋势时,就需要考虑分布式的方案了。
就本司当前情况来看,只有少量的一些应用会达到分布式的要求,其他的,因为历史原因,不适合马上切换为分布式。大量的应用还是处于读写分离即可支持的情况下,所以不一定上线,但一定要有读写分离的方案,或者是预案。
后续的一些展望
在后续的规划中,redis更加倾向于小型化,轻量化的部署。这里有两条路,一是集中化的分布式redis,虽然将数据打散了,这样解决了容量的问题,但是,但是!我们特么还是单线程!同时,集群化,也限制了一些特殊的操作,但是这些小技巧有的时候又是非常nice的。那么我们就提出了第二个方案,二级缓存。在持久化层上有几个集群,这些集群又可做读写分离,在这个大容量的缓存上每个服务,甚至是每个进程都对应一个自己的超级轻量化redis,不需要预加载,不怕数据丢失,随时可重启的这种,当然,可以做到读写分离也是极好的。每个关于缓存的请求,都会先去查询二级缓存中的redis(轻量化的那个),当不命中时,会去一级缓存(大容量的那个)中查询,如果命中,则将数据加载至二级缓存,返回结果。当一级缓存也不能命中时,就要去到持久化层获取实际的数据,并同时将数据加载到一级和二级缓存了。
二级缓存的模式下,又涉及到读写分离等问题,但那时,将是千万级别并发访问了,希望将来有一天能够看见。
TP3.2 中使用 PHPMailer 发送邮件的更多相关文章
- ThinkPHP 中使用 PHPMailer 发送邮件 支持163和QQ邮箱等
[摘要]ThinkPHP是一个开源的PHP框架, 是为了简化企业级应用开发和敏捷WEB应用开发而诞生的.本文介绍ThinkPHP 中使用 PHPMailer 发送邮件. PHP是自带可以发送邮件的Ma ...
- 在Thinkphp3.2 中使用PHPMailer 发送邮件
phpmailer发送邮件是php开发者首选的一个邮件发送插件了,下面我来介绍怎么集成phpmailer到thinkphp框架了,有需要了解的朋友可参考. phpmailer发送邮件功能很强大,今天真 ...
- Thinkphp中使用PHPmailer发送邮件
在ThinkPHP\Extend\Vendor\目录下放入PHPMailer文件夹,里面包含以下文件 重置密码发送邮件 public function recover(){ if($this-> ...
- 在Yii Framework中利用PHPMailer发送邮件(2011-06-02 14:06:23)
转载▼ 标签: it 分类: 技术共享 官方扩展链接:http://www.yiiframework.com/extension/mailer/这个扩展配置十分方便,如果有问题的话,可以打开Debug ...
- thinkphp5中使用phpmailer实现发送邮件功能(转载)
一.开启SMTP服务(使用php发送邮件需要用到SMTP服务,这里以163邮箱的SMTP服务为例). 1.登录163邮箱,在首页上找到“设置”. 2.选择开启的服务,一般都全选,POP3/SMTP/I ...
- thinkphp中怎么使用phpmailer发送邮件
phpmailer发送邮件是php开发者首选的一个邮件发送插件了,下面我来介绍怎么集成phpmailer到thinkphp框架了,有需要了解的朋友可参考. phpmailer发送邮件功能很强大,今天真 ...
- thinkphp5中使用phpmailer实现发送邮件功能
一.开启SMTP服务(使用php发送邮件需要用到SMTP服务,这里以163邮箱的SMTP服务为例). 1.登录163邮箱,在首页上找到“设置”. 2.选择开启的服务,一般都全选,POP3/SMTP/I ...
- 利用PHPMailer发送邮件时报错
利用thinkphp集成PHPMailer发送邮件时报错:Failed to connect to server: Unable to find the socket transport “ssl” ...
- 使用PHPmailer发送邮件的详细代码
一.使用PHPMailer发送邮件的原因 PHP有内置的mail()方法,但是由于一些主机空间不支持该方法,所以经常会遇到无法发送邮件的情况. 所以,可以下载PHPMailer类,实现邮件发送. 二. ...
随机推荐
- Centos7 开放防火墙端口命令
Centos 7 使用firewalld代替了原来的iptables,使用方法如下: >>>关闭防火墙 systemctl stop firewalld.service ...
- jdk源码->集合->LinkedList
类的属性 public class LinkedList<E> extends AbstractSequentialList<E> implements List<E&g ...
- 关于Mysql模糊查询的优化-全文检索和Like的使用
表A:CREATE TABLE `tableA` (`id` int(11) NOT NULL auto_increment,`content` varchar(256) default NULL,P ...
- jsp中 scope="application" 表示
jsp中 <jsp:useBean id="countbean" scope="application" class="count.counte ...
- python-networkx学习(1)
介绍: networkx是python的一个库,它为图的数据结构提供算法.生成器以及画图工具.近日在使用ryu进行最短路径获取,可以通过该库来简化工作量.该库采用函数方式进行调用相应的api,其参数类 ...
- Redis进阶实践之九 独立封装的RedisClient客户端工具类
一.引言 今天开始有关Redis学习的第九篇文章了,以后肯定会大量系统使用Redis作为缓存介质,为了更好的更好的Redis,自己写了两个工具类,但是这两个工具类,没有提供一致的接口,是为了使用的独立 ...
- Servlet第六篇【Session介绍、API、生命周期、应用、与Cookie区别】
什么是Session Session 是另一种记录浏览器状态的机制.不同的是Cookie保存在浏览器中,Session保存在服务器中.用户使用浏览器访问服务器的时候,服务器把用户的信息以某种的形式记录 ...
- ipython的用法详解
ipython是一个升级版的交互式python命令行工具. ipython安装 pip install ipython 等到命令执行完成后显示successfully表示完装成功 在命令提示符下输入i ...
- python的组合数据类型及其内置方法说明
python中,数据结构是通过某种方式(例如对元素进行编号),组织在一起数据结构的集合. python常用的组合数据类型有:序列类型,集合类型和映射类型 在序列类型中,又可以分为列表和元组,字符串也属 ...
- 利用rsync+inotify实现数据实时同步脚本文件
将代码放在Server端,实现其它web服务器同步.首先创建rsync.shell,rsync.shell代码如下: #!/bin/bash host1=133.96.7.100 host2=133. ...