高手不用Redis内存数据库一

news2024/11/18 14:45:51

不是说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中数据对!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/125257.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JavaScript基础篇2之日期时间函数

一、计算机中时间字母表示的预知识储备&#xff1a; G&#xff08;age&#xff0c;时代年龄等意思&#xff09;&#xff1a;时代标志&#xff0c;如AD&#xff08;Anno Domini公元&#xff09;、BC&#xff08;Before Christ公元前&#xff09;。 y&#xff08;year&#xff…

zabbix安装使用

1.1 Zabbix概述 Zabbix是一款能够监控各种网络参数以及服务器健康性和完整性的软件。Zabbix使用灵活的通知机制&#xff0c;允许用户为几乎任何事件配置基于邮件的告警。这样可以快速反馈服务器的问题。基于已存储的数据&#xff0c;Zabbix提供了出色的报告和数据可视化功能。…

基于python的turtle实现圣诞树的绘制

文章目录一、前言二、基于turtle实现绘制圣诞树三、效果展示四、实现步骤代码实现分步骤1. 导入库2. 配置圣诞树高度等信息3. 定义函数get_color()可获取随机颜色4. 定义函数snow() 绘制一朵雪花5. 定义函数name()可随机写一些文字6. 定义函数koc() 绘制星星7.定义函数tree()绘…

Qt中调用thrift

thrift是一个Apache公司开源的一款RPC&#xff08;Remote Procedure Call&#xff09;框架&#xff0c;让不同语言构建的服务可以做到远程调用无缝对接。 thrift库分两部分&#xff1a; libthrift - 核心库文件&#xff0c;需要依赖OpenSSL、boost libthriftnb - 包含thrift非阻…

内网穿透基本使用

内网穿透基本使用 文章目录内网穿透基本使用前言一、内网穿透二、工具1.FRP2.LCX3.NPS4.Sunny-Ngork三、Sunny-ngork使用四、Frp内网穿透代理1.一层代理2.二层代理总结前言 之前零零碎碎接触过不少关于内网渗透测试、内网穿透的知识&#xff0c;但是不得不说渗透测试很吃基础、…

初学Java web(十一)AjaxAxiosJSON

Ajax&Axios&JSON 概念:AJAX(Asynchronous JavaScript And XML):异步的JavaScript和XML AJAX作用:1.与服务器进行数据交换&#xff1a;通过AJAX可以给服务器发送请求&#xff0c;并获取服务器响应的数据 使用了AJAX和服务器进行通信&#xff0c;就可以使用HTMLAJAX来替…

ArcGIS基础实验操作100例--实验10绘制带空洞的面要素

本实验专栏来自于汤国安教授《地理信息系统基础实验操作100例》一书 实验平台&#xff1a;ArcGIS 10.6 实验数据&#xff1a;请访问实验1&#xff08;传送门&#xff09; 基础编辑篇--实验10 绘制带空洞的面要素 目录 一、实验背景 二、实验数据 三、实验步骤 方法一&…

【JavaScript】飞机大战简单网页版(源码下载)

文章目录一、效果演示设计思路二、鼠标版飞机大战代码展示1.HTML结构代码2.CSS样式代码3.JavaScript代码js.js文件plane.js文件三、键盘版飞机大战代码展示1.HTML结构代码2.CSS样式代码3.JavaScript代码四、代码资源分享一、效果演示 利用html&#xff0c;css&#xff0c;js制…

qt QCustomplot 用QCPItemStraightLine画参考线,阈值线,水平线

