redis和codis分享

来源:互联网 发布:extjs object转json 编辑:程序博客网 时间:2024/05/17 07:14

以下是自己的理解,可能会有些误解的地方,还请大家交流指点......

首先说下redis的概念,这些概念都是可以从网上查找到,

Redis的概念:

    redis是一个key-value的存储系统。和Memcached类似,它支持存储的value类型相对更多,包括string(字符串)、list(链表)、set(集合)、zset(sorted set --有序集合)和hash(哈希类型)。这些数据类型都 支持push/pop、add/remove及取交集并集和差集及更丰富的操作,而且这些操作都是原子性的。在此基础上,redis支持各种不同方式的排 序。与memcached一样,为了保证效率,数据都是缓存在内存中。区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文 件,并且在此基础上实现了master-slave(主从)同步。

Redis中包含的可执行文件:

redis-server:Redis服务器的daemon启动程序

redis-cli:Redis命令行操作工具。当然,你也可以用telnet根据其纯文本协议来操作

redis-benchmark:Redis性能测试工具,测试Redis在你的系统及你的配置下的读写性能

redis-stat:Redis状态检测工具,可以检测Redis当前状态参数及延迟状况。

Redis常用的配置参数:

daemonize:是否以后台daemon方式运行

pidfile:pid文件位置

port:监听的端口号

timeout:请求超时时间

loglevel:log信息级别

logfile:log文件位置

databases:开启数据库的数量

save * *:保存快照的频率,第一个*表示多长时间,第二个*表示执行多少次写操作。在一定时间内执行一定数量的写操作时,自动保存快照。可设置多个条件。

rdbcompression:是否使用压缩

dbfilename:数据快照 文件名(只是文件名,不包括目录)

dir:数据快照的保存目录(这个是目录)

appendonly:是否开启appendonlylog,开启的话每次写操作会记一条log,这会提高数据抗风险能力,但影响效率。

Redis主从复制:

redis的主从复制有两种方式,一种是在redis.conf配置,另一种是手动配置。

1.在redis.conf中手动配置:

    首先配置两个redis服务器,假设一台服务器的端口号是6379,另一台服务器的端口号是6378,设置master-slave,6379为主机,6378为从机,只需在从机的redis.conf配置上slaveof <masterip> <masterport>masterip:指的是主机的ip地址,masterport指的是主机redis服务器的端口号

2.手动复制:

    手动复制指的是从机复制主机,打开丛机的redis客户端,输入命令:slaveof <masterip> <masterport>,即可复制成功。

注:所有的主从复制之前,先开启redis-server服务,手动复制必须在redis-cli客户端进行,打开方式:

我所实验的是window环境下:

1. 在window环境下连接redis-server的命令:先进入redis的目录下,redis-server.exe redis.conf

2. 在window下打开redis客户端:进入redis的目录下,redis-cli.exe -h 127.0.0.1 -p 端口号


codis概念:(官方文档)

Codis 是一个分布式 Redis 解决方案, 对于上层的应用来说, 连接到 Codis Proxy 和连接原生的 Redis Server 没有明显的区别 (不支持的命令列表), 上层应用可以像使用单机的 Redis 一样使用, Codis 底层会处理请求的转发, 不停机的数据迁移等工作, 所有后边的一切事情, 对于前面的客户端来说是透明的, 可以简单的认为后边连接的是一个内存无限大的 Redis 服务.

Codis 由四部分组成:

· Codis Proxy (codis-proxy)

· Codis Manager (codis-config)

· Codis Redis (codis-server)

· ZooKeeper

codis-proxy 是客户端连接的 Redis 代理服务, codis-proxy 本身实现了 Redis 协议, 表现得和一个原生的 Redis 没什么区别 (就像 Twemproxy), 对于一个业务来说, 可以部署多个 codis-proxy, codis-proxy 本身是无状态的.

codis-config 是 Codis 的管理工具, 支持包括, 添加/删除 Redis 节点, 添加/删除 Proxy 节点, 发起数据迁移等操作. codis-config 本身还自带了一个 http server, 会启动一个 dashboard, 用户可以直接在浏览器上观察 Codis 集群的运行状态.

codis-server 是 Codis 项目维护的一个 Redis 分支, 基于 2.8.13 开发, 加入了 slot 的支持和原子的数据迁移指令. Codis 上层的 codis-proxy 和 codis-config 只能和这个版本的 Redis 交互才能正常运行.

Codis 依赖 ZooKeeper 来存放数据路由表和 codis-proxy 节点的元信息, codis-config 发起的命令都会通过 ZooKeeper 同步到各个存活的 codis-proxy.

Codis动态扩容:

1. 当内存不够时,可以添加分组,在分组中添加redis服务,给组分配slots

2. 一个group分组由一个master0到多个slave组成。

分组是采用的主从复制:主从复制的方法,可以在redis.conf中配置slaveof <masterip> <masterport>,也可以手动复制(参考redis主从复制)


Jedis和Codis性能对比:

1.下是jedis代码测试:

