SolrCloud-如何在.NET程序中使用
https://github.com/vladen/SolrNet
原来我们在我们的项目里用的是根据数据库路由到不同的单机Solr服务器,但是这样的话,每次Solr配置的修改都要修改三台不通的服务器,而且一台服务器挂了,必定会影响一部分用户不能使用搜索功能,而且还会造成一定程度的丢数据,所以我们换一种方式。
两种可选方案:
- 主从模式
- SolrCloud
经过对比,决定用SolrCloud,SolrCloud的概念和优缺点,就不再赘述了,网上一搜一大堆,这里主要写一下在C#如何使用SolrCloud。
最早我们用 EasyNet.Solr 来进行Solr查询的,但是貌似EasyNet.Solr 没有对SolrCloud的查询做封装,所以就各种找资料,最后只能自己封装了。
首先SolrCloud是通过zookeeper来调度的,那么我们就要先去zookeeper上面去load可用的节点,并且对 zookeeper的 clusterstate.json 文件做心跳检测,如果clusterstate.json 里的内容有变化,则说明节点状态有变化,需要重新load文件里的内容进行解析,否则就在应用程序第一次调用的时候加载一次,缓存起来。
献上核心代码
要先通过NuGet安装Zookeeper Client
在EasyNet.Solr根目录定义接口ISolrCloudOperrations.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace EasyNet.Solr
{
public interface ISolrCloudOperrations
{
string GetSolrCloudServer(string collectionName, bool isWrite);
}
}
在Impl文件夹里实现接口 SolrCloudOperations.cs
internal static class ZookeeperStatus
{
//每隔两秒钟pingzookeeper服务器,并监听solr服务器状态,如果状态有改变,更新状态文件,请求连接列表
private static void Ping(string zkHost) {
//如果是第一次调用,则加载配置文件
if (DataLength == 0)
{
foreach (var host in zkHost.Split(',').ToList())
{
Start(host);
}
Task.Factory.StartNew(() =>
{
while (true)
{
foreach (var host in zkHost.Split(',').ToList())
{
Task.Factory.StartNew(Start, host);
}
Thread.Sleep(2000);
}
});
}
}
private static object pingObj = new object();
private static void Start(object zkHost) {
var watcher = new Watcher();
using (var zk = new ZooKeeper(zkHost.ToString(), new TimeSpan(0, 0, 0, 10000), watcher))
{
var dataChange = watcher.WaitUntilWatched();
Org.Apache.Zookeeper.Data.Stat stat = null;
try
{
stat = zk.Exists("/clusterstate.json", false);
}
finally
{
if (stat != null)
{
byte[] data = null;
lock (pingObj)
{
if (DataLength == 0 || DataLength != stat.DataLength)
{
data = zk.GetData("/clusterstate.json", false, stat);
DataLength = stat.DataLength;
SetShard(data);
}
}
}
}
}
}
private static int DataLength = 0;
private static Dictionary<string, List<Shard>> shards = new Dictionary<string, System.Collections.Generic.List<Shard>>();
private static ReaderWriterLockSlim rw = new ReaderWriterLockSlim();
private static void SetShard(byte[] data)
{
var str = System.Text.Encoding.UTF8.GetString(data);
JObject jObj = JsonConvert.DeserializeObject<JObject>(str);
List<Shard> shardList = new List<Shard>();
try
{
rw.EnterWriteLock();
foreach (var p in jObj)
{
foreach (var item in p.Value["shards"])
{
var jItem = item.First as JObject;
if (jItem["state"].ToString() == "active")
{
foreach (var replica in jItem["replicas"])
{
var jReplica = replica.First as JObject;
if (jReplica["state"].ToString() == "active")
{
Shard shard = new Shard() { BaseUrl = jReplica["base_url"].ToString() };
if (jReplica["leader"] != null && "true" == jReplica["leader"].ToString())
{
shard.Leader = true;
}
shardList.Add(shard);
}
}
}
}
if (shards.ContainsKey(p.Key))
{
shards[p.Key] = shardList;
}
else
{
shards.Add(p.Key, shardList);
}
}
}
finally
{
rw.ExitWriteLock();
}
}
public static string ZookeeperHost = "127.0.0.1:2181";
public static string GetCollection(string collectionName, bool isWrite)
{
///第一次调用,则开始ping
if (DataLength == 0)
{
Ping(ZookeeperHost);
}
IEnumerable<Shard> tempShardList = null;
try
{
rw.EnterReadLock();
var shardList = shards[collectionName];
if (!isWrite)
{
tempShardList = shardList.Where(s => s.Leader == false);
}
//如果从库挂了,那么只能从主库读取了
if (tempShardList == null || tempShardList.Count() == 0)
tempShardList = shardList.Where(s => s.Leader == true);
}
finally
{
rw.ExitReadLock();
}
if (tempShardList == null) throw new Exception("no active shard");
//随机取值
int random = new Random().Next(tempShardList.Count() - 1);
return tempShardList.ToList()[random].BaseUrl;
}
}
internal class Shard
{
public string BaseUrl { get; set; }
public bool Leader { get; set; }
}
internal enum Changed
{
None,
Children,
Data
}
internal class Watcher : IWatcher
{
private readonly ManualResetEventSlim _changed = new ManualResetEventSlim(false);
private WatchedEvent _event;
public Changed WaitUntilWatched()
{
_changed.Wait();
if (_event == null) throw new ApplicationException("bad state");
if (_event.State != KeeperState.SyncConnected)
throw new ApplicationException("cannot connect");
if (_event.Type == EventType.NodeChildrenChanged)
{
return Changed.Children;
}
if (_event.Type == EventType.NodeDataChanged)
{
return Changed.Data;
}
return Changed.None;
}
void IWatcher.Process(WatchedEvent @event)
{
_event = @event;
_changed.Set();
}
}
这样我们如果是write操作,就会调用leader分片对应的节点进行写入,如果是查询操作,则尽量直接调用非leader来进行查询,如果非leader节点挂了,那么久从主节点进行查询。
SolrCloud-如何在.NET程序中使用的更多相关文章
- 【转】如何在 Android 程序中禁止屏幕旋转和重启Activity
原文网址:http://www.cnblogs.com/bluestorm/p/3665890.html 禁止屏幕随手机旋转变化 有时候我们希望让一个程序的界面始终保持在一个方向,不随手机方向旋转而变 ...
- 如何在 Android 程序中禁止屏幕旋转和重启Activity
禁止屏幕随手机旋转变化 有时候我们希望让一个程序的界面始终保持在一个方向,不随手机方向旋转而变化:在AndroidManifest.xml的每一个需要禁止转向的Activity配置中加入android ...
- 如何在RCP程序中添加一个banner栏
前言:这段时间还算比较空闲,我准备把过去做过的有些形形色色,甚至有些奇怪的研究总结一下,也许刚好有人用的着也不一定,不枉为之抓耳挠腮的时光和浪费的电力.以前有个客户提出要在RCP程序中添加一个bann ...
- 如何在java程序中调用linux命令或者shell脚本
转自:http://blog.sina.com.cn/s/blog_6433391301019bpn.html 在java程序中如何调用linux的命令?如何调用shell脚本呢? 这里不得不提到ja ...
- 如何在WPF程序中使用ArcGIS Engine的控件
原文 http://www.gisall.com/html/47/122747-4038.html WPF(Windows Presentation Foundation)是美国微软公司推出.NET ...
- 如何在 C# 程序中注入恶意 DLL?
一:背景 前段时间在训练营上课的时候就有朋友提到一个问题,为什么 Windbg 附加到 C# 程序后,程序就处于中断状态了?它到底是如何实现的? 其实简而言之就是线程的远程注入,这一篇就展开说一下. ...
- 如何在wpf程序中使用DependencyProperty
作为例子,我决定定义一个MyBorderEx,在WPF常用的"Border"控件中创建一个名为Transparency的属性,来指示它的透明度,这个属性值在0-255间变化,255 ...
- 如何在C#程序中模拟域帐户进行登录操作 (转载)
.NET Core .NET Core也支持用PInvoke来调用操作系统底层的Win32函数 首先要在项目中下载Nuget包:System.Security.Principal.Windows 代码 ...
- 在WPF程序中使用摄像头兼谈如何使用AForge.NET控件(转)
前言: AForge.NET 是用C#写的一个关于计算机视觉和人工智能领域的框架,它包括图像处理.神经网络.遗传算法和机器学习等.在C#程序中使用摄像头,我习惯性使用AForge.NET提供的类库.本 ...
随机推荐
- 攻城狮在路上(壹) Hibernate(十四)--- Hibernate的检索方式(下)
本节介绍HQL和QBC的高级用法:各种连接查询.投影查询.报表查询.动态查询.集合过滤和子查询等.另外将归纳优化查询程序代码,从而提高查询性能的各种技巧.一.连接查询: HQL与QBC支持的各种连接类 ...
- <转>JDBC获取DB元数据
原文链接:http://jiauwu.iteye.com/blog/1307617 package com.util.jdbc; import java.sql.Connection; import ...
- PHP保留小数位的三种方法
/** * PHP保留两位小数的几种方法 * @link http://www.phpddt.com */ $num = 10.4567; //第一种:利用round()对浮点数进行四舍五入 echo ...
- Linux命令之ar - 创建静态库.a文件和动态库.so
转自:http://blog.csdn.net/eastonwoo/article/details/8241693 用途说明 创建静态库.a文件.用C/C++开发程序时经常用到,但我很少单独在命令行中 ...
- mageView图片显示出来 ()
ImageView图片显示出来: igSign 是 ImageView的实例 igSign.setImageDrawable(getResources().getDrawable(R.drawable ...
- java中如何实现类似goto的作法
goto虽然是java中保留的keyword,但是对于跳转这个语法对新手来说这个确实好用.为了提高程序的可靠性和可读性,Java语言目前是不支持无条件跳转的goto语句!! 幸亏java中有高仿跳转的 ...
- System.Web.Caching.Cache类 缓存
1.文件缓存依赖 public partial class _Default : System.Web.UI.Page { protected void Page_Load(object sender ...
- Tomcat环境配置部署测试环境及架构
Tomcat环境配置已经在前面介绍过了,这边就为童鞋们介绍下对于Tomcat的架构是怎么样的! Tomcat的架构包含(bin.conf.lib.logs.temp.wenapps.work)等文件夹 ...
- Attribute在.net编程中的应用
Attribute FYI Link: Attribute在.net编程中的应用(一) Attribute在.net编程中的应用(二) Attribute在.net编程中的应用(三) Attribut ...
- Angular.js 以及个人学习网站
Angular.js 教程 http://www.360doc.com/content/14/0414/15/14416931_368816305.shtml web前端学习: 慕课网:http:/ ...