如何在分布式环境中同步solr索引库和缓存信息
天气依旧很好,主要是凉快。老习惯,我在北京向各位问好。
搜索无处不在,相信各位每天都免不了与它的亲密接触,那么我想你确实有必要来了解一下它们,就上周在公司实现的一个小需求来给各位分享一下:如何在分布式环境下同步索引库?
需求分析
公司数据库中的数据信息每天都免不了增、删、改操作,在执行这些简单的更新操作时,我们不仅将变更后的数据要更新到数据库中,同时还要马上同步索引库中的数据,有的时候还要同步一下缓存中的数据(本文只分享如何同步solr索引库)。
分析方案
当我们在后台管理系统中触发了更新操作时,不会紧跟着调用同步功能去更新索引库和缓存这种机制去实现,因为耦合性太高了,容易影响正常的业务流程。那么,既然我们不做,做的话就要影响业务,所以我们就有必要请一位私人秘书来替我们完成同步操作了,既然请了秘书,就没必要再去关心同步操作,而是我们只需要在更新完数据后通知这位秘书,让它去完成同步操作,岂不更妙?好了,说了这么久,这位秘书就是英俊潇洒不可或缺的消息队列——MQ,为什么使用它?主要还是开源、解耦。废话不说了,一起从简,开始上码。

哦,对了到这儿我就有必要说一下MQ的俩种使用模式,因为这个确实有点用,我就爬过这坑。主要分为2种:点对点(Queue)和发布\订阅(Topic)模式。

