使用 NCache 将 Java 微服务扩展到极致性能

        微服务已成为软件开发领域的一种变革性架构方法,提供了从整体结构到更加模块化和可扩展的系统的范式转变。微服务的核心是将复杂的应用程序分解为更小的、可独立部署的服务,这些服务可以无缝通信,从而提高敏捷性、灵活性和易维护性。这种分散的方法使开发人员能够专注于特定功能,从而实现快速开发、持续集成和高效扩展,以满足现代动态业务环境的需求。随着组织越来越多地接受微服务的好处,本文探讨了与这种架构风格相关的关键原则、优势和挑战,阐明了它在塑造软件设计和部署的未来中的关键作用。

        微服务应用程序的一个基本特征是能够利用不同的技术堆栈独立设计、开发和部署每个微服务。每个微服务都作为一个独立的自治应用程序运行,具有自己的专用持久性存储,无论是关系数据库、NoSQL 数据库,甚至是传统文件存储系统。这种自主性使单个微服务能够独立扩展,从而促进无缝的实时基础设施调整并增强整体可管理性。

NCache 微服务架构中的缓存层

        在应用程序事务激增的情况下,瓶颈可能会持续存在,尤其是在微服务将数据存储在不可扩展的关系数据库中的架构中。简单地部署微服务的其他实例并不能缓解问题。

        为了应对这些挑战,请考虑集成 NCache 作为分布式缓存在微服务和数据存储之间的缓存层。NCache 不仅用作缓存,还用作可扩展的内存中发布者/订阅者消息传递代理,促进微服务之间的异步通信。

e19e494a603192b9fef5ae635acf23f5.png

        微服务 Java 应用程序性能优化可以通过缓存技术来实现,例如 缓存项锁定、分组缓存数据、休眠缓存、SQL 查询、数据结构、spring 数据缓存技术、发布-订阅消息传递等等 NCache.请检查开箱即用的功能 NCache.

使用 NCache 作为 Hibernate 二级 Java 缓存

Hibernate 一级缓存

        Hibernate 第一级缓存充当链接到 Session 对象的基本独立(进程内)缓存,仅限于当前会话。尽管如此,第一级缓存的一个缺点是它无法在不同会话之间共享对象。如果多个会话需要同一个对象,则每个会话都会触发数据库行程来加载它,从而增加数据库流量并加剧可扩展性问题。此外,当会话结束时,所有缓存的数据都将丢失,因此需要在下次检索时从数据库中重新获取。

Hibernate 二级缓存

        对于仅依赖于第一级缓存的高流量 Hibernate 应用程序,在 Web 场中部署会带来与跨服务器缓存同步相关的挑战。在 Web 场设置中,每个节点都运行一个 Web 服务器(如 Apache、Oracle WebLogic 等),其中包含多个 httpd 进程实例来为请求提供服务。这些 HTTP 工作进程中的每个 Hibernate 一级缓存都维护着直接从数据库缓存的相同数据的不同版本,这会带来同步问题。

        这就是 Hibernate 提供具有提供程序模型的二级缓存的原因。Hibernate 二级缓存使您能够集成第三方分布式 (out-proc) 缓存提供程序,以跨会话和服务器缓存对象。与第一级缓存不同,第二级缓存与 SessionFactory 对象相关联,并且可供整个应用程序访问,扩展到单个会话之外。

        启用 Hibernate 二级缓存会导致两个缓存共存:一级缓存和二级缓存。Hibernate 首先尝试从第一级缓存中检索对象;如果不成功,它会尝试从二级缓存中获取它们。如果两次尝试都失败,则直接从数据库加载对象并缓存对象。此配置大大减少了数据库流量,因为很大一部分数据由二级分布式缓存提供。

        NCache Java 通过扩展实现了 Hibernate 二级缓存提供程序 org.hibernate.cache.CacheProvider.集成 NCache Java Hibernate 分布式缓存提供程序与 Hibernate 应用程序不需要更改代码。这种集成使您能够将 Hibernate 应用程序扩展到多服务器配置,而不会使数据库成为瓶颈。NCache 还提供企业级分布式缓存功能,包括数据大小管理、跨服务器数据同步等。

        要合并 NCache Java Hibernate 缓存提供程序,只需对 hibernate.cfg.xml 和 ncache.xml 进行简单修改即可。

        因此,随着 NCache Java Hibernate 分布式缓存提供程序,您可以无缝地实现 Hibernate 应用程序的线性可扩展性,无需更改现有代码。

代码片段

1
// Configure Hibernate properties programmatically
2Properties hibernateProperties = new Properties();
3hibernateProperties.put("hibernate.connection.driver_class", "org.h2.Driver");
4hibernateProperties.put("hibernate.connection.url", "jdbc:h2:mem:testdb");
5hibernateProperties.put("hibernate.show_sql", "false");
6hibernateProperties.put("hibernate.hbm2ddl.auto", "create-drop");
7hibernateProperties.put("hibernate.cache.use_query_cache", "true");
8hibernateProperties.put("hibernate.cache.use_second_level_cache", "true");
9hibernateProperties.put("hibernate.cache.region.factory_class", "org.hibernate.cache.jcache.internal.JCacheRegionFactory");
10hibernateProperties.put("hibernate.javax.cache.provider", "com.alachisoft.ncache.hibernate.jcache.HibernateNCacheCachingProvider");
11// Set other Hibernate properties as needed
12Configuration configuration = new Configuration()
13.setProperties(hibernateProperties).addAnnotatedClass(Product.class);
1415Logger.getLogger("org.hibernate").setLevel(Level.OFF);
1617// Build the ServiceRegistry
18ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
19.applySettings(configuration.getProperties()).build();
2021// Build the SessionFactory
22SessionFactory factory = configuration.buildSessionFactory(serviceRegistry);
2324// Create a List of Product objects
25ArrayList<Product> products = (ArrayList<Product>) getProducts();
26// Open a new Hibernate session to save products to the database. This also caches it
27try (Session session = factory.openSession()) {
28Transaction transaction = session.beginTransaction();
29// save() method saves products to the database and caches it too
30System.out.println("ProductID, Name, Price, Category");
31for (Product product : products) {
32System.out.println("- " + product.getProductID() + ", " + product.getName() + ", " + product.getPrice() + ", " + product.getCategory());
33session.save(product);
34}
35transaction.commit();
36System.out.println();
3738// Now open a new session to fetch products from the DB.
39// But, these products are actually fetched from the cache
40try (Session session = factory.openSession()) {
41List<Product> productList = (List<Product>) session.createQuery("from Product").list();
42if (productList != null) {
43printProductDetails(productList);
44}
45}
46

        集成 NCache 与 Hibernate 轻松缓存查询结果。当 Hibernate 随后获取这些对象时,它们将从缓存中检索,从而避免了昂贵的数据库之旅。

        从上面的代码示例中,产品保存在数据库中,并且还进行了缓存;现在,当新会话打开以获取产品详细信息时,它将从 Cache 中获取并避免不必要的数据库访问。

了解有关 Hibernate 缓存的更多信息

扩展与 NCache 发布/订阅消息

        NCache 是专为 .NET 设计的分布式内存缓存解决方案。它的兼容性通过本机客户端和第三方集成扩展到 Java,确保对这两个平台的无缝支持。

        NCache 作为为 .NET 和 Java 量身定制的内存分布式数据存储,为事件驱动的通信提供功能丰富的内存发布/订阅机制。这使得设置变得简单 NCache 作为消息传递代理,采用 Pub/Sub 模型实现微服务之间的无缝异步通信。

使用 NCache 内存中的 Pub/Sub 用于微服务

        NCache 通过建立微服务可以发布和订阅事件的主题来启用 Pub/Sub 功能。这些事件发布到 NCache 微服务外的消息代理。在每个订阅微服务中,都有一个事件处理程序,用于在原始微服务发布相应事件后对其进行管理。

        在 Java 微服务领域, NCache 充当事件总线或消息代理,促进将消息中继到一个或多个订阅者。

        在需要通信渠道的 Pub/Sub 模型的上下文中, NCache 作为主题的媒介。这需要发布者将消息调度到指定的主题,而订阅者通过同一主题接收通知。采用 NCache 作为主题的媒介促进了模型内的松散耦合,为分布式主题提供了增强的抽象和额外的优势。

发布

下面的代码片段初始化 messageService 对象 NCache MessagingService 包。

初始化 Topic

1// Create a Topic in NCache.
2MessagingService messagingService = cache.getMessagingService();
3Topic topic = messagingService.createTopic(topicName);
45// Create a thread pool for publishers
6ExecutorService publisherThreadPool = Executors.newFixedThreadPool(2);
78The below code snippet used to define register the subscribers to this topic 
9Register subscribers to this Topic
10MessageReceivedListener subscriptionListener1 = new MessageReceivedListener() {
11@Override
12public void onMessageReceived(Object o, MessageEventArgs messageEventArgs) {
13messageReceivedSubscription1(messageEventArgs.getMessage());
14}
15};
16MessageReceivedListener subscriptionListener2 = new MessageReceivedListener() {
17@Override
18public void onMessageReceived(Object o, MessageEventArgs messageEventArgs) {
19messageReceivedSubscription2(messageEventArgs.getMessage());
20}
21};
22TopicSubscription subscription1 = topic.createSubscription(subscriptionListener1);
23TopicSubscription subscription2 = topic.createSubscription(subscriptionListener2);
24

NCache 提供两种持久订阅变体,以满足 Java 微服务中的消息持久性需求:

  • 共享持久订阅:这允许多个订阅者连接到单个订阅。采用 Round Robin 方法在各种订阅者之间分发消息。即使订阅者退出网络,消息也会在活动订阅者之间持续流动。

  • Exclusive Durable Subscriptions:在此类型中,在任何给定时间,一个订阅都只允许一个活动订阅者。在现有连接处于活动状态之前,不接受同一订阅的新订阅者请求。

了解更多 发布/订阅消息收发 NCache 在这里实施缓存中的 Pub/Sub 消息收发:概述

缓存上的 SQL 查询

    NCache 为您的微服务提供了对索引缓存数据执行类似 SQL 的查询的能力。当存储所需信息的键的值未知时,此功能将变得特别有用。它抽象了许多较低级别的缓存 API 调用,有助于实现更清晰、更易于维护的应用程序代码。对于发现类似 SQL 的命令更直观、使用起来更舒适的人来说,此功能尤其有利。

        NCache 提供通过类似于 SQL 的 SELECT 和 DELETE 语句的查询来搜索和删除缓存数据的功能。但是,INSERT 和 UPDATE 等操作不可用。为了在缓存中执行 SELECT 查询, NCache 利用 ExecuteReader;ExecuteScalar 函数用于执行查询并从结果数据集中检索第一行的第一列,而不考虑任何额外的列或行。

        要使 NCache SQL 查询正常运行,必须在所有正在搜索的对象上建立索引。这可以通过两种方法实现:配置缓存或使用具有 “Custom Attributes” 的代码来注释对象字段。将对象添加到缓存时,此方法会自动在指定字段上创建索引。

代码片段

1String cacheName = "demoCache";
2// Connect to the cache and return a cache handle
3Cache cache = CacheManager.getCache(cacheName);
4// Adds all the products to the cache. This automatically creates indexes on various
5// attributes of Product object by using "Custom Attributes".
6addSampleData(cache);
7// $VALUE$ keyword means the entire object instead of individual attributes that are also possible
8String sql = "SELECT $VALUE$ FROM com.alachisoft.ncache.samples.Product WHERE category IN (?, ?) AND price < ?";
9QueryCommand sqlCommand = new QueryCommand(sql);
10List<String> catParamList = new ArrayList<>(Arrays.asList(("Electronics"), ("Stationery")));
11sqlCommand.getParameters().put("category", catParamList);
12sqlCommand.getParameters().put("price", 2000);
1314// ExecuteReader returns ICacheReader with the query resultset
15CacheReader resultSet = cache.getSearchService().executeReader(sqlCommand);
16List<Product> fetchedProducts = new ArrayList<>();
17if (resultSet.getFieldCount() > 0) {
18while (resultSet.read()) {
19// getValue() with $VALUE$ keyword returns the entire object instead of just one column
20fetchedProducts.add(resultSet.getValue("$VALUE$", Product.class));
21}
22}
23printProducts(fetchedProducts);
24

        利用 SQL 中 NCache 通过关注对象属性和标签,而不是仅仅依赖键来对缓存数据执行查询。

在此示例中,我们使用 “Custom Attributes” 在 Product 对象上生成索引。

        了解有关 SQL 查询的更多信息 NCache 在 Java 中使用 SQL 查询缓存中的数据

Read-Thru 和 Write-Thru

        利用数据源提供商的功能 NCache 将其定位为微服务架构中数据访问的主要接口。当微服务需要数据时,它应该首先查询缓存。如果存在数据,则缓存会直接提供该数据。否则,缓存将采用直通处理程序代表客户端从数据存储中获取数据,对其进行缓存,然后将其提供给微服务。

        以类似的方式,对于写入操作(例如 Add、Update、Delete),微服务可以对缓存执行这些操作。然后,缓存使用直通处理程序自动对数据存储执行相应的写入操作。

        此外,您还可以选择强制缓存直接从数据存储中获取数据,而不管缓存中是否存在可能过时的版本。当微服务需要最新信息时,此功能至关重要,并补充了前面提到的缓存一致性策略。

        数据源提供程序功能的集成不仅可以简化您的应用程序代码,而且当与 NCache的数据库同步功能,确保缓存始终使用新数据进行更新以进行处理。

ReadThruProvider

        为了实现 Read-Through 缓存,必须在 Java 中创建 ReadThruProvider 接口的实现

以下是开始在微服务中实施 Read-Thru 的代码片段:

1ReadThruOptions readThruOptions = new ReadThruOptions(ReadMode.ReadThru, _readThruProviderName);
2product = _cache.get(_productId, readThruOptions, Product.class);
3

        在此处阅读有关 Read-Thru 实施的更多信息:Read-Through Provider 配置和实施

WriteThruProvider 中:

        要实现 Write-Through 缓存,必须在 Java 中创建 WriteThruProvider 接口的实现

开始在微服务中实施 Write-Thru 的代码片段:

1
_product = new Product();
2WriteThruOptions writeThruOptions = new WriteThruOptions(WriteMode.WriteThru, _writeThruProviderName)
3CacheItem cacheItem= new CacheItem(_customer)
4_cache.insert(_product.getProductID(), cacheItem, writeThruOptions);
5

总结

        微服务设计为自治的,支持从其他微服务独立开发、测试和部署。虽然微服务在可扩展性和快速开发周期方面提供了优势,但应用程序堆栈的某些组件可能会带来挑战。其中一个挑战是使用关系数据库,它可能不支持必要的横向扩展来处理不断增长的负载。这就是像这样的分布式缓存解决方案的地方 NCache 变得有价值。

        我们看到了各种即用型功能,如发布/订阅消息传递、数据缓存、SQL 查询、Read-Thru 和 Write-Thru,以及 Hibernate 提供的二级 Java 缓存技术 NCache 简化和精简数据缓存与您的微服务应用程序的集成,使其成为一种轻松自然的扩展。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/147323.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

动态规划day38|322. 零钱兑换(背包满了吗?最小值怎么表示?)、279. 完全平方数、139. 单词拆分、多重背包要点、背包问题大总结

动态规划day38|322. 零钱兑换&#xff08;背包满了吗&#xff1f;最小值怎么表示&#xff1f;&#xff09;、279. 完全平方数、139. 单词拆分、多重背包要点、背包问题大总结 322. 零钱兑换279. 完全平方数139. 单词拆分多重背包要点背包问题大总结 322. 零钱兑换 给你一个整数…

后端-项目创建与sql

1.创建文件 1.在webcontent下创建.html文件 2. 在java resources下创建包&#xff0c;右键包创建servlet服务生.(要是创建普通的类&#xff0c;里面的注解里的东西不能重复&#xff09; 注意&#xff1a;class的名字要和文件名一样&#xff0c;注解里的servlet是独一无二的。 …

最新 idea 2024 入门使用详细教程

IntelliJ IDEA&#xff1a;这是一款由JetBrains公司开发的Java集成开发环境&#xff08;Integrated Development Environment&#xff09;&#xff0c;被广泛认为是目前Java开发者最好的集成开发工具之一。它支持Java、Groovy、Kotlin等多种编程语言&#xff0c;并且提供了丰富…

HCIA--实验十七:EASY IP的NAT实现

一、实验内容 1.需求/要求&#xff1a; 通过一台PC&#xff0c;一台交换机&#xff0c;两台路由器来成功实现内网访问外网。理解NAT的转换机制。 二、实验过程 1.拓扑图&#xff1a; 2.步骤&#xff1a; 1.PC1配置ip地址及网关&#xff1a; 2.AR1接口配置ip地址&#xff1…

Java免税商品优选商城:Spring Boot实战

第二章 系统开发关键技术 2.1 JAVA技术 Java主要采用CORBA技术和安全模型&#xff0c;可以在互联网应用的数据保护。它还提供了对EJB&#xff08;Enterrise JavaBeans&#xff09;的全面支持&#xff0c;java servlet AI&#xff0c;JS&#xff08;java server ages&#xff09…

Tomcat中BIO和NIO的区别(Tomcat)

BIO Tomcat中BIO的模型和理论很简单&#xff0c;例图如下 1.Acceptor线程死循环阻塞接收客户端的打过来的socket请求 2.接收到请求之后打包成一个SocketProcessor&#xff08;Runnable&#xff09;&#xff0c;扔到线程池中读取/写入数据 参数配置 1.Acceptor默认线程是1&#…

2024年1月Java项目开发指南17:自动接口文档配置

Knife4j 文档 &#xff1a;https://doc.xiaominfo.com/ 有能力的建议自己去看文档配置&#xff0c;本文仅做参考&#xff0c;因为官方文档会更新&#xff0c;本文不会&#xff0c;以后说不定本文就过时了。 ok&#xff0c;我们继续。虽然本文是2024年1月Java项目开发指南17&…

JVM面试题-说一下JVM主要组成部分及其作用

总体来说&#xff0c;方法区和堆是所有线程共享的内存区域&#xff1b;而虚拟机栈、本地方法栈和程序计数器的运行是线程私有的内存区域&#xff0c;运行时数据区域就是我们常说的JVM的内存。 类加载子系统&#xff1a;根据给定的全限定名类名(如&#xff1a;java.lang.Object…

使用Kong开源API网关的保姆级教程

什么是Kong? Kong是一个开源的、云原生、高性能的API网关,可以轻松地为任何服务提供管理、保护和扩展。它提供了一个可扩展的插件生态系统,可以满足各种各样的需求,如身份验证、授权、限流、监控等。 安装Kong 1. 环境准备 操作系统: CentOS、Ubuntu等主流Linux发行版D…

微信小程序IOS真机调试-onPullDownRefresh和onReachBottom不生效

切换真机调试2.0版本 勾选JS编译成ES5 如果使用了 uniapp&#xff0c;这里也需要勾选 重新启动

【Proteus单片机仿真】基于51单片机的循迹小车避障+气体传感器和温度传感器系统

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 开机即两个直流电机运转&#xff0c;然后三个气体传感器&#xff0c;如果超过阈值&#xff0c;即蜂鸣器报警&#xff1b; 超声波传感器&#xff0c;如果检测到障碍&#xff0c;电机停止&#xff1…

深度学习02-pytorch-06-张量的形状操作

在 PyTorch 中&#xff0c;张量的形状操作是非常重要的&#xff0c;可以让你灵活地调整和处理张量的维度和数据结构。以下是一些常用的张量形状函数及其用法&#xff0c;带有详细解释和举例说明&#xff1a; 1. reshape() 功能: 改变张量的形状&#xff0c;但不改变数据的顺序…

[Redis][List]详细讲解

目录 0.前言1.常用命令1.LPUSH / RPUSH2.LPUSHX / RPUSHX3.LRANGE4.LPOP / RPOP5.LINDEX6.LINSERT7.LLEN8.LREM9.LTRIM10.LSET 2.阻塞版本命令0.是什么&#xff1f;1.BLPOP / BRPOP 3.内部编码(旧版本&#xff0c;仅供参考)1.ziplist(压缩链表)2.linkedlist(链表)3.quicklist(快…

TK72A12N1 N沟道功率MOSFET 工业控制领域的高性能功率开关

TK72A12N1产品特性&#xff1a; 漏源电压&#xff08;Vdss&#xff09;&#xff1a;120V&#xff0c;这意味着该器件在正常工作时&#xff0c;漏极和源极之间所能承受的最大电压为 120V。如果超过这个电压&#xff0c;可能会导致器件损坏。 漏极电流&#xff08;Id&#xff0…

基于SpringBoot和Vue框架的医保管理系统的设计与实现

文未可获取一份本项目的java源码和数据库参考。 1.研究的主要内容与方法 &#xff08;1&#xff09;主要内容 医保管理系统采用B/S模式进行开发&#xff0c;采用Springboot框架、VUE技术、Idea为环境、MySQL为数据库开发。主要功能有&#xff1a;个人资料管理、投保用户管理、…

C++ 把字符串转换成整数 (atoi) - 力扣(LeetCode)

点击链接即可查看&#xff1a;LCR 192. 把字符串转换成整数 (atoi) - 力扣&#xff08;LeetCode&#xff09; 一、题目 请你来实现一个 myAtoi(string s) 函数&#xff0c;使其能将字符串转换成一个 32 位有符号整数&#xff08;类似 C/C 中的 atoi 函数&#xff09;。 函数 my…

剩余参数运算符的babel转义配置

记一次生产构建的报错 uncaught syntaxerror: unexpected token ... 背景 在处理展示markdown文本功能&#xff0c;并且其中的代码高亮功能时&#xff0c;引入了两个第三发的依赖包marked 和 highlight.js &#xff0c;本地功能调试正常之后&#xff0c;一如即往的没有build…

基于51单片机的汽车倒车防撞报警器系统

目录 一、主要功能 二、硬件资源 三、程序编程 四、实现现象 一、主要功能 本课题基于微控制器控制器&#xff0c; 设计一款汽车倒车防撞报警器系统。 要求&#xff1a; 要求&#xff1a;1.配有距离&#xff0c; 用于把车和障碍物之间的距离信号送入控制器。 2.配有报警系…

【漏洞复现】金斗云 HKMP download 任意文件读取漏洞

免责声明&#xff1a; 本文内容旨在提供有关特定漏洞或安全漏洞的信息&#xff0c;以帮助用户更好地了解可能存在的风险。公布此类信息的目的在于促进网络安全意识和技术进步&#xff0c;并非出于任何恶意目的。阅读者应该明白&#xff0c;在利用本文提到的漏洞信息或进行相关测…

[产品管理-32]:NPDP新产品开发 - 30 - 文化、团队与领导力 - 领导力与团队的可持续发展

目录 一、团队领导的领导力 1.1 领导力 1、领导力的定义 2、领导力的重要性 3、领导力的构成要素 4、如何提升领导力 1.2 情商 二、虚拟团队 1、团队定义与特征 2、团队优势 3、团队挑战与应对策略 三、可持续发展 四、团队管理和领导力中的度量指标 4.1 激励创新…