Amazon Simple Queue Service или SQS — это масштабируемая размещенная очередь сообщений, предоставляемая стеком Amazon Webservice. Amazon SQS можно использовать для полного разделения операций различных компонентов в системе, которые в противном случае обмениваются данными для выполнения независимых задач. Amazon SQS также помогает нам сохранять данные, которые будут потеряны в случае неработоспособности приложения или недоступности одного из компонентов.
Особенности Amazon SQS (скопировано непосредственно с сайта Amazon)
- Резервная инфраструктура — гарантирует доставку ваших сообщений как минимум один раз, высококонкурентный доступ к сообщениям и высокую доступность для отправки и получения сообщений.
- Несколько писателей и читателей. Несколько частей вашей системы могут отправлять или получать сообщения одновременно. SQS блокирует сообщение во время обработки, не позволяя другим частям вашей системы обрабатывать сообщение одновременно.
- Настраиваемые параметры для каждой очереди — все ваши очереди не обязательно должны быть одинаковыми. Например, одна очередь может быть оптимизирована для сообщений, которые требуют более длительного времени обработки, чем другие.
- Переменный размер сообщения — Ваши сообщения могут быть размером до 65536 байт (64 КиБ). Для более крупных сообщений вы можете хранить содержимое сообщения с помощью Amazon Simple Storage Service (Amazon S3) или Amazon SimpleDB и использовать Amazon SQS для хранения указателя на объект Amazon S3 или Amazon SDB. Кроме того, вы можете разбить большее сообщение на более мелкие.
- Контроль доступа — вы можете контролировать, кто может отправлять сообщения в очередь, а кто может получать сообщения из очереди.
- Очереди задержки. Очередь задержки — это та, в которой пользователь устанавливает задержку по умолчанию для очереди, так что доставка всех помещенных в очередь сообщений будет отложена на этот период времени. Вы можете установить значение задержки при создании очереди с помощью CreateQueue и обновить значение с помощью SetQueueAttributes. Если вы обновите значение, новое значение повлияет только на сообщения, помещенные в очередь после обновления.
Имея указанные выше знания, давайте попробуем использовать SQS для создания простого сервиса обработки фотографий.
Определение задачи для учебника
Мы будем создавать простое приложение для обработки фотографий со следующими компонентами.
- Photo Uploader serivce — это веб-сервис, который позволяет пользователям загружать фотографии в систему. После загрузки фотографии хранятся во временном хранилище. Для простоты будем предполагать, что пользователь уже загрузил фотографию и сохранил ее в заранее определенном месте.
- AWSSimpleQueueServiceUtil — это служебный класс, который упаковывает клиента Amazon SQS и выполняет основные операции CRUD в очереди SQS.
- PhotoProcessingManager — управляет всем шоу. Он вызовет AWSSimpleQueueServiceUtil для отправки / получения сообщений в SQS, а также вызовет PhotoProcessor для обработки фотографии и, наконец, удаления сообщения из очереди. В основном мы должны использовать этот класс в качестве прослушивателя SQS, но для простоты мы просто будем использовать механизм опроса для извлечения сообщений из SQS.
- PhotoProcessor — получает фото-сообщение из SQS через PhotoProcessingManager и генерирует миниатюру.
Прежде чем начать, было бы здорово, если бы вы просмотрели видео по следующей ссылке: http://docs.aws.amazon.com/AWSSimpleQueueService/latest/SQSGettingStartedGuide/Welcome.html
Шаги для начала работы
- Создайте аккаунт Amazon. Вам понадобится кредитная карта для этого
- Войдите в свою консоль console.aws.amazon.com .
- На панели управления консоли найдите SQS и нажмите на нее. Он доставит вас к вашему дому SQS.
- Создайте новую очередь SQS и назовите ее PhotoQueue. Оставьте остальные настройки по умолчанию. Мы также можем динамически создавать и удалять очередь SQS, но в этом уроке у меня есть предварительно созданная очередь, которую я буду использовать в своем коде.
- Теперь у нас есть очередь, и теперь мы создадим простой проект Java в нашем любимом редакторе Java и посмотрим, как мы можем использовать эту очередь.
- Как только вы закончите, вам нужно загрузить свои учетные данные безопасности. Для этого перейдите в раздел «Моя учетная запись» / «Учетные данные безопасности». Что нам нужно, так это учетные данные для доступа. Вы увидите, что существует 3 типа учетных данных, один из которых — «Ключи доступа». Нам это нужно для доступа к PhotoQueue и работы с ним, которые мы только что создали. Мы создадим новый набор ключей доступа и сохраним ключ доступа, а секретный ключ будет в безопасном месте.
- Теперь загрузите SDK для Java здесь. http://aws.amazon.com/sdkforjava . В папке lib sdk скопируйте файл aws-java-sdk-1.3.33.jar в путь к классам вашего проекта.
Пользователи Maven могут добавлять следующие зависимости в свои POM
12345<
dependency
>
<
groupId
>com.amazonaws</
groupId
>
<
artifactId
>aws-java-sdk</
artifactId
>
<
version
>1.3.33</
version
>
</
dependency
>
Создайте файл с именем «AwsCredentials.properties» и сохраните его в своем проекте. Этот файл будет содержать следующие свойства
12accessKey =
secretKey =
Значения этих свойств — это ключ доступа, который вы сгенерировали на шаге 6.
- Для обработки фотографий я использую imgscalr . Это легкая и удивительная библиотека для обработки фотографий в java для выполнения простых задач, таких как изменение размера, поворот, обрезка и т. Д. Вы можете скачать jar с http://www.thebuzzmedia.com/software/imgscalr-java-image-scaling-library / # скачать . Пользователи Maven могут добавить следующее в свой список зависимостей.
1234567
<
dependency
>
<
groupId
>org.imgscalr</
groupId
>
<
artifactId
>imgscalr-lib</
artifactId
>
<
version
>4.2</
version
>
<
type
>jar</
type
>
<
scope
>compile</
scope
>
</
dependency
>
Теперь мы готовы к рок-н-роллу и пачкать руки кодом.
AWSSimpleQueueServiceUtil.java
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
package com.aranin.adconnect.util.aws; import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.services.sqs.AmazonSQS; import com.amazonaws.services.sqs.AmazonSQSClient; import com.amazonaws.services.sqs.model.*; import java.io.FileInputStream; import java.util.List; import java.util.Properties; /** * Created by IntelliJ IDEA. * User: Niraj Singh * Date: 3/19/13 * Time: 10:44 AM * To change this template use File | Settings | File Templates. */ public class AWSSimpleQueueServiceUtil { private BasicAWSCredentials credentials; private AmazonSQS sqs; private String simpleQueue = "PhotoQueue" ; private static volatile AWSSimpleQueueServiceUtil awssqsUtil = new AWSSimpleQueueServiceUtil(); /** * instantiates a AmazonSQSClient http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/sqs/AmazonSQSClient.html * Currently using BasicAWSCredentials to pass on the credentials. * For SQS you need to set your regions endpoint for sqs. */ private AWSSimpleQueueServiceUtil(){ try { Properties properties = new Properties(); properties.load( new FileInputStream( "D:/samayik/adkonnection/src/main/resources/AwsCredentials.properties" )); this .credentials = new BasicAWSCredentials(properties.getProperty( "accessKey" ), properties.getProperty( "secretKey" )); this .simpleQueue = "PhotoQueue" ; this .sqs = new AmazonSQSClient( this .credentials); /** * My queue is in singapore region which has following endpoint for sqs * you can find your endpoints here * * Overrides the default endpoint for this client ("sqs.us-east-1.amazonaws.com") */ /** You can use this in your web app where AwsCredentials.properties is stored in web-inf/classes */ //AmazonSQS sqs = new AmazonSQSClient(new ClasspathPropertiesFileCredentialsProvider()); } catch (Exception e){ System.out.println( "exception while creating awss3client : " + e); } } public static AWSSimpleQueueServiceUtil getInstance(){ return awssqsUtil; } public AmazonSQS getAWSSQSClient(){ return awssqsUtil.sqs; } public String getQueueName(){ return awssqsUtil.simpleQueue; } /** * Creates a queue in your region and returns the url of the queue * @param queueName * @return */ public String createQueue(String queueName){ CreateQueueRequest createQueueRequest = new CreateQueueRequest(queueName); String queueUrl = this .sqs.createQueue(createQueueRequest).getQueueUrl(); return queueUrl; } /** * returns the queueurl for for sqs queue if you pass in a name * @param queueName * @return */ public String getQueueUrl(String queueName){ GetQueueUrlRequest getQueueUrlRequest = new GetQueueUrlRequest(queueName); return this .sqs.getQueueUrl(getQueueUrlRequest).getQueueUrl(); } /** * lists all your queue. * @return */ public ListQueuesResult listQueues(){ return this .sqs.listQueues(); } /** * send a single message to your sqs queue * @param queueUrl * @param message */ public void sendMessageToQueue(String queueUrl, String message){ SendMessageResult messageResult = this .sqs.sendMessage( new SendMessageRequest(queueUrl, message)); System.out.println(messageResult.toString()); } /** * gets messages from your queue * @param queueUrl * @return */ public List<Message> getMessagesFromQueue(String queueUrl){ ReceiveMessageRequest receiveMessageRequest = new ReceiveMessageRequest(queueUrl); List<Message> messages = sqs.receiveMessage(receiveMessageRequest).getMessages(); return messages; } /** * deletes a single message from your queue. * @param queueUrl * @param message */ public void deleteMessageFromQueue(String queueUrl, Message message){ String messageRecieptHandle = message.getReceiptHandle(); System.out.println( "message deleted : " + message.getBody() + "." + message.getReceiptHandle()); sqs.deleteMessage( new DeleteMessageRequest(queueUrl, messageRecieptHandle)); } public static void main(String[] args){ } } |
PhotoProcessor.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
package com.aranin.adconnect.util.aws; import org.imgscalr.Scalr; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.File; /** * Created by IntelliJ IDEA. * User: Niraj Singh * Date: 3/19/13 * Time: 12:32 PM * To change this template use File | Settings | File Templates. */ public class PhotoProcessor { public static void generateImage(String imagePath, String origName, String targetName, int scalabity){ String origImage = null ; String targetImage = null ; File origFile = null ; BufferedImage buffImg = null ; File targetFile = null ; try { origImage = imagePath + "/" + origName; targetImage = imagePath + "/" + targetName; origFile = new File(origImage); buffImg = ImageIO.read(origFile); buffImg = Scalr.resize(buffImg, Scalr.Method.SPEED, scalabity); targetFile = new File(targetImage); ImageIO.write(buffImg, "jpeg" , targetFile); } catch (Exception e){ System.out.println( "Exception in processing image : " + e); } finally { buffImg = null ; } } } |
PhotoFile.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
|
package com.aranin.adconnect.util.aws; /** * Created by IntelliJ IDEA. * User: Niraj Singh * Date: 3/19/13 * Time: 12:29 PM * To change this template use File | Settings | File Templates. */ public class PhotoFile { private String origName; private String targetName; public String imagePath; public String getOrigName() { return origName; } public void setOrigName(String origName) { this .origName = origName; } public String getTargetName() { return targetName; } public void setTargetName(String targetName) { this .targetName = targetName; } public String getImagePath() { return imagePath; } public void setImagePath(String imagePath) { this .imagePath = imagePath; } public String toString(){ return origName + "," + targetName + "," + imagePath; } } |
SQSPhotoManager.java
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
|
package com.aranin.adconnect.util.aws; import com.amazonaws.services.sqs.model.Message; import java.util.List; import java.util.StringTokenizer; /** * Created by IntelliJ IDEA. * User: Niraj Singh * Date: 3/20/13 * Time: 11:38 AM * To change this template use File | Settings | File Templates. */ public class SQSPhotoManager implements Runnable{ private String queueUrl; public static void main(String[] args){ AWSSimpleQueueServiceUtil awssqsUtil = AWSSimpleQueueServiceUtil.getInstance(); /** * 1. get the url for your photo queue */ String queueUrl = awssqsUtil.getQueueUrl(awssqsUtil.getQueueName()); System.out.println( "queueUrl : " + queueUrl); /** * 2. Add a photo to the queue to be processed */ PhotoFile photo = new PhotoFile(); photo.setImagePath( "C:/Users/Public/Pictures/Sample Pictures" ); photo.setOrigName( "Tree.jpg" ); photo.setTargetName( "Tree_thumb.jpg" ); /** * 3. set the photofile in queue for processing */ awssqsUtil.sendMessageToQueue(queueUrl, photo.toString()); /** * get the messages from queue */ Thread managerthread = new Thread( new SQSPhotoManager(queueUrl), "T2" ); managerthread.start(); } public SQSPhotoManager(String queueUrl){ this .queueUrl = queueUrl; } @Override public void run() { AWSSimpleQueueServiceUtil awssqsUtil = AWSSimpleQueueServiceUtil.getInstance(); boolean flag = true ; while (flag){ List<Message> messages = awssqsUtil.getMessagesFromQueue( this .queueUrl); if (messages == null || messages.size() == 0 ){ try { Thread.sleep( 1000 ); } catch (InterruptedException e) { e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates. } } else { flag = false ; for (Message message : messages) { String messagePhoto = message.getBody(); System.out.println( "photo to be processed : " + messagePhoto); StringTokenizer photoTokenizer = new StringTokenizer(messagePhoto, "," ); String source = null ; String target = null ; String path = null ; source = photoTokenizer.nextToken(); target = photoTokenizer.nextToken(); path = photoTokenizer.nextToken(); System.out.println( "source : " + source); System.out.println( "target : " + target); System.out.println( "path : " + path); /** * generate thumbmail within 150*150 container */ PhotoProcessor.generateImage(path, source, target, 150 ); } /** * finally delete the message */ for (Message message : messages) { awssqsUtil.deleteMessageFromQueue( this .queueUrl, message); } } } } } |
Это сформирует ядро для вашего приложения PhotoProcessor с помощью SQS. Этот код имеет явный недостаток. Он опрашивает SQS с использованием потока, было бы здорово, если бы вы могли создать в своем коде прослушиватель, который может подписаться на вашу очередь и предпринимать необходимые действия при поступлении нового сообщения. Это действительно тема моего следующего поста. Пока не стесняйтесь бомбардировать меня вопросами, вместе мы сможем найти ответ на них.