学习

03垃圾收集器与内存分配策略

学习《深入理解Java虚拟机》,感谢作者!

代码清单3-9 -XX:MaxTenuringThreshod=1说明 #

Eden[8M]Survivor1[1M]Survivor2[1M]Old {10M}
初始allocation1[0.25M],allocation2[4MB]
3执行时gc导致的变化+allocation1[0.25M]+allocation2[4MB]
3执行后+allocation3[4MB]+allocation1[0.25M]+allocation2[4MB]
5执行时gc导致的变化allocation2[4MB],+allocation1[0.25M]
5执行后+allocation3[4MB]allocation2[4MB],+allocation1[0.25M]

代码清单3-9 -XX:MaxTenuringThreshod=15说明 #

Eden[8M]Survivor1[1M]Survivor2[1M]Old {10M}
初始allocation1[0.25M],allocation2[4MB]
3执行时gc导致的变化+allocation1[0.25M]+allocation2[4MB]
3执行后+allocation3[4MB]+allocation1[0.25M]+allocation2[4MB]
5执行时gc导致的变化+allocation1[0.25M]allocation2[4MB]
5执行后+allocation3[4MB]+allocation1[0.25M]allocation2[4MB],+allocation1[0.25M]

代码清单3-10 说明 #

Eden[8M]Survivor1[1M]Survivor2[1M]Old {10M}
初始allocation1[0.25M],
allocation2[[0.25M],allocation3[4M]
4执行时gc导致的变化+allocation1[0.25M],
+allocation2[[0.25M],
+allocation3[4MB]
4执行后+allocation4[4MB]+allocation1[0.25M],
+allocation2[[0.25M],
+allocation3[4MB]
6执行时gc导致的变化allocation3[4MB],
+allocation1[0.25M],
+allocation2[[0.25M],
6执行后+allocation4[4MB]allocation3[4MB],
+allocation1[0.25M],
+allocation2[[0.25M],

代码清单3-11 说明 #

-XX:-HandlePromotionFailure 关 #

Eden[8M]Survivor1[1M]Survivor2[1M]Old {10M}
初始allocation1[2M],
allocation2[2M],
allocation3[2M]
allocation1[null],allocation4[2M]
5执行时gc导致的变化+allocation2[2M],+allocation3[2M] //总共4M
5执行后+allocation4[2M]+allocation2[2M],+allocation3[2M] //总共4M
6->11allocation4[2M]
+allocation5[2M],
+allocation6[2M]
allocation2[2M],
allocation3[2M] //总共4M,
此时老年代连续可用空间在6M(或者说小于6M)
11执行时gc导致的变化allocation3[4MB],
+allocation1[0.25M],
+allocation2[[0.25M],
11执行后+allocation7[2MB]allocation3[4MB],
+allocation1[0.25M],
+allocation2[[0.25M],

说明 #

  1. 书籍版权归著者和出版社所有

    ...

07B+数索引的使用

学习《MySQL是怎样运行的》,感谢作者!

InnoDB存储引擎的B+树索引:结论 #

  • 每个索引对应一颗B+树。B+树有好多层,最下边一层叶子节点,其余是内节点。所有用户记录都存在B+树的叶子节点,所有目录项记录都存在内节点
  • InnoDB 存储引擎会自动为主键建立聚簇索引(如果没有显式指定主键或者没有声明不允许存储NULL的UNIQUE 键,它会自动添加主键) , 聚簇索引叶子节点包含完整的用户记录
  • 我们可以为感兴趣的列建立二级索引,二级索引的叶子节点包含的用户记录由索引列 和主键组成。如果想通过二级索引查找完整的用户记录,需要执行回表操作, 也就是在通过二级索引找到主键值之后,再到聚簇索引中查找完整的用户记录
  • B+ 树中的每层节点都按照索引列的值从小到大的顺序排序组成了双向链表,而且每个页内的记录(无论是用户记录还是目录项记录)都按照索引列的值从小到大的顺序形成了一个单向链表。如果是联合索引, 则页面记录 按照索引列中前面的列的值排序:如果该列的值相同再按照索引列中后面的列的值排序。比如, 我们对列c2 和c3建立了联合索引 idx_c2_c3(c2, c3),那么该索引中的页面和记录就先按照c2 列的值进行排序;如果c2 列的值相同再按照c3 列的值排序
  • 通过索引查找记录时,是从B+ 树的根节点开始一层一层向下搜索的。由于每个页面(无论是内节点页面还是叶子节点页面〉中的记录都划分成了若干个组, 每个组中索引列值最大的记录页内的偏移量会被当作依次存放在页目录中(当然, 规定Supremum 记录比任何用户记录都大) ,因此可以在页目录中通过二分法快速定位到索引列等于某个值的记录

如果大家在阅读上述结论时哪怕有点疑惑, 那么下面的内容就不适合你,请回过头去反复阅读前面的章节

B+树索引示意图的简化 #

#创建新表
mysql> CREATE TABLE single_table(
      id INT NOT NULL AUTO_INCREMENT,
      key1 VARCHAR(100),
      key2 INT,
      key3 VARCHAR(100),
      key_part1 VARCHAR(100),
      key_part2 VARCHAR(100),
      key_part3 VARCHAR(100),
      common_field VARCHAR(100),
      PRIMARY KEY (id),
      KEY idx_key1(key1),
      UNIQUE KEY uk_key2(key2),
      KEY idx_key3(key3),
      KEY idx_key_part(key_part1,key_part2,key_part3)
      ) Engine=InnoDB CHARSET = utf8;

如上,建立了1个聚簇索引4个二级索引

...

06B+树索引

学习《MySQL是怎样运行的》,感谢作者!

概述 #

数据页由7个组成部分,各个数据页可以组成一个双向链表,每个数据页中的记录会按照主键值从小到大的顺序组成一个单向链表。每个数据页都会为它里面的记录生成一个页目录,在通过主键查找某条记录的时候可以在页目录中使用二分法快速定位到对应的槽,然后再遍历该槽对应分组中的记录即可快速找到指定的记录。页和记录的关系

页a,页b 可以不在物理结构上相连,只要通过双向链表相关联即可

ly-20241212142156258

没有索引时进行查找 #

假设我们要搜索某个列等于某个常数的情况:
SELECT [查询列表] FROM 表名 WHERE 列名 = xxx

在一个页中查找 #

假设记录极少,所有记录可以存放到一个页中

  • 主键位搜索条件:页目录中使用二分法快速定位到对应的,然后在遍历槽对应分组中的记录,即可快速找到指定记录
  • 其他列作为搜索条件:对于非主键,数据页没有为非主键列建立所谓的页目录,所以无法通过二分法快速定位相应的槽。只能从Infimum依次遍历单向链表中的每条记录,然后对比,效率极低

在很多页中查找 #

两个步骤:

  • 定位到记录所在的页
  • 所在页内查找相应的记录

没有索引情况下,不能快速定位到所在页,只能从第一页沿着双向链表一直往下找,而如果是主键,每一页则可以在页目录二分查找。
不过由于要遍历所有页,所以超级耗时

索引 #

#例子
mysql> CREATE TABLE index_demo(
      c1 INT,
      c2 INT,
      c3 CHAR(1),
      PRIMARY KEY(c1)
      ) ROW_FORMAT=COMPACT;

完整的行格式

ly-20241212142156429

简化的行格式
ly-20241212142156467

  • record_type:记录头信息的一项属性,表示记录的类型。0:普通记录,2:Infimum记录,3:Supremum记录,1还没用过等会再说
  • next_record:记录头信息的一项属性,表示从当前记录的真实数据下一条记录真实数据的距离
  • 各个列的值:这里只展示在index_demo表中的3个列,分别是c1、c2、c3
  • 其他信息:包括隐藏列记录的额外信息

改为竖着查看:
ly-20241212142156521

上面图6-4的箭头其实有一点点出入,应该是指向z真实数据第1列那个位置,如下 ly-20241212142156561

...

05InnoDB数据页结构

学习《MySQL是怎样运行的》,感谢作者!

不同类型的页简介 #

页是InnoDB管理存储空间的基本单位,1个页的大小一般是16KB

InnoDB为了不同目的设计多种不同类型的页,包括存放表空间头部信息 的页、存放Change Buffer 信息的页、存放INODE信息的页、存放undo 日志信息的页

这里说的是存放表中记录的那种类型的页,这种存放记录的页称为索引页(INDEX页)

暂时称之为数据页

数据页结构快览 #

1个页有16KB,这部分存储空间被划分为了多个部分(7部分),不同部分有不同的功能
ly-20241212142155323

名称中文名占用空间大小
File Header文件头部38 字节页的一些通用信息
Page Header页面头部56 字节数据页专有的一些信息
Infimum + Supremum页面中的最小记录和最大记录26 字节两个虚拟的记录
User Records用户记录不确定用户存储的记录内容
Free Space空闲空间不确定页中尚未使用的空间
Page Directory页目录不确定某些记录的相对位置
File Trailer文件尾部8 字节校验页是否完整

记录在页中的存储 #

每插入一条记录,从Free Space申请一个记录大小的空间,并将这个空间划分到UserRecords部分。当FreeSpace部分的空间全部被UserRecords部分替代掉后,意味着该页用完。如果再插入,就需要申请新的页

ly-20241212142155485

记录头信息的秘密 #

mysql> CREATE TABLE page_demo(
      c1 INT,
      c2 INT,
      c3 VARCHAR(10000),
      PRIMARY KEY(c1)
      ) CHARSET=ascii ROW_FORMAT=COMPACT;
Query OK, 0 rows affected (0.03 sec)

ly-20241212142155528

...

04InnoDB记录存储结构

学习《MySQL是怎样运行的》,感谢作者!

问题 #

表数据存在哪,以什么格式存放,MySQL以什么方式来访问
存储引擎:对表中数据进行存储写入
InnoDB是MySQL默认的存储引擎,这章主要讲InnoDB存储引擎的记录存储结构

InnoDB页简介 #

注意,是简介
InnoDB:将表中的数据存储到磁盘上
真正处理数据的过程:内存中。所以需要把磁盘中数据加载到内存中,如果是写入修改请求,还需要把内存中的内容刷新到磁盘
获取记录:不是一条条从磁盘读,InnoDB将数据划分为若干个页,以作为磁盘内存之间交互的基本单位。页大小-> 一般是16KB
一般情况:一次最少从磁盘读取16KB的内容到内存中,一次最少把内存中的16KB内容刷新到磁盘

mysql>  SHOW VARIABLES LIKE 'innodb_page_size';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| innodb_page_size | 16384 |
+------------------+-------+
1 row in set (0.00 sec)

只能在第一次初始化MySQL数据目录时指定,之后再也不能更改(通过mysqld –initialize初始化数据目录[旧版本])

InnoDB行格式 #

以记录为单位向表中插入数据,而这些记录在磁盘上的存放形式也被称为行格式或者记录格式
目前有4中不同类型的行格式:COMPACT、REDUNDANT、DYNAMIC和COMPRESSED

compact [kəmˈpækt]契约
redundant[rɪˈdʌndənt] 冗余的
dynamic[daɪˈnæmɪk]动态的
compressed [kəmˈprest] 压缩的

指定行格式的语法 #

CREATE TABLE 表名(列的信息) ROW_FORMAT=行格式名称
ALTER TABLE 表名 ROW_FORMATE=行格式名称
如下,在数据库xiaohaizi下创建一个表

CREATE TABLE record_format_demo(
      c1 VARCHAR(10),
      c2 VARCHAR(10) NOT NULL,
      c3 CHAR(10),
      c4 VARCHAR(10)
      ) CHARSET=ascii ROW_FORMAT=COMPACT;  
#回顾:ascii每个字符1字节即可表示,且只有空格标点数字字母不可见字符
#插入两条数据
INSERT INTO record_format_demo(c1,c2,c3,c4) VALUES('aaaa','bbb','cc','d'),('eeee','fff',NULL,NULL);

查询

...

03字符集和比较规则

学习《MySQL是怎样运行的》,感谢作者!

字符集 #

把哪些字符映射成二进制数据:字符范围
怎么映射:字符->二进制数据,编码;二进制->字符,解码
字符集:某个字符范围的编码规则
同一种字符集可以有多种比较规则

重要的字符集 #

ASCAII字符集:128个,包括空格标点数字大小写及不可见字符,使用一个字节编码
ISO 8859-1字符集:256个,ASCAII基础扩充128个西欧常用字符(包括德法),使用1个字节,别名Latin1
GB2312字符集:收录部分汉字,兼容ASCAII字符集,如果字符在ASCAII字符集中则采用1字节,否则两字节。即变长编码方式

区分某个字节,代表一个单独字符,还是某个字符的一部分
比如0xB0AE75,由于是16进制,所有两个代表1个字节。所以这里有三个字节,其中最后那个字节为7*16+5=117 < 127 所以代表一个单独字符。而AE=10 * 16 +15=175 >127 ,所以是某个字符的一部分

GBK字符集:对GB2312字符集扩充,编码方式兼容GB2312
UTF-8字符集:几乎收录所有字符,且不断扩充,兼容ASCAII字符集。变长:采用14字节
L->0x4C 1字节,啊->0xE5958A,两字节
UTF-8是Unicode字符集的一种编码方案,Unicode字符集有三种方案:UTF-8(1
4字节编码一个字符),UTF-16(2或4字节编码一个字符),UTF-32(4字节编码一个字符)

对于**“我”**,ASCLL中没有,UTF-8中采用3字节编码,GB22312采用2字节编码

MySQL中支持的字符集和比较规则 #

MySQL中,区分utf8mb3和utf8mb4,前者只是用13字节表示字符;后者使用14字节表示字符。MySQL中,utf8代表utf8mb3。

#查看当前MySQL支持的字符集(注意,是字符集,名称都是小写)
#Default collation 默认比较规则
mysql> SHOW CHARSET;
+----------+---------------------------------+---------------------+--------+
| Charset  | Description                     | Default collation   | Maxlen |
+----------+---------------------------------+---------------------+--------+
| big5     | Big5 Traditional Chinese        | big5_chinese_ci     |      2 |
| dec8     | DEC West European               | dec8_swedish_ci     |      1 |
| cp850    | DOS West European               | cp850_general_ci    |      1 |
| hp8      | HP West European                | hp8_english_ci      |      1 |
| koi8r    | KOI8-R Relcom Russian           | koi8r_general_ci    |      1 |
| latin1   | cp1252 West European            | latin1_swedish_ci   |      1 |  <---
| latin2   | ISO 8859-2 Central European     | latin2_general_ci   |      1 |  <---
| swe7     | 7bit Swedish                    | swe7_swedish_ci     |      1 |
| ascii    | US ASCII                        | ascii_general_ci    |      1 |  <---
| ujis     | EUC-JP Japanese                 | ujis_japanese_ci    |      3 |
| sjis     | Shift-JIS Japanese              | sjis_japanese_ci    |      2 |
| hebrew   | ISO 8859-8 Hebrew               | hebrew_general_ci   |      1 |
| tis620   | TIS620 Thai                     | tis620_thai_ci      |      1 |
| euckr    | EUC-KR Korean                   | euckr_korean_ci     |      2 |
| koi8u    | KOI8-U Ukrainian                | koi8u_general_ci    |      1 |
| gb2312   | GB2312 Simplified Chinese       | gb2312_chinese_ci   |      2 |  <---
| greek    | ISO 8859-7 Greek                | greek_general_ci    |      1 |
| cp1250   | Windows Central European        | cp1250_general_ci   |      1 |
| gbk      | GBK Simplified Chinese          | gbk_chinese_ci      |      2 |  <---
| latin5   | ISO 8859-9 Turkish              | latin5_turkish_ci   |      1 |
| armscii8 | ARMSCII-8 Armenian              | armscii8_general_ci |      1 |
| utf8     | UTF-8 Unicode                   | utf8_general_ci     |      3 |  <---
| ucs2     | UCS-2 Unicode                   | ucs2_general_ci     |      2 |
| cp866    | DOS Russian                     | cp866_general_ci    |      1 |
| keybcs2  | DOS Kamenicky Czech-Slovak      | keybcs2_general_ci  |      1 |
| macce    | Mac Central European            | macce_general_ci    |      1 |
| macroman | Mac West European               | macroman_general_ci |      1 |
| cp852    | DOS Central European            | cp852_general_ci    |      1 |
| latin7   | ISO 8859-13 Baltic              | latin7_general_ci   |      1 |  
| utf8mb4  | UTF-8 Unicode                   | utf8mb4_general_ci  |      4 |  <---
| cp1251   | Windows Cyrillic                | cp1251_general_ci   |      1 |
| utf16    | UTF-16 Unicode                  | utf16_general_ci    |      4 |  <---
| utf16le  | UTF-16LE Unicode                | utf16le_general_ci  |      4 |
| cp1256   | Windows Arabic                  | cp1256_general_ci   |      1 |
| cp1257   | Windows Baltic                  | cp1257_general_ci   |      1 |
| utf32    | UTF-32 Unicode                  | utf32_general_ci    |      4 |  <---
| binary   | Binary pseudo charset           | binary              |      1 |
| geostd8  | GEOSTD8 Georgian                | geostd8_general_ci  |      1 |
| cp932    | SJIS for Windows Japanese       | cp932_japanese_ci   |      2 |
| eucjpms  | UJIS for Windows Japanese       | eucjpms_japanese_ci |      3 |
| gb18030  | China National Standard GB18030 | gb18030_chinese_ci  |      4 |
+----------+---------------------------------+---------------------+--------+
41 rows in set (0.00 sec)

字符集的比较规则(这里先看utf8的)

...

02启动选项和系统变量

学习《MySQL是怎样运行的》,感谢作者!

启动选项和配置文件 #

在程序启动时指定的设置项,也称之为启动选项startup option(可以在命令行中/配置文件中 指定)
由于在centos7中使用systemctl start mysqld启动mysql,所以好像没法用命令行指定启动选项了

程序(可能有些程序新版本已经没有了)的对应类别和能读取的组:
ly-20241212142154302

这里讲配置文件的方式设置启动选项:

#添加配置
vim /etc/my.cnf
[server]
skip-networking #禁止tcp网络连接
default-storage-engine=MyISAM #建表默认使用M有ISAM存储引擎


#效果
▶ mysql -h127.0.0.1 -uroot -p
Enter password: 
ERROR 2003 (HY000): Can't connect to MySQL server on '127.0.0.1' (111)

#去除tcp网络连接限制后新建一个表
▶ mysql -h127.0.0.1 -uroot -p #可以连接上
mysql> create table default_storage_engine_demo(i int);
Query OK, 0 rows affected (0.01 sec)
mysql> show create table default_storage_engine_demo;
+-----------------------------+----------------------------------------------------------------------------------------------------------------+
| Table                       | Create Table                                                                                                   |
+-----------------------------+----------------------------------------------------------------------------------------------------------------+
| default_storage_engine_demo | CREATE TABLE `default_storage_engine_demo` (
  `i` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1 |

如果多个配置文件都配置了某个选项,如/etc/my.cnf /etc/mysql/my.cnf /usr/etc/my.cnf ~/.my.cnf都配置了,则以最后一个配置的为主
如果同一个配置文件,比如[server]组和[mysqld]组都出现了default-storage-engine配置,则以后出现的组中的配置为准
如果一个启动选项既在命令行中出现,又在配置文件中配置,则以命令行中的为准

...

01初识MySQL

学习《MySQL是怎样运行的》,感谢作者!

原文 #

下载与安装 #

环境Centos7

添加MySQL5.7仓库

sudo rpm -ivh https://dev.mysql.com/get/mysql57-community-release-el7-11.noarch.rpm

解决证书问题

rpm --import https://repo.mysql.com/RPM-GPG-KEY-mysql-2022

查看是否添加成功

sudo yum repolist all | grep mysql | grep 启用   
mysql-connectors-community/x86_64   MySQL Connectors Community      启用:    213
mysql-tools-community/x86_64        MySQL Tools Community           启用:     96
mysql57-community/x86_64            MySQL 5.7 Community Server      启用:    642

MySQL安装

sudo yum -y install mysql-community-server

运行与密码修改 #

Centos7中安装目录查看,在/usr/bin中,与Max有所不同

whereis mysql
mysql: /usr/bin/mysql /usr/lib64/mysql /usr/share/mysql /usr/share/man/man1/mysql.1.gz
ls /usr/bin |grep mysql
mysql
mysqladmin
mysqlbinlog
mysqlcheck
mysql_config_editor
mysqld_pre_systemd
mysqldump
mysqldumpslow
mysqlimport
mysql_install_db
mysql_plugin
mysqlpump
mysql_secure_installation
mysqlshow
mysqlslap
mysql_ssl_rsa_setup
mysql_tzinfo_to_sql
mysql_upgrade

添加mysqld目录到环境变量中(这里可省略,因为mysqld默认在/usr/bin中了

...

redis集群搭建

转载自https://www.cnblogs.com/Yunya-Cnblogs/p/14608937.html(添加小部分笔记)感谢作者!

部分参考自 https://www.cnblogs.com/ysocean/p/12328088.html

基本准备 #

ly-20241212142159186.png

架构 #

采用Centos7,Redis版本为6.2,架构如下:

ly-20241212142159238

hosts修改 #

vim /etc/hosts
#添加
192.168.1.101 node1
192.168.1.102 node2
192.168.1.103 node3

集群准备 #

对每个节点 #

  1. 下载redis并解压到 /usr/local/redis-cluster中

    cd /usr/local
    mkdir redis-cluster
    tar -zxvf redis* -C /usr/local/redis*
    
  2. 进入redis根目录

    make
    make install
    
  3. 安装完毕

  4. hosts修改

    vim /etc/hosts
    #添加
    192.168.1.101 node1
    192.168.1.102 node2
    192.168.1.103 node3
    

配置文件修改(6个节点中的每一个) #

创建多级目录

mkdir -p /usr/local/redis_cluster/redis_63{79,80}/{conf,pid,logs}

ly-20241212142159275

编写配置文件

...