2023年8月

etcd 学习笔记

在一个分布式系统中, ETCD 可以:

  1. 分布式的高度一致性的 Key-Value 存储.
  2. 支持 Service 自动发现.
  3. 高并发 每秒10000次写.
  4. 支持双向认证.
  5. 2379 客户请求, 2380 peer 通信.

CAP理论: The CAP theorem states that distributed systems can have at most two out of three of the following properties: high levels of data consistency, high availability of access to the data, and tolerance of network partitions. Networks cannot be assumed to be reliable, so distributed systems need to account for network partitions. Hence, in terms of the CAP theorem, distributed systems can either be AP or CP.

docker 安装 单实例

文档 https://etcd.io/docs/v2.3/docker_guide/ 命令稍有差别 1)改版本, 2) 改etcd 的命令路径

$ export HostIP="10.249.64.103"
$ docker run -d --restart always -v /usr/share/ca-certificates/:/etc/ssl/certs -p 4001:4001 -p 2380:2380 -p 2379:2379 \
 --name etcd quay.io/coreos/etcd /usr/local/bin/etcd \
 -name etcd0 \
 -advertise-client-urls http://${HostIP}:2379,http://${HostIP}:4001 \
 -listen-client-urls http://0.0.0.0:2379,http://0.0.0.0:4001 \
 -initial-advertise-peer-urls http://${HostIP}:2380 \
 -listen-peer-urls http://0.0.0.0:2380 \
 -initial-cluster-token etcd-cluster-1 \
 -initial-cluster etcd0=http://${HostIP}:2380 \
 -initial-cluster-state new

登录测试:

$ docker exec -it etcd sh
$ etcdctl
$ etcdctl --endpoints=http://localhost:2379 member list

认证

参考: https://etcd.io/docs/v3.5/demo/
auth, user, rule

版本差别

如果你发现你的 etcdctl 的命令比较少, 那有可能是你使用的版本是V2的命令行, 虽然你的 etcdctl 是 V3 的. 要显示设置使用 v3 的命令 (If using released versions earlier than v3.4, set ETCDCTL_API=3 to use v3 API.):

$ ETCDCTL_API=3 ./etcdctl --endpoints=http://127.0.0.1:2379 get "" --prefix

证书认证参数

这4个global 参数可以通过环境变量设置:
--dial-timeout, --cacert, --cert, --key

ETCDCTL_DIAL_TIMEOUT=3s
ETCDCTL_CACERT=/tmp/ca.pem
ETCDCTL_CERT=/tmp/cert.pem
ETCDCTL_KEY=/tmp/key.pem

ETCDCTL_API=3 /usr/local/bin/etcdctl --endpoints=https://localhost:2379 \
              --cert=/etc/etcdtls/etcd-client.crt \
              --key=/etc/etcdtls/etcd-client.key \
              --cacert=/etc/etcdtls/etcd-client-ca.crt get mykey

KV 命令

$ etcdctl put name eric --lease 2e128a4084e72b83
OK
$ etcdctl put name yuan  --lease 2e128a4084e72b83 --prev-kv
OK
name
eric

lease 命令

增: grant, 删: revoke, 改: keep-alive, 查: list, timetolive.

$ etcdctl lease grant  10
lease 2e128a4084e7269c granted with TTL(10s)
$ etcdctl lease revoke  2e128a4084e7269c
lease 2e128a4084e7269c revoked
$ etcdctl lease timetolive  2e128a4084e7269f
lease 2e128a4084e7269f already expired
$ etcdctl lease timetolive 2d8257079fa1bc0c --keys
# lease 2d8257079fa1bc0c granted with TTL(500s), remaining(472s), attached keys([foo2 foo1])
$ etcdctl lease list
32695410dcc0ca06
$ /etcdctl lease keep-alive 32695410dcc0ca0

lock 命令

$ etcdctl lock mylock
# mylock/1234534535445
$ etcdctl lock mylock1 --ttl 10
mylock1/2e128a4084e72b61
$ etcdctl lock mylock echo lock acquired
# lock acquired
$ etcdctl lock mylock ./etcdctl put foo bar
# OK

elect

candidate or observer

$ etcdctl elect president biden
president/2e128a4084e72b68
biden

$ etcdctl elect president -
president/2e128a4084e72b68
biden

$ etcdctl elect president trump

endpoint

查询 revision

etcdctl endpoint status

watch

etcdctl watch --rev=123 /foo

container 里面没有 shell

今天本地搭建了一个 etcd 的服务器, 然后接下来想用 etcdctl 去测试一些命令, 于是想去用 container 里面的这个命令, 然后执行 docker exec -it etcd sh, 竟然得到没有这个文件, 然后又试了 bash 也没有.

首先 google 一把, 发现确实有人遇到同样的问题:
https://stackoverflow.com/questions/39900369/how-could-i-get-files-from-a-docker-container-running-the-official-etcd-image-if

按照上面的答案, 我们一个个去试一下:

docker export 导出整个container 文件

