redis bind 网段

redis bind 网段,第1张

在日常开发中,很多业务场景必须保证原子性。举几个例子:

如果你只有一台服务器,只运行一个Java程序,那么可以使用Java语言自身的一些锁来实现原子性。但如果我们有多台服务器,甚至不同服务器上跑的是不同的语言。那这时候,我们就需要一个跨平台、跨语言的加锁方式。redis就是其中最方便的一种。

使用redis实现并发锁,主要是靠两个redis的命令:setnx和getset。

那我们的设计思路就是:

上面的代码使用了一个RedisService的类,里面主要是简单封装了一下redis的 *** 作,你可以替换为自己的service。代码如下:

以上代码有任何疑问,可以点击右侧边栏联系作者。收费5毛~交个朋友,欢迎来撩!

版权声明:《Springboot使用redis的setnx和getset实现并发锁、分布式锁》为CoderBBB作者「ʘᴗʘ」的原创文章,转载请附上原文出处链接及本声明。

原文链接:>

Redis 是一种开源的高性能、非关系型、基于键值对的数据存储系统,也被称为数据结构服务器。Redis 数据库支持多种数据结构,如字符串(String)、哈希(Hash)、列表(List)、集合(Set)、有序集合(Sorted Set)等,同时 Redis 还提供了事务、 Lua 脚本、持久化、复制、高可用等功能。

Redis 的设计目标是在内存中快速存储和检索数据,它通常被用作缓存、消息队列和数据存储等方面。Redis 具有快速、可扩展、高可靠性和灵活的数据模型等特点,被广泛应用于 Web 应用程序、移动应用程序、游戏、物联网(IoT)等领域。

如果仅仅是写demo,对于sprintboot项目,只要在启动类加上@EnableRedis>

  项目需要在k8s上搭建一个redis cluster集群,网上找到的教程例如:
   github原版带配置文件
   在原版基础上补充详细使用步骤但是无配置文件版
   手把手教你一步一步创建的一篇博客
  redis运行在容器中时必须选择一种外部存储方案,用来保存redis的持久化文件,否则容器销毁重建后无法读取到redis的持久化文件(随着容器一同销毁了);并且还要保证容器重建后还能读取到之前对应的持久化文件。上面的教程使用的是nfs存储,但是受于条件限制本文只能使用宿主机的本地目录来做存储,与上面的教程有一些不一样的地方。
  本文的目的是讲一下使用local pv来作为存储创建redis cluster集群的步骤,以及说明过程中需要注意的问题。

  Kubernetes支持几十种类型的后端存储卷,其中本地存储卷有3种,分别是emptyDir、hostPath、local volume,尤其是local与hostPath这两种存储卷类型看起来都是一个意思。这里讲一下区别。

emptyDir

hostPath

local volume

pv的回收策略有三种:Retain、Recycle、Delete,可以在脚本中指定:

也可以在pv创建成功后使用命令修改:

假设有一个pv叫test-pv,绑定的pvc角坐test-pvc,test-pv使用的local pv

