跳至主要內容

Redis的安装

张威大约 10 分钟redisredis安装

Redis的安装

Redis的安装

  1. redis官网上下载最新安装包到家目录

  2. 解压压缩包,然后会在家目录下面生成一个对应文件夹redis-6.0.8。

    tar zxvf redis-6.0.8.tar.gz
    
  3. 进入到解压后的目录redis-6.0.8,然后执行make

    cd redis-6.0.8
    make
    sudo make install
    
  4. 进入utils目录

    cd utils
    

    接着进入到install_server.sh文件,注释掉下面的内容(大于在77行,有8行,shell的注释是以#进行的注释)

    注释之后,保存退出并且执行下面命令

    sudo ./install_server.sh
    
  • 可以看到,安装完之后redis server已启动,默认监听6379

执行redis-server即可启动redis服务器(默认端口6379)

redis-server #启动redis服务器6379
redis-server --port 8989 #切换8989端口启动redis


redis-cli #默认连接6379
redis-cli -p 8989 #客户端连接服务器的8989端口

配置文件

redis-server --port 8989这种启动方式ctrl + c服务器程序就会结束,该端口也就不被redis服务器监听。实际工作中都是使用配置文件的方式来启动redis-server

由于redis.conf文件信息过多,我们去掉注释,并且去掉空白,导出主要信息并生成新的配置文件redis-6379.conf

cd /etc/redis/
cat 6379.conf |grep -v "#"|grep -v "^$" > redis-6379.conf #root账户执行
  • 带注释的配置文件中给出了配置大小单位,定义了一些基本度量单位,

基本配置

基本配置(指定端口、后台启动、日志文件名和路径),其他暂时不管,保存配置文件

#redis-6380.conf

# 绑定的port
port 6380	
#守护进程方法启动,yes则后台启动,没有打印信息;no则前台启动
daemonize yes 
# 后台启动时,日志文件名
logfile /var/log/redis_6380.log	 
# 后台显示时,日志文件路径
dir /var/lib/redis/6380		
redis-server redis-6380.conf #以配置文件启动redis,启动后就是守护进程
redis-cli -p 6380
redis-cli -h 127.0.0.1 -p 6380

其他相关配置

#服务器配置

#绑定主机地址
bind 127.0.0.1 
# 保护模式
protected-mode yes 
#设置数据库数量
databases 16 
#设置服务器以指定日志记录级别
loglevel debug|verbose|notice|warning 

注意:日志级别开发期设置为verbose即可,生产环境中配置为notice,简化日志输出量,降低写日志IO的频度。开发阶段一般使用debug,会打印较多的信息

Protected-mode 是为了禁止公网访问redis cache,加强redis安全的。

它启用的条件,有两个: 1) 没有bind IP 2) 没有设置访问密码

如果启用了,则只能够通过lookback ip(127.0.0.1)访问Redis cache,如果从外网访问,则会返回相应的错误信息

(error) DENIED Redis is running in protected mode because protected mode is enabled, no bind address was specified, no authentication password is requested to clients. In this mode connections are only accepted from the lookback interface. If you want to connect from external computers to Redis you may adopt one of the following solutions: 1) Just disable protected mode sending the command 'CONFIG SET protected-mode no' from the loopback interface by connecting to Redis from the same host the server is running, however MAKE SURE Redis is not publicly accessible from internet if you do so. Use CONFIG REWRITE to make this change permanent. 2) Alternatively you can just disable the protected mode by editing the Redis configuration file, and setting the protected mode option to 'no', and then restarting the server. 3) If you started the server manually just for testing, restart it with the --portected-mode no option. 4) Setup a bind address or an authentication password. NOTE: You only need to do one of the above things in order for the server to start accepting connections from the outside.
#客户端配置

#设置同一时间最大客户链接数,默认无限制。当客户端连接到达上线,Redis会关闭新的链接
maxclients 0  # 0表示没有限制

