背景
有一个需求,作为客户端需要从redis集群中获取数据。出于性能的考虑,再客户端初始化阶段,初始化了一个redis连接,后续在连接redis时,可以直接使用该连接,不用再去重新连接redis了。(这里指的连接其实就是初始化一个类对象,然后根据ip+prot连接redis集群)
但是这样的操作有一个问题就是,当有多个客户端连接redis集群时,由于连接数过多,达到redis节点连接数的限制(默认是4096个连接),这里虽然可以修改redis节点连接数的限制,但是还是没有从源头解决问题,当并发达到一定程度,仍然可以达到连接的上限。
看到这里想着是否可以使用连接池,但是我这种情况不适用。
解决方案
方案一
在真正需要从redis中获取数据时,创建连接->执行操作->释放连接,这样确实可以控制住连接数,但是对性能影响较大。
方案二
是否可以将redis连接(一个类对象)放在共享内存中,多个进程共用一个连接,这样就可以将连接数控制住,而且对性能也没有影响。
针对方案2实施测试
在网上找了linux中共享内存的例子,改写了下
共享内存使用,参考:Linux进程间通信——使用共享内存
下面都是模仿上面这个链接中的内容,如果我写的比较复杂,可以参考下这个人写的。
数据结构文件shmdata.h
我想在共享内存中放一些基本类型和复杂的类型(string vector 只要有申请空间的操作就行),看下通过共享内存访问这些复杂的变量是否可以行的通。
#ifndef _SHMDATA_H_HEADER
#define _SHMDATA_H_HEADER
#include <string>
#define TEXT_SZ 2048
class A
{
public:
A(const char *ss)
{
num =11;
str = ss;
}
const char* printlog()
{
return str;
}
void setsss (const char *s)
{
str=s;
}
int getnum()
{
return num;
}
const char* getstr()
{
return str;
}
int num;
const char * str;
std::string str_string;
};
struct shared_use_st
{
A a;
int written;//作为一个标志,非0:表示可读,0表示可写
char text[TEXT_SZ];//记录写入和读取的文本
};
#endif
从共享内存中读取A类中的变量,查看多进程下是否是基本类型可以获取,而复杂类型不能获取
数据操作文件 shmwrite.cpp
简单描述下,该文件中有
int initConnect()
int get()
pid_t fork_children(int num)
这几个函数,其中initConnect用来初始化共享内存。get从共享内存中获取数据。fork_children创建多个进程
程序是由主进程调用initConnect来初始化共享内存,然后创建3个子进程从共享内存中获取数据(这里没有考虑同步的问题,先看是否可以正常访问)。程序流程是这样的,可以看下下文中的执行结果和程序中最长的那句注释。
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <sys/shm.h>
#include "shmdata.h"
#include <iostream>
using namespace std;
A *p=NULL;
int initConnect()
{
int running = 1;
void *shm = NULL;
struct shared_use_st *shared = NULL;
char buffer[BUFSIZ + 1] = "cx test redis connect";//用于保存输入的文本
int shmid;
//创建共享内存
shmid = shmget((key_t)113, sizeof(struct shared_use_st), 0666|IPC_CREAT);
if(shmid == -1)
{
fprintf(stderr, "shmget failed\n");
exit(EXIT_FAILURE);
}
//将共享内存连接到当前进程的地址空间
shm = shmat(shmid, (void*)0, 0);
if(shm == (void*)-1)
{
fprintf(stderr, "shmat failed\n");
exit(EXIT_FAILURE);
}
printf("Memory attached at %X\n", shm);
//设置共享内存
shared = (struct shared_use_st*)shm;
printf("shared->written = %d\n",shared->written);
//向共享内存中写入数据
strncpy(shared->text, buffer, TEXT_SZ);
shared->written = 1;
p = new(shared)A("cx");
printf("if share memery is %s\n",shared->text);
cout<<"init success"<<endl;
cout<<"p->num = "<<p->num<<" p->str = "<<p->str<<endl;
p->str_string="changxin";
}
return -1;
}
int get()
{
void *shm = NULL;
struct shared_use_st *shared = NULL;
int shmid;
//创建共享内存
shmid = shmget((key_t)113, sizeof(struct shared_use_st), 0666|IPC_CREAT);
if(shmid == -1)
{
fprintf(stderr, "shmget failed\n");
exit(EXIT_FAILURE);
}
//将共享内存连接到当前进程的地址空间
shm = shmat(shmid, (void*)0, 0);
if(shm == (void*)-1)
{
fprintf(stderr, "shmat failed\n");
exit(EXIT_FAILURE);
}
printf("\n\nMemory attached at %X\n", shm);
//设置共享内存
shared = (struct shared_use_st*)shm;
p = &(shared->a);
cout<<"get shared->text = "<<shared->text<<endl;
printf("p = %x\n",p);
printf("p_num = %d\n",p->getnum());
printf("p_str= %s\n",p->getstr());
cout<<"get p->num = "<<p->num<<" p->str = "<<p->str<<endl;
cout<<"get shared->writtten = "<<shared->written<<endl;
//主要是这一句,用来打印类中的string类型,这个最后只在主进程中打印出来,在子进程中是获取不到这个变量的
//因为string的内部实现是自己创建的空间,而创建的这个空间只对当前进程有效,对其他进程不是不可用的。
cout<<"get p->str_string = "<<p->str_string<<endl;
cout<<endl<<endl;
//将共享内存和当前进程分离
if(shmdt(shm) == -1)
{
fprintf(stderr, "shmdt failed\n");
exit(EXIT_FAILURE);
}
}
//创建num个进程
pid_t fork_children(int num)
{
int i;
pid_t pid;
for (i = 1; i <= num; i++)
{
pid = fork();
if (pid == -1)
return pid;
//pid==0 is children process
if (pid == 0)
return pid;
}
return 1;
}
int main()
{
pid_t pid;
pid = fork_children(3);
//pid =0;
//主进程操作
if (pid > 0)
{
printf("test %d\n",pid);
initConnect();
get();
return 1;
}
//子进程操作
else if (pid == 0)
{
sleep(2);//保证主进程先将共享内存初始化
get();
exit(0);
}
return 1;
}
编译
g++ shmwrite.cpp -o shmwrite -lm
执行结果
最后,欢迎大家指正!!