猿博园

记录生活及工作中的点点滴滴

0%

众所周知,Redis 在内存数据库领域内,可谓是独领风骚,应用非常广泛。这主要得益于其丰富的数据类型和极高的性能。

我们可能也听说了,Redis 是单线程的,并且在面试中也会经常被问到 “为什么单线程的 Redis 性能这么快?”,这篇文章我们就聊聊此问题。

首先,我们需要先领清楚一个事实,我们通常说的 Redis 是单线程,主要是指它的网络请求和执行命令的流程是单线处理的, 而整个 Redis Server 是多线程的 。比如持久化、lazyfree、集群数据同步等都是额外的线程处理的。

所以,严格来说,Redis 并不是单线程,但是我们一般把 Redis 称为单线程高性能。接下来,我也会把 Redis 称为单线程模式。而且,这也会促使你紧接着提问:“为什么用单线程?为什么单线程能这么快?”

为什么使用单线程

官方FAQ表示,因为 Redis 是基于内存的操作,CPU 不是 Redis 的瓶颈,Redis 的瓶颈最有可能是机器内存的大小或者网络带宽。既然单线程容易实现,而且 CPU 不会成为瓶颈,那就顺理成章地采用单线程的方案了。

本想着会有很高大上的技术,没想到就是一句官方看似糊弄我们的回答!但是,我们已经可以很清楚的解释了为什么Redis这么快,并且正是由于在单线程模式的情况下已经很快了,就没有必要在使用多线程了!

基于内存的操作

Redis 是一个 Key-value 内存数据库,它内部构是一个哈希表,根据指定的 Key 访问时,计算出 Key 的 hash 值后,只需要 O(1) 的时间复杂度就可以快速的定位到对应的数据。同时,Redis 提供了丰富的数据类型,并且其底层也是用了高效的 哈希表、跳表等高性能的数据结构,同时也使用高效的操作方式进行操作,这些操作都在内存中进行,并不会大量消耗 CPU 资源,所以速度极快。

阅读全文 »

一、缓冲I/O和直接I/O

理解缓冲I/O和直接I/O,先搞清以下几个概念:

1、应用程序内存

通常是指在代码中通过 malloc/freenew/delete 等分配出来的内存。

2、用户缓冲区

用户进程通过系统调用访问系统资源的时候,需要切换到内核态,而这对应一些特殊的堆栈和内存环境,必须在系统调用前建 立好。而在系统调用结束后,cpu 会从核心模式切回到用户模式,而堆栈又必须恢复成用户进程的上下文。而这种切换就会有大量的耗时。

你看一些程序在读取文件时,会先申请一块内存数组,称为buffer,然后每次调用read,读取设定字节长度的数据,写入buffer。(用较小的次数填满buffer)。之后的程序都是从buffer中获取数据,当buffer使用完后,在进行下一次调用,填充buffer。所以说:用户缓冲区的目的是为了减少系统调用次数,从而降低操作系统在用户态与核心态切换所耗费的时间。除了在进程中设计缓冲区,内核也有自己的缓冲区。

阅读全文 »

一、键值对的结构

了解 Redis 朋友的都知道,Redis 是一种键值对 ( Key-Value Pair ) 数据库,在内存中键值对是以字典 ( Dict ) 的方式保存的,而字典的底层其实是通过 哈希表 来实现的。通过哈希表中的节点保存字典中的键值对。而这个哈希表的数据结构就是一个数组。

也就是说当我们添加或修改数据时,只需要计算出键的哈希值,然后,跟数组的大小取模,就可以很快的定位到它所对应的哈希桶的位置。所以,哈希表的最大好处就是我们可用**O(1)**的时间复杂度来快速查找键值对。(如下图所示)。

image-20210316154858330

但是,这里存在一个问题,就是当存入的键之间计算的哈希值相同时,就会出现键冲突的问题。那么,Redis是如何解决的呢?

阅读全文 »

一、Redis 安装

Redis 的安装方式非常简单,步骤如下所示:

1、下载redis安装包

Redis 官网上下载最稳定版本的源码,我们这里安装 5.0.12 版本

1
shell > wget https://download.redis.io/releases/redis-5.0.12.tar.gz

2、解压压缩包

1
shell > tar -zxvf redis-5.0.12.tar.gz

3、建立软连接

1
shell > ln -s redis-5.0.12 redis

说明:

这里建立软连接的目的是为了不把 redis 目录固定在指定版本上,有利于Redis 未来版本升级。

4、编译安装

1
shell > make 

如果此步骤出现异常可以查看 redis 编译报致命错误

5、安装

1
shell > make install  

说明:

​ 此步是把 是把 redis 安装到 /usr/local/bin 这样可以就可以在任何目录下执行 redis 的命令了。

阅读全文 »

一、Redis 简介

Redis 是一种基于键值对 (key-value) 的远程内存数据库,他不仅性能强劲,而且还具有复制特性以及未解决问题而生的独一无二的数据模型。与很多内存数据库不同的是,Redis 提供了5种不同类型的数据结构,格式各样的问题都可以很自然地映射到这些数据结构上。Redis 的数据结构致力于帮助用户解决问题,而不像其他数据库那样,要求用户扭曲问题来适应数据库。

Redis 会将所有的数据库存放在内存中,所以他的读写性能非常惊人。不仅如此,它还可以将内存的数据利用RDB(快照)和 AOF (日志追加)的形式保存到硬盘上。除了这些他还提供了数据过期、发布订阅、事务、流水线、Lua脚本等附加功能。

二、Redis 特性

1、速度快

