啰里吧嗦redis

1.redis是什么
Redis is an open source (BSD licensed), in-memory data structure store, used as a database, cache and message broker.
It supports data structures such as strings, hashes, lists, sets, sorted sets with range queries, bitmaps, hyperloglogs, geospatial indexes with radius queries and streams.
Redis has built-in replication, Lua scripting, LRU eviction, transactions and different levels of on-disk persistence, and provides high availability via Redis Sentinel and automatic partitioning with Redis Cluster
Redis是一个开源(BSD许可),内存数据结构存储,用作数据库,缓存和消息代理
它支持的数据结构有字符串、哈希表散列(键值对)、列表、集合、可随机查询的有序集合、bitmaps位图、hyperloglogs
基数统计、用于半径查询的地理位置索引
Redis已经内置功能有主从复制,LUA脚本,最近最少使用算法失效,事物、各种级别硬盘持久化,Redis哨兵保证可用性、Redis集群自动分片.....
 
简单来说我们把redis当作一个高性能的key-value数据库来使用
 
2.redis的下载安装配置
  • linux的直接去官网下载就行了,下面都有介绍,通过make命令进行安装,看不懂英语的百度下如何使用chrome自带的翻译插件
windows的比较麻烦,还得去github上下载,访问比较卡的可以参考我之前的一篇文章,直接设置hosts, 跳过DNS解析的过程
  • 下载完毕后解压,随便找个redis版本,比如redis-windows-master\redis-windows-master\downloads\redis64-3.0.501.zip解压后放到自己合适的目录下, 例E:\redis64-3.0.501
  • 在解压目录下,按住shift , 鼠标右击, 选中在此处打开命令窗口, 输入命令
redis-server.exe redis.windows.conf
如果不想每次都手写命令,可以写个脚本
目录结构 E:\redis\redis64-3.0.501-6379 在此目录下 新建一个txt @echo off redis-server.exe redis.windows.conf @pause 重命名为startRedisServer.bat bat结尾的是windows可识别的批处理程序 可以直接执行命令窗口的命令 @echo off DOS批处理中的, 不想显示器显示 dos批处理中 的 每条命令 , 加 echo off “echo off”也是命令,它本身也会显示,如果连这条也不显示,就在前面加个“@”。 @本身就是一条指令,意思是跟在它后面的指令的执行及结果都不会在DOS界面上显示出来 pause暂停命令 运行该命令时,将显示消息:请按任意键继续 . . .,一般用于看清楚屏幕上显示的内容 然后新建一个txt,在E:\redis目录下 @echo off cd redis64-3.0.501-6379 startRedisServer.bat 重命名为start6379.cmd cmd开启客户端 @echo off cd redis64-3.0.501-6379 redis-cli @pause
 
 
添加描述
出现此画面代表redis运行成功了,在此目录下接着打开一个命令行
输入如下命令 >redis-cli > set age 32 ok > get age "32"
注1:如果不想每次都进入目录下执行命令,可参考前面的zookeeper,在 系统path下配置环境变量,
这样就能在任意目录下通过redis-cli访问redis了(猜测window系统会根据命令行的命令先去 --系统path路径下找--可执行的文件)
注2:如果不想关闭cmd窗口就终止redis服务,可把redis设置成windows下的服务
设置服务命令 redis-server --service-install redis.windows-service.conf --loglevel verbose 卸载服务:redis-server --service-uninstall 开启服务:redis-server --service-start 停止服务:redis-server --service-stop
通过右击计算机---计算机管理--服务和应用程序--服务可查看多出了一个redis服务
注3:E:\redis64-3.0.501\redis.windows-service.conf
Redis安装的服务默认加载的是该文件,自定义配置信息
 
附:redis解压包和 可视化界面客户端
redis客户端工具大家找找吧,超过10M我就不上传了
 