想要在两个坐标系下都画上如下参考线(阈值线&#xff0c;或者 水平线)&#xff0c; 这个参考线随着坐标轴的拖拽能够一直显示 我们找到了QCPItemStraightLine&#xff0c;该类能够画一条无限延伸的直线&#xff0c;通过下面的代码能够实现在A坐标系画一条水平线&#xff0c;但不…

[CF-EDU]Segment Tree - part 1 - Step 1 - Practice

练习名称&#xff1a;ITMO Academy: pilot course Segment Tree 练习链接&#xff1a;Segment Tree, part 1, Step1, Practice cf官方的线段树专题练习 A. Segment Tree for the Sum 单点修改&#xff0c;区间和查询 #include <bits/stdc.h> #define lson (u <&l…

P1825 [USACO11OPEN]Corn Maze S

题目描述 This past fall, Farmer John took the cows to visit a corn maze. But this wasnt just any corn maze: it featured several gravity-powered teleporter slides, which cause cows to teleport instantly from one point in the maze to another. The slides work…

Docker安装镜像,并运行成为容器

1.Docker作用 一个项目中&#xff0c;部署时需要依赖于node.js、Redis、RabbitMQ、MySQL等&#xff0c;这些服务部署时所需要的函数库、依赖项各不相同&#xff0c;甚至会有冲突。给部署带来了极大的困难。 而Docker确巧妙的解决了这些问题, Docker为了解决依赖的兼容问题的…

关于两种单菌种发酵的豆瓣酱代谢组学方面差异研究

生活离不开柴米油盐酱醋茶&#xff0c;其中酱油是中国传统的调味品&#xff0c;主要是由大豆经过发酵酿造而成。酱油由酱演变而来&#xff0c;早在三千多年前&#xff0c;中国就有制作酱的记载了。 本期百趣代谢组学文献分享为大家分享的文献是百趣生物协助客户发表的关于两种…

Git cherry-pick

Git cherry-pick 当有多个分支&#xff0c;想将一个分支 A 的提交合并到另一个分支 B 一&#xff1a;将分支A的所有提交合并到分支B&#xff0c;执行合并即可 二&#xff1a;将分支A 的某一次提交合并到分支 B&#xff0c;需要使用 git cherry-pick commit 命令 如下图&#…

随机森林-sklearn

随机森林 1.概述 1.1 集成算法概述 本身并不是一个单独的机器学习算法&#xff0c;而是通过在数据上构建多个模型&#xff0c;集成所有模型的建模结果。以此来获得最好的结果。 集成算法的目标&#xff1a; 集成算法会考虑多个评估器的建模结果&#xff0c;汇总之后得到一个…

物联网低功耗蓝牙核心配置技术: 赋能智能家居和智能工业场景

蓝牙我们都不陌生&#xff0c;早已成为深入我们生活的一项科技。不过&#xff0c;我们所知所用的还只是蓝牙的一部分。而蓝牙目前作为物联网中的一项重要通信技术&#xff0c;其应用还远远不止这些&#xff0c;今天就为大家讲讲蓝牙技术中的低功耗技术的应用及分类。 蓝牙低功耗…

原神私服搭建教程 (最新版)

搭建教程 1.准备阶段 1.请先确保电脑内有这些安装环境&#xff0c;否则私服无法运行&#xff01;&#xff01;&#xff01; MongoDB Python3.8 java17 mitmproxy 没有请在群文件下载安装环境&#xff0c;安装即可。特别强调&#xff1a;java17直接放在C:\Program Files目录下即…

初识Kubernetes:(4)Kubernetes实战入门

初识Kubernetes&#xff1a;&#xff08;4&#xff09;Kubernetes实战入门1 前言2 Namespace2.1 概述2.2 应用示例3 Pod3.1 概述3.2 语法及应用示例1 前言 介绍如何在kubernetes集群中部署一个Nginx服务&#xff0c;并且能够对其访问。 2 Namespace 2.1 概述 Namespace是ku…

写给Java程序员的GRPC入门系列(2)

点击上方GRPC专栏看完整系列 文章目录Abstract前置依赖本文初始状态编写protobuffer文件生成代码下一步Abstract 网上有很多GRPC的例子&#xff0c;但是却没有能够写给普通Java开发人员手把手入门少走弯路的教程。 本教程保证按照步骤一步步来你就可以完成GRPC从0到1的构建。 …

模型驱动PDR、数据驱动PDR实验效果对比

本学期的室内导航位置服务课程结束了&#xff0c;最后有一个结课作业做了一些工作&#xff0c;在这里分享给大家&#xff0c;同时也是自己的一个记录。 主要内容包括以下四个方面&#xff1a; 模型驱动PDR数据驱动PDR实验效果对比模型驱动PDR测试效果数据驱动PDR-RoNIN官方预训…