解决docker容器的目录权限的总结
背景
1 | version: '3' |
部署mysql的时候,将mysql目录进行挂载时提示
1 | cannot read directory '/var/lib/mysql/': Permission denied |
原因
我们聚集到entrypoint.sh这个文件,因为docker的镜像变成运行态的时候,也就是容器的时候,是需要命令来启动的,这个启动的命令就是entrypoint.sh,也就是说,启动的这个文件肯定是篡改了原来的目录,下面具体看下这个文件的某个关键代码片段
1 | # allow the container to be started with `--user` |
这段代码的意思是说,该程序运行指定用户来启动mysql,但是如果你不指定用户,他会默认用mysql用户来给DATADIR赋权限,并用mysql用户来执行脚本,所以实际上,用户就变mysql了,但是为啥在宿主机上,却是polkitd呢?
1 | // 容器内查看用户名为`mysql` 对应的用户ID和组ID为`999` |
1 | // 宿主机器查看999所对应的用户名 |
如上图,可以看到,在容器内部,他的用户为mysql,他的用户ID为999,然后退出容器,在宿主机上,可以看到ID为999的用户ID对应的用户变成了polkitd,所以,到了这里就明白了,实际上容器内部和外部是用的同一套用户,名字可能不同,但是ID用的是同一个,从而导致,ID虽然相同,但是用户不一致,从而权限也出现了差别。
1、其实在操作系统中,真正决定用户和用户组的东西并不是用户名和组名,而是相应的用户id 和 对应的组id,当我们刚创建用户时系统就会给用户分配对应的用户id 和 组id,可以在/etc/passwd中查看
2、在遇到的问题描述中,因为容器中只创建了一个mysql用户和组,因此容器中查看到mysql用户id和组id为999:999,因此给/var/lib/mysql
目录用户权限时其实是给予的用户id和组id为999:999权限,因此,在宿主机中./data
此目录的用户权限也变为999:999,因为宿主机中此用户id和组id对应的为polkitd,因此就显示为polkitd。
解决
方法1 推荐
在配置my.cnf时,指定error-log的位置在/var/log/
下,否则error的默认位置为例如/var/lib/mysql
下的mysqld.log文件因为目录映射后有权限问题,写入不了日志。
方法2
宿主机器更改与docker相同的用户ID和组id
chown 999
方法3
同步宿主/etc/passwd
到容器内,从而达到宿主和容器内相同的用户id和组ID
1 | [root@localhost ~]# getenforce |
实验
一直以来比较困惑容器挂载卷的文件权限问题,今天特地梳理下docker的挂载卷权限问题
首先,本地挂载点新建测试文件test.txt,然后将该目录挂载到容器的test目录
可以看到我们在容器外新建的test.txt文件在容器内的所有者变成了1000,然后我们在容器内新建文件查看容器外的权限,发现容器中新建的test1.txt所有者变成了root
接着查看下UID:1000所属用户
最后我们在指定wag用户启动docker,然后在容器内新建test3.txt文件,查看文件所有者
从以上可以得出,docker启动容器如果不指定用户,会默认以root(UID=0)方式运行,导致其中新建的文件所有者映射到容器外为root,容器外新建的文件映射到容器内所有者UID不变。
OLAP之Doris的docker镜像和集群搭建
制作Doris镜像
我们在OLAP之Doris编译的基础上,开始制作docker镜像
我们为我们的目录增加Dockerfile_fe
、Dockerfile_be
两个Dockerfile文件
- fe镜像Dockerfile(cd到编译好的output目录)
Dockerfile_fe
1 | FROM primetoninc/jdk:1.8 |
构建fe镜像,创建并配置镜像映射文件doris-meta和conf,启动容器
1 | docker build -t doris-fe:0.15.0 -f Dockerfile_fe . |
- be镜像Dockerfile
Dockerfile_be
1 | FROM primetoninc/jdk:1.8 |
构建be镜像,配置be镜像映射文件storage,启动3个be容器组成集群。Doris默认至少安装3个be实例。
1 | docker build -t doris-be:0.15.0 -f Dockerfile_be . |
需要使用镜像可从官方pull,已经上传最新
1 | docker pull bulolo/doris-fe:0.15.0 |
docker运行
docker run
不推荐使用docker run,因为还要进入容器内查看IP,再添加对应ip的backends
FE 运行
1 | docker run -itd --name fe_1 -p 8030:8030 -p 9030:9030 -v <LOCAL_PATH>/fe_1/conf:/opt/fe/conf -v <LOCAL_PATH>/fe_1/log:/opt/fe/log -v <LOCAL_PATH>/fe_1/doris-meta:/opt/fe/doris-meta doris-fe:0.15.0 |
BE 运行
1 | docker run -itd --name be_1 -p 9150:9050 -v <LOCAL_PATH>/be_1/conf:/opt/be/conf -v <LOCAL_PATH>/be_1/storage:/opt/be/storage doris-be:0.15.0 |
docker-compose
推荐使用docker-compose
docker-compose.yml
1 | version: '3.7' |
说明:
ipv4_address:容器绑定固定ip
ulimits:设置系统最大打开文件句柄数,就是:
1 | vi /etc/security/limits.conf |
fe.conf
根据ip修改priority_networks
1 | priority_networks = 172.66.0.100/16 |
be.conf
根据ip修改priority_networks
1 | priority_networks = 172.66.0.101/16 |
执行docker-compose up -d
在 FE 中添加所有 BE 节点。本地需要安装mysql,Doris实现mysql协议,使用mysql客户端登录fe,默认用root密码为空。
1 | mysql -P9030 -uroot -p |
修改密码
1 | SET PASSWORD FOR 'root' = PASSWORD('123456'); |
使用 mysql-client 连接到 FE,并执行 SHOW PROC '/backends';
查看 BE 运行情况。如一切正常,isAlive 列应为 true。
查看 Follower 或 Observer 运行状态。使用 mysql-client 连接到任一已启动的 FE,并执行:SHOW PROC '/frontends';
可以查看当前已加入集群的 FE 及其对应角色。
至此Doris安装完成,portal页面地址:http://localhost:8030/
打开后输入root和密码进入,如果没有修改过密码,则不填写密码
查看FE
查看BE
基础使用
- 添加删除查看FE
1
2
3
4ALTER SYSTEM ADD FOLLOWER "hostname:9050";
ALTER SYSTEM DROPP FOLLOWER "hostname:9050";
SHOW PROC '/frontends';
show backends \G - 增加删除查看BE
1
2
3
4
5ALTER SYSTEM ADD BACKEND "hostname:9050";
ALTER SYSTEM DROPP BACKEND "hostname:9050"; // 不推荐
ALTER SYSTEM DECOMMISSION BACKEND "hostname:9050"; 推荐
SHOW PROC '/backends';
SHOW PROC '/backends'\G - 创建数据库
1
create database doris;
- 创建用户
1
create user 'doris' identified by 'password';
- 赋权
1
grant all on doris to doris;
- 创建表
1
2
3
4
5
6
7
8
9create table table1(
id int default '0',
name varchar(32) default '',
city_code smallint,
pv bigint sum default '0'
)
aggregate key(id, name, city_code)
distributed by hash(id) buckets 10
properties('replication_num' = '3');1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16create table table2(
id int default '0',
name varchar(32) default '',
city_code smallint,
event_day date,
pv bigint sum default '0'
)
aggregate key(id, name, city_code, event_day)
partition by range(event_day)
(
partition p202107 values less than ('2021-08-01'),
partition p202108 values less than ('2021-09-01'),
partition p202109 values less than ('2021-10-01')
)
distributed by hash(id) buckets 10
properties('replication_num' = '3'); - 插入表
1
insert into table1(id, name, city_code, pv) values(2, 'grace', 1, 2),(5, 'helen', 3, 3),(3, 'tom', 2, 2);
相关链接
Flink CDC实践之Doris预聚合
背景及目标
1.尝试 CDC mysql 数据到doris
2.通过网站访问pv,使用doris实践对数据的PV进行预聚合
源表
创建Mysql数据库表
1
2
3
4
5
6CREATE TABLE `mysql_pv` (
siteid INT DEFAULT '10',
citycode SMALLINT,
username VARCHAR(32) DEFAULT '',
pv BIGINT DEFAULT '0'
);创建doris表
这里对PV进行SUM预聚合
1
2
3
4
5
6
7
8
9
10CREATE TABLE doris_pv
(
siteid INT DEFAULT '10',
citycode SMALLINT,
username VARCHAR(32) DEFAULT '',
pv BIGINT SUM DEFAULT '0'
)
AGGREGATE KEY(siteid, citycode, username)
DISTRIBUTED BY HASH(siteid) BUCKETS 10
PROPERTIES("replication_num" = "1");
映射表
source
mysql
1 | CREATE TABLE mysql_pv_source ( |
sink
doris
1 | CREATE TABLE doris_pv_sink ( |
执行
1 | INSERT INTO doris_pv_sink select siteid,citycode,username,pv from mysql_pv_source |
相关链接
OLAP之Doris编译
背景
OLAP下,我选doris,来试试如何安装。
编译
根据自己的情况选择对应的环境,我这里按照0.15为例
docker pull apache/incubator-doris:build-env-for-0.15.0
运行镜像
方式一:提前下载好源码,挂载到镜像中
1 | docker run -it -v /your/local/.m2:/root/.m2 -v /your/local/incubator-doris-DORIS-x.x.x-release/:/root/incubator-doris-DORIS-x.x.x-release/ apache/incubator-doris:build-env-for-0.15.0 |
这条命令挂载了源码,和maven的本地库,可以避免一些包每次都要下载,其中:/your/local/.m2
: 本地maven仓库的地址/your/local/incubator-doris-DORIS-x.x.x-release/
:源码的路径/root/incubator-doris-DORIS-x.x.x-release/
:源码挂载后的目录名apache/incubator-doris:build-env-for-0.15.0
:刚才拉取的环境
方式二:在docker中拉取源码
1 | ① docker run -it apache/incubator-doris:build-env-for-0.15.0 |
如果是最新主干版本代码,使用 apache/incubator-doris:build-env-latest
进行编译
更改jdk版本
从 build-env-1.3.1 的docker镜像起,同时包含了 OpenJDK 8 和 OpenJDK 11,并且默认使用 OpenJDK 11 编译。请确保编译使用的 JDK 版本和运行时使用的 JDK 版本一致,否则会导致非预期的运行错误。你可以使用在进入编译镜像的容器后,使用以下命令切换默认 JDK 版本:
切换到 JDK 8:
1 | $ alternatives --set java java-1.8.0-openjdk.x86_64 |
切换到 JDK 11:
1 | $ alternatives --set java java-11-openjdk.x86_64 |
编译
1 | sh build.sh |
注意:
如果你是第一次使用 build-env-for-0.15.0 或之后的版本,第一次编译的时候要使用如下命令:sh build.sh --clean --be --fe --ui
这是因为 build-env-for-0.15.0 版本镜像升级了 thrift(0.9 -> 0.13),需要通过 –clean 命令强制使用>新版本的 thrift 生成代码文件,否则会出现不兼容的代码。
注:编译整个过程大概2小时以上,是极为痛苦的。T T,本人编译超过10次以上,2台电脑开docker编译,编译过程,遇到多次fail退出,大部分问题是docker内存不足导致,所以务必将docker的内存调到至少10GB,否则一旦编译内存不足就会失败。
2017款macbook pro 编译成功
2022款macbookpro M1 pro 编译失败
痛哭流涕,终于编译完成,见到这个编译完成命令。
进入到output目录,可以看到be,fe,udf三个文件夹,接下来就是安装部署了
我们看到整个doris社区很多人想体验Doris进行尝鲜,但是苦于环境以及服务器的限制,那么我们来制作一下Doris的镜像及尝试用docker搭建集群
OLTP VS OLAP
背景
在OLAP的选型上,陆陆续续有1年多了。做个总结。
OLTP
OLTP:On-Line Transaction Processing,联机(线上)事务处理。指处理事务型应用的场景,事务这个词的英文是 Transaction,其实就是交易(一般指金融交易)。这种场景有个最常见的业务,就是转账,从一个账户转到另一个账户。一般要求实时处理,对响应的速度要求很高,并且要保证事务的 ACID 特性。面向 OLTP 场景的数据库管理系统就叫做 OLTP DBMS。一般涉及大量的增删改操作。
OLTP 与 NSM(N-ary storage model)行存储: OLTP 的场景一般需要一次操作一个对象的多个属性,比如查询一个人的姓名、银行账号、余额等。而 NSM 这种将一个对象的多个属性连续存储的行式存储模型就很适合 OLTP 的场景了。同时 NSM 也适用于写密集场景,一个对象的写入只需要一次写磁盘就能完成。
传统的关系数据库都是面向 OLTP 场景的,如 Oracle 通常用在银行系统、医疗系统等对操作的响应速度要求很高的场景。
OLAP
OLAP:On-Line Analytical Processing,联机(线上)分析处理。指处理分析型应用的场景。进入大数据时代,数据多了,计算机计算能力增强,并出现了分布式存储、分布式计算等技术,人们开始对大量的数据有分析的需求了。这种分析型的场景一般需要查询大量的数据进行分析,对速度的要求没有 OLTP 高,每天晚上或每周做一次,慢慢分析就好了。一般涉及大量的查询操作,对数据的修改需求不高。
列存数据库等就是面向 OLAP 的,因此,列式存储在大数据时代这种分析型场景中火了一把,如数据仓库 HBase。
OLAP的12准则
- 准则1 OLAP模型必须提供多维概念视图
- 准则2 透明性准则
- 准则3 存取能力准则
- 准则4 稳定的报表能力
- 准则5 客户/服务器体系结构
- 准则6 维的等同性准则
- 准则7 动态的稀疏矩阵处理准则
- 准则8 多用户支持能力准则
- 准则9 非受限的跨维操作
- 准则10 直观的数据操纵
- 准则11 灵活的报表生成
- 准则12 不受限的维与聚集层次
OLAP场景的关键特征
- 大多数是读请求
- 数据总是以相当大的批(> 1000 rows)进行写入
- 不修改已添加的数据
- 每次查询都从数据库中读取大量的行,但是同时又仅需要少量的列
- 宽表,即每个表包含着大量的列
- 较少的查询(通常每台服务器每秒数百个查询或更少)
- 对于简单查询,允许延迟大约50毫秒
- 列中的数据相对较小:数字和短字符串(例如,每个URL 60个字节)
- 处理单个查询时需要高吞吐量(每个服务器每秒高达数十亿行)
- 事务不是必须的
- 对数据一致性要求低
- 每一个查询除了一个大表外都很小
- 查询结果明显小于源数据,换句话说,数据被过滤或聚合后能够被盛放在单台服务器的内存中
场景示例:
- 市场营销:当 OLAP 用于营销时,它使营销分析师能够更多地了解他们的客户、哪些产品是有价值的、区域和季节性趋势等等。
- 医疗保健:医疗保健数据仓库使用 OLAP 可用于预测健康风险和结果、与保险公司共享信息并生成报告。
- 金融服务:公司首席财务官可以利用 OLAP 多维数据集为他们提供将数据转换为所需信息的方法,同时允许他们轻松生成定制财务报告。
OLAP分析的分类:ROLAP与MOLAP
- ROLAP(RelationalOLAP)
这是一种通过在RDMS后端服务和客户前端之间建立中间层的OLAP实现方式。通过RDMS来存储和管理数据仓库数据,而通过OLAP中间件来实现多维数据上的操作映射为标准关系操作。其优点在于可以利用RMDS中本身固有的一些功能,例如: 本质上来讲 “slicing and dicing”的操作等同于在SQL语句中添加“WHERE”子句。
- MOLAP(MultidimensionalOLAP)
这些服务器通过基于数据的多维存储引擎,支持数据的多维视图。能够将多维视图直接映射到数据立方体数组结构。其数据都存在多维数据立方体(multidimensional cube)中,以专有的格式存储。使用数据立方体的优点是能够对预计算的汇总数据进行快速索引,尤其是对”slicing and dicing”有着非常优秀的支持。
- HOLAP(HybridOLAP)混合型OLAP
HOLAP结合了ROLAP和MOALP技术,从而继承了ROLAP的伸缩性强和MOLAP快速计算的优点。例如HOLAP利用多维数据集技术来提高性能,而当需要详细数据时,HOALP可以从多维数据“钻取”到底层的RDMS中去获取数据。
名称 | 描述 | 细节数据存储位置 | 聚合后的数据存储位置 |
---|---|---|---|
ROLAP(Relational OLAP) | 基于关系数据库的OLAP实现 | 关系型数据库 | 关系型数据库 |
MOLAP(Multidimensional OLAP) | 基于多维数据组织的OLAP实现 | 数据立方体 | 数据立方体 |
HOLAP(Hybrid OLAP) | 基于混合数据组织的OLAP实现 | 关系型数据库 | 数据立方体 |
对比
联机分析处理(OLAP,On-line Analytical Processing),数据量大,DML少。使用数据仓库模板
联机事务处理(OLTP,On-line Transaction Processing),数据量少,DML频繁。使用一般用途或事务处理模板
OLTP与OLAP 不同的是,OLTP系统强调数据库内存效率,强调内存各种指标的命令率,强调绑定变量,强调并发操作,强调事务性。
OLAP系统则强调数据分析,强调SQL执行时长,强调磁盘I/O,强调分区。
总的来说,可以认为OLAP的产生是因为一些特性OLTP无法满足,所以一些OLTP异变了一些特性,变成了OLAP,OLAP可以看做是OLTP的一种延展,一个让OLTP产生的数据发现价值的过程。
OLAP数据库选型
常见的OLTP如,mysql、PostgreSQL、Oracle等,不需要多讲,但是OLAP随着这些年层出不穷,我们汇总选型一下,并看看他们的特点。
目前市面上主流的开源OLAP引擎包含不限于:Hive、Spark SQL、Presto、Kylin、Impala、Druid、Clickhouse、Greeplum等,可以说目前没有一个引擎能在数据量,灵活程度和性能上做到完美,用户需要根据自己的需求进行选型。
- Hive
- Spark SQ
- Presto
- Elasticsearch
- Impala
- Druid
- Clickhouse
- Greeplum
- Kylin
- Drios
- StarRocks
按数据量划分
按建模类型划分
1、ROLAP
Elasticsearch
solr
ClickHouse
Druid
GreenPlum
Drios
StarRocks
2、MOLAP
3、HOLAP
Flink CDC关于source和sink全调研及实践
背景
我们之前在Flink CDC同步数据实践 快速的体验了从mysql和pg获取数据,最后在es打成宽表数据。但是对于其他的数据库如sql server等source表的实际能力还未可知,本次就一次的调研实践一次。
安装:从代码编译
正常情况下直接下载编译好的即可
因为flink cdc新特性在master分支,并且没有release,比如新版sql server在master,未发布release-2.2,我们来从源码编译
1 | git clone https://github.com/ververica/flink-cdc-connectors.git |
常见FlinkSql命令
首先你得启动吧
1 | // 启动集群 |
1 | // 启动集群后,进入flink sql 客户端命令行界面 |
1 | SHOW CATALOGS; |
Source表
DataGen ☑️ 测试通过
在flink 1.11中,内置提供了一个DataGen 连接器,主要是用于生成一些随机数,用于在没有数据源的时候,进行流任务的测试以及性能测试等。
1 | CREATE TABLE datagen ( |
filesystem ☑️ 测试通过
1 | CREATE TABLE employee_information ( |
mongodb ☑️ 测试通过
先决条件:副本集要求,你懂的
1 | CREATE TABLE offices ( |
mysql ☑️ 测试通过
先决条件:binlog开启,你懂的
1 | CREATE TABLE products ( |
postgres ☑️ 测试通过
1 | CREATE TABLE shipments ( |
sql Server ☑️ 测试通过
先决条件:需要先开启sql server的cdc能力:
EXEC sys.sp_cdc_enable_db;
1 | CREATE TABLE material ( |
Sink表
elasticsearch
http验证通过 ✅
https、ssl,带证书未知如何配置 ❎
1 | CREATE TABLE enriched_orders ( |
Doris
1 | CREATE TABLE doris_test_sink ( |
执行插入Sink表
1 | INSERT INTO department_counts |
相关链接
从线上事故看mongodb事务ACID强弱
在未使用mongodb副本集引入事务能力前,我们来通过一些例子看看mongodb在没有事务的情况下的影响,并再一次从案例去验证强事务的系统是否适合使用mongodb,以及判断在引入副本集后实际的事务能力。
事务的原子性(Atomic)
背景
某一天,突然发现,我们的一个上传excel需求,上传后提示报错,但是数据正常上传成功了。
数据结构如下:文件表
+ 订单表
,订单表关联文件表ID
文件表
1 |
|
订单表
1 | { |
1 | // 创建文件 |
排查
经过日志排查,发现
创建文件
创建订单
都成功了,但是发送通知
失败了,错误原因为redis版本过低导致异常无法正常发送。
理论
什么是事务的原子性
- 一个事务包含多个操作,这些操作要么全都执行,要么全都不执行。
- 实现事务的原子性,要支持
回滚
操作,在某个操作失败后,回滚到事务执行前的状态。
结论
我们可以理解为 创建文件
创建订单
发送通知
这三个步骤是一个事务,要么全部成功,要们全部不执行,
当发送通知
失败的时候,我们应当将创建文件
创建订单
进行回滚,从而达到 创建文件
创建订单
发送通知
这三个步骤都不执行。
事务的隔离性(Isolation)
背景
某一天,销售反馈,我的确认操作无法提交了。
数据表如下:订单表
+ 发票表
+ 发票池表
订单确认操作过程
1、校验订单是否开过发票
和发票池
。
2、创建发票池表
数据,而后创建发票表
。
发票表中
invoiceNum
具有唯一索引
1 | // 1.校验是否开过发票和发票池 |
排查
经过排查,我们先发现数据库发票编号invoiceNum唯一索引报错了。说明多个请求拿到了同一个invoiceNum发票编号
1 | 2022-02-21 10:58:17,497 ERROR 30265 [-/116.233.76.38/-/25ms POST /orders/6212ff47fa481876394ee21c/status] error_handler: MongoError: E11000 duplicate key error collection: biocitydb.sys_invoices index: invoiceNum_1 dup key: { invoiceNum: "P2202211321" } |
我们继续排查发现一共有2次请求,拿到了同一个invoiceNum发票编号,说明出现了并发问题
。
第一次请求,销售员王璐
成功使用P2202211296
发票编号创建了发票,未遇到唯一索引
第二次请求,销售员沈梦婷
,因为在几乎同一时刻与销售员王璐
发出请求,发票编号未有事务加锁,导致发生了脏读
注意看请求的时间与invoiceNum,发现请求时间几乎同一时刻,相同的发票编号。
1 | 2022-02-21 10:57:38,020 INFO 30265 发票invoiceOpts { |
1 | 2022-02-21 10:57:38,022 INFO 30265 发票invoiceOpts { |
并发脏读图解:
T1 王璐 | T2 沈梦婷 |
---|---|
(1)读发票编号P2202211296 | |
(2)创建发票池 | (1)读发票编号P2202211296 -> T1未完成就读取现在的发票编号,导致脏读 |
(3)创建发票 | (2)创建发票池 |
(4)更新当前发票自增编号 | (3)创建发票 |
(4)更新当前发票自增编号 |
理论
脏读
事务A修改了一个数据,但未提交,事务B读到了事务A未提交的更新结果,如果事务A提交失败,事务B读到的就是脏数据。不可重复读
同一事务中,对于同一份数据读取到的结果不一致。如事务B在事务A提交前后读取的数据不一致。
原因:事务并发修改记录。
解决:加锁。但这会导致锁竞争加剧,影响性能。另一种方法是通过MVCC可以在无锁的情况下,避免不可重复读。幻读
同一事务中,同一个查询多次返回的结果不一致。如事务B在事务A提交前后查询到的数据记录变多了。
原因:并发事务增加记录。
解决:串行。
事务的隔离级别从低到高有:
- Read Uncommitted
最低的隔离级别,什么都不需要做,一个事务可以读到另一个事务未提交的结果。所有的并发事务问题都会发生。
- Read Committed
只有在事务提交后,其更新结果才会被其他事务看见。可以解决脏读
问题。
- Repeated Read
在一个事务中,对于同一份数据的读取结果总是相同的,无论是否有其他事务对这份数据进行操作,以及这个事务是否提交。可以解决脏读、不可重复读
。
- Serialization
事务串行化执行,隔离级别最高,牺牲了系统的并发性。可以解决并发事务的所有问题
。
结论
- 2个并发请求,导致出现事务的
脏读
问题,2个并发同时拿到了同一个自增编号(发票编号),mongodb支持的锁机制弱,无法使用悲观锁,虽然乐观锁无法解决脏读,但是可以使用乐观锁+事务回滚。可查看了没有mongodb事务的支持下,我这种思路的解决:分布式锁设计实践- 出现
脏读
问题后,因为数据库有唯一索引,创建失败后,出现多表操作的原子性问题。
事务的一致性(Consistency)
todo
事务的持久性(Durability)
todo
monstache实践mongodb同步es
monstache实践
背景
我们已经通过 Enterprise Search 企业搜索实践快速搭建起了搜索引擎,
并且通过评估 mongodb同步elasticSearch方案评估,了解到社区和行业主流monstache同步方案。
我们按照Enterprise Search 企业搜索实践,先创建Engine Schema
,提前设置好mapping字段。
设置字段
查看字段数据
我们来实践一下monstache
monstache配置
假设我们已经有了mongodb和elasticsearch,我们来配置同步设置
1 | # 启用调试日志 |
- [logs]: 记录错误信息
- [[mapping]]: 改写默认的索引名称。在上面我们的索引名称为 mongodb
- **[[script]]**:是一种中间件,能够转换,删除文档或定义索引元数据。 可以使用 Javascript 或 Golang 作为插件编写该中间件。
用于转换文档的脚本示例
1 | module.exports = function (doc) { |
同步完后,我们来看看同步的数据情况
正确同步了所有数据
正常搜索
我们同时也评估了使用flinkCDC同步,可查看
Flink CDC实践mongodb到es
相关链接
SSL/TLS 加密传输与数字证书
背景
配置elastic系列产品时,卡了2天在了Enterprise Search 企业搜索实践的证书ssl配置,说明对证书还是有不理解。数字证书、HTTPS、SSL/TLS、加密… 无数的词汇在脑海中席卷而来,这都是些啥啊?为了解答这些困惑,今天这篇文章,我将借此带大家走进 SSL/TLS 加密传输与数字证书,希望从此刻开始,令人眼花缭乱的证书格式不会再成为你的困扰。
本篇着重点在于自签证书
证书与加密
对于数字证书的第一印象,通常来自于 HTTPS 协议。大家都知道HTTP 协议是不需要数字证书的。对于HTTPS协议的理解,可以简单粗暴的认为它约等于 HTTP + SSL,所以,从这个协议诞生的那一刻起,加密算法与数字证书就密不可分,因为从本质上来讲,HTTPS协议就是为了解决如何在不安全的网络上、安全地传输数据的问题。事实上,HTTPS 协议的实现,背后依托 SSL/TLS、数字签名、对称/非对称加密等一系列的知识。也许,在读到这篇文章以前,对于 HTTPS 的理解,永远止步于 HTTP + SSL。那么,我希望下面的解释可以帮助到你,通常,HTTPS 认证可以分为 单向认证 和 双向认证 两种,这里我们以为以单向认证为例,来说明数字证书与加密算法两者间的联系:
- 如图所示,HTTPS 单向认证流程主要经历了下面 7 个步骤,它们分别是:
- 客户端发起 HTTPS 请求
- 服务器返回证书信息,本质上是公钥
- 客户端/浏览器通过 CA 根证书验证公钥,如果验证失败,将会收到警告信息
- 客户端随机生成一个对称密钥 Key,并利用公钥对 Key 进行加密
- 服务器使用私钥解密获得对称密钥 Key
- 通过对称密钥 Key 对确认报文进行加密
- 双方开始通信
由此,我们可以看出,整个 HTTPS 单向认证流程,实际上是结合了 对称加密
和 非对称加密
两种加密方式。
其中,非对称加密
主要用于客户端、服务器双方的“试探”环节,即证书验证部分;对称加密
主要用于客户端、服务器双方的“正式会话”阶段,即数据传输部分。
关于 对称加密 和 非对称加密 两者的区别,我们可以从下面的图中找到答案:
因为客户端持有服务器端返回的公钥,所以,两者可以使用 非对称加密
对随机密钥 Key 进行加/解密。
同理,因为客户/服务器端使用相同的随机密钥,所以,两者可以使用 对称加密
对数据进行加/解密。
我们来看看天猫这个网站,来看看客户端是怎么对服务端的证书进行校验的。
事实上,浏览器在对服务器端返回的证书进行校验时,主要关心下面这些信息:
- 判断域名、有效期等信息是否正确:这些信息在证书中是公开的,可以非常容易地获得。
- 判断证书是否被篡改:需要由 CA 服务器进行校验。
- 判断证书来源是否合法:每一份签发的证书都可以按照证书链找到对应的根证书,所以,可以通过操作系统中安装的根证书对证书的来源进行验证。
- 判断证书是否被吊销:需要由 CRL(Certificate Revocation List,即 证书注销列表)和 OCSP(Online Certificate Status Protocol, 即 在线证书状态协议) 来实现。
这里引入了一个新的概念,即 CA(Certification Authority)
。那么,什么是 CA
呢? 通俗来讲,CA
就是一个负责签发、认证和管理证书的机构。可能有朋友会想,客户端和服务器端通过非对称加密相互校验证书就好了啊,为什么还需要这样一个第三方的机构呢?事实上,这相当于一种担保/信用体系,因为服务器端的公钥对任何人来说都是可见的,我们来考虑这样一种情形。假设客户端从服务器端获得了某个公钥,并且它认为这个公钥是可信的,此时,有一个不怀好意的中间人截获了这个公钥,它如法炮制伪造了一个相同的公钥并返回,那么,此时客户端会如何看待这个公钥呢?虽然这个中间人不可能伪造出与服务端相同的私钥,可这无疑会让客户端感到困惑,因为它没有办法判断这个证书的真假。
证书创建
目前,全球主流的 CA 机构有Comodo、Symantec、GeoTrust、DigiCert、Thawte、GlobalSign、RapidSSL 等,其中 Symantec、GeoTrust 都是 DigiCert 机构的子公司,占据数字证书体系中的垄断地位.实际操作中,通常有自签名证书和CA证书两种,两者唯一的差别就在于权威性不同.
CA证书
就是前往Comodo、Symantec、GeoTrust、DigiCert、Thawte、GlobalSign、RapidSSL进行签署,像阿里云腾讯云都有提供相关的证书申请。
自签名证书
所谓自签名证书,其实就是自建一个CA,然后利用这个CA对证书进行签名。
openssl
1 | -new :说明生成证书请求文件 |
创建根证书
用openssl x509来自签署。自签署时,使用“-req”选项明确表示输入文件为证书请求文件,否则将默认以为是证书文件,再使用“-signkey”提供自签署时使用的私钥。
1 | // 生成私钥(key文件) |
或openssl req命令生成自签名证书。
1 | // 生成私钥ca.key |
在这个过程中,OpenSSL 会要求我们提供下列信息:国家、省份、城市、组织 以及 全域名(FQDN)。在此之前,关于天猫的那个例子,实际上证书上的那些信息就是从这里来的。当我们有了这样一个自建的 CA 以后,我们就可以用这个自建的 CA 去签发证书,这就是自签名 CA 证书,如何生成这个证书呢?
签发证书
使用 CA 根证书签名服务器证书
1 | // 生成私钥 |
证书的编码格式
X.509 标准的证书文件具有不同的编码格式,一般包括 PEM 和 DER 两种。
- PEM: Privacy Enhanced Mail 的缩写,以文本的方式进行存储。它的文件结构以 —–BEGIN XXX—–,并以 —–END XXX—– 结尾,中间 Body 内容为 Base64 编码过的数据。
例如,以 PEM 格式存储的证书结构大概如下:
1 | -----BEGIN CERTIFICATE----- |
一般 Apache 和 Nginx 服务器应用偏向于使用 PEM 这种编码格式。
- DER: Distinguished Encoding Rules 的缩写,以二进制方式进行存储,文件结构无法直接预览,同样可以通过如下 OpenSSL 命令查看其证书内容:
一般 Java 和 Windows 服务器应用偏向于使用 DER 这种编码格式。
证书的几种文件扩展名
如上所述,对于 X.509 标准的证书两种不同编码格式,一般采用 PEM 编码就以 .pem 作为文件扩展名,若采用 DER 编码,就应以 .der 作为扩展名。但常见的证书扩展名还包括 .crt、.cer、.p12 等,他们采用的编码格式可能不同,内容也有所差别,但大多数都能互相转换,现总结如下:
.csr: Certificate Signing Request 的缩写,即证书签名请求,它并不是证书的格式,而是用于向权威证书颁发机构(Certificate Authority, CA)获得签名证书的申请,其核心内容包含一个 RSA 公钥和其他附带信息,在生成这个 .csr 申请的时候,同时也会生成一个配对 RSA 私钥,私钥通常需要严格保存于服务端,不能外泄。
.key: 通常用来存放一个 RSA 公钥或者私钥,它并非 X.509 证书格式,编码同样可能是 PEM,也可能是 DER,查看方式如下
.pem: 采用 PEM 编码格式的 X.509 证书的文件扩展名;
.der: 采用 DER 编码格式的 X.509 证书的文件扩展名;
.crt: 即 certificate 的缩写,常见于类 UNIX 系统,有可能是 PEM 编码,也有可能是 DER 编码,但绝大多数情况下此格式证书都是采用 PEM 编码;
.cer: 也是 certificate 的缩写,常见于 Windows 系统,同样地,可能是 PEM 编码,也可能是 DER 编码,但绝大多数情况下此格式证书都是采用 DER 编码;
.p12: 也写作 .pfx,全称:PKCS #12,是公钥加密标准(Public Key Cryptography Standards,PKCS)系列的一种,它定义了描述个人信息交换语法(Personal Information Exchange Syntax)的标准,可以用来将包含了公钥的 X.509 证书和证书对应的私钥以及其他相关信息打包,进行交换。简单理解:一份 .p12 文件 = X.509 证书+私钥;
1 | // .pem -> .pfx |