如何在分布式环境中同步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的原理比较复杂,它 ...
随机推荐
- .Net Reactor 5脱壳教程
今天别人发来一个.Net的DLL让我脱壳,第一步自然是先扔进de4dot 我这个de4dot 是集成了 Ivancito0z / TheProxy / PC-RET 4.9mod / wuhenso ...
- java 5年规划---
偶然看到别人,觉得写的很好,尤其对刚出来工作的人,不一定是最好,但至少可以给你一个方向,所以就把这篇文章放到自己博客来,时刻提醒自己 第一部分 在搭建SSM的过程中,可能会经常接触到一个叫maven的 ...
- 【Linux】CentOS7无法使用tab补全功能
公司新项目在云环境上用CentOS7搭服务器的时候,遇见了无法Tab键自动补齐的情况,上网搜了一下,是因为Centos7在使用最小化安装的时候,没有安装自动补全的包,需要自己手动安装. yum ins ...
- MySql COUNT(),SUM()组合用法
需求:统计工作室表的数量,按创建时间分组 问题:按创建时间分组,如何将计数后的结果求和 解决:用COUNT(DISTINCT col_name)讲每行计数为1,再求和分组 SELECT DATE_FO ...
- linux下FTP服务器搭建教程1
你买了个主机就像是买了块地皮,搭建FTP就像是盖房子,我在地皮上建房子,然后创建的用户就像是钥匙,我给谁钥匙(权限),谁就可以到我家去玩,去放东西,拿东西. 虽然我们买不起现实的房子,但是我们可以买互 ...
- Celery基本原理探讨
本文对Celery进行了研究,由于其实现相对比较复杂没有足够的时间和精力对各方各面的源码进行分析,因此本文根据Celery的使用方法以及实际行为分析其运行原理,并根据查阅相关代码进行了一定程度的验证. ...
- 再起航,我的学习笔记之JavaScript设计模式16(享元模式)
### 享元模式 **享元模式(Flyweight):** 运用共享技术有效地支持大量的细粒度的对象,避免对象间拥有相同内容造成多余的开销. 上回我们在组合模式中创建了文章列表类,这次我们要向不同的文 ...
- [2015-10-11]tfs2015 vs2013 配置持续集成
今天刚配置完tfs2015+vs2013的持续集成(自动构建+自动发布),记录一下走过的坑. tfs2015和tfs build server是之前其他同事装的,略去不讲,列一下几个坑以及埋坑方法. ...
- 前端开发【第一篇:HTML】
HTML初识 1.什么是HTML HTML是英文Hyper Text Mark-up Language(超文本标记语言)的缩写,他是一种制作万维网页面标准语言(标记).相当于定义统一的一套规则,大家都 ...
- JS中的phototype JS的三种方法(类方法、对象方法、原型方法)
JS中的phototype是JS中比较难理解的一个部分 本文基于下面几个知识点: 1 原型法设计模式 在.Net中可以使用clone()来实现原型法 原型法的主要思想是,现在有1个类A,我想要创建一个 ...