从上图可以看出,这俩种模式最主要的区别就是发送出去的消息可以由多少个消费者来接受,很明显:
发布\订阅模式:需要一个生产者发送消息到主题版块(Topic)中,可以有多个消费者订阅该版块来接受消息。消费者接受消息时,必须处于运行状态,而且只能接受运行之后的消息。
点对点模式:需要一个生产者发送消息到队列版块(Queue)中,只能有一个消费者从该队列(Queue)中接受该消息。生产者发送消息时,消费者不需要处于运行状态。
好,明确这点就够了,我们先用起来,至于它的一些细节,你们自己去找找资料好好读读,因为本人也是初次使用到,后期有机会再和大家共勉。
一路走好,码到成功
步骤一:安装MQ(activeMQ)
狠简单,解压即用。如有需要请参考http://www.cnblogs.com/1315925303zxz/p/6377551.html。
步骤二:spring整合MQ
<!-- 真正可以产生Connection的ConnectionFactory,由对应的 JMS服务厂商提供 -->
<bean id="targetConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://192.168.136.139:61616"/>
</bean>
<!-- Spring用于管理真正的ConnectionFactory的ConnectionFactory -->
<bean id="connectionFactory"
class="org.springframework.jms.connection.SingleConnectionFactory">
<!-- 目标ConnectionFactory对应真实的可以产生JMS Connection的ConnectionFactory -->
<property name="targetConnectionFactory" ref="targetConnectionFactory"/>
</bean> <!-- 生产者 -->
<!-- Spring提供的JMS工具类,它可以进行消息发送、接收等 -->
<bean id="jmsTemplate" class="org.springframework.jms.core.JmsTemplate">
<!-- 这个connectionFactory对应的是我们定义的Spring提供的那个ConnectionFactory对象 -->
<property name="connectionFactory" ref="connectionFactory"/>
</bean>
<!--这个是队列目的地:(俩种配置方式)
一、点对点模式:需要一个生产者发送消息到队列版块(Queue)中,只能有一个消费者从该队列(Queue)中接受该消息。
【生产者发送消息时,消费者不需要处于运行状态】。
二、发布订阅模式:需要一个生产者发送消息到主题版块(Topic)中,可以有多个消费者订阅该版块来接受消息。
【生产者发送消息时,消费者必须处于运行状态,而且只能接受运行之后的消息】。
-->
<!-- 点对点模式 -->
<!-- <bean id="testQueue" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg>
<value>test-queue</value>
</constructor-arg>
</bean> -->
<!-- 发布订阅模式 -->
<bean id="testTopic" class="org.apache.activemq.command.ActiveMQTopic">
<constructor-arg value="test-topic"/>
</bean> <!-- 消费者 -->
<!-- 配置自定义消息监听器 -->
<bean id="myMessageListener" class="cn.soa.mq.MyMessageListener"></bean>
<!-- 配置MessageListenerContainer -->
<bean id="jmsContainer"
41 class="org.springframework.jms.listener.DefaultMessageListenerContainer">
42 <property name="connectionFactory" ref="connectionFactory"/>
43 <property name="destination" ref="testTopic"/> <!-- 这儿注意生产者使用的是那种模式并且用哪个队列来发送消息的 -->
44 <property name="messageListener" ref="myMessageListener"/>
45 </bean>
步骤三:执行更新操作时,通知秘书去同步索引库、缓存等
@Autowired
private ItemMapper itemMapper;
//消息队列
@Autowired
private JmsTemplate jmsTemplate;
@Resource(name="testTopic")
private Destination testTopic;
@Override
public int saveItem(Item item) {
final String itemId = UUIDUtils.getUUID();
if(StringUtil.isNullOrBlank(item.getId())){
//如果商品主键为空,则设置一个ID
item.setId(itemId);
}
if(StringUtil.isNullOrBlank(String.valueOf(item.getCreateTime()))){
//如果创建时间为空,则设置当前时间为创建时间
item.setCreateTime(DateTimeUtils.getCurrentDate());
}
int save = itemMapper.saveItem(item);
if(save == 1){
//如果新增商品成功,则发送商品ID到消息队列中,目的同步索引库、缓存等
jmsTemplate.send(testTopic, new MessageCreator(){
23 @Override
24 public Message createMessage(Session session) throws JMSException {
25 // 将商品ID发送出去
26 logger.error("发送新增商品的ID到MQ消息队列中:{}==============================");
27 TextMessage message = session.createTextMessage(itemId);
28 return message;
29 }
30 });
}
return save;
}
步骤四:使用MQ监听器同步索引库(监听器需在spring配置文件中配置)
public class MyMessageListener implements MessageListener{
private final static Logger logger = LoggerFactory.getLogger(MyMessageListener.class);
@Autowired
private SolrServer solrServer;
@Autowired
private ItemService itemService;
/**
* 根据监听到的商品ID来同步索引库数据。
*/
@Override
public void onMessage(Message message) {
logger.info("============开始同步索引库================");
// 根据不同业务逻辑进行相应处理
if(message instanceof TextMessage){
try {
TextMessage textMessage = (TextMessage) message;
21 String ID = textMessage.getText(); //监听到新商品ID
Item newItem = itemService.findItemById(ID); //根据新主键查询到商品信息
// 将商品数据封装到SolrInputDocument对象
SolrInputDocument doc = new SolrInputDocument();
doc.addField("id", newItem.getId());
doc.addField("product_catalog_name", "忠哥系列");
doc.addField("product_price", newItem.getPrice());
doc.addField("product_name", newItem.getItemName());
// 添加到索引库
solrServer.add(doc);
// 提交
solrServer.commit();
} catch (Exception e) {
logger.error("同步索引库失败:{}"+e.getMessage());
}
}
}
}
步骤五:校验数据是否同步成功,马上就可以在索引库中搜到我们刚刚新增的信息

