生产者向消息队列发送一个消息之后,只能被消费者消费一次。
消息生产者向频道发送一个消息之后,多个消费者可以从频道订阅到这条信息并消费。
发布与订阅模式与观察者模式有以下不同:
- 观察者模式中,观察者和主题都知道对方的存在,而在发布与订阅模式中,发布者与订阅者不知道对方的存在,它们之间通过频道进行通信。
- 观察者模式是同步的,当事件触发时,主题会调用观察者的方法,然后等待方法返回;而发布与订阅模式是异步的,发布者向频道发出一个消息之后,就不需要关心订阅者何时去订阅这条消息,可以立刻返回。
发送者将消息发送给消息队列之后,不需要同步等待消息接收者处理完毕,而是立刻返回进行其他操作,消息接收者从消息队列中订阅消息之后异步处理。
例如在注册流程中通常需要发送验证邮件来确保注册用户身份的合法性,可以使用消息队列使发送验证邮件的操作异步处理,用户在填写完注册信息之后就可以完成注册,而将发送验证邮件这一消息发送到消息队列中。
只有在业务流程允许异步处理的情况下才能这么做,例如上面的注册流程中,如果要求用户对验证邮件进行点击之后才能完成注册的话,就不能再使用消息队列。
在高并发的情况下,如果短时间有大量的请求达到会压垮服务器。
可以将请求发送到消息队列中,服务器按照其处理能力从消息队列中订阅消息进行处理。
如果模块之间不直接调用,模块之间的耦合性就会很低,那么修改一个模块或者新添一个模块对其他模块的影响就会很小,从而实现可扩展性。
通过消息队列,一个模块只需要向消息队列中发送消息,其他模块可以选择性地从消息队列中订阅消息从而完成调用。
发送端完成操作后一定能将消息发送到消息队列。
实现方法:
- 在本地数据库建一张消息表,将消息数据与业务数据保存在同一数据库实例中,这样就可以利用本地数据库的事务机制。事务提交成功之后,将消息表中的消息转移到消息队列中,若转移成功则删除消息表中的数据,否则继续重传。
接收端能够从消息队列中消费一次消息。
两种实现方法:
- 保证接收端处理消息的业务逻辑具有幂等性:只要具有幂等性,那么消费多少次信息,最后处理的结果都是一样的。
- 保证消息具有唯一编号,并使用一张日志表来记录已经消费的消息编号。
当某个请求能够通过访问缓存得到响应时,称为缓存命中。
缓存命中率越高,缓存的利用率也就越高。
缓存通常位于内存中,内存的空间通常比磁盘小很多,因此缓存的最大空间不可能非常大。
当缓存存放的数据量超过最大空间,就需要淘汰部分数据来存放到达的数据。
- FIFO(First In First Out):先进先出策略,在实时的场景下,需要场景访问最新的数据,那么就可以使用FIFO,使得先进入的数据(最晚的数据)被淘汰。
- LRU(least Recently Used):最近最久未使用策略,优先淘汰最久未使用的数据,也就是上次被访问时间距离现在最久的数据,该策略可以保证内存中的数据都是热点数据,也就是经常被访问的数据,从而保证缓存命中率。算法可基于双向链表+hashMap实现。
当HTTP响应允许进行缓存时,浏览器会将HTML、CSS、JavaScript、图片等静态资源进行缓存。
网络服务提供商(ISP)是网络访问的第一跳,通过将数据缓存在ISP中能够大大提高用户的访问速度。
反向代理位于服务器之前,请求与相应都需要经过反向代理。通过将数据缓存在反向代理中,在用户请求反向代理时直接就可以直接使用缓存进行相应。
使用Guava cache将数据缓存在服务器本地内存上,服务器代码可以直接读取本地内存中的缓存,速度非常快。
使用Redis、Memcache等分布式缓存将数据缓存在分布式缓存系统中。
相对于本地缓存来说、分布式缓存单独部署,可以根据需求分配硬件资源。不仅如此,服务器集群都已访问分布式缓存,而本地缓存需要在服务器集群之间进行同步,实现难度和性能开销非常大。
Mysql等数据库管理系统具有自己的查询缓存机制来提高查询效率。
Content Delivery Network,即内容分发网络。
基本思路:
- 尽可能避免互联网可能影响数据传输速度和稳定性的瓶颈环节,使内容传输更快、更稳定。通过在网络各处放置节点服务器所构成的在现有的互联网基础之上的一层智能虚拟网络,CDN系统能够实时地根据网络流量和各节点的连接、负载情况以及到用户的距离和响应时间等综合信息将用户的请求导向离用户最近的服务器节点上。
更深入: [CDN是什么?使用CDN有什么优势?][2]