在本文中,我们将带你了解大数据系列11:Gora–大数据持久化在这篇文章中,我们将为您详细介绍大数据系列11:Gora–大数据持久化的方方面面,并解答大数据可持续发展常见的疑惑,同时我们还将给您一些技
在本文中,我们将带你了解大数据系列11:Gora – 大数据持久化在这篇文章中,我们将为您详细介绍大数据系列11:Gora – 大数据持久化的方方面面,并解答大数据 可持续发展常见的疑惑,同时我们还将给您一些技巧,以帮助您实现更有效的5月16日云栖精选夜读:从0到1构建大数据生态系列1:数据蛮荒中的拓荒之举、docker 系列 - 容器数据持久化和数据共享、docker拉取oracle11g镜像并配置数据持久化、EMQ X 插件持久化系列 (三)EMQ X Redis 数据持久化。
本文目录一览:- 大数据系列11:Gora – 大数据持久化(大数据 可持续发展)
- 5月16日云栖精选夜读:从0到1构建大数据生态系列1:数据蛮荒中的拓荒之举
- docker 系列 - 容器数据持久化和数据共享
- docker拉取oracle11g镜像并配置数据持久化
- EMQ X 插件持久化系列 (三)EMQ X Redis 数据持久化
大数据系列11:Gora – 大数据持久化(大数据 可持续发展)
wget http://mirrors.cnnic.cn/apache/gora/0.3/apache-gora-0.3-src.zip
unzip apache-gora-0.3-src.zip
cd apache-gora-0.3
mvn clean package
1、创建项目
mvn archetype:create -DgroupId=org.apdplat.demo.gora -DartifactId=gora-demo
2、增加依赖
vi gora-demo/pom.xml
在<dependencies>标签内增加:
<dependency>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-core</artifactId>
<version>1.2.1</version>
</dependency>
<dependency>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase</artifactId>
<version>0.94.12</version>
</dependency>
<dependency>
<groupId>org.apache.gora</groupId>
<artifactId>gora-core</artifactId>
<version>0.3</version>
<exclusions>
<exclusion>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-core</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-frontend-jaxrs</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.gora</groupId>
<artifactId>gora-hbase</artifactId>
<version>0.3</version>
<exclusions>
<exclusion>
<groupId>org.apache.hbase</groupId>
<artifactId>hbase</artifactId>
</exclusion>
<exclusion>
<groupId>org.apache.hadoop</groupId>
<artifactId>hadoop-test</artifactId>
</exclusion>
</exclusions>
</dependency>
3、数据建模
mkdir -p gora-demo/src/main/avro
vi gora-demo/src/main/avro/person.json
输入:
{
"type": "record",
"name": "Person",
"namespace":"org.apdplat.demo.gora.generated",
"fields" : [
{"name":"idcard", "type": "string"},
{"name":"name", "type": "string"},
{"name":"age", "type": "string"}
]
}
4、生成JAVA类
bin/gora goracompiler gora-demo/src/main/avro/person.json gora-demo/src/main/java/
5、模型映射
mkdir -p gora-demo/src/main/resources/
vi gora-demo/src/main/resources/gora-hbase-mapping.xml
输入:
<gora-orm>
<table name="Person">
<familyname="basic"/>
<familyname="detail"/>
</table>
<class table="Person"name="org.apdplat.demo.gora.generated.Person"key>
<field name="idcard"family="basic" qualifier="idcard"/>
<field name="name"family="basic" qualifier="name"/>
<field name="age"family="detail" qualifier="age"/>
</class>
</gora-orm>
6、Gora配置
vi gora-demo/src/main/resources/gora.properties
输入:
gora.datastore.default=org.apache.gora.hbase.store.HBaseStore
gora.datastore.autocreateschema=true
7、Hbase配置
vi gora-demo/src/main/resources/hbase-site.xml
输入:
<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl"href="configuration.xsl"?>
<configuration>
<property>
<name>hbase.zookeeper.property.clientPort</name>
<value>2181</value>
</property>
<property>
<name>hbase.zookeeper.quorum</name>
<value>host001</value>
</property>
</configuration>
8、编写PersonManager.java和PersonAnalytics.java
vi gora-demo/src/main/java/org/apdplat/demo/gora/PersonManager.java
输入:
package org.apdplat.demo.gora;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.text.ParseException;
import org.apache.avro.util.Utf8;
import org.apache.gora.query.Query;
import org.apache.gora.query.Result;
import org.apache.gora.store.DataStore;
import org.apache.gora.store.DataStoreFactory;
import org.apache.hadoop.conf.Configuration;
import org.apdplat.demo.gora.generated.Person;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
publicclass PersonManager {
privatestaticfinal Logger log = LoggerFactory.getLogger(PersonManager.class);
private DataStore<String, Person> dataStore;
public PersonManager() {
try{
init();
} catch(IOException ex) {
thrownew RuntimeException(ex);
}
}
privatevoid init() throws IOException {
Configuration conf = new Configuration();
dataStore= DataStoreFactory.getDataStore(String.class, Person.class, conf);
}
privatevoid parse(String input) throws IOException,ParseException, Exception {
log.info("解析文件:" + input);
BufferedReader reader = new BufferedReader(new FileReader(input));
longlineCount = 0;
try{
String line = reader.readLine();
do {
Person person = parseLine(line);
if(person != null) {
//入库
storePerson(person.getIdcard().toString(), person);
}
lineCount++;
line = reader.readLine();
} while(line != null);
} finally{
reader.close();
}
log.info("文件解析完毕. 总人数:" + lineCount);
}
private Person parseLine(String line) throws ParseException {
String[] attrs = line.split(" ");
String idcard = attrs[0];
String name = attrs[1];
String age = attrs[2];
Person person = new Person();
person.setIdcard(new Utf8(idcard));
person.setName(new Utf8(name));
person.setAge(new Utf8(age));
return person;
}
privatevoid storePerson(String key,Person person) throwsIOException, Exception {
log.info("保存人员信息: " + person.getIdcard()+"\t"+person.getName()+"\t"+person.getAge());
dataStore.put(key,person);
}
privatevoid get(String key) throws IOException, Exception{
Person person = dataStore.get(key);
printPerson(person);
}
privatevoid query(String key) throws IOException, Exception{
Query<String, Person> query = dataStore.newQuery();
query.setKey(key);
Result<String, Person> result = query.execute();
printResult(result);
}
privatevoid query(String startKey,String endKey) throwsIOException, Exception {
Query<String, Person> query = dataStore.newQuery();
query.setStartKey(startKey);
query.setEndKey(endKey);
Result<String, Person> result = query.execute();
printResult(result);
}
privatevoid delete(String key) throws Exception {
dataStore.delete(key);
dataStore.flush();
log.info("身份证号码为:" + key + " 的人员信息被删除");
}
privatevoid deleteByQuery(StringstartKey, String endKey) throws IOException, Exception {
Query<String, Person> query = dataStore.newQuery();
query.setStartKey(startKey);
query.setEndKey(endKey);
dataStore.deleteByQuery(query);
log.info("身份证号码从 " + startKey + " 到 " + endKey + " 的人员信息被删除");
}
privatevoid printResult(Result<String, Person> result) throws IOException, Exception {
while(result.next()){
String resultKey =result.getKey();
Person resultPerson =result.get();
System.out.println(resultKey + ":");
printPerson(resultPerson);
}
System.out.println("人数:" + result.getOffset());
}
privatevoid printPerson(Personperson) {
if(person== null){
System.out.println("没有结果");
} else{
System.out.println(person.getIdcard()+"\t"+person.getName()+"\t"+person.getAge());
}
}
privatevoid close() throws IOException, Exception{
if(dataStore != null)
dataStore.close();
}
privatestaticfinal String USAGE = "PersonManager -parse<input_person_file>\n" +
" -get <idcard>\n" +
" -query <idcard>\n" +
" -query <startIdcard> <endIdcard>\n" +
" -delete <idcard>\n" +
" -deleteByQuery <startIdcard> <endIdcard>\n";
publicstaticvoid main(String[] args) throws Exception {
if(args.length < 2) {
System.err.println(USAGE);
System.exit(1);
}
PersonManager manager = new PersonManager();
if("-parse".equals(args[0])){
manager.parse(args[1]);
} elseif("-get".equals(args[0])){
manager.get(args[1]);
} elseif("-query".equals(args[0])){
if(args.length == 2)
manager.query(args[1]);
else
manager.query(args[1], args[2]);
} elseif("-delete".equals(args[0])){
manager.delete(args[1]);
} elseif("-deleteByQuery".equalsIgnoreCase(args[0])){
manager.deleteByQuery(args[1], args[2]);
} else{
System.err.println(USAGE);
System.exit(1);
}
manager.close();
}
}
vi gora-demo/src/main/java/org/apdplat/demo/gora/PersonAnalytics.java
输入:
package org.apdplat.demo.gora;
import java.io.IOException;
import org.apache.avro.util.Utf8;
import org.apache.gora.mapreduce.GoraMapper;
import org.apache.gora.store.DataStore;
import org.apache.gora.store.DataStoreFactory;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.conf.Configured;
import org.apache.hadoop.fs.Path;
import org.apache.hadoop.io.LongWritable;
import org.apache.hadoop.io.Text;
import org.apache.hadoop.mapreduce.Job;
import org.apache.hadoop.mapreduce.Reducer;
import org.apache.hadoop.mapreduce.lib.output.TextOutputFormat;
import org.apache.hadoop.util.Tool;
import org.apache.hadoop.util.ToolRunner;
import org.apdplat.demo.gora.generated.Person;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
publicclass PersonAnalytics extends Configured implements Tool {
privatestaticfinal Logger log= LoggerFactory
.getLogger(PersonAnalytics.class);
publicstaticclassPersonAnalyticsMapper extends
GoraMapper<String,Person, Text, LongWritable> {
private LongWritable one = new LongWritable(1L);
@Override
protectedvoid map(String key, Person person, Contextcontext)
throws IOException,InterruptedException {
Utf8 age =person.getAge();
context.write(new Text(age.toString()), one);
};
}
publicstaticclassPersonAnalyticsReducer extends
Reducer<Text,LongWritable, Text, LongWritable> {
@Override
protectedvoid reduce(Text key,Iterable<LongWritable> values,
Context context) throws IOException,InterruptedException {
long sum = 0L;
for (LongWritable value :values) {
sum += value.get();
}
context.write(key, new LongWritable(sum));
};
}
public Job createJob(DataStore<String,Person> inStore, int numReducer)
throws IOException {
Job job = new Job(getConf());
job.setJobName("Person Analytics");
log.info("Creating Hadoop Job: " +job.getJobName());
job.setNumReduceTasks(numReducer);
job.setJarByClass(getClass());
GoraMapper.initMapperJob(job,inStore, Text.class,LongWritable.class,
PersonAnalyticsMapper.class, true);
job.setReducerClass(PersonAnalyticsReducer.class);
job.setOutputKeyClass(Text.class);
job.setOutputValueClass(LongWritable.class);
TextOutputFormat
.setOutputPath(job,newPath("person-analytics-output"));
return job;
}
@Override
publicint run(String[] args) throws Exception {
DataStore<String,Person> inStore;
Configuration conf = new Configuration();
if (args.length == 1) {
String dataStoreClass =args[0];
inStore =DataStoreFactory.getDataStore(dataStoreClass,
String.class, Person.class, conf);
} else {
inStore =DataStoreFactory.getDataStore(String.class, Person.class,
conf);
}
Job job = createJob(inStore,2);
boolean success = job.waitForCompletion(true);
inStore.close();
log.info("PersonAnalytics completed with "
+ (success ? "success": "failure"));
return success ? 0 : 1;
}
publicstaticvoidmain(String[] args) throws Exception {
int ret = ToolRunner.run(new PersonAnalytics(),args);
System.exit(ret);
}
}
9、准备数据
vi gora-demo/src/main/resources/persons.txt
输入:
533001198510125839 杨尚川 25
533001198510125840 杨尚华 22
533001198510125841 刘德华 55
533001198510125842 刘亦菲 25
533001198510125843 蔡卓妍 25
533001198510125844 林志玲 22
533001198510125845 李连杰 55
10、在Linux命令行使用maven2编译运行项目
cd gora-demo
mvn clean compile
mvn exec:java -Dexec.mainClass=org.apdplat.demo.gora.PersonManager
mvn exec:java -Dexec.main-Dexec.args="-parse src/main/resources/persons.txt"
mvn exec:java -Dexec.mainClass=org.apdplat.demo.gora.PersonAnalytics
cat person-analytics-output/part-r-00000
mvn exec:java -Dexec.main-Dexec.args="-get 533001198510125842"
mvn exec:java -Dexec.main-Dexec.args="-query 533001198510125844"
mvn exec:java -Dexec.main-Dexec.args="-query 533001198510125842 533001198510125845"
mvn exec:java -Dexec.main-Dexec.args="-delete 533001198510125840"
mvn exec:java -Dexec.main-Dexec.args="-deleteByQuery 533001198510125841 533001198510125842"
mvn exec:java -Dexec.main-Dexec.args="-deleteByQuery 533001198510125845 533001198510125846"
mvn exec:java -Dexec.main-Dexec.args="-query 533001198510125838 533001198510125848"
11、在windows下使用eclipse编译运行项目
mvn clean package
rm -r target
vi .classpath
删除所有包含path="M2_REPO的行
删除<classpathentry kind="src" path="target/maven-shared-archive-resources"excluding="**/*.java"/>
通过WinSCP把gora-demo传到windows
从http://yangshangchuan.iteye.com/blog/1839784下载修改过的hadoop-core-1.2.1.jar替换文件gora-demo\lib\hadoop-core-1.2.1.jar
将gora-demo导入eclipse
将lib下的所有jar加入构建路径
12、打包项目并提交Hadoop运行
cd gora-demo
mvn clean package
mkdir job
cp -r lib job/lib
cp -r target/classes/* job
hadoop fs -put persons.txt persons.txt
jar -cvf gora-demo.job *
hadoop jar gora-demo.job org.apdplat.demo.gora.PersonAnalytics
APDPlat旗下十大开源项目
5月16日云栖精选夜读:从0到1构建大数据生态系列1:数据蛮荒中的拓荒之举
摘要: 我们都知道,当前大数据的需求基本属于遍地开花。无论是帝都、魔都,还是广州、深圳,亦或是全国其他各地,都在搞大数据;不管是不到百人的微小公司,还是几百上千人的中型公司,亦或是上万的大型公司,都在需求数据岗位。
我们都知道,当前大数据的需求基本属于遍地开花。无论是帝都、魔都,还是广州、深圳,亦或是全国其他各地,都在搞大数据;不管是不到百人的微小公司,还是几百上千人的中型公司,亦或是上万的大型公司,都在需求数据岗位。
数据时代
从0到1构建大数据生态系列1:数据蛮荒中的拓荒之举
未来的企业都将是数据驱动的企业
城市计算,大数据的用武之地!
知识整理
linux常用命令
10款常见MySQL高可用方案选型解读
Java设计模式中单例设计模式
JavaScript实现自适应窗口大小的网页
浅析 JavaScript 中的 “闭包”
美文回顾
PHP最佳实践(译)
影响JavaScript应用可扩展性因素
大数据的五大误区及其破解之道
Linux操作系统中的7功能详解
触类旁通,从400错误看Nginx常见故障与修复
分布式实时数据处理实战:从选型、应用到优化
Elasticsearch + php + msyql+nginx安装流程
docker 系列 - 容器数据持久化和数据共享
docker 主要有两种数据存储形式,一种是 storage driver (也叫做 Graph driver), 另一种是 volume driver. stroage driver 主要是存储那些无状态的数据,写入密集型的场景应该使用 volume driver.
======================
storage driver
======================
容器运行的文件系统是镜像层和容器层组成的,一层一层叠加,只有最上面的那层是可写的,其他层都是只读的. Docker 通过 Union FS 技术支持文件的读写和新建,Docker 采用插件式的方式支持多种 Union FS 实现,官方文档中一般使用 stroage driver 术语,目前已经有多种实现的插件,比如: aufs/overlay/overlay2/devicemanger 等等.
boot2docker 缺省使用的 storage-driver 为 aufs, 下面命令将创建一个使用 overlay2 的 storage driver docker 运行环境.
docker-machine create --driver virtualbox --engine-storage-driver overlay2 test2
正式的 docker 环境,需要修改 /etc/docker/daemon.json 文件,具体参考选用 btrfs driver 的官方文档 https://docs.docker.com/storage/storagedriver/btrfs-driver/#configure-docker-to-use-the-btrfs-storage-driver
{
"storage-driver": "btrfs"
}
对于不同的 Linux 发行版的主机,官方有一些推荐说明:
https://docs.docker.com/storage/storagedriver/select-storage-driver/
https://success.docker.com/article/compatibility-matrix
对于 CentOS 7 推荐使用 overlay2, 可参考 https://blog.csdn.net/lusyoe/article/details/80208260 ,
几个查询 storage driver 的命令:
docker info 命令,查询 docker 运行环境使用的 storage-driver.
docker image inspect 命令,查看镜像使用的存储 driver.
docker container inspect 命令,查看容器使用的存储 driver.
======================
volume driver
======================
volume driver 经常用来实现数据持久化和文件共享功能,具体有两种存在方式,分别是:
1. bind mount 方式:
是将 host 的目录或文件直接 mount 到容器中,host 的目录或文件既可以容器运行之前就已存在的,也可以是在容器运行之前不存在的.
如果在 docker run 命令中采用了 -v /host/dir_or_file:/container/dir_or_file 的形式,就是 bind mount 方式,即指定了 host 的挂载点的绝对路径.
2. volume 方式:是由 Docker 管理,该 volume 最终存储到 host 的 /var/lib/docker/volumes 下. volume 方式还分为 named volume 和 Anonymous volume.
named volume 有两种创建方法,
(1) docker run 命令中采用了 -v one_volume_name:/container/dir_or_file , 这里的 one_volume_name 不是 host 中的绝对路径,而是一个名称.
(2) 通过 docker volume create 创建的,该命令支持更多的选项,推荐使用.
匿名 volume 方式 是通过 docker run 命令中传入了 -v /container/dir 类型的参数.
3. bind mount 方式和 volume 方式的简单对比:
bind mount 方式,docker 容器直接访问 host 的目录或文件,性能是最好的.
bind mount 方式,docker 容器直接访问 host 的目录或文件,对于该 host 绝对目录可能会引入权限问题。如果容器仅需要只读访问权限,最好是显式设定只读方式.
对于 volume 方式,如果 host 中落地目录为空,docker 先将容器中的对应目录复制到 host 下,然后再进行挂载操作;对于 bind mount 方式,挂载之前没有复制操作.
容器要依赖 host 主机的一个绝对路径,使得容器的移植性变差,docker 官方并不推荐这个方法,而是推荐使用 volume.
几个示例说明:
docker run -d --name web0 -v myetc:/etc busybox /bin/sh -c "while true; do echo hello world; sleep 1; done"
#创建了一个named volume, 该volume 在 /var/lib/docker/volume/myetc 下.
docker run -d --name web1 -v /etc busybox /bin/sh -c "while true; do echo hello world; sleep 1; done"
#创建了一个匿名的volume, 该volume在/var/lib/docker/volume父目录下, 具体子目录不确定,
#比如 /var/lib/docker/volume/9170d32e15b7578240afde81d5514637beece7d469b7ea253e23759a23b0a397
docker run -d --name web2 -v /etc2:/etc busybox /bin/sh -c "while true; do echo hello world; sleep 1; done"
#使用 bind mount 方式, host上的目录为 /etc2
docker run 命令的 --volume 和 --mount 参数
--volume 和 --mount 两种参数写法都支持上述 volume 和 bind mount 方式,--mount 采用 key-value 的写法,支持更多的设置选项,docker 新版更加推荐使用 --mount 参数写法,但 --volume 写法更加简洁,仍然给广泛使用.
另一种推荐的 volume 写法是,显式地使用 docker volume create 命令创建 named volume, 更多信息见官方文档: https://docs.docker.com/engine/reference/commandline/volume_create/#usage
有了上面的知识,很容易就能实现容器和 Host 之间共享数据。对于同一 Host 下多个容器共享数据,直接 docker run -v 参数非常不方便,最好是使用 data container 作为桥梁。一般 data container 不启任何应用,也不需要将容器真正运行起来,仅仅是挂载一下 volume, data container 除了用于多个容器之间数据共享之外,也可用于 volume 的备份和恢复.
data container 和 volume 的备份恢复
#创建一个名 为 dbstore 的数据容器, 设置一个匿名的/dbdata volume.
docker create -v /dbdata --name dbstore busybox /bin/sh
#创建一个名为 web3 的应用容器, 将 dbstore 数据容器的volume 挂载过来.
docker run -d --name web3 --volumes-from dbstore busybox /bin/sh -c "while true; do echo hello world; sleep 1; done"
#备份数据容器 dbstore 的/dbdata目录到容器到host的host_backup目录下, 最终在host上的文件名为 /host_backup/backup.tar
docker run --rm --volumes-from dbstore -v /host_backup:/backup busybox tar -cvf /backup/backup.tar /dbdata
#恢复数据容器dbstore 的/dbdata目录, 数据源为host上的文件 /host_backup/backup.tar
docker run --rm --volumes-from dbstore -v /host_backup:/backup busybox /bin/sh -c "cd /dbdata && tar -xvf /backup/backup.tar --strip 1"
======================
容器之间的通讯
======================
同一个 docker daemon 下的容器,When containers are placed in the same network, they are reachable by each other using their container name and other alias as host.
https://stackoverflow.com/questions/35832095/difference-between-links-and-depends-on-in-docker-compose-yml
======================
参考
======================
http://www.cnblogs.com/sammyliu/p/5932996.html
http://www.cnblogs.com/lkun/p/7750629.html
https://blog.csdn.net/lusyoe/article/details/80208260
docker拉取oracle11g镜像并配置数据持久化
一、拉取oracle11g镜像
下载过程稍长,镜像大小6.8G(之前拉取过了,所以就不截图了)
#docker pull registry.cn-hangzhou.aliyuncs.com/helowin/oracle_11g
镜像详情:https://dev.aliyun.com/detail.html?spm=5176.1972343.2.8.E6Cbr1&repoId=1969
下载完成后 查看镜像
# docker images
二、创建容器初步了解如何使用镜像
1、创建容器
# docker run -v /opt:/data -p 1521:1521 --name oracle11g -h demo --restart=always -d registry.cn-hangzhou.aliyuncs.com/helowin/oracle_11g
说明
-v(映射主机目录到容器内,把opt目录映射到容器根目录data下)
--name(容器名)
--restart=always(设置容器开机自启动)
-d(创建容器之后不自动进入容器)
2、进入容器
# docker exec -it oracle11g bash
3、切换到root 用户下
$ su root
密码:helowin
4、编辑profile文件配置ORACLE环境变量
# vi /etc/profile
在最后面添加如下内容
export ORACLE_HOME=/home/oracle/app/oracle/product/11.2.0/dbhome_2 #oracle路径
export ORACLE_SID=helowin #oracle启动数据库实例名
export PATH=$ORACLE_HOME/bin:$PATH #添加系统环境变量
5、立即生效
# source /etc/profile
6、创建软连接
ln -s $ORACLE_HOME/bin/sqlplus /usr/bin
7、切换到oracle 用户
这里还要说一下,一定要写中间的内条 - 必须要,否则软连接无效
# su - oracle
8、登录oracle数据库
$ sqlplus /nolog
SQL> conn /as sysdba
9、修改sys、system密码
SQL> alter user system identified by system;
SQL> alter user sys identified by sys;
也可以创建用户 create user test identified by test;
并给用户赋予权限 grant connect,resource,dba to test;
修改oracle默认用户密码永不过期
SQL> ALTER PROFILE DEFAULT LIMIT PASSWORD_LIFE_TIME UNLIMITED;
SQL> exit
exit 是退休sql 软连接
10、查看监听是否成功启动
$ lsnrctl status
11、查看监听配置文件
注意:oracle监听文件不要随意更改,如若更改需要先备份一份
$ cat /home/oracle/app/oracle/product/11.2.0/dbhome_2/network/admin/tnsnames.ora
# tnsnames.ora Network Configuration File: /home/oracle/app/oracle/product/11.2.0/dbhome_2/network/admin/tnsnames.ora
# Generated by Oracle configuration tools.
LISTENER_HELOWIN =
(ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))
HELOWIN =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = TCP)(HOST = localhost)(PORT = 1521))
(CONNECT_DATA =
(SERVER = DEDICATED)
(SERVICE_NAME = helowin)
)
)
$ cd /home/oracle/app/oracle/product/11.2.0/dbhome_2/network/admin/
$ vi listener.ora
# listener.ora Network Configuration File: /home/oracle/app/oracle/product/11.2.0/dbhome_2/network/admin/listener.ora
# Generated by Oracle configuration tools.
LISTENER =
(DESCRIPTION_LIST =
(DESCRIPTION =
(ADDRESS = (PROTOCOL = IPC)(KEY = EXTPROC1521))
(ADDRESS = (PROTOCOL = TCP)(HOST = )(PORT = 1521))
)
)
ADR_BASE_LISTENER = /home/oracle/app/oracle
连接oracle数据库时,先检查端口映射是否成功
打开Windows的doc窗口输入一下内容
telnet ip地址 端口号
三、制作属于自己定制的oracle11g镜像
两种方法
方法一:编写Dockerfile文件
方法二:容器打包成镜像
方法一:过程如下
有时间再写
方法二:过程如下
1、创建容器
# docker run --name oracle11g -d oracle_11g
[root@docker-servers ~]# docker run --name oracle11g -d oracle_11g
4826bc11291ebe022a159544d7ad233896723ede260b913c38d2fc101112b04f
[root@docker-servers ~]#
[root@docker-servers ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4826bc11291e oracle_11g "/bin/sh -c ''/home..." 44 seconds ago Up 19 seconds 1521/tcp oracle11g
2、进入容器
# docker exec -it oracle11g bash
[root@docker-servers ~]# docker exec -it oracle11g bash
[oracle@4826bc11291e /]$
[oracle@4826bc11291e /]$
3、切换到root 用户下
root密码为:helowin
[oracle@4826bc11291e /]$ su root
Password:
[root@4826bc11291e /]#
4、编辑profile文件配置ORACLE环境变量
# vi /etc/profile
在最后面添加如下内容
export ORACLE_HOME=/home/oracle/app/oracle/product/11.2.0/dbhome_2
export ORACLE_SID=helowin
export PATH=$ORACLE_HOME/bin:$PATH
5、立即生效
# source /etc/profile
6、创建软连接
# ln -s $ORACLE_HOME/bin/sqlplus /usr/bin
7、切换到oracle 用户
# su - oracle
8、登录oracle数据库
$ sqlplus / as sysdba
9、修改sys、system密码
SQL> alter user system identified by system;
SQL> alter user sys identified by sys;
SQL> ALTER PROFILE DEFAULT LIMIT PASSWORD_LIFE_TIME UNLIMITED;
[root@4826bc11291e /]# vi /etc/profile
[root@4826bc11291e /]# source /etc/profile
[root@4826bc11291e /]# ln -s $ORACLE_HOME/bin/sqlplus /usr/bin
[root@4826bc11291e /]#
[root@4826bc11291e /]# su - oracle
[oracle@4826bc11291e ~]$
[oracle@4826bc11291e ~]$ sqlplus / as sysdba
SQL*Plus: Release 11.2.0.1.0 Production on Wed Aug 14 18:09:43 2019
Copyright (c) 1982, 2009, Oracle. All rights reserved.
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
SQL>
SQL> alter user system identified by system;
User altered.
SQL> alter user sys identified by sys;
User altered.
SQL> ALTER PROFILE DEFAULT LIMIT PASSWORD_LIFE_TIME UNLIMITED;
Profile altered.
SQL>
10、退出容器打包成镜像
退出容器
# exit
根据某个“容器 ID”来创建一个新的“镜像”
# docker commit oracle11g oracle_11g:v1
[root@docker-servers ~]# docker commit oracle11g oracle_11g:v1
sha256:cbe72388da002ee16fa37a448221ec64f1bb5ab534d6904076f1276c3a7a4b72
[root@docker-servers ~]#
[root@docker-servers ~]# docker images
REPOSITORY TAG IMAGE ID CREATED SIZE
oracle_11g v1 cbe72388da00 6 seconds ago 6.86 GB
oracle_11g latest 3fa112fd3642 3 years ago 6.85 GB
可以看到,和之前的容器相比,镜像文件大了一点点
11、根据新镜像运行一个容器
# docker run -p 1523:1521 --name oracle11g_test -d oracle_11g:v1
[root@docker-servers ~]# docker run -p 1523:1521 --name oracle11g_test -d oracle_11g:v1
2963da8bbe11d451c727d27a501af647d4655106e62fe97b509fd6f7590e860a
[root@docker-servers ~]#
[root@docker-servers ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2963da8bbe11 oracle_11g:v1 "/bin/sh -c ''/home..." 31 seconds ago Up 9 seconds 0.0.0.0:1523->1521/tcp oracle11g_test
12、外部测试连接
先监听一下端口
# netstat -tunlp | grep 1523
[root@docker-servers ~]# netstat -tunlp | grep 1523
tcp 0 0 :::1523 :::* LISTEN 23654/docker-proxy-
未能连接成功,实验失败
四、oracle容器数据持久化
具体方法说明:
如需映射oracle的数据文件 把容器内对应的文件,拷贝到宿主机,映射即可(如下)
/home/oracle/app/oracle/oradata/
/home/oracle/app/oracle/flash_recovery_area/helowin/
我映射的命令
# docker run -v /home/oracle11g-dev-pub/oradata:/home/oracle/app/oracle/oradata -v /home/oracle11g-dev-pub/flash_recovery_area/helowin/:/home/oracle/app/oracle/flash_recovery_area/helowin/ -p 1522:1521 --name oracle11g-dev -h dev -d oracle_11g
# docker run -v /opt/oracle11g-demo-pub/oradata:/home/oracle/app/oracle/oradata -v /opt/oracle11g-demo-pub/flash_recovery_area/helowin/:/home/oracle/app/oracle/flash_recovery_area/helowin/ -p 1521:1521 --name oracle11g-demo -h demo -d oracle_11g
具体操作如下:
1、先建一个测试容器
# docker run --name oracle11g_test -d oracle_11g
[root@localhost ~]# docker run --name oracle11g_test -d oracle_11g
0237fc1d788290398508749846bcce02640d17cfc588c460e2d46df31ebcf325
2、新建目录
# mkdir -p /opt/oracle11g-demo-pub/flash_recovery_area
# mkdir -p /opt/oracle11g-demo-pub/oradata
[root@localhost ~]# mkdir -p /opt/oracle11g-demo-pub/flash_recovery_area
[root@localhost ~]# mkdir -p /opt/oracle11g-demo-pub/oradata
3、拷贝数据
# docker cp oracle11g_test:/home/oracle/app/oracle/oradata/helowin /opt/oracle11g-demo-pub/oradata
# docker cp oracle11g_test:/home/oracle/app/oracle/flash_recovery_area/helowin/ /opt/oracle11g-demo-pub/flash_recovery_area
[root@localhost ~]# docker cp oracle11g_test:/home/oracle/app/oracle/oradata/helowin /opt/oracle11g-demo-pub/oradata
[root@localhost ~]# docker cp oracle11g_test:/home/oracle/app/oracle/flash_recovery_area/helowin/ /opt/oracle11g-demo-pub/flash_recovery_area
4、创建容器
# docker run -v /opt/oracle11g-demo-pub/oradata:/home/oracle/app/oracle/oradata -v /opt/oracle11g-demo-pub/flash_recovery_area/helowin/:/home/oracle/app/oracle/flash_recovery_area/helowin/ -p 1521:1521 --name oracle11g-demo_new -h demo -d oracle_11g
[root@localhost ~]# docker run -v /opt/oracle11g-demo-pub/oradata:/home/oracle/app/oracle/oradata -v /opt/oracle11g-demo-pub/flash_recovery_area/helowin/:/home/oracle/app/oracle/flash_recovery_area/helowin/ -p 1521:1521 --name oracle11g-demo -h demo -d oracle_11g
416f7073da96fb4a1bd1fc5bde05ba29007dce0ba68b717f50101527cc39f441
[root@localhost ~]#
查看容器
[root@localhost flash_recovery_area]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
416f7073da96 oracle_11g "/bin/sh -c ''/home..." About a minute ago Up 59 seconds 0.0.0.0:1521->1521/tcp oracle11g-demo
0237fc1d7882 oracle_11g "/bin/sh -c ''/home..." 4 minutes ago Up 4 minutes 1521/tcp oracle11g_test
5、进入容器root授权
# docker exec -it oracle11g-demo bash
[root@localhost flash_recovery_area]# docker exec -it oracle11g-demo bash
[oracle@demo /]$
[oracle@demo /]$ cd /home/oracle/app/oracle/flash_recovery_area/helowin/
bash: cd: /home/oracle/app/oracle/flash_recovery_area/helowin/: Permission denied
目录授权
$ su root
密码:helowin
[oracle@demo /]$ su root
Password:
[root@demo /]#
# cd /home/oracle/app/oracle/
# chown -R oracle.oinstall oradata
[root@demo oradata]# cd /home/oracle/app/oracle/
[root@demo oracle]#
[root@demo oracle]# ll
total 0
drwxr-x--- 1 oracle oinstall 21 Jan 4 2016 admin
drwxr-xr-x 5 oracle oinstall 43 Aug 23 2014 cfgtoollogs
drwxr-xr-x 3 oracle oinstall 17 Aug 23 2014 checkpoints
drwxrwxr-x 1 oracle oinstall 34 Aug 23 2014 diag
drwxr-x--- 4 oracle oinstall 36 Jan 4 2016 flash_recovery_area
drwxr-xr-x 3 root root 21 Aug 14 19:58 oradata
drwxr-xr-x 3 oracle oinstall 18 Aug 26 2014 oradiag_oracle
drwxr-xr-x 1 oracle oinstall 20 Aug 27 2014 product
[root@demo oracle]#
[root@demo oracle]# chown -R oracle.oinstall oradata
[root@demo oracle]#
[root@demo oracle]# ll
total 0
drwxr-x--- 1 oracle oinstall 21 Jan 4 2016 admin
drwxr-xr-x 5 oracle oinstall 43 Aug 23 2014 cfgtoollogs
drwxr-xr-x 3 oracle oinstall 17 Aug 23 2014 checkpoints
drwxrwxr-x 1 oracle oinstall 34 Aug 23 2014 diag
drwxr-x--- 4 oracle oinstall 36 Jan 4 2016 flash_recovery_area
drwxr-xr-x 3 oracle oinstall 21 Aug 14 19:58 oradata
drwxr-xr-x 3 oracle oinstall 18 Aug 26 2014 oradiag_oracle
drwxr-xr-x 1 oracle oinstall 20 Aug 27 2014 product
# cd /home/oracle/app/oracle/flash_recovery_area
# chown -R oracle.oinstall helowin
[root@demo oracle]# cd /home/oracle/app/oracle/flash_recovery_area
[root@demo flash_recovery_area]#
[root@demo flash_recovery_area]# ll
total 0
drwxr-x--- 4 oracle oinstall 41 Jan 4 2016 HELOWIN
drwxr-x--- 2 root root 52 Jan 4 2016 helowin
[root@demo flash_recovery_area]#
[root@demo flash_recovery_area]# chown -R oracle.oinstall helowin
[root@demo flash_recovery_area]#
[root@demo flash_recovery_area]# ll
total 0
drwxr-x--- 4 oracle oinstall 41 Jan 4 2016 HELOWIN
drwxr-x--- 2 oracle oinstall 52 Jan 4 2016 helowin
6、修改环境变量创建软连接
# vi /etc/profile
export ORACLE_HOME=/home/oracle/app/oracle/product/11.2.0/dbhome_2
export ORACLE_SID=helowin
export PATH=$ORACLE_HOME/bin:$PATH
# source /etc/profile
# ln -s $ORACLE_HOME/bin/sqlplus /usr/bin
[root@demo oracle]# vi /etc/profile
[root@demo oracle]# source /etc/profile
[root@demo oracle]# ln -s $ORACLE_HOME/bin/sqlplus /usr/bin
[root@demo oracle]#
7、重启数据库
# su - oracle
$ sqlplus / as sysdba
SQL> shutdown immediate;
SQL> startup
[oracle@demo ~]$ sqlplus / as sysdba
SQL*Plus: Release 11.2.0.1.0 Production on Thu Aug 15 17:47:24 2019
Copyright (c) 1982, 2009, Oracle. All rights reserved.
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
SQL>
SQL> shutdown immediate;
ORA-01507: database not mounted
ORACLE instance shut down.
SQL> startup
ORACLE instance started.
Total System Global Area 1603411968 bytes
Fixed Size 2213776 bytes
Variable Size 402655344 bytes
Database Buffers 1191182336 bytes
Redo Buffers 7360512 bytes
Database mounted.
Database opened.
SQL>
8、修改sys、system密码
SQL> alter user system identified by system;
SQL> alter user sys identified by sys;
设置密码永不过期
SQL> ALTER PROFILE DEFAULT LIMIT PASSWORD_LIFE_TIME UNLIMITED;
SQL> alter user system identified by system;
User altered.
SQL> alter user sys identified by sys;
User altered.
SQL> ALTER PROFILE DEFAULT LIMIT PASSWORD_LIFE_TIME UNLIMITED;
Profile altered.
SQL>
9、创建逻辑备份目录和普通用户存放的表空间的目录
$ cd /home/oracle/app/oracle/oradata
$ mkdir oracle_imp_exp
$ mkdir tablespace
SQL> exit
Disconnected from Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
[oracle@demo ~]$
[oracle@demo ~]$ cd /home/oracle/app/oracle/oradata
[oracle@demo oradata]$
[oracle@demo oradata]$ ls
helowin
[oracle@demo oradata]$
[oracle@demo oradata]$ mkdir oracle_imp_exp
[oracle@demo oradata]$ mkdir tablespace
[oracle@demo oradata]$ ll
total 0
drwxr-x--- 2 oracle oinstall 225 Jan 4 2016 helowin
drwxr-xr-x 2 oracle oinstall 6 Aug 15 19:11 oracle_imp_exp
drwxr-xr-x 2 oracle oinstall 6 Aug 15 19:12 tablespace
10、外部就可以测试连接了
已经成功连接上数据库
五、持久化数据异机迁移
1、关闭容器数据打包
# docker stop oracle11g-demo
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
416f7073da96 oracle_11g "/bin/sh -c ''/home..." 32 minutes ago Up 32 minutes 0.0.0.0:1521->1521/tcp oracle11g-demo
0237fc1d7882 oracle_11g "/bin/sh -c ''/home..." 36 minutes ago Up 36 minutes 1521/tcp oracle11g_test
[root@localhost ~]#
[root@localhost ~]# docker stop oracle11g-demo
oracle11g-demo
[root@localhost ~]#
数据打包
# tar zcvf oracle11g-demo-pub.tar.gz oracle11g-demo-pub/
[root@localhost ~]# cd /opt/
[root@localhost opt]#
[root@localhost opt]# ls
oracle11g-demo-pub
[root@localhost opt]#
[root@localhost opt]# tar zcvf oracle11g-demo-pub.tar.gz oracle11g-demo-pub/
2、迁移数据到别的Linux机器且具有docker环境
[root@localhost opt]# ls
ip.sh oracle11g-demo-pub oracle11g-demo-pub.tar.gz
[root@localhost opt]#
[root@localhost opt]# du -sh oracle11g-demo-pub.tar.gz
276M oracle11g-demo-pub.tar.gz
[root@localhost opt]#
[root@localhost opt]# du -sh oracle11g-demo-pub
1.6G oracle11g-demo-pub
# scp oracle11g-demo-pub.tar.gz root@192.168.2.207:/opt/
[root@localhost opt]# scp oracle11g-demo-pub.tar.gz root@192.168.2.207:/opt/
The authenticity of host ''192.168.2.207 (192.168.2.207)'' can''t be established.
ECDSA key fingerprint is SHA256:1Pr9kAu2Qnph9tGbSOiW0hshVdzR0NAwknNOX5KwQII.
ECDSA key fingerprint is MD5:df:5d:6a:b9:a9:80:76:37:b6:90:61:a2:f3:c3:c1:7c.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added ''192.168.2.207'' (ECDSA) to the list of known hosts.
root@192.168.2.207''s password:
oracle11g-demo-pub.tar.gz 100% 275MB 34.4MB/s 00:08
[root@localhost opt]#
3、另一台机器数据解压
# tar zxvf oracle11g-demo-pub.tar.gz
[root@docker-servers ~]# cd /opt/
[root@docker-servers opt]#
[root@docker-servers opt]# ls
oracle11g-demo-pub.tar.gz
[root@docker-servers opt]#
[root@docker-servers opt]# tar zxvf oracle11g-demo-pub.tar.gz
解压后
[root@docker-servers opt]# ls
oracle11g-demo-pub oracle11g-demo-pub.tar.gz
[root@docker-servers opt]#
[root@docker-servers opt]# du -sh oracle11g-demo-pub
1.6G oracle11g-demo-pub
[root@docker-servers opt]#
[root@docker-servers opt]# du -sh oracle11g-demo-pub.tar.gz
276M oracle11g-demo-pub.tar.gz
[root@docker-servers opt]#
4、创建容器
# docker run -v /opt/oracle11g-demo-pub/oradata:/home/oracle/app/oracle/oradata -v /opt/oracle11g-demo-pub/flash_recovery_area/helowin/:/home/oracle/app/oracle/flash_recovery_area/helowin/ -p 1521:1521 --name oracle11g-demo_new -h demo -d oracle_11g
5、重启数据库
# docker exec -it oracle11g-demo bash
$ su root
# su - oracle
$ sqlplus / as sysdba
SQL> shutdown immediate;
SQL> startup
[root@localhost opt]# docker exec -it oracle11g-demo bash
[oracle@demo /]$
[oracle@demo /]$ su root
Password:
[root@demo /]#
[root@demo /]# su - oracle
[oracle@demo ~]$
[oracle@demo ~]$ sqlplus / as sysdba
SQL*Plus: Release 11.2.0.1.0 Production on Sat Aug 17 22:11:22 2019
Copyright (c) 1982, 2009, Oracle. All rights reserved.
Connected to:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - 64bit Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options
SQL>
SQL> shutdown immediate;
Database closed.
Database dismounted.
ORACLE instance shut down.
SQL>
SQL>
SQL> startup
ORACLE instance started.
Total System Global Area 1603411968 bytes
Fixed Size 2213776 bytes
Variable Size 402655344 bytes
Database Buffers 1191182336 bytes
Redo Buffers 7360512 bytes
Database mounted.
Database opened.
SQL>
6、外部连接,测试数据是否存在
经实验,可以连接,并数据存在
参考博客
Docker拉取oracle11g镜像配置
https://blog.csdn.net/qq_38380025/article/details/80647620
Docker 下拉取oracle 11g镜像配置
https://blog.csdn.net/zwx521515/article/details/77982884
EMQ X 插件持久化系列 (三)EMQ X Redis 数据持久化
EMQ X 数据持久化简介
数据持久化的主要使用场景包括将客户端上下线状态,订阅主题信息,消息内容,消息抵达后发送消息回执等操作记录到 Redis、MySQL、PostgreSQL、MongoDB、Cassandra、AWS DynamoDB 等各类数据库中供外部服务快速查询或在服务宕机 / 客户端异常离线时保留当前运行状态,连接恢复时恢复到之前状态;持久化亦可用于客户端代理订阅,设备客户端上线时,持久化模块直接从数据库加载预设的主题并完成代理订阅,降低系统设计复杂度和减少客户端订阅通信开销。
用户也可以通过订阅相关主题的方式来实现类似的功能,但是在企业版中内置的这些持久化的支持执行效率更高、可靠性更强,大大降低了开发者的工作量并提升了系统稳定性。
数据持久化是 EMQ X 的重要功能,仅在企业版支持。
持久化设计
持久化原理是配置事件钩子触发时调用处理函数(action), 处理函数获取到相应的数据后按照配置的指令进行处理,实现数据的增、删、改、查。相同事件钩子在不同数据库中可用参数是一样的,但处理函数(action)因数据库特性不同有所差异。整个持久化工作模式和流程如下:
一对一消息存储
- Publish 端发布一条消息;
- Backend 将消息记录数据库中;
- Subscribe 端订阅主题;
- Backend 从数据库中获取该主题的消息;
- 发送消息给 Subscribe 端;
- Subscribe 端确认后 Backend 从数据库中移除该消息;
一对多消息存储
- PUB 端发布一条消息;
- Backend 将消息记录在数据库中;
- SUB1 和 SUB2 订阅主题;
- Backend 从数据库中获取该主题的消息;
- 发送消息给 SUB1 和 SUB2;
- Backend 记录 SUB1 和 SUB2 已读消息位置,下次获取消息从该位置开始。
Redis 数据持久化
本文以实际例子来说明如何通过 Redis 来存储相关的信息。
Redis 是完全开源免费遵守 BSD 协议的高性能 key-value 数据库。
相比其他 key-value 缓存产品 Redis 有以下特点:
- Redis 性能极高,单机支持十万级别的读写速度。
- Redis 支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
- Redis 不仅仅支持简单的 key-value 类型的数据,同时还提供 list,set,zset,hash 等数据结构的存储。
- Redis 支持数据的备份,即 master-slave 模式的数据备份。
读者可以参考 Redis 官方的 Quick Start 来安装 Redis(写本文的时候,Redis 版本为 5.0),通过 redis-server
命令来启动 Redis 服务器。
配置 EMQ X 服务器
通过 RPM 方式安装的 EMQ X,Redis 相关的配置文件位于 /etc/emqx/plugins/emqx_backend_redis.conf
,如果只是测试 Redis 持久化的功能,大部分配置不需要做更改。唯一需要更改的地方可能是 Redis 服务器的地址:如果读者安装的 Redis 不与 EMQ X 在同一服务器上,请指定正确的 Redis 服务器的地址与端口。如下所示:
## Redis Server 127.0.0.1:6379, Redis Sentinel: 127.0.0.1:26379
backend.redis.pool1.server = 127.0.0.1:6379
保持剩下部分的配置文件不变,然后启动该插件:
emqx_ctl plugins load emqx_backend_redis
客户端在线状态存储
客户端上下线时,更新在线状态、上下线时间、节点客户端列表至 Redis 数据库。
尽管 EMQ X 本身提供了设备在线状态 API,但在需要频繁获取客户端在线状态、上下线时间的场景下,直接从数据库获取该记录比调用 EMQ X API 更高效。
配置项
打开配置文件,配置 Backend 规则:
## 上线
backend.redis.hook.client.connected.1 = { "action": { "function": "on_client_connected" }, "pool": "pool1"}
## 下线
backend.redis.hook.client.disconnected.1 = {"action": {"function": "on_client_disconnected"}, "pool": "pool1"}
使用示例
浏览器打开 http://127.0.0.1:18083
EMQ X 管理控制台,在 工具 -> Websocket 中新建一个客户端连接,指定 clientid 为 sub_client:
打开 redis-cli
命令行窗口,执行命令 keys *
,结果如下所示,读者可以看到在 Redis 中存储了两个 key:
127.0.0.1:6379> keys *
1) "mqtt:node:emqx@127.0.0.1"
2) "mqtt:client:sub_client"
连接列表
插件以 mqtt:node:{node_name}
格式的 key 记录节点下客户端列表及连接时间戳信息,等效操作:
## redis key 为 mqtt:node:{node_name}
HMSET mqtt:node:emqx@127.0.0.1 sub_client 1542272836
字段说明:
## 节点下在线设备信息
127.0.0.1:6379> HGETALL mqtt:node:emqx@127.0.0.1
1) "sub_client1" # clientid
2) "1542272836" # 上线时间时间戳
3) "sub_client"
4) "1542272836"
连接详细信息
插件以 mqtt:client:{client_id}
格式的 key 记录客户端在线状态、上线时间,等效操作:
## redis key 为 mqtt:client:{client_id}
HMSET mqtt:client:sub_client state 1 online_at 1542272854
字段说明:
## 客户端在线状态
127.0.0.1:6379> HGETALL mqtt:client:sub_client
1) "state"
2) "0" # 0 离线 1 在线
3) "online_at"
4) "1542272854" # 上线时间戳
5) "offline_at"
6) "undefined" # 离线时间戳
客户端代理订阅
客户端上线时,存储模块直接从数据库读取预设待订阅列表,代理加载订阅主题。在客户端需要通过预定主题通信(接收消息)场景下,应用能从数据层面设定 / 改变代理订阅列表。
配置项
打开配置文件,配置 Backend 规则:
## hook: client.connected
## action/function: on_subscribe_lookup
backend.redis.hook.client.connected.2 = {"action": {"function": "on_subscribe_lookup"}, "pool": "pool1"}
使用示例
当 sub_client
设备上线时,需要为其订阅 sub_client/upstream
与 sub_client/downlink
两个 QoS 1 的主题:
- 插件以
mqtt:sub:{client_id}
格式 key 在 Redis 中初始化代理订阅 Hash:
## redis key 为 mqtt:sub:{client_id}
## HSET key {topic} {qos}
127.0.0.1:6379> HSET mqtt:sub:sub_client sub_client/upstream 1
(integer) 0
127.0.0.1:6379> HSET mqtt:sub:sub_client sub_client/downlink 1
(integer) 0
- EMQ X 管理控制台 WebSocket 页面,以 clientid
sub_client
新建一个客户端连接,切换至订阅页面,可见当前客户端自动订阅了sub_client/upstream
与sub_client/downlink
两个 QoS 1 的主题:
- 切换回管理控制台 WebSocket 页面,向
sub_client/downlink
主题发布消息,可在消息订阅列表收到发布的消息。
持久化发布消息
配置项
打开配置文件,配置 Backend 规则,支持使用 topic
参数进行消息过滤,此处使用 #
通配符存储任意主题消息:
## hook: message.publish
## action/function: on_message_publish
backend.redis.hook.message.publish.1 = {"topic": "#", "action": {"function": "on_message_publish"}, "pool": "pool1"}
使用示例
在 EMQ X 管理控制台 WebSocket 页面中,使用 clientid sub_client
建立连接,向主题 upstream_topic
发布多条消息。针对每条消息, EMQ X 将持久化消息列表、消息详情两条记录。
消息列表
EMQ X 将消息列表以 message id 持久化至 mqtt:msg:{topic}
Redis 集合中:
## 获取 upstream_topic 主题集合中所有 message id
127.0.0.1:6379> ZRANGE mqtt:msg:upstream_topic 0 -1
1) "2VFsyhDm0cPIQvnY9osj"
2) "2VFszTClyjpVtLDLrn1u"
3) "2VFszozkwkYOcbEy8QN9"
4) "2VFszpEc7DfbEqC97I3g"
5) "2VFszpSzRviADmcOeuXd"
6) "2VFszpm3kvvLkJTcdmGU"
7) "2VFt0kuNrOktefX6m4nP"
127.0.0.1:6379>
消息详情
每条消息详情将以 mqtt:msg:{message_id}
格式的 key 存储在 Redis Hash 中:
## 获取 message id 为 2VFt0kuNrOktefX6m4nP 的消息详情
127.0.0.1:6379> HGETALL mqtt:msg:2VFt0kuNrOktefX6m4nP
1) "id"
2) "2VFt0kuNrOktefX6m4nP" ## message id
3) "from"
4) "sub_client" ## client id
5) "qos"
6) "2"
7) "topic"
8) "up/upstream_topic"
9) "payload"
10) "{ \"cmd\": \"reboot\" }"
11) "ts"
12) "1542338754" ## pub 时间戳
13) "retain"
14) "false"
获取离线消息
配置项
打开配置文件,配置 Backend 规则:
## hook: session.subscribed
## action/function: on_message_fetch_for_queue、on_message_fetch_for_pubsub
## 一对一离线消息
backend.redis.hook.session.subscribed.1 = {"topic": "queue/#", "action": {"function": "on_message_fetch_for_queue"}, "pool": "pool1"}
## 一对多离线消息
backend.redis.hook.session.subscribed.2 = {"topic": "pubsub/#", "action": {"function": "on_message_fetch_for_pubsub"}, "pool": "pool1"}
使用示例
MQTT 离线消息需满足以下条件:
- 以 clean_session = false 连接
- 订阅 QoS > 0
- 发布 QoS > 0
在 EMQ X 管理控制台中以如下配置建立连接,
持久化 Retain 消息
配置项
打开配置文件,配置 Backend 规则:
## hook: message.publish
## action/function: on_client_connected、on_message_retain
backend.redis.hook.message.publish.2 = {"topic": "#", "action": {"function": "on_message_retain"}, "pool": "pool1"}
backend.redis.hook.message.publish.3 = {"topic": "#", "action": {"function": "on_retain_delete"}, "pool": "pool1"}
消息列表
EMQ X 将消息列表以 message id 持久化至 mqtt:retain:{topic}
Redis Hash 中:
## 获取 upstream_topic 主题集合中所有 message id
127.0.0.1:6379> ZRANGE mqtt:retain:upstream_topic 0 -1
1) "2VFsyhDm0cPIQvnY9osj"
127.0.0.1:6379>
消息详情
每条消息详情将以 mqtt:msg:{message_id}
格式的 key 存储在 Redis Hash 中:
## 获取 message id 为 2VFt0kuNrOktefX6m4nP 的消息详情
127.0.0.1:6379> HGETALL mqtt:msg:2VFt0kuNrOktefX6m4nP
1) "id"
2) "2VFt0kuNrOktefX6m4nP" ## message id
3) "from"
4) "sub_client" ## client id
5) "qos"
6) "2"
7) "topic"
8) "up/upstream_topic"
9) "payload"
10) "{ \"cmd\": \"reboot\" }"
11) "ts"
12) "1542338754" ## pub 时间戳
13) "retain"
14) "false"
总结
读者在理解了 Redis 中所存储的数据结构之后,可以利用各种 Redis 客户端来实现对相关信息的读取,
今天的关于大数据系列11:Gora – 大数据持久化和大数据 可持续发展的分享已经结束,谢谢您的关注,如果想了解更多关于5月16日云栖精选夜读:从0到1构建大数据生态系列1:数据蛮荒中的拓荒之举、docker 系列 - 容器数据持久化和数据共享、docker拉取oracle11g镜像并配置数据持久化、EMQ X 插件持久化系列 (三)EMQ X Redis 数据持久化的相关知识,请在本站进行查询。
本文标签: