从上一个upload试用 后,现在我们需要上传图片到redis,由于upload模块会缓存到文件夹,后续处理时再从文件夹读取。这样多出来的io操作希望尽量避免的情况下,我们舍弃upload模块,只使用redis模块来完成上传,因为我们暂时不需要处理这些上传数据,就算要处理从redis中拿出来应该会更快。
安装并运行redis-server,默认的redis-server没有设置密码,且默认127.0.0.1:6379(nginx.conf中redis2_pass的设置对应),我们测试使用默认的就行了。
$ sudo apt install redis-server
$ redis-server
使用redis,我们需要一些模块:redis2-nginx-module, redis2需要用到set-misc-nginx-module,而这个set-misc-nginx模块需要ngx-devel-kit模块。
下载上述3个模块并提取(我的模块存放目录:/home/dyan/OpenSource/workspace/nginx-modules)
nginx源码重新编译一下 (nginx源码目录/home/dyan/OpenSource/nginx-1.4.2),在该目录下编译
$ ./configure --add-module=/home/dyan/OpenSource/workspace/nginx-modules/redis2-nginx-module-master
--add-module=/home/dyan/OpenSource/workspace/nginx-modules/ngx_devel_kit-master
--add-module=/home/dyan/OpenSource/workspace/nginx-modules/set-misc-nginx-module-master
nginx已经安装到/usr/local/nginx下
然后修改/usr/local/nginx/conf/nginx.conf(修改前记得先备份),
但是,这个nginx默认的上传大小限制太小了我们需要对http字段修改client_header_buffer_size和client_body_buffer_size的限制。
client_body_buffer_size 1024k;
client_header_buffer_size 1024k; #这个是为了方便我们测试,redis2模块上传功能时直接把数据放到header中,这样似乎不合理
在http字段server字段中添加如下配置
#$curl "localhost/get?key=ask" location = /get { set_unescape_uri $key $arg_key; redis2_query get $key; redis2_pass 127.0.0.1:6379; } #$curl "localhost/set?key=ask&val=answer" location = /set { set_unescape_uri $key $arg_key; set_unescape_uri $val $arg_val; redis2_query set $key $val; redis2_pass 127.0.0.1:6379; }
这时确认新的配置没有问题后重载nginx配置
$ sudo /usr/local/nginx/sbin/nginx -t -c /usr/local/nginx/conf/nginx.conf
nginx: the configuration file /usr/local/nginx/conf/nginx.conf syntax is ok
nginx: configuration file /usr/local/nginx/conf/nginx.conf test is successful
$ ps -ef|grep nginx
root 9111 3070 0 8月01 ? 00:00:00 nginx: master process sbin/nginx
dyan 28862 9111 0 22:57 ? 00:00:00 nginx: worker process
dyan 30167 6058 0 23:50 pts/19 00:00:00 grep --color=auto nginx
$ sudo kill -HUP 9111
查看效果,
$ curl "localhost/set?key=hello&val=world"
+OK
$ curl "localhost/get?key=hello"
$5 #这里的$不是shell,是redis的返回值部分
world
附上一个demo_redis_set.cpp检验redis的set功能
//demo_redis_set.cpp
#include <curl/curl.h> #include <iostream> #include <sstream> #include <string.h> #include <hiredis/hiredis.h> using namespace std; size_t write_data(void* ptr, size_t size, size_t nmemb, void* stream) { string data((const char*) ptr, (size_t) size * nmemb); *((stringstream*) stream) << data << endl; return size * nmemb; } int main() { FILE *fp = fopen("test8.png","rb"); if(NULL == fp) { cout<<"open file failed"<<endl; return -1; } fseek(fp,0,SEEK_END); size_t file_len = ftell(fp); fseek(fp,0,SEEK_SET); char *data = new char[file_len]; fread(data,1,file_len,fp); fclose(fp); CURL *m_curl = curl_easy_init(); cout<<"file_len:"<<file_len<<endl; char *encode_data = curl_easy_escape(m_curl,data,file_len); // cout<<"encode len:"<<encode_data<<endl; string url="localhost/set"; url += "?key=inquire&val="; url += encode_data;
//释放curl_easy_escape分配的内存
curl_free(encode_data); cout<<url.length()<<endl; stringstream ssanswer; curl_easy_setopt(m_curl,CURLOPT_SSL_VERIFYPEER,false); curl_easy_setopt(m_curl,CURLOPT_URL,url.c_str()); curl_easy_setopt(m_curl, CURLOPT_WRITEFUNCTION, write_data); curl_easy_setopt(m_curl, CURLOPT_WRITEDATA, &ssanswer); CURLcode res = curl_easy_perform(m_curl); string ans = ssanswer.str(); cout<<ans<<endl; //redis 连接 struct timeval timeout = {2, 0}; //2s的超时时间 //redisContext是Redis操作对象 redisContext *pRedisContext = (redisContext*)redisConnectWithTimeout("127.0.0.1", 6379, timeout); if ( (NULL == pRedisContext) || (pRedisContext->err) ) { if (pRedisContext) { std::cout << "connect error:" << pRedisContext->errstr << std::endl; } else { std::cout << "connect error: can't allocate redis context." << std::endl; } return -1; } //redisReply是Redis命令回复对象 redis返回的信息保存在redisReply对象中 redisReply *pRedisReply = (redisReply*)redisCommand(pRedisContext, "get inquire"); //执行INFO命令 int decode_len=0; cout<<"pRedisReply->len:"<<pRedisReply->len<<endl; FILE *fw = fopen("output3.png","wb"); if(NULL == fw) { cout<<"open file failed"<<endl; return -1; } cout<<"redis data len:"<<pRedisReply->len<<endl; int ret = fwrite(pRedisReply->str,1,pRedisReply->len,fw); cout<<"write len:"<<ret<<endl; fclose(fw); //当多条Redis命令使用同一个redisReply对象时 //每一次执行完Redis命令后需要清空redisReply 以免对下一次的Redis操作造成影响 freeReplyObject(pRedisReply); delete[] data; delete[] encode_data; return 0; }
编译并执行,
$ g++ -g demo_redis_set.cpp -o test -lcurl -lhiredis -std=c++11 $ ./test file_len:41558 104068 +OK pRedisReply->len:41558 redis data len:41558 write len:41558
看上去一切正常,最后比较一下输入文件与输出文件
$ diff test8.png output3.png
#结果返回是一个空行,说明这2个文件是相同的。如果不同就会返回:二进制文件 test8.png 和 output3.png 不同