会删除test-pv在对应存储空间上的数据。NFS目前不支持 Delete,支持Delete的存储空间有AWS EBS、GCE PD、Azure Disk、OpenStack Cinder Volume 等(网上看的,没测试过)。

  前面已经说过,redis有数据持久化需求,并且同一个pod重启后需要读取原来对应的持久化数据,这一点在不使用k8s时很容易实现(只使用docker不使用k8s时也很容易),启动redis cluster每个节点时指定其持久化目录就行了,但是k8s的Deployment的调度对于我们这个需求来说就显得很随机,你无法指定deployment的每个pod使用哪个存储,并且重启后仍然使用那个存储。
  Deployment不行,Statefulset可以。官方对Statefulset的优点介绍是:

  看完还是比较迷糊,我们可以简单的理解为原地更新,更新后还是原来那个pod,只更新了需要更新的内容(一般是修改自己写的程序,与容器无关)。
  Statefulset和local pv结合,redis cluster的每个pod挂掉后在k8s的调度下重启时都会使用之前自己的持久化文件和节点信息。

  创建StorageClass的目的是deployment中根据StorageClass来自动为每个pod选择一个pv,否则手动为每个pod指定pv又回到了老路上。

  创建6个pv,因为redis cluster最低是三主三从的配置,所以最少需要6个pod。后面的pv2~pv5我就不贴出来了。

  Headless service是StatefulSet实现稳定网络标识的基础,需要提前创建。

  每个Pod都会得到集群内的一个DNS域名,格式为 (service name)$(namespace)svcclusterlocal。可以在pod中ping一下这些域名,是可以解析为pod的ip并ping通的。

  这个service是可以自由发挥的,使用port-forward、NodePort还是ingress你自己选择,我这里只是一个内网访问统一入口。

  至此,redis cluster的六个节点都已经创建成功。下面需要创建集群(此时就是6个单节点的redis,并不是一个集群)。

  我们之前都是通过外部安装redis-trib创建的集群,但是根据 这篇文章 redis 50之后已经内置了redis-trib工具,感兴趣的可以尝试。
  专门启动一个Ubuntu/CentOS的容器,可以在该容器中安装Redis-tribe,进而初始化Redis集群,执行:
kubectl run -i --tty centos --image=centos --restart=Never /bin/bash
成功后,我们可以进入centos容器中,执行如下命令安装基本的软件环境:

然后执行如下命令创建集群:

根据提示一步一步完成。

  否则报错例如 MOVED 1545 102443239:6379","data":false
  如本文的情况,redis cluster的每个节点都是一个跑在k8s里面的pod,这些pod并不能被外部直接访问,而是通过ingress等方法对外暴露一个访问接口,即只有一个统一的ip:port给外部访问。经由k8s的调度,对这个统一接口的访问会被发送到redis集群的某个节点。这时候对redis的用户来说,看起来这就像是一个单节点的redis。但是, 此时无论是直接使用命令行工具redis-cli,还是某种语言的sdk,还是需要按照集群来配置redis的连接信息,才能正确连接 ,例如

  这里-c就代表这是访问集群,又或者springboot的redis配置文件

第一:Redis 是什么?

Redis是基于内存、可持久化的日志型、Key-Value数据库 高性能存储系统,并提供多种语言的API

第二:出现背景

数据结构(Data Structure)需求越来越多, 但memcache中没有, 影响开发效率

性能需求, 随着读 *** 作的量的上升需要解决,经历的过程有: 
数据库读写分离(M/S)–>数据库使用多个Slave–>增加Cache (memcache)–>转到Redis

解决写的问题: 
水平拆分,对表的拆分,将有的用户放在这个表,有的用户放在另外一个表;

可靠性需求 
Cache的"雪崩"问题让人纠结 
Cache面临着快速恢复的挑战

开发成本需求 
Cache和DB的一致性维护成本越来越高(先清理DB, 再清理缓存, 不行啊, 太慢了!) 
开发需要跟上不断涌入的产品需求 
硬件成本最贵的就是数据库层面的机器,基本上比前端的机器要贵几倍,主要是IO密集型,很耗硬件;

维护性复杂 
一致性维护成本越来越高; 
BerkeleyDB使用B树,会一直写新的,内部不会有文件重新组织;这样会导致文件越来越大;大的时候需要进行文件归档,归档的 *** 作要定期做; 
这样,就需要有一定的down time;

基于以上考虑, 选择了Redis

第三:Redis 在新浪微博中的应用

Redis简介

1 支持5种数据结构

支持strings, hashes, lists, sets, sorted sets 
string是很好的存储方式,用来做计数存储。sets用于建立索引库非常棒;

2 K-V 存储 vs K-V 缓存

新浪微博目前使用的98%都是持久化的应用,2%的是缓存,用到了600+服务器 
Redis中持久化的应用和非持久化的方式不会差别很大: 
非持久化的为8-9万tps,那么持久化在7-8万tps左右; 
当使用持久化时,需要考虑到持久化和写性能的配比,也就是要考虑redis使用的内存大小和硬盘写的速率的比例计算;