public class RedisShardPoolTest {   
    static ShardedJedisPool pool;
    static{
        JedisPoolConfig config =new JedisPoolConfig();//Jedis池配置
        config.setMaxActive(300);//最大活动的对象个数
        config.setMaxIdle(1000 * 60);//对象最大空闲时间
        config.setMaxWait(1000 * 10);//获取对象时最大等待时间
        config.setTestOnBorrow(true);
        String hostA = "127.0.0.1";
        int portA = 6379;
        String hostB = "127.0.0.1";
        int portB = 6378;
        List<JedisShardInfo> jdsInfoList =new ArrayList<JedisShardInfo>(2);
        JedisShardInfo infoA = new JedisShardInfo(hostA, portA);
        JedisShardInfo infoB = new JedisShardInfo(hostB, portB);
        jdsInfoList.add(infoA);
        jdsInfoList.add(infoB);
        pool =new ShardedJedisPool(config, jdsInfoList);
     }
    public static void main(String[] args) {
        long s1=System.currentTimeMillis();        
        Map<String, String> map=new HashMap<String, String>();
        for(int i=0; i<1000; i++){
              ShardedJedis jds = null;//切片连接池
              jds = pool.getResource();
            try {               
                map.put("s"+i, "s"+i);
                jds.hmset("s"+i, map);               
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                pool.returnResource(jds);
            }
        }
        long s2=System.currentTimeMillis();
        System.out.println(testTime(s2-s1));        
    }   
    public static String testTime(long ss){
        String aa=null;
        long zongmiaoshu = ss / 1000;
        long dangqianmiaoshu = zongmiaoshu % 60;
        long zongfenshu = zongmiaoshu /60;
        long dangqianfenshu = zongfenshu % 60;
        long zongshishu = zongfenshu / 60;
        long dangqianshishu = zongshishu % 24;    
        aa="当前时间:" + dangqianshishu + ":" + dangqianfenshu + ":" + dangqianmiaoshu;    
        return aa;            
    }
}

2.codis代码测试:先配置codis,codis的安装配置就不讲了,我测试在集成在spring中了。

spring中的配置:

<bean id="ehcacheService" class="net.okdi.core.common.redis.RedisServiceImpl"/>
    <context:property-placeholder location="classpath:/redis.properties"
    ignore-unresolvable="true" />
    <bean id="jedisConfig" class="redis.clients.jedis.JedisPoolConfig">
        <property name="maxActive" value="${redis_max_active}"></property>
        <property name="maxIdle" value="${redis_max_idle}"></property>
        <property name="maxWait" value="${redis_max_wait}"></property>
        <property name="testOnBorrow" value="${redis_test_on_borrow}"></property>
    </bean>
    <bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
        <property name="hostName" value="${redis_addr}"></property>
        <property name="port" value="${redis_port}"></property>
        <property name="password" value="${redis_auth}"></property>
        <property name="poolConfig" ref="jedisConfig"></property>
    </bean>
    <bean id="redisTemplate" class="org.springframework.data.redis.core.StringRedisTemplate">
        <property name="connectionFactory" ref="connectionFactory" />
        如果不配置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.JdkSerializationRedisSerializer" />
        </property>
    </bean>   

redis配置
redis_addr=192.168.31.204
redis_port=19000 (codis代理服务器端口)
redis_auth=okdi
redis_max_active=1024
redis_max_idle=200
redis_max_wait=10000
redis_timeout=10000
redis_test_on_borrow=true

封装的redis方法,用的是redisTemplate

public class RedisServiceImpl implements EhcacheService {

    private static Logger logger = Logger.getLogger(EhcacheServiceImpl.class);

    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private RedisConstant redisConstant;
    
    @Override
    public void put(String cacheName, String key, String value) {
//        boolean bool = redisTemplate.hasKey(cacheName);
        if (cacheName==null || "".equals(cacheName) || key==null || "".equals(key)) {
            return;
        }
        //放入redis
        redisTemplate.opsForHash().put(cacheName, key, value);
        
        long expireTime = redisConstant.getExpireTime(cacheName);
        //如果不等于-1,则该cacheName配置有过期时间
        if(expireTime != -1){
            redisTemplate.expire(cacheName, expireTime, TimeUnit.SECONDS);
        }
    }

    @Override
    public void put(String cacheName, String key, Object value) {
        if (cacheName==null || "".equals(cacheName) || key==null || "".equals(key)) {
            return;
        }
        //放入redis
        redisTemplate.opsForHash().put(cacheName, key, JSON.toJSONString(value));
        
        long expireTime = redisConstant.getExpireTime(cacheName);
        //如果不等于-1,则该cacheName配置有过期时间
        if(expireTime != -1){
            redisTemplate.expire(cacheName, expireTime, TimeUnit.SECONDS);
        }
    }

用junit测试:

public class test11 extends BaseTest{
    
    @Autowired
    private EhcacheService redisService;    
    @SuppressWarnings("rawtypes")
    @Test
    public void test1(){    
        long s1=System.currentTimeMillis();

        for(int i=0;i<10000;i++){
            redisService.put("a"+i, "a"+i,"a"+i);
            redisService.remove("a"+i, "a"+i);
        }
        long s2=System.currentTimeMillis();
        System.out.println(testTime(s2-s1));
        System.out.println(redisService.getValueByKey("eeee9", "e9"));
    }














0 0