$ docker export etcd > /tmp/etcd.tar
$ ls -lah /tmp/etcd.tar
-rw-rw-r-- 1 supra supra 193M Aug 27 23:51 etcd.tar
$ mkdir /tmp/etcd
$ tar xvf /tmp/etcd.tar -C /tmp/etcd
$ ls -lah /tmp/etcd/bin/
total 8.0K
drwxr-xr-x  2 supra supra 4.0K Apr  2 04:55 .
drwxrwxr-x 16 supra supra 4.0K Aug 27 23:53 ..

$ find /tmp/etcd/ -name etcdctl
/tmp/etcd/usr/local/bin/etcdctl

可以看到, /bin 目录啥都没有. 但是我们找到了 etcdctl 在哪里.

docker cp 复制出 /bin 目录

$ mkdir /tmp/tmpbin
$ docker cp etcd:/bin /tmp/tmpbin/
$ ls -lah /tmp/tmpbin/bin/

可以看到内部啥也没有.

gremlin 操作 janusgraph 的基本语句

核心概念:

  1. Vertex, Edge, Property.
  2. Graph, Directed.
  3. 图数据库即是内存密集型也是CPU密集型.
  4. 图数据库做为其它数据库的一个补充.

建立本地连接

:remote connect tinkerpop.server conf/remote.yaml session
:remote console timeout none

打印 schema

mgmt = graph.openManagement()
mgmt.printSchema()
mgmt.printVertexLabels()
mgmt.printEdgeLabels()
mgmt.printPropertyKeys()
mgmt.printIndexes()

create schema & index

mgmt = graph.openManagement()
batch = mgmt.makeVertexLabel('batch').make()
date = mgmt.makePropertyKey('date').dataType(String.class).make()
hour = mgmt.makePropertyKey('hour').dataType(Integer.class).make()
mgmt.addProperties(batch, date, hour)

mgmt.buildIndex('indexBatchByDateHour', Vertex.class).addKey(date).addKey(hour).buildCompositeIndex()

# 只在这个 Vertex 上的 index
mgmt.buildIndex('indexBatchByDateHour', Vertex.class).addKey(date).addKey(hour).indexOnly(batch).unique().buildCompositeIndex()

mgmt.commit()
g.tx().commit();

对已有数据建立 index

graph.tx().rollback()
mgmt = graph.openManagement()
key = mgmt.getPropertyKey('key')
myIndex = mgmt.buildIndex('byKey', Vertex.class).addKey(key).unique().buildCompositeIndex()
mgmt.commit()
graph.tx().commit();

//Wait for the index to become available
ManagementSystem.awaitGraphIndexStatus(graph, 'byKey').call()


//Reindex the existing data
mgmt = graph.openManagement()
mgmt.updateIndex(mgmt.getGraphIndex("byKey"), SchemaAction.REINDEX).get()
mgmt.commit()

未结束的 transactions

graph.getOpenTransactions()
graph.getOpenTransactions().getAt(0).rollback()
graph.getOpenTransactions().getAt(0).commit()

查看 index

mgmt.getGraphIndexes(Vertex.class)
mgmt.getGraphIndexes(Edge.class)
mgmt.getGraphIndex("indexBatchByDateHour")

查看 console 信息

$> Gremlin.version()
$> :show imports

查看当前 Graph 支持的 features

$ graph.features()
$ graph.toString()

使用 tinkergraph

$ :plugin use tinkerpop.tinkergraph
$ graph = TinkerGraph.open()
$ g = graph.traversal()

注入 JavaScript on chrome 网页

为什么需要这个功能

有时候, 我们不能更改一个别人做的网页, 但是发现这个页面有些方面不是自己习惯的, 或者它给它添加某些功能, 那么我们可能需要通过页面 注入JavaScript的方式去修改或增强它.

如何做

你可以在每次打开这个页面的时候, 运行一段 JavaScript脚本. 但是这样需要每次都手工打开 Inspect 然后打开console 然后运行脚本.

如果我们可以让它每次打开这页面的时候, 自动执行这个脚本, 岂不是更棒.

所以, 我们可以通过写一个 chrome extension 的方式, 让它自动注入这些脚本.

并且我们可以定义很多自定义脚本, 每当打开某些网页的时候, 自动注入.

最简单的例子

一共4步, 每一步都很简单.

1. 创建一个文件夹

mkdir myext

2. 创建 manifest.json

在上面的文件夹中创建文件 manifest.json, 内容如下:

{
  "manifest_version": 3,
  "name": "My Extension",
  "version": "1.0",
  "permissions": [
    "tabs"
  ],
  "host_permissions": [
    "https://www.google.com/"
  ],
  "content_scripts": [
    {
      "matches": [
        "https://www.google.com/"
      ],
      "js": [
        "google.js"
      ]
    }
  ]
}

3. 创建需要注入的脚本

在上面的文件夹中创建需要注入的脚本文件, 这里跟上面 content_scripts.js里面的保持一致就好.

console.log("running on google.com");

document.querySelector("textarea").value = "llama";
document.querySelector("input[value='Google Search']").click();

4. 加载新插件

打开 chrome 的 extension 管理界面, 然后在页面右上角打开: 开发者模式, 然后选择 加载未打包 的extension, 加载完成后测试即可.