添加描述
 
 
3.redis实战,spring和redis的结合
项目中如何使用redis呢,思路3部曲,先导包,再配置,最后测试
我自建的项目都是maven方式管理jar包
首先在pom.xml文件添加依赖,因为我用的spring框架,所以导了一个spring-data-redis,jackson包是为了能保持对象 <dependencies> <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.7.1</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.6.2.RELEASE</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>2.1.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.1.0</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-annotations</artifactId> <version>2.1.0</version> </dependency> </dependencies>
在src/main/resources目录下新建一个redis.properties文件里面配置redis的信息
#访问地址 redis.host=127.0.0.1 #访问端口 redis.port=6379 #注意,如果没有password,此处不设置值,但这一项要保留 redis.password= #最大空闲数,数据库连接的最大空闲时间。超过空闲时间,数据库连接将被标记为不可用,然后被释放。设为0表示无限制。 redis.maxIdle=300 #连接池的最大数据库连接数。设为0表示无限制 redis.maxActive=600 #最大建立连接等待时间。如果超过此时间将接到异常。设为-1表示无限制。 redis.maxWait=1000 #在borrow一个jedis实例时,是否提前进行alidate操作;如果为true,则得到的jedis实例均是可用的; redis.testOnBorrow=true
在applicationContext.xml下配置好自动注解扫描,bean文件扫描
<!-- 扫描类包,将标注Spring注解的类自动转化Bean,同时完成Bean的注入 --> <context:component-scan base-package="com.one.*" /> <!--写自己的包的路径 --> <!-- 加载bean配置 --> <import resource="classpath*:conf/beans-*.xml"/> <!-- 因为我的bean文件都是 conf目录下的 名字以beans-开头的 例如 beans-redis.xml -->
 
 
目录结构
在beans-redis.xml文件里配置bean信息
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd "> <!--  如果在多个spring配置文件中引入<context:property-placeholder .../>标签, 最后需要加上ignore-unresolvable="true",否则会报错。 ignore-unresolvable="true" 在加载第一个property-placeholder时出现解析不了的占位符进行忽略掉 --> <!-- 连接池基本参数配置,类似数据库连接池 --> <context:property-placeholder location="classpath:redis.properties" ignore-unresolvable="true" /> <!-- redis连接池 --> <bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxTotal" value="${redis.maxActive}" /> <property name="maxIdle" value="${redis.maxIdle}" /> <property name="testOnBorrow" value="${redis.testOnBorrow}" /> </bean> <!-- 连接池配置,类似数据库连接池 --> <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <property name="hostName" value="${redis.host}"></property> <property name="port" value="${redis.port}"></property> <!-- <property name="password" value="${redis.pass}"></property> --> <property name="poolConfig" ref="poolConfig"></property> </bean> <!--redis操作模版,使用该对象可以操作redis --> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" > <property name="connectionFactory" ref="jedisConnectionFactory"/><!--如果不配置Serializer,那么存储的时候缺省使用String,如果用User类型存储,那么会提示错误User can't cast to String!! --><property name="keySerializer"><bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/></property><property name="valueSerializer"><bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/></property><property name="hashKeySerializer"><bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/></property><property name="hashValueSerializer"><bean class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/></property><!--开启事务 --><property name="enableTransactionSupport" value="true"></property></bean ><!-- 下面这个是整合Mybatis的二级缓存使用的 <bean id="redisCacheTransfer"class="cn.qlq.jedis.RedisCacheTransfer"><property name="jedisConnectionFactory" ref="jedisConnectionFactory"/></bean>--></beans>
最后编写测试类开启测试啦, 工具类网上找找, 下面的代码注入RedisUtil报错,涉及的先都去掉
package com.one.redis; import java.io.InputStream; import java.util.*; import javax.annotation.Resource; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import redis.clients.jedis.Jedis; @RunWith(SpringJUnit4ClassRunner.class) // @ContextConfiguration("classpath:applicationContext-*.xml") @ContextConfiguration(locations = {"classpath:applicationContext.xml"}) // 加载配置文件 @SuppressWarnings("all") public class RedisTest { // @Autowired // private RedisUtil redisUtil; // 1.导包 // applicationContext.xml <import resource="classpath*:conf/beans-*.xml"/> // beans-redis.xml // <bean id="redisTemplate" // class="org.springframework.data.redis.core.RedisTemplate" > @Resource(name = "redisTemplate") private RedisTemplate redisTemplate; @Test public void testSpringRedis() { // stringRedisTemplate的操作 // String读写 redisTemplate.delete("myStr"); redisTemplate.opsForValue().set("myStr", "skyLine"); System.out.println(redisTemplate.opsForValue().get("myStr")); System.out.println("---------------"); // org.springframework.data.redis.RedisConnectionFailureException: // Cannot get Jedis connection; nested exception is // redis.clients.jedis.exceptions.JedisConnectionException: Could not // get a resource from the pool // List读写 redisTemplate.delete("myList"); redisTemplate.opsForList().rightPush("myList", "T"); redisTemplate.opsForList().rightPush("myList", "L"); redisTemplate.opsForList().leftPush("myList", "A"); List<String> listCache = redisTemplate.opsForList().range("myList", 0, -1); for (String s : listCache) { System.out.println(s); } System.out.println("---------------"); // Set读写 redisTemplate.delete("mySet"); redisTemplate.opsForSet().add("mySet", "A"); redisTemplate.opsForSet().add("mySet", "B"); redisTemplate.opsForSet().add("mySet", "C"); redisTemplate.opsForSet().add("mySet", "C"); Set<String> setCache = redisTemplate.opsForSet().members("mySet"); for (String s : setCache) { System.out.println(s); } System.out.println("---------------");// ABC // Hash读写 redisTemplate.delete("myHash"); redisTemplate.opsForHash().put("myHash", "BJ", "北京"); redisTemplate.opsForHash().put("myHash","SH","上海"); redisTemplate.opsForHash().put("myHash","HN","河南"); Map<String, String> hashCache = redisTemplate.opsForHash().entries("myHash");for(Map.Entry entry : hashCache.entrySet()){ System.out.println(entry.getKey()+" - "+ entry.getValue());} System.out.println("---------------");// Redis Incrby 命令将 key 中储存的数字加上指定的增量值,如果 key 不存在,那么 key 的值会先被初始化为 0// ,然后再执行 INCR 操作 double stringValueDouble = redisTemplate.opsForValue().increment("doubleValue",5); System.out.println("通过increment(K key, double delta)方法以增量方式存储double值:"+ stringValueDouble);// incrBy:将 key 所储存的值加上给定的增量值(increment) 。 Jedis jedis =newJedis("127.0.0.1",6379); jedis.incrBy("key3",5); String v3 = jedis.get("key3"); System.out.println("结果:"+ v3);} @Test publicvoiddelete(){ redisTemplate.delete("myStr"); redisTemplate.delete("mySet"); redisTemplate.delete("myHash"); redisTemplate.delete("key3"); String str ="string";// 1.字符串 redisUtil.set("str", str); System.out.println(redisTemplate.opsForValue().get("str"));} @Autowired private RedisUtil redisUtil; @Test publicvoidtestSpringRedis2(){ String str ="string";// 1.字符串 List<String> list =newArrayList<String>();// list list.add("0"); list.add("中国"); list.add("2"); Set<String>set=newHashSet<String>();// setset.add("0");set.add("中国");set.add("2"); Map<String, Object> map =newHashMap();// map map.put("key1","str1"); map.put("key2","中国"); map.put("key3","str3"); redisUtil.del("myStr","str");// 删除数据// 1.字符串操作 System.out.println(str); redisUtil.set("str", str); redisUtil.expire("str",120);// 指定失效时间为2分钟 String str1 =(String) redisUtil.get("str"); System.out.println(redisTemplate.opsForValue().get("str")); System.out.println("str1= "+ str1);// 2.list操作 redisUtil.lSet("list", list); redisUtil.expire("list",120);// 指定失效时间为2分钟 List<Object> list1 = redisUtil.lGet("list",0,-1); System.out.println(list1);// 3.set操作 redisUtil.sSet("set",set); redisUtil.expire("set",120);// 指定失效时间为2分钟 Set<Object> set1 = redisUtil.sGet("set"); System.out.println(set1);// 3.map操作 redisUtil.hmset("map", map); redisUtil.expire("map",120);// 指定失效时间为2分钟 Map<Object, Object> map1 = redisUtil.hmget("map"); System.out.println(map1);}// TODO 哨兵集群// TODO CDN}
这里要说明下,真实这些配置文件的地址其实都在classes 也就是classpath根目录下
E:\e\eclipse\work\one-parent\one-common\target\classes,如果读spring源码就大概能知道,spring是如何先读xml,然后在通过classpath 判断 怎么读配置文件
有的没引入单元测试包的
<properties> <junit.version>4.9</junit.version> <spring-version>3.1.2.RELEASE</spring-version> </properties> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring-version}</version> </dependency>
4.redis哨兵集群
上面再介绍redis的基本情况的时候,官网把这个哨兵 sentinel放在最前面讲, 应该是很重要, 主要我们项目中封装了一层又一层,找了好久才找到redis的真实地址,才知道运用了哨兵集群
//遍历哨兵地址和端口号 执行xxx 可忽略 Jedis jedis = new Jedis("", ); HostAndPort master = MyHostAndPort.toHostAndPort(jedis.sentinelGetMasterAddrByName(masterName));
首先是这样,既然redis要集群, 那么就得有集群管理工具,Redis 的 Sentinel 系统用于管理多个 Redis 服务器(instance),Redis 的 Sentinel 为Redis提供了高可用性,包括 监控,提醒,自动故障迁移
什么是高可用, 就是你挂了,我接着跑,生产环境偶尔会遇到服务器宕机,redis连接失败等情况
  • 先来看redis集群,简单来说就是master-slave,主从复制, slave同步master的数据, 用于读写分离和容灾恢复
