mongodb实验报告_Dropwizard,MongoDB和Gradle实验
mongodb實驗報告
介紹
我使用Dropwizard,MongoDB和Gradle創建了一個小項目。 它實際上是作為一個實驗性的Guava緩存開始的,作為將計數器發送到MongoDB(或任何其他DB)的緩沖區。 我也想嘗試MondleDB插件的Gradle。 接下來,我想創建某種界面來檢查此框架,因此我決定嘗試使用DropWizard。 這就是這個項目的創建方式。
本文不是使用任何選定技術的教程。 這是一個小展示柜,我做過實驗。 我猜有一些缺陷,也許我沒有使用所有“最佳實踐”。 但是,我確實相信,在本文的幫助下,該項目可以成為我使用的各種技術的良好起點。 我還嘗試顯示一些設計選擇,這些選擇有助于實現SRP,去耦,內聚等。
我決定從用例描述及其實現方式開始。 之后,我將解釋我對Gradle,MongoDB(和嵌入式)和Dropwizard所做的工作。
在開始之前,這里是源代碼:
- https://github.com/eyalgo/CountersBuffering
用例:帶緩沖區的計數器
我們對服務器有一些輸入請求。 在請求過程中,我們選擇用一些數據(由某些邏輯決定)“繪制”它。 有些請求將由Value-1繪制,某些請求將由Value-2繪制,等等。有些將根本不會繪制。 我們要限制繪畫請求的數量(每個繪畫值)。 為了有限制,對于每個繪制值,我們知道最大值,但是還需要計算(每個繪制值)繪制請求的數量。 由于系統具有多個服務器,因此計數器應由所有服務器共享。
延遲至關重要。 通常,每個請求處理會得到4-5毫秒(對于所有流程。不僅僅是繪畫)。 因此,我們不希望增加計數器會增加延遲。 相反,我們將保留一個緩沖區,客戶端將向緩沖區發送“增加”。 緩沖區將定期以“批量增量”增加存儲庫。
我知道可以直接使用Hazelcast或Couchbase或其他類似的快速內存數據庫。 但是對于我們的用例,那是最好的解決方案。
原理很簡單:
- 從屬模塊將調用服務以增加某個密鑰的計數器
- 該實現為每個鍵保留一個計數器緩沖區
- 這是線程安全的
- 編寫在單獨的線程中進行
- 每次寫入都會大量增加
柜臺高級設計
緩沖
對于緩沖區,我使用了Google Guava 緩存 。
緩沖結構
創建緩沖區:
private final LoadingCache<Counterable, BufferValue> cache; ...this.cache = CacheBuilder.newBuilder().maximumSize(bufferConfiguration.getMaximumSize()).expireAfterWrite(bufferConfiguration.getExpireAfterWriteInSec(), TimeUnit.SECONDS).expireAfterAccess(bufferConfiguration.getExpireAfterAccessInSec(), TimeUnit.SECONDS).removalListener((notification) -> increaseCounter(notification)).build(new BufferValueCacheLoader()); ...( 可逆的描述如下)
BufferValueCacheLoader實現了CacheLoader接口。 當我們調用增加(見下文)時,我們首先通過鍵從緩存中獲取。 如果鍵不存在,則加載器返回值。
BufferValueCacheLoader:
public class BufferValueCacheLoader extends CacheLoader<Counterable, BufferValue> {@Overridepublic BufferValue load(Counterable key) {return new BufferValue();} }BufferValue包裝一個AtomicInteger (在某些時候我需要將其更改為Long)
增加柜臺
增加計數器,如果超過閾值則發送:
public void increase(Counterable key) {BufferValue meter = cache.getUnchecked(key);int currentValue = meter.increment();if (currentValue > threashold) {if (meter.compareAndSet(currentValue, currentValue - threashold)) {increaseCounter(key, threashold);}} }當增加一個計數器時,我們首先從緩存中獲取當前值(在加載程序的幫助下。如上所述)。 compareAndSet將自動檢查是否具有相同的值(未被另一個線程修改)。 如果是這樣,它將更新該值并返回true。 如果成功(返回true),則緩沖區調用更新程序。
查看緩沖區
開發服務之后,我想要一種查看緩沖區的方法。 因此,我實現了以下方法,該方法由前端層(Dropwizard的資源)使用。 Java 8 Stream和Lambda表達式的小示例。
獲取所有計數器在緩存中:
return ImmutableMap.copyOf(cache.asMap()).entrySet().stream().collect(Collectors.toMap((entry) -> entry.getKey().toString(),(entry) -> entry.getValue().getValue()));MongoDB
我之所以選擇MongoDB是因為兩個原因:
我試圖設計系統,以便可以選擇其他任何持久性實現并進行更改。
我使用嗎啡作為MongoDB客戶端層,而不是直接使用Java客戶端。 使用Morphia,您可以創建dao ,它是與MongoDB集合的連接。 您還聲明了一個簡單的Java Bean(POJO),它表示集合中的文檔。 一旦有了dao,就可以使用相當簡單的API以“ Java方式”對集合進行操作。 您可以查詢和其他任何CRUD操作,以及更多。
我有兩個操作:增加計數器和獲取所有計數器。 服務實現不擴展Morphia的BasicDAO,而是具有一個繼承它的類。 我使用了組合 (過度繼承),因為我希望兩種服務都具有更多的行為。
為了與鍵表示保持一致,并從依賴代碼中隱藏其實現方式,我使用了一個接口:可通過單個方法counterCount()來 抵消 。
public interface Counterable {String counterKey(); }DAO,是服務內部的組成部分:
final class MongoCountersDao extends BasicDAO<Counter, ObjectId> {MongoCountersDao(Datastore ds) {super(Counter.class, ds);} }增加柜臺
MongoCountersUpdater擴展了實現CountersUpdater的AbstractCountersUpdater:
@Override protected void increaseCounter(String key, int value) {Query<Counter> query = dao.createQuery();query.criteria("id").equal(key);UpdateOperations<Counter> ops = dao.getDs().createUpdateOperations(Counter.class).inc("count", value);dao.getDs().update(query, ops, true); }嵌入式MongoDB
為了在持久層上運行測試,我想使用內存數據庫。 有一個MongoDB插件。 使用此插件,您可以通過僅在運行時創建服務器來運行服務器,或者在Gradle中的maven / task中作為目標運行。
- https://github.com/flapdoodle-oss/de.flapdoodle.embed.mongo
- https://github.com/sourcemuse/GradleMongoPlugin
Gradle上的嵌入式MongoDB
稍后我將詳細介紹Gradle,但這是設置嵌入式mongo所需的操作。
dependencies {// More dependencies heretestCompile 'com.sourcemuse.gradle.plugin:gradle-mongo-plugin:0.4.0' }設置屬性
mongo {// logFilePath: The desired log file path (defaults to 'embedded-mongo.log')logging 'console'mongoVersion 'PRODUCTION'port 12345// storageLocation: The directory location from where embedded Mongo will run, such as /tmp/storage (defaults to a java temp directory) }嵌入式MongoDB Gradle任務
- startMongoDb只會啟動服務器。 它將運行直到停止它。
- stopMongoDb將停止它。
- startManagedMongoDb test ,這兩個任務將在測試運行之前啟動嵌入式服務器。 jvm完成(測試完成)后,服務器將關閉
盡管我只觸碰到冰山一角,但我開始看到Gradle的力量。 設置項目甚至都不是那么困難。
Gradle設置
首先,我在eclipse中創建了Gradle項目(安裝插件后)。 我需要設置依賴項。 很簡單。 就像行家一樣。
一個大的JAR輸出
當我想從Maven中的所有庫中創建一個大jar時,我會使用shade插件。 我在尋找類似的東西,并發現gradle-one-jar插入。 https://github.com/rholder/gradle-one-jar我添加了該插件apply plugin: 'gradle-one-jar' 。 在類路徑中添加了一個jar:
buildscript {repositories { mavenCentral() }dependencies {classpath 'com.sourcemuse.gradle.plugin:gradle-mongo-plugin:0.4.0'classpath 'com.github.rholder:gradle-one-jar:1.0.4'} }并添加了一個任務:
mainClassName = 'org.eyalgo.server.dropwizard.CountersBufferApplication' task oneJar(type: OneJar) {mainClass = mainClassNamearchiveName = 'counters.jar'mergeManifestFromJar = true }這些是我需要執行的必要操作,才能使應用程序運行。
Dropwizard
Dropwizard是一堆庫,可以輕松快速地創建Web服務器。 它將Jetty用于HTTP,將Jersey用于REST。 它具有其他成熟的庫來創建復雜的服務。 它可以用作易于開發的微服務。
正如我在簡介中所解釋的,我不會介紹Dropwizard的所有功能和/或設置。 有很多的網站。 我將簡要介紹為使應用程序運行而執行的操作。
Gradle運行任務
run { args 'server', './src/main/resources/config/counters.yml' }第一個參數是服務器。 第二個參數是配置文件的位置。 如果不將Dropwizard作為第一個參數,則會收到有關可能選項的錯誤消息。
positional arguments:{server,check} available commands我已經在Gradle部分中展示了如何創建一個jar。
組態
在Dropwizard中,您可以使用擴展Configuration的類來設置應用程序。 類中的字段應與yml配置文件中的屬性對齊。
優良作法是根據屬性的用途/職責將其分組。 例如,我為mongo參數創建了一個組。
為了使配置類正確讀取子組,您需要創建一個與組中的屬性對齊的類。
然后,在主配置中,將該類添加為成員,并使用批注進行標記: @JsonProperty 。
例:
@JsonProperty("mongo") private MongoServicesFactory servicesFactory = new MongoServicesFactory(); @JsonProperty("buffer") private BufferConfiguration bufferConfiguration = new BufferConfiguration();示例:更改端口
這是配置文件的一部分,用于設置應用程序的端口。
server:adminMinThreads: 1adminMaxThreads: 64applicationConnectors:- type: httpport: 9090adminConnectors:- type: httpport: 9091健康檢查
Dropwizard提供了開箱即用的基本管理API。 我將端口更改為9091。我為MongoDB連接創建了運行狀況檢查。 您需要擴展HealthCheck并實施檢查方法。
private final MongoClient mongo; ... protected Result check() throws Exception {try {mongo.getDatabaseNames();return Result.healthy();} catch (Exception e) {return Result.unhealthy("Cannot connect to " + mongo.getAllAddress());} }其他功能幾乎是不言自明的,或者像任何入門教程一樣簡單。
增強想法
這些是我可能會嘗試添加的內容。
- 將測試添加到Dropwizard部分。
該項目以PoC開頭,因此與往常不同,我跳過了服務器部分中的測試。
Dropwizard擁有“ 測試Dropwizard” ,我想嘗試一下。 - 不同的持久性實現。 (couchbase?Hazelcast?)。
- 使用Google Guice進行注射。 并借助它注入不同的持久性實現。
就這樣。 希望有幫助。
- 源代碼: https : //github.com/eyalgo/CountersBuffering
翻譯自: https://www.javacodegeeks.com/2015/02/dropwizard-mongodb-and-gradle-experimenting.html
mongodb實驗報告
總結
以上是生活随笔為你收集整理的mongodb实验报告_Dropwizard,MongoDB和Gradle实验的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 拟彻底“抛弃”半导体业务 百年东芝退市后
- 下一篇: guava集合操作类的使用_使用Guav