Redis 执行命令的速度非常快,官方给出的数据,在正常情况下读写性能可以达到10万/秒。造成Redis如此之快的速度,主要以下几点:

  • Redis 是以 键值对的方式把数据存储在内存中
  • Redis 是使用 C语言实现,执行速度相对更快
  • Redis 使用单线程架构模式,防止了多线程中线程切换和竞争问题。

扩展知识:

  1. Redis 是单线程,
    主要是指 Redis 的网络 I/O 和键值对读写是由一个线程来完成的,这也是 Redis 对外提供键值存储服务的主要流程。但 Redis 的其他功能,比如持久化、异步删除、集群数据同步等,其实是由额外的线程执行的。

  2. 为什么单线程还能这么快?

    • 所有的数据都以键值对方式存在内存中,查找数据快。
    • 非阻塞 I/O,Redis 使用epoll 作为I/O 多路复用技术的实现,在网络I/O浪费时间很少。
    • 单线程避免了线程切换和竞态产生的消耗
  3. 单线程存在的问题
    在单线程中命令是按顺序执行的,如果某个命令执行过长,会造成其他命令阻塞,所以Redis是面向快速执行场景的数据库。

阅读全文 »

一、安装依赖包

1.1、 安装gcc-c++

由于nginx是采用c语言开发的,所以在采用源码安装时需要先进行编译。在Linux环境上编译时要用到 gcc-c++,所以首先需要先安装或者更新 gcc-c++;

  • 执行命令
1
yum -y install gcc-c++

1.2、安装pcre pcre-devel

由于nginx 中 http模块是用 pcre 解析正则表达式。所以需要安装pcre 库。

  • 执行命令
1
2
yum -y install pcre  pcre-devel

1.3、安装 zlib zlib-devel

nginx中需要对响应数据进行压缩,需要用到zlib包。

  • 执行命令
1
2
3

yum -y install zlib zlib-devel

阅读全文 »

一、问题

centOS7环境下安装redis-5.0.4时在编译阶段遇到了致命错误:jemalloc/jemalloc.h:没有那个文件或目录

二、原因分析

RedisREADME.md有如下一段话:

Allocator

Selecting a non-default memory allocator when building Redis is done by setting
the MALLOC environment variable. Redis is compiled and linked against libc
malloc by default, with the exception of jemalloc being the default on Linux
systems. This default was picked because jemalloc has proven to have fewer
fragmentation problems than libc malloc.

To force compiling against libc malloc, use:

% make MALLOC=libc

To compile against jemalloc on Mac OS X systems, use:

% make MALLOC=jemalloc

说关于分配器 allocator, 如果有MALLOC 这个环境变量,会有用这个环境变量的 去建立Redis。而且libc 并不是默认 的分配器,默认的是 jemalloc, 因为jemalloc被证明比libc有更少的fragmentation problems。但是如果你又没有jemalloc 而只有 libc 当然 make 出错。 所以加这么一个参数。

阅读全文 »

一、概述

Linux环境下配置完多实例MySQL后,每次开机都要手动启动,现配置成开机自启动模式。在多实例情况下命令chkconfig 不再起作用,所有就需要我们手动配置了。

二、Linux启动小知识

在配置MySQL 多实例启动时,首先让我们了解一下,Linux启动的知识点。正常情况下Linux的启动顺序如下:

  1. 加载内核
  2. 执行init程序
  3. /etc/rc.d/rc.sysinitinit 执行的第一个脚本
  4. /etc/rc.d/rc $RUNLEVEL $RUNLEVEL为缺省的运行模式,linux 共有7种运行模式。
  5. /etc/rc.d/rc.local 相应级别服务启动之后、在执行该文件(其实也可以把需要执行的命令写到该文件中)
  6. /sbin/mingetty 等待用户登录

这里有好几种方法,我们选择第五条,即将执行命令加到/etc/rc.d/rc.local 中。

阅读全文 »

一、MySQL多实例介绍

1.1.什么是MySQL多实例

MySQL多实例就是在一台机器上开启多个不同的服务端口(如:3306,3307),运行多个MySQL服务进程,通过不同的socket监听不同的服务端口来提供各自的服务;

1.2.MySQL多实例的特点有以下几点

  1. 有效利用服务器资源,当单个服务器资源有剩余时,可以充分利用剩余的资源提供更多的服务。
  2. 节约服务器资源
  3. 资源互相抢占问题,当某个服务实例服务并发很高时或者开启慢查询时,会消耗更多的内存、CPU、磁盘IO资源,导致服务器上的其他实例提供服务的质量下降;
阅读全文 »

一、问题描述

mysql5.7 版本创建如下表结构时出现,timestamp 字段默认值错误:如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
CREATE TABLE `login_log` (
`id` bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT ,
`uuid` VARCHAR(34) UNIQUE NOT NULL COMMENT '登录编号',
`number` VARCHAR(20) NOT NULL COMMENT '登录账号',
`name` VARCHAR(20) NOT NULL DEFAULT '' COMMENT '登录姓名',
`login_time` TIMESTAMP DEFAULT CURRENT_TIMESTAMP COMMENT '登录时间',
`logout_time` TIMESTAMP COMMENT '退出时间',
`login_ip` VARCHAR(15) COMMENT '登录IP',
`device` VARCHAR(15) COMMENT '设备类型',
`status` INT(3) COMMENT '登录状态',
`message` VARCHAR(30) COMMENT '登录结果描述',
PRIMARY KEY (`id`)
)ENGINE=InnoDB DEFAULT CHARACTER SET=utf8 COLLATE=utf8_general_ci COMMENT='登录日志';

[Err] 1067 - Invalid default value for 'logout_time'

错误信息为:

[Err] 1067 - Invalid default value for ‘logout_time’

阅读全文 »