#客户端不活动占用连接最大时长,达到最大时长后关闭连接。如需关闭该功能,设置为0
timeout 300  # 300s
#多服务器快捷配置

#导入并加载指定配置文件信息,用于快速创建redis公共配置较多的redis实例配置文件,便于维护。这里有点像继承了,先include一个基础配置文件,然后再添加其他的配置
include /path/base_server.conf
#RDB,快照相关配置

#保存快照
save 900 1              
#在900秒(15分钟)之后,如果至少有1个key发生变化,则dump内存快照。
save 300 10            
#在300秒(5分钟)之后,如果至少有10个key发生变化,则dump内存快照。
save 60 10000       
 #在60秒(1分钟)之后,如果至少有10000个key发生变化,则dump内存快照。

#快照文件名
dbfilename dump.rdb
#保存目录名
dir /var/lib/redis/6379
#AOF持久化方式配置

# 是否使用AOF持久化方式。默认不使用
appendonly yes  
#持久化的AOF文件名
appendfilename "appendonly6381.aof"  

#在Redis的配置文件中存在三种AOF同步方式,它们分别是:
#每次有数据修改发生时都会写入AOF文件。
appendfsync always    
#每秒钟同步一次,该策略为AOF的缺省策略。
appendfsync everysec  
#从不同步。高效但是数据不会被持久化。
appendfsync no          

编译安装库文件

编译顺序为:先编译hiredis,后编译redis_plus_plus

redis/hiredis: Minimalistic C client for Redis >= 1.2 (github.com)open in new window

redis-plus-plus库:https://github.com/sewenew/redis-plus-plus

编译hiredis

编译最新版,安装到默认路径(/usr/local)

$ git clone https://github.com/redis/hiredis.git
 
$ cd hiredis
$ make
$ sudo make install

make install只做了如下简单的操作 ,想移除hiredis的安装只需要做如下操作的逆操作即可

编译redis_plus_plus

默认编译生成动态库和静态库,使用C++17标准(注意:你的应用程序也必须使用C++17版本,即)。redis_plus_plus支持C++11、C++14、C++17语言标准。

如果cmake没有安装,可以自行安装:$ sudo apt install cmake

$ git clone https://github.com/sewenew/redis-plus-plus.git
 
$ cd redis-plus-plus
 
$ mkdir build
 
$ cd build
 
$ cmake -DREDIS_PLUS_PLUS_CXX_STANDARD=17 ..   #使用C++17版本,C++11则修改为11,C++14则修改为14
 
$ make
 
$ sudo make install

make install做了如下操作:

dog@dog:build$ sudo make install
[ 47%] Built target redis++
[ 94%] Built target redis++_static
[100%] Built target test_redis++
Install the project...
-- Install configuration: "Release"
-- Installing: /usr/local/lib/libredis++.a
-- Installing: /usr/local/lib/libredis++.so.1.3.3
-- Installing: /usr/local/lib/libredis++.so.1
-- Installing: /usr/local/lib/libredis++.so
-- Set runtime path of "/usr/local/lib/libredis++.so.1.3.3" to ""
-- Installing: /usr/local/share/cmake/redis++/redis++-targets.cmake
-- Installing: /usr/local/share/cmake/redis++/redis++-targets-release.cmake
-- Installing: /usr/local/include/sw/redis++/cmd_formatter.h
-- Installing: /usr/local/include/sw/redis++/command.h
-- Installing: /usr/local/include/sw/redis++/command_args.h
-- Installing: /usr/local/include/sw/redis++/command_options.h
-- Installing: /usr/local/include/sw/redis++/connection.h
-- Installing: /usr/local/include/sw/redis++/connection_pool.h
-- Installing: /usr/local/include/sw/redis++/errors.h
-- Installing: /usr/local/include/sw/redis++/pipeline.h
-- Installing: /usr/local/include/sw/redis++/queued_redis.h
-- Installing: /usr/local/include/sw/redis++/queued_redis.hpp
-- Installing: /usr/local/include/sw/redis++/redis++.h
-- Installing: /usr/local/include/sw/redis++/redis.h
-- Installing: /usr/local/include/sw/redis++/redis.hpp
-- Installing: /usr/local/include/sw/redis++/redis_cluster.h
-- Installing: /usr/local/include/sw/redis++/redis_cluster.hpp
-- Installing: /usr/local/include/sw/redis++/reply.h
-- Installing: /usr/local/include/sw/redis++/sentinel.h
-- Installing: /usr/local/include/sw/redis++/shards.h
-- Installing: /usr/local/include/sw/redis++/shards_pool.h
-- Installing: /usr/local/include/sw/redis++/subscriber.h
-- Installing: /usr/local/include/sw/redis++/transaction.h
-- Installing: /usr/local/include/sw/redis++/utils.h
-- Installing: /usr/local/include/sw/redis++/tls.h
-- Installing: /usr/local/include/sw/redis++/cxx_utils.h
-- Installing: /usr/local/share/cmake/redis++/redis++-config.cmake
-- Installing: /usr/local/share/cmake/redis++/redis++-config-version.cmake
-- Installing: /usr/local/lib/pkgconfig/redis++.pc