参考https://blog.csdn.net/u010648555/article/details/79427606 这么操作 1.先将E:\redis\redis64-3.0.501复制三份,分别命名为redis64-3.0.501-6379,redis64-3.0.501-6379, redis64-3.0.501-6381 2.修改6380 6381下的redis.windows.conf文件,改成各自对应的端口号,都做6379的从节点 port 6380 # slaveof <masterip> <masterport> slaveof 127.0.0.1 6379 3.通过上面介绍的cmd脚本形式启动6379, 然后启动6380,然后启动6379客户端,看下图 命令info replication
 
 
 
 
主节点可读可写,从节点只能读不可写,具体的可以自己试试
发现我写个打开redis-cli脚本,打开6380,弹出的命令窗口还是127.0.0.1:6379>, 于是修改redis.windows-service.conf
也没用,后来查原来是从节点是要加个参数
@echo off cd redis64-3.0.501-6380 redis-cli -p 6380 @pause
 
 
当主节点重新启动后,从节点的状态【从节点依然可以连接主节点】
 
 
  • redis主从复制的缺点: 每次slave断开重连后,都要重新全部同步一遍, 复制延迟,如果master不能写入,会导致业务出错,可用性不高,所以采用哨兵模式
  • 接着上文的基础看redis-sentinel模式的配置,已经有了主从配置,E:\redis\redis64-3.0.501-6379在每个文件夹下添加一个sentinel.conf的配置文件,这个文件在官网下载linux版本目录下直接有
