Apache GeodeのRegion Shortcutsを解説する

### はじめに
Geodeにデータを登録する時は、Regionというデータ領域を作成することが前提となります。
データに対して、永続化したいのか、LRU形式で消していきたいのか、レプリケートしたいのか、データを分散したいのか、選択することになりますが、RegionのShortcutを利用することで、簡易に設定を行うことができます。
もちろん、個別に詳細な設定を行うことは可能ですが、その場合は、コマンドによる設定よりも、cache.xmlを作成することをオススメします。
公式のRegion Shortcutsは下記を参考にしてください。
[Region Shortcuts Reference](http://geode.apache.org/docs/guide/16/reference/topics/region_shortcuts_reference.html)

ショートカットには大きく３つに別れます。LOCAL、PARTITION、REPLICATE。
LOCALはローカルサーバへのデータ配置、PARTITIONはクラスタ内のサーバに分散してデータを配置、REPLICATEはクラスタ内のすべてのサーバでデータを配置します。
LOCALは利用ケースが限定されますし、REPLICATEは想像しやすいため、PARTITIONを主軸に説明していきます。

### PARTITIONの設定
今回は、locator1台、server３台のクラスタ構成で検証していきます。
まずは、locatorからPARTITIONのRegionを作成します。

```
gfsh>create region --name=pregion --type=PARTITION
Member  | Status
------- | --------------------------------------
server1 | Region "/pregion" created on "server1"
server2 | Region "/pregion" created on "server2"
server3 | Region "/pregion" created on "server3"
```
各serverへregionが作成されました。
続いてデータをputします。

```
gfsh>put --region=pregion --key=pkey --value=pvalue
Result      : true
Key Class   : java.lang.String
Key         : pkey
Value Class : java.lang.String
Old Value   : <NULL>
```
次にこのデータがどこに配置されてかを、metrics機能を使ってみてみましょう。

```
gfsh>show metrics --region=pregion --member=server1 --categories=partition

Metrics for region:/pregion On Member server1

Category  |           Metric            | Value
--------- | --------------------------- | -----
partition | putLocalRate                | 0.0
          | putRemoteRate               | 0.0
          | putRemoteLatency            | 0
          | putRemoteAvgLatency         | 0
          | bucketCount                 | 0
          | primaryBucketCount          | 0
          | configuredRedundancy        | 0
          | actualRedundancy            | 0
          | numBucketsWithoutRedundancy | 0
          | totalBucketSize             | 0

gfsh>show metrics --region=pregion --member=server2 --categories=partition

Metrics for region:/pregion On Member server2

Category  |           Metric            | Value
--------- | --------------------------- | -----
partition | putLocalRate                | 0.0
          | putRemoteRate               | 0.0
          | putRemoteLatency            | 0
          | putRemoteAvgLatency         | 0
          | bucketCount                 | 0
          | primaryBucketCount          | 0
          | configuredRedundancy        | 0
          | actualRedundancy            | 0
          | numBucketsWithoutRedundancy | 0
          | totalBucketSize             | 0

gfsh>show metrics --region=pregion --member=server3 --categories=partition

Metrics for region:/pregion On Member server3

Category  |           Metric            | Value
--------- | --------------------------- | -----
partition | putLocalRate                | 0.0
          | putRemoteRate               | 0.0
          | putRemoteLatency            | 0
          | putRemoteAvgLatency         | 0
          | bucketCount                 | 1
          | primaryBucketCount          | 1
          | configuredRedundancy        | 0
          | actualRedundancy            | 0
          | numBucketsWithoutRedundancy | 0
          | totalBucketSize             | 1

```
server3にのみ、bucketCountとprimaryBucketCountが増加しました。
今回のputされた結果は、server3に配置されたようです。

では、server3が停止してしまった場合、このデータはどうなってしまうでしょうか。

```
gfsh>stop server --name=server3
Stopping Cache Server running in /xxxx/geode/server3 on xxx04.yahoo.co.jp[40404] as server3...
Process ID: 26662

gfsh>get --region=pregion --key=pkey 
Result      : false
Key Class   : java.lang.String
Key         : pkey
Value Class : java.lang.String
Value       : <NULL>
```
データは消えてしまいまいした。
PARTITIONは分散してデータを保持するので、大量のデータを保持するのに向いていますが、
サーバダウンなどで、データがロストするのは許容できないケースもあるかもしれません。
### PARTITION_REDUNDANT
REDUNDANTを利用するとクラスタ内の別のサーバにコピーを置いておくことができます。

```
gfsh>create region --name=prregion --type=PARTITION_REDUNDANT
Member  | Status
------- | ---------------------------------------
server1 | Region "/prregion" created on "server1"
server2 | Region "/prregion" created on "server2"
server3 | Region "/prregion" created on "server3"

gfsh>put --region=prregion --key=pkey --value=pvalue
Result      : true
Key Class   : java.lang.String
Key         : pkey
Value Class : java.lang.String
Old Value   : <NULL>
```
さて、どのように配置されたでしょうか。

```
gfsh>show metrics --region=prregion --member=server1 --categories=partition

Metrics for region:/prregion On Member server1

Category  |           Metric            | Value
--------- | --------------------------- | -----
partition | putLocalRate                | 0.0
          | putRemoteRate               | 0.0
          | putRemoteLatency            | 0
          | putRemoteAvgLatency         | 0
          | bucketCount                 | 1
          | primaryBucketCount          | 0
          | configuredRedundancy        | 1
          | actualRedundancy            | 1
          | numBucketsWithoutRedundancy | 0
          | totalBucketSize             | 1

gfsh>show metrics --region=prregion --member=server2 --categories=partition

Metrics for region:/prregion On Member server2

Category  |           Metric            | Value
--------- | --------------------------- | -----
partition | putLocalRate                | 0.0
          | putRemoteRate               | 0.0
          | putRemoteLatency            | 0
          | putRemoteAvgLatency         | 0
          | bucketCount                 | 1
          | primaryBucketCount          | 1
          | configuredRedundancy        | 1
          | actualRedundancy            | 1
          | numBucketsWithoutRedundancy | 0
          | totalBucketSize             | 1

# server3はオール0のため割愛
```
server2にbucketCountとprimaryBucketCountが付き、server1にbucketCountが付きました。
では、server2を落とすとどうなるでしょうか。

```
gfsh>stop server --name=server2
Stopping Cache Server running in /xxxx/geode/server2 on xxx03.yahoo.co.jp[40404] as server2...
Process ID: 16789

gfsh>get --region=prregion --key=pkey
Result      : true
Key Class   : java.lang.String
Key         : pkey
Value Class : java.lang.String
Value       : pvalue
```
データは無事取得できました。分散状況はどうなったのでしょうか。

```
gfsh>show metrics --region=prregion --member=server1 --categories=partition

Metrics for region:/prregion On Member server1

Category  |           Metric            | Value
--------- | --------------------------- | -----
partition | putLocalRate                | 0.0
          | putRemoteRate               | 0.0
          | putRemoteLatency            | 0
          | putRemoteAvgLatency         | 0
          | bucketCount                 | 1
          | primaryBucketCount          | 1
          | configuredRedundancy        | 1
          | actualRedundancy            | 1
          | numBucketsWithoutRedundancy | 0
          | totalBucketSize             | 1

gfsh>show metrics --region=prregion --member=server3 --categories=partition

Metrics for region:/prregion On Member server3

Category  |           Metric            | Value
--------- | --------------------------- | -----
partition | putLocalRate                | 0.0
          | putRemoteRate               | 0.0
          | putRemoteLatency            | 0
          | putRemoteAvgLatency         | 0
          | bucketCount                 | 1
          | primaryBucketCount          | 0
          | configuredRedundancy        | 1
          | actualRedundancy            | 1
          | numBucketsWithoutRedundancy | 0
          | totalBucketSize             | 1
```
server1がprimaryデータになり、server3がコピーを保持しています。
しかし、これでは、サーバが全ダウンしてしまうと、結局、データは消えてしまいます。
### PARTITION_PERSISTENT
PERSISTENTはデータをディスクに書き込むことで永続化を実現します。

```
gfsh>create region --name=ppragion --type=PARTITION_PERSISTENT
Member  | Status
------- | ---------------------------------------
server1 | Region "/ppragion" created on "server1"
server2 | Region "/ppragion" created on "server2"
server3 | Region "/ppragion" created on "server3"

gfsh>put --region=ppragion --key=ppkey --value=ppvalue
Result      : true
Key Class   : java.lang.String
Key         : ppkey
Value Class : java.lang.String
Old Value   : <NULL>

gfsh>show metrics --region=ppragion --member=server3 --categories=partition

Metrics for region:/ppragion On Member server3

Category  |           Metric            | Value
--------- | --------------------------- | -----
partition | putLocalRate                | 0.0
          | putRemoteRate               | 0.0
          | putRemoteLatency            | 0
          | putRemoteAvgLatency         | 0
          | bucketCount                 | 1
          | primaryBucketCount          | 1
          | configuredRedundancy        | 0
          | actualRedundancy            | 0
          | numBucketsWithoutRedundancy | 0
          | totalBucketSize             | 1

#他のserverはオール0です
```
通常のPARTITIONと同様に１つのserverにのみデータが配置されます。
serverを落としてデータを取得してみます。

```
gfsh>stop server --name=server3
Stopping Cache Server running in /xxxx/geode/server3 on xxx02.yahoo.co.jp[40404] as server3...
Process ID: 29016

gfsh>get --region=ppragion --key=ppkey 
Message : Region /ppragion bucket 41 has persistent data that is no longer online stored at these locations: [/xxx.xxx.xxx.xx2:/xxxx/geode/server3/. created at timestamp 1529286342011 version 0 diskStoreId 128a514489e64645-929e75128346f8f4 name null]
Result  : false
```
少しいつもとエラー内容が違いますが、データの取得は当然できませんでした。
再度、立ち上げます。

```
# server3
gfsh>start server --name=server3 --locators=xxx02.yahoo.co.jp[10334]
Starting a Geode Server in /home/mkatsube/geode/server3...

# locator1
gfsh>get --region=ppragion --key=ppkey 
Result      : true
Key Class   : java.lang.String
Key         : ppkey
Value Class : java.lang.String
Value       : ppvalue
```
データが復活しました。

ちなみに、REDUNDANTとPERSISTENTを組み合わせたPARTITION_REDUNDANT_PERSISTENTというものもあります。
### メモリあふれ時の方針
メモリに制限がある以上、データが増え続け、増設しないのであればデータはあふれてしまいます。
ショートカットとしては、HEAP_LRUとOVERFLOWの2つの手段が用意されています。
HEAP_LRUはLRU（Least Recently Used）形式で使われていないデータから消えていきます。OVERFLOWも設定上はLRUになっており、データは消さずに、ディスクに書き込まれます。

今回は割愛しますが、以前、HEAP_LRUの検証をしてたところ、HEAP_LRUの設定が効くことは確認できたのですが、その時は、かなり過剰にデータが消えてしまったので、いずれ再検証してみたいと思います。
###まとめ
REPLICATEがすべてのサーバでデータを保持するという点がわかれば、ここまでの説明で、ショートカットの概ねの挙動が理解できると思います。
どのショートカットを選択するかは、データの量とライフサイクル方針、永続化の必要性、サーバの信頼性などを勘案しながら決定していくことになります。

Rgionのより細かい設定については、またの機会に。

次回は、Geodeの[Javaクライアント](https://qiita.com/mkatsube0605/items/ff2aa540e4c5f689851f)について書きます。

### おまけ
運用時、バグによる不正データが大量に発生したため、一旦、Region内のデータを全削除が必要になったのですが。
PARTITIONは、removeのall削除が効かないので困りました。下手な作業をして動作不良になっても困るため、その時は、サーバを再構築しました。（すべて全自動化されているため、その方が早いため）

```
gfsh>remove --region=ppragion --all
Result  : false
Message : Option --all is not supported on partitioned region
```

### 参考
[公式 cache.xmlの説明](https://geode.apache.org/docs/guide/16/reference/topics/chapter_overview_cache_xml.html)