参考:
http://www.cnblogs.com/1315925303zxz/p/6254016.html 仿京东站内搜索案例
http://www.cnblogs.com/1315925303zxz/p/6372004.html solrcloud集群环境搭建
与君共勉!每天都有新技能!
如何在分布式环境中同步solr索引库和缓存信息的更多相关文章
- ZooKeeper学习第五期--ZooKeeper管理分布式环境中的数据
引言 本节本来是要介绍ZooKeeper的实现原理,但是ZooKeeper的原理比较复杂,它涉及到了paxos算法.Zab协议.通信协议等相关知识,理解起来比较抽象所以还需要借助一些应用场景,来帮我们 ...
- 【Zookeeper系列】ZooKeeper管理分布式环境中的数据(转)
原文地址:https://www.cnblogs.com/sunddenly/p/4092654.html 引言 本节本来是要介绍ZooKeeper的实现原理,但是ZooKeeper的原理比较复杂,它 ...
- Java多线程编程——并发编程原理(分布式环境中并发问题)
在分布式环境中,处理并发问题就没办法通过操作系统和JVM的工具来解决,那么在分布式环境中,可以采取一下策略和方式来处理: 避免并发 时间戳 串行化 数据库 行锁 统一触发途径 避免并发 在分布式环境中 ...
- ZooKeeper系列(5):管理分布式环境中的数据
引言 本节本来是要介绍ZooKeeper的实现原理,但是ZooKeeper的原理比较复杂,它涉及到了paxos算法.Zab协议.通信协议等相关知 识,理解起来比较抽象所以还需要借助一些应用场景,来帮我 ...
- ZooKeeper管理分布式环境中的数据
Reference: http://www.cnblogs.com/wuxl360/p/5817549.html 本节本来是要介绍ZooKeeper的实现原理,但是ZooKeeper的原理比较复杂,它 ...
- 分布式服务框架 Zookeeper — 管理分布式环境中的数据
本节本来是要介绍ZooKeeper的实现原理,但是ZooKeeper的原理比较复杂,它涉及到了paxos算法.Zab协议.通信协议等相关知识,理解起来比较抽象所以还需要借助一些应用场景,来帮我们理解. ...
- 高并发分布式环境中获取全局唯一ID[分布式数据库全局唯一主键生成]
需求说明 在过去单机系统中,生成唯一ID比较简单,可以使用MySQL的自增主键或者Oracle中的sequence, 在现在的大型高并发分布式系统中,以上策略就会有问题了,因为不同的数据库会部署到不同 ...
- 【转】Java多线程编程(十)-并发编程原理(分布式环境中并发问题)
转载地址:http://blog.csdn.net/leicool_518/article/details/42268947 在分布式环境中,处理并发问题就没办法通过操作系统和JVM的工具来解决,那么 ...
- ZooKeeper学习第五期--ZooKeeper管理分布式环境中的数据(转)
转载来源:https://www.cnblogs.com/sunddenly/p/4092654.html 引言 本节本来是要介绍ZooKeeper的实现原理,但是ZooKeeper的原理比较复杂,它 ...
随机推荐
- centos下从源码安装openssl
cd /usr/src wget https://www.openssl.org/source/openssl-1.0.1g.tar.gz -O openssl-1.0.1g.tar.gz tar - ...
- Microsoft Edge 浏览器远程代码执行漏洞POC及细节(CVE-2017-8641)
2017年8月8日,CVE官网公布了CVE-2017-8641,在其网上的描述为: 意思是说,黑客可以通过在网页中嵌入恶意构造的javascript代码,使得微软的浏览器(如Edege),在打开这个网 ...
- Maven详解(一)------ Maven概述
1.引言 你能搜到这个教程,说明你对 Maven 感兴趣,但是又不是太理解.那么接下来这个系列的教程将会详细讲解 Maven 的用法,相信你看完之后,一定能对 Maven 的理解更进一步! 2.常规项 ...
- 分页(将数据库中的多条数据一页一页的显示在jsp页面中)
一.显示数据库中的多条数据为什么要用分页 在真正的开发中,数据库中所存储的数据绝对不像我们平时所写的那样,仅仅有几条数据,而是有几十条甚至上百条,像淘宝京东的用户把都是上几十万甚至百万的.如果这时候在 ...
- tomcat替换.class文件并没有生效的原因(失效原因)(转)
紧急关头难免会替换class文件,但一定要注意一下几点. 1.小心class内中的project 的类的后,替换文件需要加上 $classMapper这个类, 编译成class的时候,会把public ...
- MySQL 账户管理
一.当前日期.当前用户.当前数据库版本 mysql> select curdate(),version(),database(),user(); +------------+---------- ...
- oracle撤销表空间和回滚段
/* 撤销表空间 */ 通过使用撤销技术,能够为Oracle数据库提供以下功能: * 使用ROLLBACK语句撤销事务 * 进行数据库恢复 * 提供数据的读一致性 Oracle强烈建议DBA在Orac ...
- 【踩坑】angularJS 1.X版本中 ng-bind 指令多空格展示
做项目的时候遇到的问题 1.问题描述 用户在表单某个值输入多个空格,例如:A B,保存至服务器 在列表查询页面中使用bg-bind的指令单向绑定,结果展示位A B,连续的空格被替换为单个空格 ...
- 一起学ASP.NET Core 2.0学习笔记(二): ef core2.0 及mysql provider 、Fluent API相关配置及迁移
不得不说微软的技术迭代还是很快的,上了微软的船就得跟着她走下去,前文一起学ASP.NET Core 2.0学习笔记(一): CentOS下 .net core2 sdk nginx.superviso ...
- zetcode :: First programs in PyQt5
练习代码,详见网站 http://zetcode.com/gui/pyqt5/firstprograms/ import sys from PyQt5 import QtWidgets from Py ...