3 社区活跃

Redis目前有3万多行代码, 代码写的精简,有很多巧妙的实现,作者有技术洁癖 
Redis的社区活跃度很高,这是衡量开源软件质量的重要指标,开源软件的初期一般都没有商业技术服务支持,如果没有活跃社区做支撑,一旦发生问题都无处求救;

Redis基本原理

redis持久化(aof) append online file: 
写log(aof), 到一定程度再和内存合并 追加再追加, 顺序写磁盘, 对性能影响非常小

1 单实例单进程

Redis使用的是单进程,所以在配置时,一个实例只会用到一个CPU; 
在配置时,如果需要让CPU使用率最大化,可以配置Redis实例数对应CPU数, Redis实例数对应端口数(8核Cpu, 8个实例, 8个端口), 以提高并发: 
单机测试时, 单条数据在200字节, 测试的结果为8~9万tps;

2 Replication

过程: 数据写到master–>master存储到slave的rdb中–>slave加载rdb到内存。 
存储点(save point): 当网络中断了, 连上之后, 继续传 
Master-slave下第一次同步是全传,后面是增量同步;、

3 数据一致性

长期运行后多个结点之间存在不一致的可能性; 
开发两个工具程序: 
1对于数据量大的数据,会周期性的全量检查; 
2实时的检查增量数据,是否具有一致性;

对于主库未及时同步从库导致的不一致,称之为延时问题; 
对于一致性要求不是那么严格的场景,我们只需要要保证最终一致性即可; 
对于延时问题,需要根据业务场景特点分析,从应用层面增加策略来解决这个问题; 
例如: 
1新注册的用户,必须先查询主库; 
2注册成功之后,需要等待3s之后跳转,后台此时就是在做数据同步。

第四:分布式缓存的架构设计

1架构设计

由于redis是单点,项目中需要使用,必须自己实现分布式。基本架构图如下所示:

2分布式实现

通过key做一致性哈希,实现key对应redis结点的分布。

一致性哈希的实现:

l        hash值计算:通过支持MD5与MurmurHash两种计算方式,默认是采用MurmurHash,高效的hash计算

l        一致性的实现:通过java的TreeMap来模拟环状结构,实现均匀分布

3client的选择

对于jedis修改的主要是分区模块的修改,使其支持了跟据BufferKey进行分区,跟据不同的redis结点信息,可以初始化不同的 ShardInfo,同时也修改了JedisPool的底层实现,使其连接pool池支持跟据key,value的构造方法,跟据不同 ShardInfos,创建不同的jedis连接客户端,达到分区的效果,供应用层调用

4模块的说明

l        脏数据处理模块,处理失败执行的缓存 *** 作。

l        屏蔽监控模块,对于jedis *** 作的异常监控,当某结点出现异常可控制redis结点的切除等 *** 作。

整个分布式模块通过hornetq,来切除异常redis结点。对于新结点的增加,也可以通过reload方法实现增加。(此模块对于新增结点也可以很方便实现)

对于以上分布式架构的实现满足了项目的需求。另外使用中对于一些比较重要用途的缓存数据可以单独设置一些redis结点,设定特定的优先级。另外对 于缓存接口的设计,也可以跟据需求,实现基本接口与一些特殊逻辑接口。对于cas相关 *** 作,以及一些事物 *** 作可以通过其watch机制来实现。

声明:所有博客服务于分布式框架,作为框架的技术支持及说明,框架面向企业,是大型互联网分布式企业架构,后期会介绍linux上部署高可用集群项目。

public boolean removeListAll(final K key) {
return redisTemplateexecute(new RedisCallback<Boolean>() {
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
long res = redisTemplateopsForList()remove(key, -1, null);
return res >= 0 true : false;
}
});
}
此方法里就是
redisTemplateopsForList()remove(key, -1, null);
这句不能实现功能
在ListOperations接口里,都是pop相关的方法,但是也没看到执行批量 *** 作的方法


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/dianzi/13282756.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2023-07-07
下一篇 2023-07-07

发表评论

登录后才能评论

评论列表(0条)

保存