测试redis_plus_plus

查看redis_server状态:

$ systemctl restart redis-server # 重启
$ systemctl stop redis-server    # 停止
$ systemctl start redis-server   # 启动

测试代码

#include <sw/redis++/redis++.h>
#include <iostream>
#include <unordered_set>
#include <algorithm>
 
using namespace std;
using namespace sw::redis;
 
// cout << vector
template <typename T>
std::ostream &operator<<(std::ostream &out, const std::vector<T> &v)
{
    if (!v.empty())
    {
        out << '[';
        std::copy(v.begin(), v.end(), std::ostream_iterator<T>(out, ", "));
        out << "\b\b]"; // 删除末尾的", "
    }
    return out;
}
 
// cout << unordered_map
template <typename T, typename U>
std::ostream &operator<<(std::ostream &out, const std::unordered_map<T, U> &umap)
{
    out << '[';
    for (auto item : umap)
    {
        out << "(" << item.first << "," << item.second << "),";
    }
    out << "\b]"; // 删除末尾的","
 
    return out;
}
 
// cout << unorderd_set
template <typename T>
std::ostream &operator<<(std::ostream &out, const std::unordered_set<T> &uset)
{
    out << '(';
    for (auto item : uset)
    {
        cout << item << ",";
    }
    out << "\b)"; // 删除末尾的","
 
    return out;
}
 