# Example sentinel.conf # *** IMPORTANT *** # # By default Sentinel will not be reachable from interfaces different than # localhost, either use the 'bind' directive to bind to a list of network # interfaces, or disable protected mode with "protected-mode no" by # adding it to this configuration file. # # Before doing that MAKE SURE the instance is protected from the outside # world via firewalling or other means. # # For example you may use one of the following: # # bind 127.0.0.1 192.168.1.1 # # protected-mode no # port <sentinel-port> # The port that this sentinel instance will run on当前Sentinel服务运行的端口 port 26379 # sentinel announce-ip <ip> # sentinel announce-port <port> # # The above two configuration directives are useful in environments where, # because of NAT, Sentinel is reachable from outside via a non-local address. # # When announce-ip is provided, the Sentinel will claim the specified IP address # in HELLO messages used to gossip its presence, instead of auto-detecting the # local address as it usually does. # # Similarly when announce-port is provided and is valid and non-zero, Sentinel # will announce the specified TCP port. # # The two options don't need to be used together, if only announce-ip is # provided, the Sentinel will announce the specified IP and the server port # as specified by the "port" option. If only announce-port is provided, the # Sentinel will announce the auto-detected local IP and the specified port. # # Example: # # sentinel announce-ip 1.2.3.4 # dir <working-directory> # Every long running process should have a well-defined working directory. # For Redis Sentinel to chdir to /tmp at startup is the simplest thing # for the process to don't interfere with administrative tasks such as # unmounting filesystems. dir /tmp # sentinel monitor <master-name> <ip> <redis-port> <quorum> # # Tells Sentinel to monitor this master, and to consider it in O_DOWN # (Objectively Down) state only if at least <quorum> sentinels agree. # # Note that whatever is the ODOWN quorum, a Sentinel will require to # be elected by the majority of the known Sentinels in order to # start a failover, so no failover can be performed in minority. # # Slaves are auto-discovered, so you don't need to specify slaves in # any way. Sentinel itself will rewrite this configuration file adding # the slaves using additional configuration options. # Also note that the configuration file is rewritten when a # slave is promoted to master. # # Note: master name should not include special characters or spaces. # The valid charset is A-z 0-9 and the three characters ".-_".哨兵监听的主服务器 #sentinel monitor [master-group-name] [ip] [port] [quorum] #master-group-name:master名称(可以自定义) #quorun:票数,Sentinel需要协商同意master是否可到达的数量。 #指示 Sentinel 去监视一个名为 mymaster 的主服务器, 这个主服务器的 IP 地址为 127.0.0.1 , 端口号为 6379 #而将这个主服务器判断为失效至少需要 2 个 Sentinel 同意 (只要同意 Sentinel 的数量不达标,自动故障迁移就不会执行)。 sentinel monitor mymaster 127.0.0.1 6379 2 # sentinel auth-pass <master-name> <password> # # Set the password to use to authenticate with the master and slaves. # Useful if there is a password set in the Redis instances to monitor. # # Note that the master password is also used for slaves, so it is not # possible to set a different password in masters and slaves instances # if you want to be able to monitor these instances with Sentinel. # # However you can have Redis instances without the authentication enabled # mixed with Redis instances requiring the authentication (as long as the # password set is the same for all the instances requiring the password) as # the AUTH command will have no effect in Redis instances with authentication # switched off. # # Example: # # sentinel auth-pass mymaster MySUPER--secret-0123passw0rd # sentinel down-after-milliseconds <master-name> <milliseconds> # # Number of milliseconds the master (or any attached slave or sentinel) should # be unreachable (as in, not acceptable reply to PING, continuously,for the # specified period)in order to consider it in S_DOWN state(Subjectively # Down). # # Default is 30 seconds.3s内mymaster无响应,则认为mymaster宕机了 Sentinel 认为服务器已经断线所需的毫秒数 #如果服务器在给定的毫秒数之内, 没有返回 Sentinel 发送的 PING 命令的回复, 或者返回一个错误, 那么 Sentinel 将这个服务器标记为主观下线(subjectively down,简称 SDOWN ) #只有在足够数量的 Sentinel 都将一个服务器标记为主观下线之后, 服务器才会被标记为客观下线(objectively down, 简称 ODOWN ), 这时自动故障迁移才会执行。 sentinel down-after-milliseconds mymaster 30000 # sentinel parallel-syncs <master-name><numslaves> # # How many slaves we can reconfigure to point to the newslave simultaneously # during the failover. Use a low number if you use the slaves to serve query # to avoid that all the slaves will be unreachable at about the same # time while performing the synchronization with the master.执行故障转移时, 最多有1个从服务器同时对新的主服务器进行同步 # 选项指定了在执行故障转移时, 最多可以有多少个从服务器同时对新的主服务器进行同步, 这个数字越小, 完成故障转移所需的时间就越长。 sentinel parallel-syncs mymaster 1 # sentinel failover-timeout <master-name><milliseconds> # # Specifies the failover timeout in milliseconds. It is used in many ways: # # - The time needed to re-start a failover after a previous failover was # already tried against the same master by a given Sentinel, is two # times the failover timeout. # # - The time needed for a slave replicating to a wrong master according # to a Sentinel current configuration, to be forced to replicate # with the right master, is exactly the failover timeout(counting since # the moment a Sentinel detected the misconfiguration). # # - The time needed to cancel a failover that is already in progress but # did not produced any configuration change(SLAVEOF NO ONE yet not # acknowledged by the promoted slave). # # - The maximum time a failover in progress waits for all the slaves to be # reconfigured as slaves of the newmaster. However even after this time # the slaves will be reconfigured by the Sentinels anyway, but not with # the exact parallel-syncs progression as specified. # # Default is 3 minutes. 如果180秒后,mysater仍没启动过来,则启动failover sentinel failover-timeout mymaster 180000 # SCRIPTS EXECUTION # # sentinel notification-script and sentinel reconfig-script are used in order # to configure scripts that are called to notify the system administrator # or to reconfigure clients after a failover. The scripts are executed # with the following rules for error handling: # # If script exits with"1" the execution is retried later(up to a maximum # number of times currently set to 10). # # If script exits with"2"(or an higher value) the script execution is # not retried. # # If script terminates because it receives a signal the behavior is the same # as exit code 1. # # A script has a maximum running time of60 seconds. After this limit is # reached the script is terminated with a SIGKILL and the execution retried. # NOTIFICATION SCRIPT # # sentinel notification-script <master-name><script-path> # # Call the specified notification script for any sentinel event that is # generated in the WARNING level(for instance -sdown,-odown, and so forth). # This script should notify the system administrator via email, SMS, or any # other messaging system, that there is something wrong with the monitored # Redis systems. # # The script is called with just two arguments: the first is the event type # and the second the event description. # # The script must exist and be executable in order for sentinel to start if # this option is provided. # # Example: # # sentinel notification-script mymaster /var/redis/notify.sh # CLIENTS RECONFIGURATION SCRIPT # # sentinel client-reconfig-script <master-name><script-path> # # When the master changed because of a failover a script can be called in # order to perform application-specific tasks to notify the clients that the # configuration has changed and the master is at a different address. # # The following arguments are passed to the script: # # <master-name><role><state><from-ip><from-port><to-ip><to-port> # # <state> is currently always "failover" # <role> is either "leader" or "observer" # # The arguments from-ip,from-port, to-ip, to-port are used to communicate # the old address of the master and the newaddressof the elected slave # (now a master). # # This script should be resistant to multiple invocations. # # Example: # # sentinel client-reconfig-script mymaster /var/redis/reconfig.sh # SECURITY # # By default SENTINEL SET will not be able to change the notification-script # and client-reconfig-script at runtime. This avoids a trivial security issue # where clients can set the script to anything and trigger a failover in order # to get the program executed. sentinel deny-scripts-reconfig yes
在复制的redis文件夹里也加下该文件,然后改一下端口,26380,和 26381
可以在redis解压目录下 通过redis-server.exe redis.windows.conf redis-server.exe sentinel.conf --sentinel 命令, 先启动Redis集群,再启动哨兵实例 也可以像之前那样,写个脚本执行 示例文件做了详细的配置说明,启动不了,估计是里面哪里配置有误,懒得找了,用下面的简化版sentinel.conf port 26379 sentinel monitor mymaster 127.0.0.1 6379 2 sentinel down-after-milliseconds mymaster 3000 sentinel failover-timeout mymaster 10000 sentinel config-epoch mymaster 0 执行后你会发现该文件有变化,写入了从服务器的信息 # Generated by CONFIG REWRITE dir "E:\\redis\\redis64-3.0.501-6379" sentinel leader-epoch mymaster 0 sentinel known-slave mymaster 127.0.0.1 6380 sentinel known-slave mymaster 127.0.0.1 6381 sentinel current-epoch 0 如果报Invalid argument during startup: Failed to open the .conf file: 一般都是配置文件的问题,把它从其他地方关闭
 
 
生成哨兵ID(Sentinel ID),并自动识别主服务器和从服务器
启动后,可以使用shutdown命令关闭master,看slave选举日志,80 81竞争master,恢复79,79就作为slave了
Redis-Sentinel是Redis官方推荐的高可用性(HA) 解决方案,Redis-sentinel本身也是一个独立运行的进程,它能监控多个master-slave集群,发现master宕机后能进行自动切换。Sentinel可以监视任意多个主服务器(复用),以及主服务器属下的从服务器,并在被监视的主服务器下线时,自动执行故障转移操作。
 
