高手不用Redis内存数据库一

不是说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. 先删除缓存,再更新数据库
  2. 更新了数据库之后,再更新(1次)缓存

如果先更新数据库,再更新缓存,如果缓存更新失败,就会导致数据库和Redis中的数据不一致。

如果是先删除缓存,再更新数据库,理想情况是应用下次访问Redis的时候,发现Redis里面的数据是空的,就从数据库加载保存到Redis里面,那么数据是一致的。但是在极端情况下,由于删除Redis和更新数据库这两个操作并不是原子的,所以这个过程如果有其他线程来访问,还是会存在数据不一致问题。
通俗讲,你刚刚删除了Redis当中的缓存(还没来的及更新 mysql之前);此时,你忘记禁止Redis的缓存机制触发);此时有个 急性子张三(触发了个急性子线程 Z3)它把Mysql中的数据读进Redis 并且使用了!

你改Mysql数据改成:redis中数据错;

你改Mysql 没改成,Redis中数据对!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值