int main()
{
    try
    {
        // Create an Redis object, which is movable but NOT copyable.
        auto redis = Redis("tcp://127.0.0.1:6379");
 
        /// ***** STRING commands *****
        redis.set("key", "val");
        auto val = redis.get("key"); // val is of type OptionalString. See 'API Reference' section for details.
        if (val)
        {
            // Dereference val to get the returned value of std::string type.
            std::cout << *val << std::endl;
        } // else key doesn't exist.
 
        /// ***** LIST commands *****
        // std::vector<std::string> to Redis LIST.
        std::vector<std::string> vec = {"a", "b", "c"};
        redis.rpush("list", vec.begin(), vec.end());
 
        // std::initializer_list to Redis LIST.
        redis.rpush("list", {"a", "b", "c"});
 
        // Redis LIST to std::vector<std::string>.
        vec.clear();
        redis.lrange("list", 0, -1, std::back_inserter(vec));
 
        cout << "list: " << vec << endl;
 
        /// ***** HASH commands *****
        redis.hset("hash", "field", "val");
 
        // Another way to do the same job.
        redis.hset("hash", std::make_pair("field", "val"));
 
        // std::unordered_map<std::string, std::string> to Redis HASH.
        std::unordered_map<std::string, std::string> m = {
            {"field1", "val1"},
            {"field2", "val2"}};
        redis.hmset("hash", m.begin(), m.end());
 
        // Redis HASH to std::unordered_map<std::string, std::string>.
        m.clear();
        redis.hgetall("hash", std::inserter(m, m.begin()));
 
        cout << "hash:" << m << endl;
 
        // Get value only.
        // NOTE: since field might NOT exist, so we need to parse it to OptionalString.
        std::vector<OptionalString> vals;
        redis.hmget("hash", {"field1", "field2"}, std::back_inserter(vals));
 
        /// ***** SET commands *****
        redis.sadd("set", "m1");
 
        // std::unordered_set<std::string> to Redis SET.
        std::unordered_set<std::string> set = {"m2", "m3"};
        redis.sadd("set", set.begin(), set.end());
 
        // std::initializer_list to Redis SET.
        redis.sadd("set", {"m2", "m3"});
 
        // Redis SET to std::unordered_set<std::string>.
        set.clear();
        redis.smembers("set", std::inserter(set, set.begin()));
 
        cout << "set:" << set << endl;
 
        if (redis.sismember("set", "m1"))
        {
            std::cout << "m1 exists" << std::endl;
        } // else NOT exist.
 
        /// ***** SORTED SET commands *****
        redis.zadd("sorted_set", "m1", 1.3);
 
        // std::unordered_map<std::string, double> to Redis SORTED SET.
        std::unordered_map<std::string, double> scores = {
            {"m2", 2.3},
            {"m3", 4.5}};
        redis.zadd("sorted_set", scores.begin(), scores.end());
 
        // Redis SORTED SET to std::vector<std::pair<std::string, double>>.
        // NOTE: The return results of zrangebyscore are ordered, if you save the results
        // in to `std::unordered_map<std::string, double>`, you'll lose the order.
        std::vector<std::pair<std::string, double>> zset_result;
        redis.zrangebyscore("sorted_set",
                            UnboundedInterval<double>{}, // (-inf, +inf)
                            std::back_inserter(zset_result));
 
        // Only get member names:
        // pass an inserter of std::vector<std::string> type as output parameter.
        std::vector<std::string> without_score;
        redis.zrangebyscore("sorted_set",
                            BoundedInterval<double>(1.5, 3.4, BoundType::CLOSED), // [1.5, 3.4]
                            std::back_inserter(without_score));
 
        // Get both member names and scores:
        // pass an back_inserter of std::vector<std::pair<std::string, double>> as output parameter.
        std::vector<std::pair<std::string, double>> with_score;
        redis.zrangebyscore("sorted_set",
                            BoundedInterval<double>(1.5, 3.4, BoundType::LEFT_OPEN), // (1.5, 3.4]
                            std::back_inserter(with_score));
 
        /// ***** SCRIPTING commands *****
        // Script returns a single element.
        auto num = redis.eval<long long>("return 1", {}, {});
 
        // Script returns an array of elements.
        std::vector<std::string> nums;
        redis.eval("return {ARGV[1], ARGV[2]}", {}, {"1", "2"}, std::back_inserter(nums));
 
        // mset with TTL
        auto mset_with_ttl_script = R"(
        local len = #KEYS
        if (len == 0 or len + 1 ~= #ARGV) then return 0 end
        local ttl = tonumber(ARGV[len + 1])
        if (not ttl or ttl <= 0) then return 0 end
        for i = 1, len do redis.call("SET", KEYS[i], ARGV[i], "EX", ttl) end
        return 1
    )";
 
        // Set multiple key-value pairs with TTL of 60 seconds.
        auto keys = {"key1", "key2", "key3"};
        std::vector<std::string> args = {"val1", "val2", "val3", "60"};
        redis.eval<long long>(mset_with_ttl_script, keys.begin(), keys.end(), args.begin(), args.end());
 
        /// ***** Pipeline *****
        // Create a pipeline.
        auto pipe = redis.pipeline();
 
        // Send mulitple commands and get all replies.
        auto pipe_replies = pipe.set("key", "value")
                                .get("key")
                                .rename("key", "new-key")
                                .rpush("list", {"a", "b", "c"})
                                .lrange("list", 0, -1)
                                .exec();
 
        // Parse reply with reply type and index.
        auto set_cmd_result = pipe_replies.get<bool>(0);
 
        auto get_cmd_result = pipe_replies.get<OptionalString>(1);
 
        // rename command result
        pipe_replies.get<void>(2);
 
        auto rpush_cmd_result = pipe_replies.get<long long>(3);
 
        std::vector<std::string> lrange_cmd_result;
        pipe_replies.get(4, back_inserter(lrange_cmd_result));
 
        /// ***** Transaction *****
        // Create a transaction.
        auto tx = redis.transaction();
 
        // Run multiple commands in a transaction, and get all replies.
        auto tx_replies = tx.incr("num0")
                              .incr("num1")
                              .mget({"num0", "num1"})
                              .exec();
 
        // Parse reply with reply type and index.
        auto incr_result0 = tx_replies.get<long long>(0);
 
        auto incr_result1 = tx_replies.get<long long>(1);
 
        std::vector<OptionalString> mget_cmd_result;
        tx_replies.get(2, back_inserter(mget_cmd_result));
 
        /// ***** Generic Command Interface *****
        // There's no *Redis::client_getname* interface.
        // But you can use *Redis::command* to get the client name.
        val = redis.command<OptionalString>("client", "getname");
        if (val)
        {
            std::cout << *val << std::endl;
        }
 
        // Same as above.
        auto getname_cmd_str = {"client", "getname"};
        val = redis.command<OptionalString>(getname_cmd_str.begin(), getname_cmd_str.end());
 
        // There's no *Redis::sort* interface.
        // But you can use *Redis::command* to send sort the list.
        std::vector<std::string> sorted_list;
        redis.command("sort", "list", "ALPHA", std::back_inserter(sorted_list));
 
        // Another *Redis::command* to do the same work.
        auto sort_cmd_str = {"sort", "list", "ALPHA"};
        redis.command(sort_cmd_str.begin(), sort_cmd_str.end(), std::back_inserter(sorted_list));
 
        /// ***** Redis Cluster *****
        // Create a RedisCluster object, which is movable but NOT copyable.
        auto redis_cluster = RedisCluster("tcp://127.0.0.1:7000");
 
        // RedisCluster has similar interfaces as Redis.
        redis_cluster.set("key", "value");
        val = redis_cluster.get("key");
        if (val)
        {
            std::cout << *val << std::endl;
        } // else key doesn't exist.
 
        // Keys with hash-tag.
        redis_cluster.set("key{tag}1", "val1");
        redis_cluster.set("key{tag}2", "val2");
        redis_cluster.set("key{tag}3", "val3");
 
        std::vector<OptionalString> hash_tag_res;
        redis_cluster.mget({"key{tag}1", "key{tag}2", "key{tag}3"},
                           std::back_inserter(hash_tag_res));
    }
    catch (const Error &e)
    {
        // Error handling.
    }
 
    return 0;
}

使用静态库:

g++ -std=c++17 -o app main.cpp /path/to/your/libredis++.a /path/to/your/libhiredis.a -pthread

使用动态库:

$ g++ -std=c++17 -o app main.cpp -lredis++ -lhiredis -pthread

运行提示找不到“libredis++.so.1 :

$ ./app
./app: error while loading shared libraries: libredis++.so.1: cannot open shared object file: No such file or directory

因为找不到libredis++.so.1的路径,需要将其路径添加到LD_LIBRARY_PATH中。redis_plus_plus库默认安装路径如下:

在“~/.bashrc”末尾为LD_LIBRARY_PATH添加“/usr/local/lib”路径即可:

保存“~/.bashrc”修改,关闭terminal终端,重启打开新terminal终端,在新终端运行app: