-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adjust user memory via api #4917
base: master
Are you sure you want to change the base?
Conversation
58fdb50
to
12467b7
Compare
@@ -426,3 +426,22 @@ object EventMessage extends DefaultJsonProtocol { | |||
|
|||
def parse(msg: String) = Try(format.read(msg.parseJson)) | |||
} | |||
|
|||
case class ByteSizeMessage(userMemory: ByteSize) extends Message { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the name should denote its purpose more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm.. already changed it from ByteSizeMessage
to UserMemoryMessage
``` | ||
Note: you can add `?limit` to specify target invokers, e.g. specify invoker0 and invoker1 | ||
``` | ||
curl -u ${username}:${password} -X POST http://${controllerAddress}:${controllerPort}/config/memory?limit=0:1 -d '1024 MB' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel this API should be based on JSON and have a better protocol.
For example, the name of the invoker may not be simple like just invoker0
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently, i changed it to like below
curl -u admin:admin -X POST http://xxx.xxx.xxx.xxx:10001/config/memory -d '
[{"invoker":0,"memory": "20480 MB"}, {"invoker":1,"memory": "10240 MB"}]
'
@@ -305,6 +308,13 @@ class ContainerPool(childFactory: ActorRefFactory => ActorRef, | |||
case RescheduleJob => | |||
freePool = freePool - sender() | |||
busyPool = busyPool - sender() | |||
case message: ByteSizeMessage => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hope this also has a more detailed protocol.
This might be extended for general configurations.
@@ -74,6 +76,7 @@ class ContainerPool(childFactory: ActorRefFactory => ActorRef, | |||
var busyPool = immutable.Map.empty[ActorRef, ContainerData] | |||
var prewarmedPool = immutable.Map.empty[ActorRef, PreWarmedData] | |||
var prewarmStartingPool = immutable.Map.empty[ActorRef, (String, ByteSize)] | |||
var latestUserMemory = poolConfig.userMemory |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I hope we can avoid using var
if possible.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm.. seems the lastUserMemory
need to support changable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can take advantage of Option
.
s"user memory is reconfigured from ${latestUserMemory.toString} to ${message.userMemory.toString}") | ||
latestUserMemory = message.userMemory | ||
case UserMemoryQuery => | ||
sender() ! latestUserMemory.toString |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about sending the intact obejct directly and handle the type conversion in the InvokerServer layer?
I think this kind of type conversion is only related to the InvokerServer and the client.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hm..
When we want to change invoker's user memory, in this pr, need to send the request to controller, there has one benefit that can modfiy many invoker's user memory with one request only. e.g.
curl -u admin:admin -X POST http://xxx.xxx.xxx.xxx:10001/config/memory -d '
[
{"invoker":0,"memory": "20480 MB"},
{"invoker":1,"memory": "10240 MB"}
{"invoker":2,"memory": "51200 MB"}
]
'
if send change invoker user memory
request to invokerServer, if want to modify many invokers's user memory, need to send http request many times.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok since this is just a ByteSize
I think we can take this approach.
entity(as[String]) { memory => | ||
try { | ||
val userMemoryMessage = ByteSizeMessage(ByteSize.fromString(memory)) | ||
if (userMemoryMessage.userMemory.size == 0) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is not the only precondition to configure memory.
This value can be smaller than MemoryLimit.min
then invokers would not be able to run any container.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated accordingly, the user meomry can't be less than MemoryLimit.min
logging.info( | ||
this, | ||
s"user memory is reconfigured from ${latestUserMemory.toString} to ${message.userMemory.toString}") | ||
latestUserMemory = message.userMemory |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even if controllers check the validity of this value, it would be great to cross-check the value again in the invoker layer.
And regarding the check, I feel the application should not concern the condition of the underlying host.
But on the other hand, I am not sure it would be reasonable to allow a bigger memory than the invoker host has.
I would defer this to other reviewers.
f9dd602
to
c7f68ff
Compare
* @param userMemory | ||
* @param targetInvokers | ||
*/ | ||
def sendUserMemoryToInvoker(userMemoryMessage: UserMemoryMessage, targetInvoker: Int): Unit = {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about changing the name like this?
def sendUserMemoryToInvoker(userMemoryMessage: UserMemoryMessage, targetInvoker: Int): Unit = {} | |
def sendChangeRequestToInvoker(userMemoryMessage: UserMemoryMessage, targetInvoker: Int): Unit = {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated
extractCredentials { | ||
case Some(BasicHttpCredentials(username, password)) => | ||
if (username == controllerCredentials.username && password == controllerCredentials.password) { | ||
entity(as[String]) { memory => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can't we directly convert this to ConfigMemoryList
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, updated.
entity(as[String]) { memory => | ||
val configMemoryList = memory.parseJson.convertTo[ConfigMemoryList] | ||
|
||
val existIllegalUserMemory = configMemoryList.items.exists { configMemory => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Scalaism. I think we can change this something like this:
configMemoryList.items.find(MemoryLimit.MIN_MEMORY.compare(.memory) > 0)) match {
case Some() =>
// reject the request
case None =>
}
@@ -74,6 +76,7 @@ class ContainerPool(childFactory: ActorRefFactory => ActorRef, | |||
var busyPool = immutable.Map.empty[ActorRef, ContainerData] | |||
var prewarmedPool = immutable.Map.empty[ActorRef, PreWarmedData] | |||
var prewarmStartingPool = immutable.Map.empty[ActorRef, (String, ByteSize)] | |||
var latestUserMemory = poolConfig.userMemory |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we can take advantage of Option
.
s"user memory is reconfigured from ${latestUserMemory.toString} to ${message.userMemory.toString}") | ||
latestUserMemory = message.userMemory | ||
case UserMemoryQuery => | ||
sender() ! latestUserMemory.toString |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok since this is just a ByteSize
I think we can take this approach.
@@ -220,9 +223,3 @@ trait InvokerServerProvider extends Spi { | |||
def instance( | |||
invoker: InvokerCore)(implicit ec: ExecutionContext, actorSystem: ActorSystem, logger: Logging): BasicRasService | |||
} | |||
|
|||
object DefaultInvokerServer extends InvokerServerProvider { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is this removed?
This is being used.
https://github.com/apache/openwhisk/blob/master/common/scala/src/main/resources/reference.conf#L30
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I moved it to core/invoker/src/main/scala/org/apache/openwhisk/core/invoker/DefaultInvokerServer.scala
} | ||
|
||
case class ConfigMemory(invoker: Int, memory: ByteSize) | ||
case class ConfigMemoryList(items: List[ConfigMemory]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe we can directly unmarshal a list of ConfigMemory
rather than haveing this case class.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated
def parse(msg: String) = Try(serdes.read(msg.parseJson)) | ||
} | ||
|
||
case class ConfigMemory(invoker: Int, memory: ByteSize) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about changing the name to InvokerConfiguration
.
We might extend this to other invoker configurations as well in the future.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated
c7f68ff
to
65086cf
Compare
Description
Related issue and scope
My changes affect the following components
Types of changes
Checklist: