ソースURL:https://github.com/zhzhair/stepsrank-spring-boot.git。
1.サブテーブル32を作成し、ステップアナログアップロードタイマタスクをユーザの数カウントデータ挿入ステップと、
前記アイテムが初期化を開始します。記録紙32の前面200は、前面200に空にした後、セットのMongoDB(テーブル)に挿入され名前が記録されている
とのRedisにステップ200の数(閾値);
3.ユーザが閾値より大きい場合、工程数をアップロードし、ステップの数は、MongoDBの挿入、又は記録されたMongoDBの中に挿入されていない。
4.定期的なタスク10秒ごとに205のMongoDB後でテーブル内のレコードを削除し、
200の5更新タイマタスク数(閾値)を1秒毎にステップRedisのために、記録Redisのキューにしばらくトップ200;
6。 MongoDBのテーブルを確認するために行ってきました見つけ出す、キューRedisのステップ数を照会することが第一位。
同時テスト7.jmeterクエリのパフォーマンスを確認します。
プログラミングの概要:
テクニカルアーキテクチャ:java8、春のboot2.0.0、mysqlの、 Redisの、MongoDBは、MyBatisの、闊歩、JMeterは、アイデア、達人。
(I)試験データ追加:ユーザID 32に従って新たなテーブル32は、毎秒300件のレコードを追加または変更し、別のテーブルにタスクを実行するタイミングをモジュロテストデータを追加しています。USER_IDとテーブルは、ステップの数は(ステップの新しい番号を追加するために)、ユーザは、ユーザのステップ数の変更に記録日を有する場合、ステップの累積数は、しばらく毎に一度携帯電話を渡すと仮定し、2つのフィールドSTEP_COUNT、またはレコード直接添加含みます。次のようにコードの一部:
@LogForTask
@Scheduled( "?* * * * 0/1" =クーロン)
公共ボイドuploadStep(){//スケジュールされたタスクを毎秒300のレコードの追加または変更
()IntStream.range(0300).PARALLELを.forEach(I-> stepService.uploadStep(32));
}
(II)プログラミング:高同時メモリの場合(メモリ不足の例外!)の関心事である、単一の文書には、あまりにも多くのデータを入れないでMongoDBの、あなたは、メモリから読み出されたディスクを設定する必要があります。それは大きなテーブルのソートを避けるために、「ダウンサイジング」照会表に、しきい値として使用することができるように考慮に入れると最初の200のステップの合計数は、減少し、より「安定」より後方にされることはありません。
初期化(すなわち、場合プロジェクト開始):表32の事前のMongoDBこと200が文書内に配置される必要があり、200番号は内部のRedisにステップ200に格納されている間、前の文書とその文書のBSONを置き換えるために、一部コードは次のとおりです。
@Resource
プライベートstepService stepServiceは、
プライベート静的StepServiceサービス。
@PostConstruct
公共ボイドのinit(){
サービス= this.stepServiceと、
}
静的な無効メインパブリック(文字列[]引数){
SpringApplication.run(StepsApplication.class、引数);
//ランキングプロジェクトの初期化開始
service.recordTopAll(32);
}
@Override
公共ボイドrecordTopAll(INT tableCount){
mongoTemplate.dropCollection( StepsTop.class); //ドキュメントを削除
IntStream.range(0、tableCount).PARALLEL( )はforEach(本:: insertOneTable);. // MySQLはMongoのドキュメントにデータを挿入する
200リストを削除する前に置きます/ *、 Mongoのは、リストデータの現在の文書データを更新する* /
.. =(新しい新しいソート(Sort.Direction.DESC、「totalCountプロパティ」))の制限(200は)を使用して新しい新しいクエリクエリクエリ();
リスト<StepsTop> = mongoTemplateリスト。検索(クエリ、StepsTop.class);
IF(list.isEmpty())のリターン;
mongoTemplate.dropCollection(StepsTop.class);
mongoTemplate.insertAll(一覧);
/ * Redisの格納閾値- * /の数最初のステップ200
INTサイズが= Math.min(200であり、はlist.size());
。redisTemplate.opsForValue()SET(redisKey、String.valueOf(List.get(サイズ- 1).getTotalCount()));
}
ステップ数がアップロード:Redisのタスクのデータ更新タイミングを行い、閾値、閾値段階の数は、受信または更新されるたびに比べて工程数を増やす、この閾値より、この「より」非常に頻繁になりますモンゴ、モンゴのドキュメントをチェックし、更新を行うかの操作を挿入するために出て取得しますが、Redisの「恐れない」高い同時実行、我々は心配する必要はありません。これは非常に非常に迅速にデータのクエリとMongoの文書をソートした後、データの小さな量を確保するために、文書のモンゴ、モンゴドキュメントの操作を軽減します。コードの一部を次のように
@Override
公共ボイドuploadStep(INT tableCount){
にuserId INT新しい新しい=ランダム()nextInt(500_0000);.
のInt 1 + =新しい新しいStepCountランダム()nextInt(5000);.。
整数COUNT = commonMapper.getStepCount(接頭辞をuserIdの%+は、ユーザーID)をtableCount;
IF(COUNT = null)を{!
commonMapper.updateSteps(接頭辞+ tableCountはuserIdの%は、ユーザーID、StepCount + COUNT);
}他{
commonMapper.insertTables(接頭辞+はuserId%tableCountは、ユーザーID、stepCount)。
}
文字列tailSteps = redisTemplate.opsForValue()(redisKey)を得ます。
int型totalCountプロパティ= == nullのstepCountを数える:?+ stepCountを数えます。
もし(tailSteps!= nullの&& totalCountプロパティ> Integer.valueOf(tailSteps)){//步数超过阈值就插入或更新用户的记录
クエリのクエリ=新しいクエリ(Criteria.where( "userIdを")。(USERID)です) ;
(もし!mongoTemplate.exists(クエリ、StepsTop.class)){
StepsTop stepsTop =新しいStepsTop();
stepsTop.setUserId(USERID)。
stepsTop.setTotalCount(stepCount)。
mongoTemplate.insert(stepsTop)。
} {他
のSystem.out.println( "更新" + tailSteps)。
アップデートアップデート=新しいアップデート();
update.set( "totalStep"、totalCountプロパティ);
mongoTemplate.upsert(クエリ、更新、StepsTop.class);
}
}他{
StepsTop stepsTop新しい新しいStepsTop =();
stepsTop.setUserId(USERID);
stepsTop.setTotalCount(StepCount)。
mongoTemplate.insert(stepsTop);
}
}
タイマタスク:10秒ごとの閾値は、文書200 Mongoの以外のデータを削除、更新、Redisのをプッシュする順序付けられたデータの上位200の毎秒行からクエリをモンゴキューは、順位が簡単にRedisのから削除します。コードの一部が次のように
オーバーライドが閾値200よりMongoの削除文書データ更新// @
公共ボイドflushRankAllを(){
「totalCountプロパティ」//新しい新しいクエリのクエリのクエリ=()(新しい新しいソート(Sort.Direction.DESCと。))限界(201);
//リスト<StepsTop> mongoTemplate.find一覧=(クエリ、StepsTop.class); //やすい高度に並行シナリオメモリ例外:メモリ例外のうち
TypedAggregation <StepsTop>集約キーワード= Aggregation.newAggregation(
StepsTop.class、
プロジェクト( "はuserId"、 "totalCountプロパティ")で使用される、//クエリフィールド
の並べ替え(Sort.Direction.DESC、 "totalCountプロパティ")、
リミット(200)
).withOptions(newAggregationOptions()allowDiskUse(真).build()); // ディスクの読み取りおよび書き込み、高い並行性に対処するのに十分なメモリ
AggregationResults <StepsTop>結果= mongoTemplate.aggregate(凝集、StepsTop.class、StepsTop.class)。
リスト<StepsTop> = results.getMappedResultsリスト();
IF(はlist.size()== 201){
int型= List.get totalCountプロパティ(199).getTotalCount();
クエリのクエリQuery1を新しい新=(Criteria.where(「totalCountプロパティ「).LT(totalCountプロパティ));
mongoTemplate.remove(Query1を、StepsTop.class);
}
}
200のRedisのは、プッシュするキューの前に@オーバーライド//クエリは、データをソートし
ます。public void recordRankAll(){
//クエリのクエリ=新しい新しいクエリを()(新しい新しいソート(Sort.Direction.DESC、 "totalCountプロパティ"))で。 .limit(200は);
//リスト<StepsTop> mongoTemplate.find一覧=(クエリ、StepsTop.class);
TypedAggregation <StepsTop> = Aggregation.newAggregation集約(
StepsTop.class、
プロジェクト( "はuserId"、 "totalCountプロパティ")、 //クエリフィールドが使用される
ソート(Sort.Direction.DESC、 "totalCountプロパティ")、
制限(200)
。).withOptions(newAggregationOptions()(真の)allowDiskUse .buildを()); //ディスクに十分なメモリが読み取りおよび書き込み高い並行処理への対応
AggregationResults <StepsTop>結果= mongoTemplate.aggregate(集約、StepsTop.class、StepsTop.class);
リスト<StepsTop> results.getMappedResults一覧=();
IF(はlist.size()== 200){
List.get StepCount =整数(199).getTotalCount();
redisTemplate.opsForValue()SET(redisKey、String.valueOf(StepCount));.
}
IF(list.isEmpty()!){
RedisListTemplate.delete(redisQueueKey)。
未確認// noinspection
redisListTemplate.opsForList()rightPushAll(redisQueueKey、リスト);.
}
}
クエリリスト:今、単純な、直接クエリに缶Redisのキュー、コードの一部を次のよう
@ApiOperation(値=「クエリーステップ日の合計位置番号は、クエリ日ランキング工程の合計数"=ノート" ")
@RequestMappingを(値=" / getRankAll」、メソッドRequestMethod.GET = {} = {MediaType.APPLICATION_JSON_VALUEが生産})
パブリックBaseResponse <リスト<>> getRankAll StepsRankAllResp (開始のint、int型のpageSize){
BaseResponse <リスト<>> StepsRankAllResp基地=新しい基地応答レスポンス<>();
一覧<StepsRankAllResp>リスト= stepService.getRankAllFromRedis(、pageSizeをし始めます)。
もし(list.isEmpty())リスト= stepService.getRankAll(、pageSizeをし始める); // Redisの查不到数据就从モンゴ查
baseResponse.setCode(0);
baseResponse.setMsg( "返回数据成功");
baseResponse.setData(リスト);
baseResponseを返します。
}
@ // TODOの从のRedisのを上書き读取
パブリックリスト<StepsRankAllResp> getRankAllFromRedisを(int型開始、INTページサイズを){
リスト<StepsTop> stepsList = redisListTemplate.opsForList()範囲(redisQueueKeyを、pageSizeをを開始します)。
一覧<StepsRankAllResp>リスト=新しいArrayListを<>(stepsList.size());
以下のために(INT i = 0; iは++; iはstepsList.size()<){
=新しいStepsRankAllResp StepsRankAllResp stepsRankAllRespを();
StepsTop = stepsList.get StepsTop(I);
BeanUtils.copyProperties(stepsTop、stepsRankAllResp);
stepsRankAllResp.setRank;(私は+始める+ 1)
List.add(stepsRankAllResp);
}
戻り値のリスト;
}
JMeterの同時試験:アクセスインタフェース文書- -http:// localhostを:8080 /闊歩 -ui.html /、 インタフェースクエリ調整位置は、5秒のインターフェイスコンフィギュレーション5000を調整し、重合は次のように: