为什么需要使用分布式缓存

转载:http://in.relation.to/Bloggers/StrongLiu

为什么需要使用分布式缓存(数据网格)呢? 本文旨在回到这个问题.

首先, 它是进化的产物.

本地缓存 > 集群缓存 > 分布式缓存(数据网格)

使用分布式缓存的原因中包括了为什么使用缓存集群, 而使用缓存集群的原因中包括了为什么使用本地缓存.(译注: 这句话感觉上真怪.)

性能

访问本地缓存中的一个对象比直接访问远端数据存储引擎(例如数据库)要快很多.

直接访问一个已经存在的对象比从数据创建一个对象要快.

  • 数据可能已经被存储在某(几)个地方了
  • 数据可能需要通过多条查询来被获取
  • 数据可能很复杂

另外, 数据网格支持一些性能调优特性 可能不被集群缓存所支持. 例如, 应用程序可以根据数据之间关联关系的紧密程度来确保相互关联的对象被保存在相同的缓存节点上.

更进一步, JBoss Data Grid还有一些自己所特有的性能调优方法, 例如, 它可以被配置成使用异步通讯并且提供了一个异步API.

一致性

本地缓存只有在应用程序被部署到单一的应用服务器上的时候才有意义, 如果它被部署到了多台应用服务器上的话, 那么本地缓存一点意义都没有, 问题出在过期数据. 集群缓存通过复制和让缓存数据失效来解决这个问题的.

除了支持JTA事物之外, 数据网格还支持XA(分布式)和两阶段提交事物.

最后, JBoss Data Grid还支持额外支持某些其它数据网格产品可能不支持的保证数据一致性的特性, 例如它支持事物处理恢复, 和基于版本号的更新或删除.

可伸缩性

集群缓存和数据网格的区别就在于可伸缩性. 数据网格是可伸缩的. 缓存数据是通过动态的分区被分发的. 结果就是, 增加一个缓存节点即提高了吞吐量也提高了容量.

JBoss Data Grid通过使用一致性Hash算法, 最小化的降低了增加或者删除一个结点所带来的结点(译注: 推荐阅读这篇文章, 或者这篇, 是中文的), 当增加或者删除一个结点的时候, 只有一部分数据被重新移动已达到平衡. 所以, 增加或者删除一个结点只会对数据网格中的一部分结点产生影响, 而别的算法就很可能会影响到数据网格中的所有结点了.

独立性

另外一个集群缓存和数据网格之间的不同点即是否支持独立访问了.

如果把一个数据网格集成进应用程序里面的话, 那么它就和应用程序耦合在一起了, 也就是, 当扩展这个内置的数据网格的时候, 同事也需要扩展应用程序, 结果, 扩展网格的同时, 增加了与之关联的应用程序(和应用服务器)的管理成本.

如下面的例子, 一个web应用被部属到了多个应用服务器, 并且它使用了内置的数据网格系统, 当这个数据网格缓存了足够多的内容的时候, 它就需要被扩容了.

这意味着什么呢?

需要安装并配置一个新的应用服务器, 然后把应用也部属到这个新的应用服务器中.

这意味着?

IT人员需要多管理一个应用服务器, 增加了管理成本.

  • 如果应用被重新部署, 内置的数据网格结点就被重新部署.*
  • 如果数据网格升级, 应用升序也得跟着升级(并且重新部署)

* 一个数据网格结点被重新部署的话, 那么整个数据网格的拓扑结构是会变化两次的: 一次是当结点被移出的时候, 另外一次是结点被部属的时候. 并且, 一旦数据网格拓扑结构发生变化, 网格内的数据会在结点之间被移动已达到平衡的(尽管只是一部分数据). 所以, 重新部属一个应用程序会对其它节点上运行着的数据网格产生影响, 并且是两次.

如果数据网格需要被调整的运行更快而应用不需要呢?

部属应用到额外的应用服务器, 尽管瓶颈并不在应用这里的话, 这样合理么? 考虑了资源利用率了么? 仅仅为了增加数据网格的吞吐量就增加应用服务器, 尽管会出现应用服务器空载, 这样又合理么?

解决方案就是使用独立的数据网格.

如下面的例子. 同样的, 一个web应用被部署到多个应用服务器, 但是, 这里, 它使用一个独立的数据王哥系统. 这时候, 数据网格达到了它所支持的最大容量, 需要被扩容.

这又意味着?

一个新的数据网格结点被安装并且配置, 就这么简单.

这样的架构允许数据网格能够独立于应用服务器而被独立的扩展. 也让数据网格的服务器能够被指派与应用服务器不同的资源. 例如, 一个数据网格结点服务器可能需要更多的内存但是更少的CPU, 相比于应用服务器的服务器.

这样的架构也让数据网格的基础架构能够独立于应用服务器的被惯例和调整.

数据网格能够独立于应用而被升级, 应用的重新部署也不会对数据网格本身产生任何影响.

基础架构

对比在基础架构中作为顶级系统的独立数据网格和内置于其它系统之中的二级数据网格服务.

举个例子, 一个企业有一个应用程序部属于应用服务器集群当中, 并且这个应用程序内置了一个数据网格系统. 接着, 这个企业有…

  • 增加了一个基于ESB的服务, 这个服务内部也内置了一个数据网格系统
  • 增加了一个门户, 部属于Portal平台, 它也内置了数据网格
  • 增加了业务流程服务跑在规则管理系统之上, 同样的, 它也内置了数据网格

能看出问题吧.

现在, 这个企业拥有多个独立的(内置)数据网格需要被管理, 也就增加了管理成本. 如果它们缓存的相同的数据(例如客户信息), 那么, 如同使用本地缓存的应用被部署到多台应用服务器一样, 面临着数据过期的风险. 如果数据被一个数据网格更新了, 那么, 在别的数据网格当中的相同数据也就没有意义了, 并且, 如果都存储的一样的数据的话, 那么数据网格的效率也是个问题, 这样, 只有他们容量总和的一部分是有效被利用的, 如同缓存集群一样, 重复的数据.

解决方案就是使用在基础架构中作为顶级系统的独立数据网格服务.

当然, 使用内置的数据网格服务也有其自身的优点, 可能会也可能不会超过使用独立缓存服务所带来的好处.

最后, 扼要重述, 使用数据网格的好处是它的可扩展性, 和独立性, 并且, 作为顶级基础设施组件, 它能够同时提供本地缓存和集群缓存所能够提供的性能和一致性.

转载于:https://www.cnblogs.com/zhujudah/p/4106883.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
是的,上述代码中通过使用分布式缓存来实现生成access_token的方法。在这个例子中,使用的是Redis作为分布式缓存。 以下是使用Redis作为分布式缓存的代码示例: ```java @Autowired private RedisTemplate<String, String> redisTemplate; public ApiWxAuthorizeResponse generateAccessToken() { ApiWxAuthorizeResponse apiResponse = new ApiWxAuthorizeResponse(); try { String tokenCacheKey = "xcx_accessToken_" + Const.APP_ID; String redisData = redisTemplate.opsForValue().get(tokenCacheKey); if (StringUtils.isBlank(redisData)) { // 缓存中不存在access_token,需要从微信服务器获取 // 这里省略了获取access_token的具体实现,假设通过wxService的getToken方法获取到了access_token String accessToken = wxService.getToken(globalConfig.getAppId(), globalConfig.getAppSecret()); if (StringUtils.isNotBlank(accessToken)) { // 将access_token存储到redis缓存中 redisTemplate.opsForValue().set(tokenCacheKey, accessToken, expiresIn, TimeUnit.SECONDS); apiResponse.setAccessToken(accessToken); apiResponse.setExpiresIn(String.valueOf(expiresIn)); } else { // 从微信服务器获取access_token失败 // 这里可以根据具体需求进行处理,例如返回错误信息或者抛出异常 } } else { // 缓存中存在access_token,直接使用缓存中的值 apiResponse.setAccessToken(redisData); apiResponse.setExpiresIn(String.valueOf(redisTemplate.getExpire(tokenCacheKey, TimeUnit.SECONDS))); } return apiResponse; } catch (Exception e) { // 异常处理 log.error("异常:生成token接口失败", e); return apiResponse; } } ``` 上述代码中,使用了@Autowired注解注入了RedisTemplate对象,用于操作Redis缓存。在方法中,首先尝试从Redis缓存中获取access_token,如果缓存中不存在,则通过调用wxService的getToken方法从微信服务器获取access_token,并将其存储到Redis缓存中。最后,返回包含access_token和有效期的ApiWxAuthorizeResponse对象。 请注意,上述示例代码中的tokenCacheKey和expiresIn是需要根据实际情况进行替换和设置的变量。另外,为了简化示例,省略了一些具体的实现细节,例如如何获取access_token。实际应用中,可能还需要根据业务需求进行错误处理、日志记录等操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值