关于MQ 消息队列的通俗理解和 rabbitMQ 使用
消息队列,一听很高大上,现在很多分布式系统都在用这个消息中间件 网上一搜, 说的都是些原理。
说下我的通俗理解, 你网上买了, 快递员给你投递, 会出现什么问题呢? 1 你不定时在家, 快递员 来了几次你都不在,不能到你手里。 2. 快递员很忙,手里一堆货物, 最后送到你手里就很慢了。
有问题就要解决,1: 你不定时在家? 1 送到你的房东家,然后你回去挨个找, 2 放到小区的 快递投递点,那里很多家 门牌号的 小柜子 ,你的东西就在那, 你自己去取 。
2 : 快递员很忙? 把快递放在仓库, 哪个快递员有空闲就去给你送。
这里对应的就是生产消费了。 我们知道, RPC 分布式服务, 把我们的业务系统都给划分了, 而不是之前一个复杂的系统了, 用户?拆分。 订单?拆分。 交易?拆分。基础服务?拆分。关系?拆分。各司其职。 分布式系统好处利大于弊。
各个业务 明确自己干什么, 另外可以针对性的提示性能 比如 用户业务访问的明显比订单多, 用户 业务 服务器加 三台, 如果你是一个复杂的大系统就不好调试了, 跑题了。 各业务必然有关联, 用户注册。必须要通过基础服务的 发短信, 推送。
这里就必须要中间件了,消息队列 有两种方式, 广播 , 排队,小区快递柜对应的各家的, 就是广播, 你自己拿你自己的。 不耽误快递员时间, 不耽误你时间, 也不耽误别人的时间, 排队,就是放在 房东家, 自己挨个去找。 不管如何, 这种异步方式都是
极大的提升了效率。
这里放个RabbitMQ 的简单示例, 现在各种中间件 都不错, 各有所长。
1 启动类
public class RechargeApplication implements CommandLineRunner {
private static final Logger logger = LoggerFactory.getLogger(RechargeApplication.class); @Autowired
private Environment env; public static void main(String[] args) {
SpringApplication.run(RechargeApplication.class, args);
//启动的时候注册消费者, 一旦 注册, 消费者就会监听 队列,有数据就去拿,基于AMQP协议 , 举个例子, 你的快递被放到小区快递箱了, 手机收到短信, 你的快递到了。 快去A503 快递箱收取, 验证码 123456.
SpringBeanHelper.getBean(Consumer.class).payConsumer();
} public void run(String... strings) throws Exception {
logger.info("Coupon service started, run at {} environment", env.getActiveProfiles());
} }
SpringBeanHelper
public class SpringBeanHelper implements ApplicationContextAware {
private static final Logger LOG = LoggerFactory.getLogger(SpringBeanHelper.class);
protected static ApplicationContext applicationContext; @Override
public void setApplicationContext(ApplicationContext applicationContext) {
SpringBeanHelper.applicationContext = applicationContext;
} public static <T> T getBean(Class<T> requiredClass) {
try {
return applicationContext.getBean(requiredClass);
} catch (NoSuchBeanDefinitionException e) {
LOG.warn("no qualifying bean of type: {}", requiredClass);
return null;
}
} public static <T> T getBean(String beanName, Class<T> requiredClass) {
try {
return applicationContext.getBean(beanName, requiredClass);
} catch (NoSuchBeanDefinitionException e) {
LOG.warn("no qualifying bean of name: {}, type: {}", beanName, requiredClass);
return null;
}
} public static String projectDir(){
return System.getProperty("user.dir");
} public static String contextPath() {
String basePath = applicationContext.getEnvironment().getProperty("server.context-path");
return StringUtils.isBlank(basePath) ? "" : basePath;
} public static String applicationName() {
return applicationContext.getEnvironment().getProperty("spring.application.name");
} public static Integer applicationPort(){
return Integer.parseInt(applicationContext.getEnvironment().getProperty("server.port"));
} public static String applicationEnv() {
String[] envList = applicationContext.getEnvironment().getActiveProfiles();
if (!CollectionUtils.isNullOrEmpty(envList)) {
return envList[0];
}
return "";
} /**
* 判断给定的 taskNum 是不是本机要同步的房间
*/
public static boolean isMineTask(long taskNum) {
DiscoveryClient discoveryClient = applicationContext.getBean(DiscoveryClient.class);
//通过服务发现取所有本服务的实例
List<ServiceInstance> serviceList = discoveryClient.getInstances(applicationName());
if (CollectionUtils.isNullOrEmpty(serviceList)) {
return false;
}
SortedSet<EurekaDiscoveryClient.EurekaServiceInstance> esiSet = Sets.newTreeSet((o1, o2) -> {
if (NetworkUtils.ip2long(o1.getHost()) < NetworkUtils.ip2long(o2.getHost())) {
return 1;
} else if(NetworkUtils.ip2long(o1.getHost()) == NetworkUtils.ip2long(o2.getHost())){
if(o1.getPort() < o2.getPort()){
return 1;
}else {
return -1;
}
} else {
return -1;
}
});
//过滤状态为UP的实例并按IP排序
for (ServiceInstance si : serviceList) {
if (si instanceof EurekaDiscoveryClient.EurekaServiceInstance) {
EurekaDiscoveryClient.EurekaServiceInstance esi = (EurekaDiscoveryClient.EurekaServiceInstance) si;
if (InstanceInfo.InstanceStatus.UP == esi.getInstanceInfo().getStatus()) {
esiSet.add(esi);
}
}
}
if (CollectionUtils.isNullOrEmpty(esiSet)) {
return false;
}
int index = 0, esiSize = esiSet.size();
long theIp = NetworkUtils.ip2long(NetworkUtils.ofInnerIp());
if (1 == esiSet.size()) {
return theIp == NetworkUtils.ip2long(esiSet.first().getHost());
}
//找到本机实例并且当 taskNum 对所有实例数取余等于本机实例 index 值时处理
for (EurekaDiscoveryClient.EurekaServiceInstance esi : esiSet) {
if (NetworkUtils.ip2long(esi.getHost()) == theIp && index == taskNum % esiSize) {
return true;
}
index++;
}
return false;
}
}
3 。生成者 , 快递员:
public void producer(Enum topic, Object message) {
if (LOG.isDebugEnabled()) {
LOG.debug("rabbit producer topic: {}, message: {}", topic, JsonUtils.toJSONString(message));
}
try {
AMQP.BasicProperties props = propertyOf(message);
senderChannel.queueDeclare(topic.name(), true, false, false, null);
this.senderChannel.basicPublish("", topic.name(), props, JsonUtils.toJSONBytes(message));
} catch (Exception e) {
throw new RuntimeException("rabbitmq send message error.....", e);
}
}
4 消费者
public class Consumer { public static final Logger LOGGER = LoggerFactory.getLogger(Consumer.class); @Autowired
private RabbitOperations rabbitOperations; @Autowired
private RechargeService rechargeService; /**
* 支付成功回调
*/
public void payConsumer() {
rabbitOperations.consumer(TradeCallBackTopic.CHARGE, 3, (contentType, body) -> {
String content = StringUtils.toEncodedString(body, Charset.forName("UTF-8"));
LOGGER.info("=======消费者:payConsumer start, content:{}============", content);
CallBackDto dto = JSON.parseObject(content, CallBackDto.class);
if (dto.getCallBackType() == PaymentConstant.CallBackNotifyType.PAY
&& dto.getTradeStatus() == PaymentConstant.TradeStatus.SUCCESS) {
} }); } }
关于MQ 消息队列的通俗理解和 rabbitMQ 使用的更多相关文章
- IM开发基础知识补课(五):通俗易懂,正确理解并用好MQ消息队列
1.引言 消息是互联网信息的一种表现形式,是人利用计算机进行信息传递的有效载体,比如即时通讯网坛友最熟悉的即时通讯消息就是其具体的表现形式之一. 消息从发送者到接收者的典型传递方式有两种: 1)一种我 ...
- Java语言快速实现简单MQ消息队列服务
目录 MQ基础回顾 主要角色 自定义协议 流程顺序 项目构建流程 具体使用流程 代码演示 消息处理中心 Broker 消息处理中心服务 BrokerServer 客户端 MqClient 测试MQ 小 ...
- 多维度对比5款主流分布式MQ消息队列,妈妈再也不担心我的技术选型了
1.引言 对于即时通讯网来说,所有的技术文章和资料都在围绕即时通讯这个技术方向进行整理和分享,这一次也不例外.对于即时通讯系统(包括IM.消息推送系统等)来说,MQ消息中件间是非常常见的基础软件,但市 ...
- 使用Rabbit MQ消息队列
使用Rabbit MQ消息队列 综合概述 消息队列 消息队列就是一个消息的链表,可以把消息看作一个记录,具有特定的格式以及特定的优先级.对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息 ...
- 阿里云ACE共创空间——MQ消息队列产品测试
一.产品背景消息队列是阿里巴巴集团自主研发的专业消息中间件. 产品基于高可用分布式集群技术,提供消息订阅和发布.消息轨迹查询.定时(延时)消息.资源统计.监控报警等一系列消息云服务,是企业级互联网架构 ...
- 手把手教你用redis实现一个简单的mq消息队列(java)
众所周知,消息队列是应用系统中重要的组件,主要解决应用解耦,异步消息,流量削锋等问题,实现高性能,高可用,可伸缩和最终一致性架构.目前使用较多的消息队列有 ActiveMQ,RabbitMQ,Zero ...
- 初识MQ消息队列
MQ 消息队列 消息队列(Message Queue)简称MQ,是阿里巴巴集团中间件技术部自主研发的专业消息中间件. 产品基于高可用分布式集群技术,提供消息发布订阅.消息轨迹查询.定时(延时)消息.资 ...
- MQ(消息队列)常见的应用场景解析
前言 提高系统性能首先考虑的是数据库的优化,之前一篇文章<数据库的使用你可能忽略了这些>中有提到过开发中,针对数据库需要注意的事项.但是数据库因为历史原因,横向扩展是一件非常复杂的工程,所 ...
- 高并发架构系列:MQ消息队列的12点核心原理总结
消息队列已经逐渐成为分布式应用场景.内部通信.以及秒杀等高并发业务场景的核心手段,它具有低耦合.可靠投递.广播.流量控制.最终一致性 等一系列功能. 无论是 RabbitMQ.RocketMQ.Act ...
随机推荐
- (十三)在ASP.NET CORE中使用Options
这一节介绍Options方法,继续在OptionsBindSample项目下. 在项目中添加一个Controllers文件夹,文件夹添加一个HomeController控制器 HomeControll ...
- !important的用法及作用
定义及语法 !important,作用是提高指定样式规则的应用优先权(优先级).语法格式{ cssRule !important },即写在定义的最后面,例如:box{color:red !impor ...
- 配置Spring Security 错误:Property or field 'ROLE_USER' cannot be found
在学习http://www.mkyong.com/spring-security/spring-security-hello-world-example/时,出现以下错误: Property or f ...
- 尝试 zabbix 小记
server : Ubuntu 16.04 zabbix: 2.2.23源码包 安装 gcc,curl,make,snmp 软件和zabbix依赖一些php 扩展包 sudo apt-get inst ...
- CF528E Triangles3000
题意:给你一个不存在三线共交点的一次函数组a[i]x+b[i]y+c[i]=0. 问等概率选取三条直线,围成三角形的面积的期望. n<=3000. 标程: #include<bits/st ...
- Makefile 从入门到放弃
//如有侵权 请联系我进行删除 email:YZFHKM@163.com { 什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作, ...
- thinkphp 使用函数
我们往往需要对模板输出变量使用函数,可以使用: 大理石平台支架 {$data.name|md5} 编译后的结果是: <?php echo (md5($data['name'])); ?> ...
- for双重循环中的结构分离(语法结构问题)
//增加搜索列表 function addSearchList(){ $.get("/mall/h5_get_search_list.html","",func ...
- springboot集成websocket实现向前端浏览器发送一个对象,发送消息操作手动触发
工作中有这样一个需示,我们把项目中用到代码缓存到前端浏览器IndexedDB里面,当系统管理员在后台对代码进行变动操作时我们要更新前端缓存中的代码怎么做开始用想用版本方式来处理,但这样的话每次使用代码 ...
- kafka-node+socket.io 测试配置
1.安装需要插件 npm install express npm install socket.io npm install kafka-node 2.kafkatest.js文件 var exp ...