.NET 访问 Coherence 全解析
1. 配置基础
在 .NET 中访问 Coherence 时,过滤器注册与 Java 非常相似,主要差异在于根元素的命名空间声明和类名的指定方式。在 .NET 客户端,指定类名时,除了要给出完全限定类名,还需包含类所在的程序集名称。例如,
PasswordBasedEncryptionFilter
类将从
Coherence.Encryption
程序集中加载。
2. 缓存配置
在 .NET 客户端,只能配置部分缓存方案,这是因为并非集群中所有的缓存方案都适用于 Coherence*Extend 客户端。可配置的方案包括本地、近程和远程缓存方案,以及远程调用服务。以下是一个 .NET 缓存配置文件示例:
<cache-config xmlns="http://schemas.tangosol.com/cache">
<caching-scheme-mapping>
<cache-mapping>
<cache-name>*</cache-name>
<scheme-name>extend-tcp</scheme-name>
</cache-mapping>
</caching-scheme-mapping>
<caching-schemes>
<remote-cache-scheme>
<scheme-name>extend-tcp</scheme-name>
<service-name>ExtendTcpCacheService</service-name>
<initiator-config>
<tcp-initiator>
<remote-addresses>
<socket-address>
<address>localhost</address>
<port>9099</port>
</socket-address>
</remote-addresses>
<connect-timeout>30s</connect-timeout>
</tcp-initiator>
<outgoing-message-handler>
<heartbeat-interval>1s</heartbeat-interval>
<heartbeat-timeout>10s</heartbeat-timeout>
<request-timeout>30s</request-timeout>
</outgoing-message-handler>
<use-filters>
<filter-name>symmetric-encryption</filter-name>
</use-filters>
</initiator-config>
</remote-cache-scheme>
</caching-schemes>
</cache-config>
3. POF 配置
POF 配置文件除了命名空间声明和类名指定方式的差异外,与 Java 中的配置文件基本相同。以下是一个 POF 配置文件示例:
<pof-config xmlns="http://schemas.tangosol.com/pof">
<user-type-list>
<include>
assembly://Coherence/Tangosol.Config/coherence-pof-config.xml
</include>
<user-type>
<type-id>1000</type-id>
<class-name>
BankTerminal.Domain.Account, BankTerminal
</class-name>
</user-type>
<user-type>
<type-id>1001</type-id>
<class-name>
BankTerminal.Domain.Transaction, BankTerminal
</class-name>
</user-type>
</user-type-list>
</pof-config>
重要的是,类型标识符要与集群中配置的标识符相匹配,并且要包含标准的
coherence-pof-config.xml
文件,该文件包含了 Extend 协议或 Coherence API 所需的所有内置 Coherence 类型的定义。
4. Coherence for .NET 的资源加载
4.1 资源抽象
Coherence for .NET 提供了四种
IResource
实现:
| 类名 | 描述 |
| ---- | ---- |
| FileResource | 提供对文件系统中文件的访问,是除 ASP.NET Web 应用程序外所有应用程序的默认资源类型。 |
| WebResource | 提供对 Web 应用程序中文件的访问,是 ASP.NET Web 应用程序的默认资源类型。 |
| EmbeddedResource | 提供对程序集嵌入资源的访问。 |
| UrlResource | 提供对 HTTP 或 FTP 资源的访问。 |
文件资源和 Web 资源虽然都代表磁盘上的物理文件,但在解析路径时行为不同。在 Web 应用程序中,不应使用
FileResource
,因为路径可能无法按预期解析。
4.2 协议和资源加载器
可以根据资源名称的协议部分来确定使用哪种
IResource
实现:
| 协议 | 资源 | 示例 |
| ---- | ---- | ---- |
| file | FileResource | file://config/my-pof-config.xml
file://c:/config/my-cache-config.xml
c:\MyDir\coherence.xml (如果文件是默认类型) |
| web | WebResource | web://config/my-pof-config.xml (相对于当前路径)
web://~/config/my-pof-config.xml (相对于根路径)
~/my-pof-config.xml (如果 Web 是默认类型) |
| assembly、asm | EmbeddedResource | assembly://MyAssembly/My.Name.Space/pof.xml
asm://MyAssembly/My.Name.Space/cache-config.xml |
| http、ftp | UrlResource | http://config.mycompany.com/my-pof-config.xml
ftp://user:pass@ftp.mycompany.com/config/pof.xml |
5. .NET 客户端配置方法
Coherence for .NET 支持三种客户端配置方法:
-
基于约定的配置
:依赖于将具有知名名称的文件放在应用程序目录中,适用于桌面和 ASP.NET Web 应用程序。需要创建以下文件:
-
coherence.xml
:用于操作描述符。
-
coherence-cache-config.xml
:用于缓存配置文件。
-
coherence-pof-config.xml
:用于 POF 配置文件。
Coherence for .NET 客户端库在启动时会自动检测这些文件并使用它们进行配置,除非被其他机制覆盖。
-
显式配置
:在某些情况下,可能需要将配置文件放在网络共享目录中,或使用不同名称的文件。可以通过编程方式或在标准 .NET 配置文件(如
Web.config
或
App.config
)中指定配置文件名来实现。以下是在
App.config
或
Web.config
中配置的示例:
<configuration>
<configSections>
<section name="coherence"
type="Tangosol.Config.CoherenceConfigHandler, Coherence"/>
</configSections>
<!-- 其他配置 -->
</configuration>
- 编程式配置 :对于某些应用程序(如 Microsoft Office 插件),上述两种方法可能不适用。可以将配置文件嵌入到插件的程序集中,并在插件初始化时以编程方式配置 Coherence 客户端:
const string baseUrl = "assembly://CoherenceRTD/CoherenceRTD.Config/";
CacheFactory.SetCacheFactoryConfig(baseUrl + "coherence.xml");
CacheFactory.SetCacheConfig(baseUrl + "cache-config.xml");
CacheFactory.SetPofConfig(baseUrl + "pof-config.xml");
6. Coherence 与 Excel 的集成
上述编程式配置示例来自一个将 Coherence 用作数据源的 Excel RTD 服务器的概念验证。当 Coherence 集群中的数据发生变化时,Excel 工作表和图表会实时更新。你可以在 Dave Felcey 的博客(http://blogs.oracle.com/felcey/)上查看最终演示和使用说明。
7. 客户端应用程序实现
7.1 基本缓存操作
要获取命名缓存的引用,需要使用
Tangosol.Net.CacheFactory
类并调用其
GetCache
方法:
INamedCache cache = CacheFactory.GetCache("countries");
获取缓存实例后,可以使用
IDictionary
接口的标准成员(如
Count
、
Add
、
Remove
和
Clear
)以及索引器来操作缓存中的数据:
cache.Add("SRB", "Serbia");
cache.Add("USA", "United States");
cache["USA"] = "United States of America";
cache.Remove("SRB");
Console.WriteLine("USA = " + cache["USA"]);
Console.WriteLine("Cache size = " + cache.Count);
cache.Clear();
Add
方法在尝试添加已存在键的对象时会抛出异常,若要替换现有条目,可使用索引器。
也可以使用
Tangosol.Net.ICache
接口中定义的方法:
public interface ICache : IDictionary
{
object Insert(object key, object value);
object Insert(object key, object value, long millis);
void InsertAll(IDictionary dictionary);
IDictionary GetAll(ICollection keys);
}
前三个方法的行为与 Java 中的
put
和
putAll
方法类似,允许插入新条目并覆盖现有条目,还可以指定条目的过期时间或批量插入多个条目。
GetAll
方法允许在单个网络调用中按键检索多个条目,显著提高读取性能。
7.2 实现数据对象
为了使 Coherence 的大多数功能正常工作,.NET 数据对象必须使用 POF 作为序列化格式,并且可能需要在集群中提供对应的 Java 实现。虽然技术上可以使用 .NET 二进制或 XML 序列化,但在大多数情况下不建议这样做,因为这会使 Coherence 集群节点无法反序列化对象,从而失去集群端的大部分功能。
在 Coherence 3.5 之前,进行集群端处理(如查询、聚合、条目处理器等)绝对需要 Java 类。但现在,即使没有 Java 类,也可以在集群中反序列化对象,甚至可以使用
PofUpdater
直接更新集群中的二进制数据。不过,实现并行类层次结构仍然是最佳方法,原因如下:
- 实现数据亲和性或使用读写穿透方法持久化缓存对象时需要 Java 类。
- 在条目处理器和聚合器中使用强类型的 Java 类比使用二进制数据更容易。
- 集群中存在 Java 类会使调试更加容易。
7.3 实现
IPortableObject
接口
有两种方法可以使对象具有可移植性。第一种是直接在类中实现
Tangosol.IO.POF.IPortableObject
接口:
public class Customer : IPortableObject
{
// ---- 数据成员 -------------------------------------
private long id;
private String name;
private DateTime dateOfBirth;
// ---- 构造函数 -------------------------------------
public Customer()
{
// 反序列化构造函数
}
public Customer(long id, String name, DateTime dateOfBirth)
{
// 初始化代码
}
// ---- 属性省略以简化代码 -----------------
// ---- IPortableObject 实现 -------------------
public virtual void ReadExternal(IPofReader reader)
{
id = reader.ReadInt64(0);
name = reader.ReadString(1);
dateOfBirth = reader.ReadDateTime(2);
}
public virtual void WriteExternal(IPofWriter writer)
{
writer.WriteInt64( 0, id);
writer.WriteString( 1, name);
writer.WriteDateTime(2, dateOfBirth);
}
// ---- Equals、GetHashCode 和 ToString 省略 -------
}
7.4 实现外部序列化器
以下是
EnumPofSerializer
的 .NET 实现示例:
public class EnumPofSerializer : IPofSerializer
{
public void Serialize(IPofWriter writer, object o)
{
if (o == null || !o.GetType().IsEnum)
{
throw new ArgumentException(
"EnumPofSerializer can only be used to serialize enum types.");
}
writer.WriteString(0, o.ToString());
writer.WriteRemainder(null);
}
public object Deserialize(IPofReader reader)
{
IPofContext pofContext = reader.PofContext;
Type enumType = pofContext.GetType(reader.UserTypeId);
if (!enumType.IsEnum)
{
throw new ArgumentException(
"EnumPofSerializer can only be used to deserialize enum types.");
}
object enumValue = Enum.Parse(enumType, reader.ReadString(0));
reader.ReadRemainder();
return enumValue;
}
}
8. 执行查询
从 Coherence for .NET 客户端执行查询与从 Java 应用程序执行查询非常相似,只需创建一个过滤器并使用
Tangosol.Net.Cache.IQueryCache
接口中定义的方法执行它:
public interface IQueryCache : ICache
{
object[] GetKeys(IFilter filter);
// 其他方法
}
排序操作在客户端执行,不会给缓存服务器节点增加额外负载,但
LimitFilter
除外,它需要在集群中进行排序以确定要返回的第一页结果,这在分布式环境中是一项相当昂贵的操作,应尽量避免。如果需要集群端排序,可以考虑使用 Coherence Tools
TopAggregator
。
9. 实现过滤器和值提取器
在定义过滤器时,需要使用值提取器。Coherence for .NET 中包含了所有在查询数据网格时描述的过滤器和值提取器,可以像在 Java 中一样轻松使用。
过滤器和值提取器的执行位置取决于所使用的缓存类型。如果对远程缓存发出查询,过滤器和值提取器会被序列化并传输到代理服务器执行;如果对本地或连续查询缓存(除非仅缓存键而不缓存值)执行查询,则会在客户端直接评估,这可以显著提高性能并减少缓存服务器的负载。
为了使过滤器和值提取器在客户端和集群中都能正常工作,它们必须在 Java 和 .NET 中有并行实现,并且要在相应的 POF 配置文件中使用相同的类型标识符进行正确注册。
10. 在 C# 中实现
PropertyExtractor
内置的
ReflectionExtractor
在 C# 中使用时不太自然,因为它要求根据缓存类型指定不同的访问器方法名称,这可能导致开发过程中更改缓存配置时出现错误。以下是
PropertyExtractor
的 .NET 实现:
public class PropertyExtractor
: AbstractExtractor, IValueExtractor, IPortableObject
{
// ---- 数据成员 -------------------------------------
private const BindingFlags BINDING_FLAGS =
BindingFlags.Public
| BindingFlags.Instance
| BindingFlags.IgnoreCase;
private String m_propertyName;
[NonSerialized]
private PropertyInfo m_property;
// ---- 构造函数 -------------------------------------
public PropertyExtractor()
{}
public PropertyExtractor(String propertyName)
: this(propertyName, VALUE)
{}
public PropertyExtractor(String propertyName, int target)
{
if (String.IsNullOrEmpty(propertyName))
{
throw new ArgumentNullException(
"propertyName", "Property name cannot be null");
}
m_propertyName = propertyName;
m_target = target;
}
// ---- IValueExtractor 实现 -------------------
public override Object Extract(Object target)
{
if (target == null)
{
return null;
}
Type targetType = target.GetType();
try
{
PropertyInfo property = m_property;
if (property == null || property.DeclaringType != targetType)
{
m_property = property =
targetType.GetProperty(m_propertyName, BINDING_FLAGS);
}
return property.GetValue(target, null);
}
catch (Exception)
{
throw new Exception("Property " + m_propertyName +
" does not exist in the class " + targetType);
}
}
// ---- IPortableObject 实现 -------------------
public void ReadExternal(IPofReader reader)
{
m_propertyName = reader.ReadString(0);
m_target = reader.ReadInt32( 1);
}
public void WriteExternal(IPofWriter writer)
{
writer.WriteString(0, m_propertyName);
writer.WriteInt32( 1, m_target);
}
// ---- Equals、GetHashCode 和 ToString 省略 -------
}
通过以上步骤和代码示例,你可以在 .NET 环境中全面使用 Coherence 的各项功能,实现高效的数据缓存和处理。
.NET 访问 Coherence 全解析
11. 实现
StartsWithFilter
在 Java 中我们已经实现了
StartsWithFilter
,现在来实现其 .NET 版本。
StartsWithFilter
用于筛选出属性值以指定字符串开头的条目。以下是具体实现:
public class StartsWithFilter : IFilter, IPortableObject
{
private string m_propertyName;
private string m_prefix;
public StartsWithFilter()
{
}
public StartsWithFilter(string propertyName, string prefix)
{
m_propertyName = propertyName;
m_prefix = prefix;
}
public bool Evaluate(object o)
{
if (o == null)
{
return false;
}
PropertyExtractor extractor = new PropertyExtractor(m_propertyName);
object value = extractor.Extract(o);
if (value is string strValue)
{
return strValue.StartsWith(m_prefix);
}
return false;
}
public void ReadExternal(IPofReader reader)
{
m_propertyName = reader.ReadString(0);
m_prefix = reader.ReadString(1);
}
public void WriteExternal(IPofWriter writer)
{
writer.WriteString(0, m_propertyName);
writer.WriteString(1, m_prefix);
}
}
这个过滤器会根据指定的属性名和前缀,筛选出对象中对应属性值以该前缀开头的对象。
12. 示例应用流程
为了更好地理解如何在实际应用中使用上述功能,下面给出一个完整的示例应用流程:
1.
配置环境
- 创建
coherence.xml
、
coherence-cache-config.xml
和
coherence-pof-config.xml
文件,按照前面介绍的配置方法进行配置。
- 在
coherence-pof-config.xml
中注册自定义的数据对象和过滤器、提取器等。
2.
实现数据对象
- 创建实现
IPortableObject
接口的数据对象,如
Customer
类。
- 或者实现外部序列化器,如
EnumPofSerializer
。
3.
配置缓存
- 使用
CacheFactory
获取缓存实例,如
INamedCache cache = CacheFactory.GetCache("myCache");
。
4.
操作缓存数据
- 使用
Insert
、
InsertAll
、
GetAll
等方法操作缓存数据。
- 示例代码如下:
INamedCache cache = CacheFactory.GetCache("myCache");
Customer customer = new Customer(1, "John Doe", DateTime.Now);
cache.Insert(1, customer);
IDictionary result = cache.GetAll(new List<int> { 1 });
-
执行查询
-
创建过滤器,如
StartsWithFilter,并使用IQueryCache接口的方法执行查询。 - 示例代码如下:
-
创建过滤器,如
IQueryCache queryCache = (IQueryCache)cache;
StartsWithFilter filter = new StartsWithFilter("name", "J");
object[] keys = queryCache.GetKeys(filter);
13. 性能优化建议
在使用 Coherence for .NET 时,为了获得更好的性能,可以考虑以下几点建议:
-
批量操作
:尽量使用
InsertAll
和
GetAll
方法进行批量插入和读取操作,减少网络开销。例如:
IDictionary data = new Dictionary<int, Customer>();
data.Add(1, new Customer(1, "John", DateTime.Now));
data.Add(2, new Customer(2, "Jane", DateTime.Now));
cache.InsertAll(data);
- 本地缓存 :对于一些经常访问的数据,可以使用本地缓存,减少对远程缓存的请求。可以通过配置近程缓存方案来实现。
-
避免不必要的排序
:如前面提到的,
LimitFilter在集群中排序开销较大,尽量避免使用。如果需要排序,可以考虑在客户端进行或者使用TopAggregator。 - 合理配置超时时间 :在缓存配置文件中,合理配置连接超时、心跳间隔、心跳超时和请求超时等参数,避免因超时设置不合理导致性能问题。例如:
<tcp-initiator>
<remote-addresses>
<socket-address>
<address>localhost</address>
<port>9099</port>
</socket-address>
</remote-addresses>
<connect-timeout>30s</connect-timeout>
</tcp-initiator>
<outgoing-message-handler>
<heartbeat-interval>1s</heartbeat-interval>
<heartbeat-timeout>10s</heartbeat-timeout>
<request-timeout>30s</request-timeout>
</outgoing-message-handler>
14. 总结
通过以上内容,我们全面了解了在 .NET 环境中访问 Coherence 的各个方面,包括配置、资源加载、数据操作、查询以及过滤器和提取器的实现等。以下是整个过程的流程图:
graph LR
A[配置环境] --> B[实现数据对象]
B --> C[配置缓存]
C --> D[操作缓存数据]
D --> E[执行查询]
E --> F[性能优化]
在实际应用中,要根据具体需求选择合适的配置和实现方式,同时注意性能优化,以确保系统的高效运行。通过合理使用 Coherence for .NET,我们可以实现高效的数据缓存和处理,为应用程序提供更好的性能和可扩展性。
希望以上内容能帮助你在 .NET 项目中顺利使用 Coherence,实现强大的数据处理功能。如果你在实践过程中遇到问题,可以根据本文提供的方法和代码进行排查和解决。
超级会员免费看
11

被折叠的 条评论
为什么被折叠?