为了防止sentinel的单点故障,可以对sentinel进行集群化,创建多个sentinel。
 

 
5.几个常见的redis问题
  • Redis 有哪些类型
官方文档: strings, hashes, 我理解就是hashmap, lists, sets, sorted sets with range queries, 后面3个不知道是啥 bitmaps, hyperloglogs, geospatial indexes with radius queries and streams.
  • Redis 内部结构
了解一点,redis使用 c实现的, 使用kev-value的形式存储数据, 熟悉c语言的更好理解一点结构
1.大多数情况下数据以字符串形式展现 2.双端链表,Redis list的实现为一个双向链表,即可以支持反向查找和遍历 3.字典 4.跳跃表 Redis sorted set的内部使用HashMap和跳跃表(SkipList)来保证数据的存储和有序
 
 
  • 聊聊 Redis 使用场景
1.项目里面比如系统参数配置用到的是string, 还有经常要用的比如产品库存 2.Hash, 项目中用到的是 银行编码+缓存唯一标识做key , 身份证 , 用户ID key , 电子账号 , 用户ID 3.Redis的list是每个子元素都是String类型的双向链表,可以通过push和pop操作从列表的头部或者尾部添加或者删除元素, 这样List即可以作为栈,也可以作为队列。 list可以用在消息队列场景,最新消息排行 比如一些最新评论,展示在首页的可以用redis , 只有点击--显示全部--才需要访问数据库, 降低数据库
  • Redis 持久化机制
