不是说Redis不好,不用Redis用别的(比如:Memcached 2、VoltDB 3、MongoDB 4、Hazelcast 5、Aerospike)
No! No! No!!! Redis 很好,我不拦着您用……
而是说,我们的水平更高了以后,您一定会感受到 内存数据库 不够用、不够灵活、不够高效……等等。
咋办?
自力更生,自己造更好的轮子呗……
下面Server端和 Client端代码是 Mac调试通过,Linux ubuntu也应没问题;
需要Windows 端或者 Centos Linux等的代码可以私信我。或者干脆Email:
cio@elonCloud.com
Server端:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <semaphore.h>
//#include <sys/stat.h>
//#include <sys/types.h>
//#include <fcntl.h>
//#include <errno.h>
#include<time.h>
#define Sleep10 100000
#define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
//计数器结构体
struct shmstruct
{
int count;
};
//同步有名信号量
sem_t *mutex;
const char *argv[3]={"server","sh01","se2"};
int main(int argc,char *arg0old001v[])
{
int fd;
struct shmstruct *ptr;
if(argc != 3)
{
printf("usage: server1 <shmname> <semname>.\n");
// exit(0);
}
//防止所需共享内存区对象已经存在
shm_unlink(argv[1]);
//创建一个新的共享内存区对象
if((fd = shm_open(argv[1],O_RDWR | O_CREAT | O_EXCL,FILE_MODE)) == -1)
{
perror("shm_open error");
exit(-1);
}
//指定新创建的共享内存区对象的大小
ftruncate(fd,sizeof( struct shmstruct));
//将新创建的共享内存区映射到调用进程的地址空间
if((ptr = (struct shmstruct *)mmap(NULL,sizeof(struct shmstruct),PROT_READ | PROT_WRITE,MAP_SHARED,fd,0)) == MAP_FAILED)
{
perror("mmap error");
exit(-1);
}
//关闭对象描述符
close(fd);
//防止所需的信号量已经存在
sem_unlink(argv[2]);
//创建有名信号量,作为互斥锁用
if((mutex = sem_open(argv[2],O_CREAT|O_EXCL,FILE_MODE,1)) == SEM_FAILED)
{
perror("sem_open error");
exit(-1);
}
//关闭信号量
//-Loop-------------------------------------------------
#define N10 10 //每10次clockClick 判断一次是否 WorkLoop
unsigned long oldTimeUL=clock()/N10;
int In0workCount001=0;//LoopWork计数🧮,工作Loop:Workloop才计数
clock_t starTimeSec=clock();// 用于计时⌛️
pid_t pid = getpid();
int flag0001= false; //false 没干完活儿 true 干完了
for(unsigned long ULi00=0; true;++ULi00) //i<nloop;i++)
{//for440
//------------------------------
if(clock()/N10==oldTimeUL) //不至于轮询太快,没有sleep时间
{
printf("<i:%lu》",ULi00);
usleep(1); //第2个睡觉点,自觉让出cpu
continue;
}//if220
oldTimeUL=clock()/10;//此处及时更新 oldTimeUL;如循环体Work后再更新,缺点是 Work的时间就没计入节奏(拖慢节奏也无法计量
//intre LoopCodeing…内部循环体
//------------------------------
sem_wait(mutex); //锁住信号量
printf("[%d]",ptr->count);
printf("{i:%ld",ULi00);
printf("(pid %ld): %d\n",(long) pid,ptr->count);
//将共享内存数据持久化到硬盘
msync(ptr,sizeof(shmstruct), MS_SYNC);
// msync(shm_start, SHM_SIZE, MS_SYNC);
sem_post(mutex); //释放信号量
usleep(10*Sleep10);
if(true==flag0001) { usleep(20*Sleep10); break;}
}//for440
//-Loop-End=============================================
sem_close(mutex);
exit(0);
}//10main
受到toyota行星齿轮⚙️的启发;
大循环避免不了…… 降低计算机资源消耗的方式就是:尽量提前 continue,尽量减少判断,没事赶快进入 sleep让出cpu
1、干完活儿一定进入sleep;
2、clockClick的时间没跳够,也继续sleep;
你一Server 啥也不干才好,除了显示活着,数据有变…… 剩下全去Sleep!
(根据《Terry轮询法-泰瑞轮询法则》
Client端,client端可以同时运行多个client.exe进程同时运行……
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <errno.h>
#include <semaphore.h>
#define Sleep20 50000
#define FILE_MODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)
struct shmstruct
{int count;
};
sem_t *mutex;
const char *argv[4]={"client","sh01","se2","9999"};
int main(int argc,char *arg01old001v[])
{
int fd,i,nloop;
pid_t pid;
struct shmstruct *ptr;
if(argc != 4)
{
printf("usage: client1 <shmname> <semname> <#loops>.\n");
// exit(0);
}
nloop = atoi(argv[3]);
//打开共享内存区
if((fd = shm_open(argv[1],O_RDWR,FILE_MODE)) == -1)
{
perror("shm_open erro35r");
exit(0);
}
//将共享内存区映射到进程地址空间
if( (ptr = (struct shmstruct *)mmap(NULL,sizeof(struct shmstruct),PROT_READ | PROT_WRITE,MAP_SHARED,fd,0)) == MAP_FAILED)
{
perror("mmap error");
exit(-1);
}
close(fd);
//打开信号量
if((mutex = sem_open(argv[2],0)) == SEM_FAILED)
{
printf("sem_open error");
exit(-1);
}
pid = getpid();
for(i=0;true;++i)//i<nloop;i++)
{
sem_wait(mutex); //锁住信号量
printf(":%d _(pid%d)\n",ptr->count++,(long)pid );
sem_post(mutex); //释放信号量
usleep(20*Sleep20);
}
exit(0);
}
client端当然简单,查数据、改数据,OK
(to be continued)
(二)
按照Terry泰瑞式轮询规范,在每一个 clockClick里面:
- 先删除缓存,再更新数据库
- 更新了数据库之后,再更新(1次)缓存
如果先更新数据库,再更新缓存,如果缓存更新失败,就会导致数据库和Redis中的数据不一致。
如果是先删除缓存,再更新数据库,理想情况是应用下次访问Redis的时候,发现Redis里面的数据是空的,就从数据库加载保存到Redis里面,那么数据是一致的。但是在极端情况下,由于删除Redis和更新数据库这两个操作并不是原子的,所以这个过程如果有其他线程来访问,还是会存在数据不一致问题。
通俗讲,你刚刚删除了Redis当中的缓存(还没来的及更新 mysql之前);此时,你忘记禁止Redis的缓存机制触发);此时有个 急性子张三(触发了个急性子线程 Z3)它把Mysql中的数据读进Redis 并且使用了!
你改Mysql数据改成:redis中数据错;
你改Mysql 没改成,Redis中数据对!