1.RDB持久化 Redis DataBase 2.AOF持久化 Append Only File
  • Redis 如何实现持久化
1.RDB : 默认的,内存中数据以 快照 的方式写入到 二进制文件 中,默认的文件名为dump.rdb 例子: save 900 1 #900秒内如果超过1个key被修改,则发起快照保存 方便备份,恢复快,最大化 Redis 的性能 不能避免在服务器故障时丢失数据:RDB 文件需要保存整个数据集的状态,并不是一个轻松的操作 可能会至少 5 分钟才保存一次 RDB 文件。 在这种情况下, 一旦发生故障停机, 你就可能会丢失好几分钟的数据 2.AOF : 当redis重启时会通过重新执行文件中保存的写命令来在内存中重建整个数据库的内容 AOF 持久化会让 Redis 变得非常耐久(much more durable) AOF 的默认策略为每秒钟 fsync 一次,在这种配置下,Redis 仍然可以保持良好的性能,并且就算发生故障停机, 也最多只会丢失一秒钟的数据( fsync 会在后台线程执行,所以主线程可以继续努力地处理命令请求) appendonly yes //启用aof持久化方式 # appendfsync always //每次收到写命令就立即强制写入磁盘,最慢的,但是保证完全的持久化,不推荐使用 appendfsync everysec //每秒钟强制写入磁盘一次,在性能和持久化方面做了很好的折中,推荐 # appendfsync no //完全依赖os,性能最好,持久化没保证
  • Redis 集群方案与实现
参考上面的 哨兵集群
  • Redis 为什么是单线程的
因为Redis是基于内存的操作,CPU不是Redis的瓶颈, 100000+的QPS(每秒内查询次数) per second Redis的瓶颈最有可能是机器内存的大小或者网络带宽 了解: 单线程的方式是无法发挥多核CPU 性能,不过我们可以通过在单机开多个Redis 实例 可以在同一个多核的服务器中,可以启动多个实例,组成master-master或者master-slave的形式 耗时的读命令可以完全在slave进行 单线程,只是在处理我们的网络请求的时候只有一个线程来处理 一个正式的Redis Server运行的时候肯定是不止一个线程的
  • 缓存崩溃
集群,哨兵部署起来 redis备份和预热 缓存预热:系统上线后,将相关的缓存数据直接加载到缓存系统,比如我们用一个job,可以手动执行,去加载所有需要缓存的信息 项目中, 先查缓存, 缓存不存在则从数据库查, 查到结果,置入缓存 由于原有缓存失效,新缓存未到期间(例如:我们设置缓存时采用了相同的过期时间,在同一时刻出现大面积的缓存过期), 所有原本应该访问缓存的请求都去查询数据库了 一个简单方案就时讲缓存失效时间分散开,比如我们可以在原有的失效时间基础上增加一个随机值, 比如1-5分钟随机,这样每一个缓存的过期时间的重复率就会降低,就很难引发集体失效的事件 缓存标记,我们项目中就使用了一个标记string字段: 在项目上线后, 将key :isReliable value:1做缓存,设置永久 先去查缓存,如果缓存中没有,可能是redis全部挂了, 也可能是真的没有数据, 那么查该标记,如果为空可能就是缓存挂了, 再去查数据库的里的表,因为我们做了分表要一次性查20张表的数据 性能很低 如果不为空,说明缓存没挂,在根据业务逻辑进行处理,说明可能真的没存,直接找对应的表
  • 缓存降级
当访问量剧增,仍然要保证核心服务可用, 非核心服务提供有损的也可以,比如本来显示余额的 给它显示一个 "客观别急" 降级方式:可以通过一些数据进行自动降级 通过人工开关进行降级 服务降级的目的,是为了防止Redis服务故障,导致数据库跟着一起发生雪崩问题。因此,对于不重要的缓存数据, 可以采取服务降级策略,例如一个比较常见的做法就是,Redis出现问题,不去数据库查询,而是直接返回默认值给用户
缓存穿透: 缓存命中率问题, 用户查数据,数据库没有,则没有置入缓存,缓存中没有,每次都去查数据库 如果一个查询返回的数据为空(不管是数据不存在,还是系统故障),我们仍然把这个空结果进行缓存,但它的过期时间会很短, 最长不超过五分钟。通过这个直接设置的默认值存放到缓存,这样第二次到缓冲中获取就有值了,而不会继续访问数据库 可以给key设置一些格式规则,然后查询之前先过滤掉不符合规则的Key
  • 使用缓存的合理性问题
1.热点数据 ,当然一些系统参数可以设置永久 2.包括上面提到的缓存降级,预热,穿透等等 3.频繁修改的数据要考虑是否会经常读

猜你喜欢

转载自www.cnblogs.com/tom-kang/p/10592902.html